From c91d2d6b292d95cf93b091121f56c94b55ac8fd0 Mon Sep 17 00:00:00 2001 From: threeandthreee Date: Mon, 24 Feb 2025 10:06:10 -0500 Subject: [PATCH] merge upstream/main --- .github/pyright-config.json | 16 +- .github/workflows/ctest.yml | 4 +- .github/workflows/strict-type-check.yml | 2 +- BaseClasses.py | 40 +- CommonClient.py | 61 +- Fill.py | 28 +- Generate.py | 25 +- LinksAwakeningClient.py | 4 + LttPAdjuster.py | 5 + Main.py | 3 +- MultiServer.py | 104 +- NetUtils.py | 9 +- OoTAdjuster.py | 2 - Options.py | 24 +- Utils.py | 27 +- WebHostLib/api/__init__.py | 4 +- WebHostLib/api/user.py | 2 +- WebHostLib/customserver.py | 5 +- WebHostLib/static/assets/faq/en.md | 2 +- data/client.kv | 5 + data/lua/connector_bizhawk_generic.lua | 29 +- data/lua/connector_oot.lua | 4 +- docs/CODEOWNERS | 6 +- docs/entrance randomization.md | 18 +- docs/network protocol.md | 13 +- docs/options api.md | 2 +- docs/world api.md | 37 +- entrance_rando.py | 5 +- kvui.py | 82 +- pytest.ini | 3 + requirements.txt | 2 +- settings.py | 25 +- test/benchmark/locations.py | 10 +- test/cpp/CMakeLists.txt | 6 +- test/general/__init__.py | 10 +- test/general/test_entrance_rando.py | 31 + test/general/test_entrances.py | 63 + test/general/test_helpers.py | 11 +- test/general/test_implemented.py | 11 +- test/general/test_items.py | 4 +- test/general/test_locations.py | 6 + test/general/test_memory.py | 11 +- test/general/test_names.py | 4 +- test/general/test_reachability.py | 4 +- test/general/test_state.py | 29 + worlds/AutoWorld.py | 4 + worlds/LauncherComponents.py | 12 +- worlds/_bizhawk/README.md | 10 +- worlds/_bizhawk/__init__.py | 38 +- worlds/_bizhawk/client.py | 16 +- worlds/_bizhawk/context.py | 25 +- worlds/adventure/Options.py | 5 +- worlds/adventure/Regions.py | 2 +- worlds/adventure/Rom.py | 12 +- worlds/adventure/__init__.py | 23 +- worlds/ahit/DeathWishRules.py | 18 +- worlds/ahit/Locations.py | 7 +- worlds/ahit/Options.py | 2 +- worlds/ahit/Rules.py | 14 +- worlds/ahit/__init__.py | 4 +- worlds/ahit/docs/setup_en.md | 4 +- worlds/alttp/Bosses.py | 4 +- worlds/alttp/Client.py | 2 +- worlds/alttp/ItemPool.py | 5 +- worlds/alttp/Items.py | 8 +- worlds/alttp/Rules.py | 6 +- worlds/alttp/Shops.py | 3 +- worlds/alttp/StateHelpers.py | 47 +- worlds/alttp/docs/multiworld_es.md | 241 +- worlds/alttp/test/dungeons/TestGanonsTower.py | 14 +- worlds/alttp/test/dungeons/TestMiseryMire.py | 2 +- worlds/aquaria/__init__.py | 11 +- worlds/blasphemous/__init__.py | 6 +- worlds/celeste64/docs/guide_en.md | 8 +- worlds/dark_souls_3/docs/setup_en.md | 68 +- worlds/dkc3/Client.py | 3 +- worlds/dkc3/Items.py | 2 +- worlds/dkc3/Options.py | 3 +- worlds/dkc3/Regions.py | 5 +- worlds/dkc3/Rom.py | 3 +- worlds/dkc3/Rules.py | 4 +- worlds/dkc3/__init__.py | 8 +- worlds/factorio/Client.py | 5 +- worlds/factorio/Options.py | 30 +- worlds/factorio/__init__.py | 29 +- worlds/factorio/data/mod/lib.lua | 104 + worlds/factorio/data/mod_template/control.lua | 24 +- worlds/factorio/test_file_validation.py | 39 + worlds/faxanadu/__init__.py | 23 +- worlds/ffmq/Options.py | 3 +- worlds/ffmq/__init__.py | 11 +- worlds/hk/Options.py | 2 +- worlds/hk/__init__.py | 84 +- worlds/hk/test/__init__.py | 1 - worlds/hk/test/test_grub_count.py | 3 +- worlds/kdl3/rules.py | 34 +- worlds/kh1/Regions.py | 3 + worlds/kh1/__init__.py | 9 +- worlds/kh2/Client.py | 216 +- worlds/kh2/Regions.py | 178 +- worlds/kh2/Rules.py | 11 +- worlds/kh2/__init__.py | 4 +- worlds/kh2/docs/setup_en.md | 4 +- worlds/ladx/LADXR/generator.py | 1 + worlds/ladx/LADXR/itempool.py | 6 +- worlds/ladx/LADXR/locations/itemInfo.py | 9 + worlds/ladx/LADXR/logic/overworld.py | 12 +- worlds/ladx/LADXR/logic/requirements.py | 3 +- worlds/ladx/LADXR/patches/core.py | 14 +- worlds/ladx/Locations.py | 13 +- worlds/ladx/Options.py | 9 + worlds/ladx/__init__.py | 92 +- worlds/lingo/__init__.py | 12 +- worlds/lingo/data/generated.dat | Bin 149485 -> 149504 bytes worlds/lingo/data/ids.yaml | 1 + worlds/lingo/items.py | 1 + worlds/lingo/options.py | 10 + worlds/lingo/test/TestOptions.py | 9 +- worlds/lingo/utils/assign_ids.rb | 3 + worlds/meritous/__init__.py | 13 +- worlds/mm2/client.py | 11 +- worlds/mm2/options.py | 2 +- worlds/mm2/rules.py | 61 +- worlds/mmbn3/Items.py | 29 +- worlds/mmbn3/Locations.py | 37 +- worlds/mmbn3/Names/ItemName.py | 2 + worlds/mmbn3/Names/LocationName.py | 2 + worlds/mmbn3/Options.py | 12 +- worlds/mmbn3/Regions.py | 4 +- worlds/mmbn3/__init__.py | 178 +- worlds/mmbn3/data/bn3-ap-patch.bsdiff | Bin 59914 -> 61276 bytes worlds/musedash/Items.py | 1 + worlds/musedash/MuseDashCollection.py | 98 +- worlds/musedash/MuseDashData.py | 615 ++ worlds/musedash/MuseDashData.txt | 597 -- worlds/musedash/Options.py | 29 +- worlds/musedash/__init__.py | 9 +- worlds/musedash/test/TestDifficultyRanges.py | 12 +- worlds/noita/items.py | 4 +- worlds/noita/options.py | 4 + worlds/oot/Patches.py | 2 +- worlds/oot/__init__.py | 3 +- worlds/pokemon_emerald/CHANGELOG.md | 13 + worlds/pokemon_emerald/__init__.py | 3 +- worlds/pokemon_emerald/client.py | 7 +- worlds/pokemon_emerald/locations.py | 36 +- worlds/pokemon_emerald/options.py | 61 +- worlds/pokemon_rb/regions.py | 2 +- worlds/sa2b/docs/setup_en.md | 36 +- worlds/shivers/__init__.py | 2 +- worlds/shivers/docs/en_Shivers.md | 4 +- worlds/shivers/docs/setup_en.md | 12 +- worlds/sm/Rom.py | 45 +- worlds/sm/__init__.py | 30 +- worlds/sm/variaRandomizer/randomizer.py | 26 +- worlds/sm/variaRandomizer/rom/ips.py | 19 +- worlds/sm/variaRandomizer/rom/rom.py | 62 +- worlds/sm/variaRandomizer/rom/rompatcher.py | 9 +- worlds/sm64ex/__init__.py | 27 + worlds/smz3/__init__.py | 21 +- worlds/soe/options.py | 2 +- worlds/soe/requirements.txt | 73 +- worlds/soe/test/test_oob.py | 45 +- worlds/stardew_valley/__init__.py | 72 +- worlds/stardew_valley/bundles/bundle_room.py | 2 +- worlds/stardew_valley/content/mods/sve.py | 19 +- worlds/stardew_valley/content/vanilla/base.py | 2 +- .../content/vanilla/qi_board.py | 1 - worlds/stardew_valley/data/bundle_data.py | 4 +- worlds/stardew_valley/data/craftable_data.py | 21 +- worlds/stardew_valley/data/locations.csv | 6 +- worlds/stardew_valley/data/recipe_data.py | 42 +- worlds/stardew_valley/data/recipe_source.py | 2 +- worlds/stardew_valley/locations.py | 9 +- worlds/stardew_valley/logic/ability_logic.py | 10 +- worlds/stardew_valley/logic/action_logic.py | 1 - worlds/stardew_valley/logic/farming_logic.py | 15 +- worlds/stardew_valley/logic/skill_logic.py | 8 +- .../stardew_valley/mods/logic/item_logic.py | 7 +- .../stardew_valley/mods/logic/quests_logic.py | 5 +- worlds/stardew_valley/options/options.py | 58 +- worlds/stardew_valley/options/presets.py | 2 +- worlds/stardew_valley/regions.py | 621 +- worlds/stardew_valley/scripts/update_data.py | 8 +- worlds/stardew_valley/stardew_rule/base.py | 4 +- worlds/stardew_valley/stardew_rule/state.py | 45 +- .../strings/ap_names/event_names.py | 6 +- .../stardew_valley/strings/craftable_names.py | 4 + worlds/stardew_valley/test/TestBooksanity.py | 8 +- .../test/TestMultiplePlayers.py | 2 - .../test/TestNumberLocations.py | 9 +- .../stardew_valley/test/TestWalnutsanity.py | 16 +- worlds/stardew_valley/test/__init__.py | 7 + .../test/assertion/rule_assert.py | 41 +- .../test/assertion/world_assert.py | 2 +- worlds/stardew_valley/test/mods/TestMods.py | 85 +- .../stardew_valley/test/mods/TestModsFill.py | 28 + worlds/stardew_valley/test/rules/TestBooks.py | 8 +- .../stardew_valley/test/rules/TestFishing.py | 9 +- .../stardew_valley/test/rules/TestShipping.py | 11 +- .../stardew_valley/test/rules/TestSkills.py | 10 +- worlds/stardew_valley/test/rules/TestTools.py | 5 +- worlds/subnautica/__init__.py | 9 +- worlds/tloz/docs/multiworld_en.md | 2 +- worlds/tunic/__init__.py | 201 +- worlds/tunic/combat_logic.py | 304 +- worlds/tunic/er_data.py | 14 +- worlds/tunic/er_rules.py | 68 +- worlds/tunic/er_scripts.py | 61 +- worlds/tunic/grass.py | 7946 +++++++++++++++++ worlds/tunic/items.py | 6 +- worlds/tunic/locations.py | 33 +- worlds/tunic/options.py | 49 +- worlds/tunic/regions.py | 47 +- worlds/tunic/rules.py | 7 +- worlds/tunic/test/test_combat.py | 119 + worlds/zillion/__init__.py | 61 +- worlds/zillion/item.py | 28 + worlds/zillion/options.py | 15 + worlds/zillion/requirements.txt | 2 +- worlds/zillion/test/TestOptions.py | 17 +- worlds/zork_grand_inquisitor/__init__.py | 2 +- 222 files changed, 12200 insertions(+), 2725 deletions(-) create mode 100644 test/general/test_entrances.py create mode 100644 test/general/test_state.py create mode 100644 worlds/factorio/test_file_validation.py create mode 100644 worlds/musedash/MuseDashData.py delete mode 100644 worlds/musedash/MuseDashData.txt create mode 100644 worlds/stardew_valley/test/mods/TestModsFill.py create mode 100644 worlds/tunic/grass.py create mode 100644 worlds/tunic/test/test_combat.py diff --git a/.github/pyright-config.json b/.github/pyright-config.json index 7d98177890..de7758a715 100644 --- a/.github/pyright-config.json +++ b/.github/pyright-config.json @@ -1,8 +1,20 @@ { "include": [ - "type_check.py", + "../BizHawkClient.py", + "../Patch.py", + "../test/general/test_groups.py", + "../test/general/test_helpers.py", + "../test/general/test_memory.py", + "../test/general/test_names.py", + "../test/multiworld/__init__.py", + "../test/multiworld/test_multiworlds.py", + "../test/netutils/__init__.py", + "../test/programs/__init__.py", + "../test/programs/test_multi_server.py", + "../test/utils/__init__.py", + "../test/webhost/test_descriptions.py", "../worlds/AutoSNIClient.py", - "../Patch.py" + "type_check.py" ], "exclude": [ diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 9492c83c9e..a0ae2cb252 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -11,7 +11,7 @@ on: - '**.hh?' - '**.hpp' - '**.hxx' - - '**.CMakeLists' + - '**/CMakeLists.txt' - '.github/workflows/ctest.yml' pull_request: paths: @@ -21,7 +21,7 @@ on: - '**.hh?' - '**.hpp' - '**.hxx' - - '**.CMakeLists' + - '**/CMakeLists.txt' - '.github/workflows/ctest.yml' jobs: diff --git a/.github/workflows/strict-type-check.yml b/.github/workflows/strict-type-check.yml index bafd572a26..2ccdad8d11 100644 --- a/.github/workflows/strict-type-check.yml +++ b/.github/workflows/strict-type-check.yml @@ -26,7 +26,7 @@ jobs: - name: "Install dependencies" run: | - python -m pip install --upgrade pip pyright==1.1.358 + python -m pip install --upgrade pip pyright==1.1.392.post0 python ModuleUpdate.py --append "WebHostLib/requirements.txt" --force --yes - name: "pyright: strict check on specific files" diff --git a/BaseClasses.py b/BaseClasses.py index e19ba5f777..3d0004806c 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -869,21 +869,40 @@ class CollectionState(): def has(self, item: str, player: int, count: int = 1) -> bool: return self.prog_items[player][item] >= count + # for loops are specifically used in all/any/count methods, instead of all()/any()/sum(), to avoid the overhead of + # creating and iterating generator instances. In `return all(player_prog_items[item] for item in items)`, the + # argument to all() would be a new generator instance, for example. def has_all(self, items: Iterable[str], player: int) -> bool: """Returns True if each item name of items is in state at least once.""" - return all(self.prog_items[player][item] for item in items) + player_prog_items = self.prog_items[player] + for item in items: + if not player_prog_items[item]: + return False + return True def has_any(self, items: Iterable[str], player: int) -> bool: """Returns True if at least one item name of items is in state at least once.""" - return any(self.prog_items[player][item] for item in items) + player_prog_items = self.prog_items[player] + for item in items: + if player_prog_items[item]: + return True + return False def has_all_counts(self, item_counts: Mapping[str, int], player: int) -> bool: """Returns True if each item name is in the state at least as many times as specified.""" - return all(self.prog_items[player][item] >= count for item, count in item_counts.items()) + player_prog_items = self.prog_items[player] + for item, count in item_counts.items(): + if player_prog_items[item] < count: + return False + return True def has_any_count(self, item_counts: Mapping[str, int], player: int) -> bool: """Returns True if at least one item name is in the state at least as many times as specified.""" - return any(self.prog_items[player][item] >= count for item, count in item_counts.items()) + player_prog_items = self.prog_items[player] + for item, count in item_counts.items(): + if player_prog_items[item] >= count: + return True + return False def count(self, item: str, player: int) -> int: return self.prog_items[player][item] @@ -911,11 +930,20 @@ class CollectionState(): def count_from_list(self, items: Iterable[str], player: int) -> int: """Returns the cumulative count of items from a list present in state.""" - return sum(self.prog_items[player][item_name] for item_name in items) + player_prog_items = self.prog_items[player] + total = 0 + for item_name in items: + total += player_prog_items[item_name] + return total def count_from_list_unique(self, items: Iterable[str], player: int) -> int: """Returns the cumulative count of items from a list present in state. Ignores duplicates of the same item.""" - return sum(self.prog_items[player][item_name] > 0 for item_name in items) + player_prog_items = self.prog_items[player] + total = 0 + for item_name in items: + if player_prog_items[item_name] > 0: + total += 1 + return total # item name group related def has_group(self, item_name_group: str, player: int, count: int = 1) -> bool: diff --git a/CommonClient.py b/CommonClient.py index fc6ae6d9a5..33792f0ed2 100644 --- a/CommonClient.py +++ b/CommonClient.py @@ -31,6 +31,7 @@ import ssl if typing.TYPE_CHECKING: import kvui + import argparse logger = logging.getLogger("Client") @@ -459,6 +460,13 @@ class CommonContext: await self.send_msgs([payload]) await self.send_msgs([{"cmd": "Get", "keys": ["_read_race_mode"]}]) + async def check_locations(self, locations: typing.Collection[int]) -> set[int]: + """Send new location checks to the server. Returns the set of actually new locations that were sent.""" + locations = set(locations) & self.missing_locations + if locations: + await self.send_msgs([{"cmd": 'LocationChecks', "locations": tuple(locations)}]) + return locations + async def console_input(self) -> str: if self.ui: self.ui.focus_textinput() @@ -701,8 +709,16 @@ class CommonContext: logger.exception(msg, exc_info=exc_info, extra={'compact_gui': True}) self._messagebox_connection_loss = self.gui_error(msg, exc_info[1]) - def make_gui(self) -> typing.Type["kvui.GameManager"]: - """To return the Kivy App class needed for run_gui so it can be overridden before being built""" + def make_gui(self) -> "type[kvui.GameManager]": + """ + To return the Kivy `App` class needed for `run_gui` so it can be overridden before being built + + Common changes are changing `base_title` to update the window title of the client and + updating `logging_pairs` to automatically make new tabs that can be filled with their respective logger. + + ex. `logging_pairs.append(("Foo", "Bar"))` + will add a "Bar" tab which follows the logger returned from `logging.getLogger("Foo")` + """ from kvui import GameManager class TextManager(GameManager): @@ -891,6 +907,7 @@ async def process_server_cmd(ctx: CommonContext, args: dict): ctx.disconnected_intentionally = True ctx.event_invalid_game() elif 'IncompatibleVersion' in errors: + ctx.disconnected_intentionally = True raise Exception('Server reported your client version as incompatible. ' 'This probably means you have to update.') elif 'InvalidItemsHandling' in errors: @@ -1041,6 +1058,32 @@ def get_base_parser(description: typing.Optional[str] = None): return parser +def handle_url_arg(args: "argparse.Namespace", + parser: "typing.Optional[argparse.ArgumentParser]" = None) -> "argparse.Namespace": + """ + Parse the url arg "archipelago://name:pass@host:port" from launcher into correct launch args for CommonClient + If alternate data is required the urlparse response is saved back to args.url if valid + """ + if not args.url: + return args + + url = urllib.parse.urlparse(args.url) + if url.scheme != "archipelago": + if not parser: + parser = get_base_parser() + parser.error(f"bad url, found {args.url}, expected url in form of archipelago://archipelago.gg:38281") + return args + + args.url = url + args.connect = url.netloc + if url.username: + args.name = urllib.parse.unquote(url.username) + if url.password: + args.password = urllib.parse.unquote(url.password) + + return args + + def run_as_textclient(*args): class TextContext(CommonContext): # Text Mode to use !hint and such with games that have no text entry @@ -1053,7 +1096,7 @@ def run_as_textclient(*args): if password_requested and not self.password: await super(TextContext, self).server_auth(password_requested) await self.get_username() - await self.send_connect() + await self.send_connect(game="") def on_package(self, cmd: str, args: dict): if cmd == "Connected": @@ -1082,17 +1125,7 @@ def run_as_textclient(*args): parser.add_argument("url", nargs="?", help="Archipelago connection url") args = parser.parse_args(args) - # handle if text client is launched using the "archipelago://name:pass@host:port" url from webhost - if args.url: - url = urllib.parse.urlparse(args.url) - if url.scheme == "archipelago": - args.connect = url.netloc - if url.username: - args.name = urllib.parse.unquote(url.username) - if url.password: - args.password = urllib.parse.unquote(url.password) - else: - parser.error(f"bad url, found {args.url}, expected url in form of archipelago://archipelago.gg:38281") + args = handle_url_arg(args, parser=parser) # use colorama to display colored text highlighting on windows colorama.init() diff --git a/Fill.py b/Fill.py index a040794fd1..d1773c8213 100644 --- a/Fill.py +++ b/Fill.py @@ -502,7 +502,13 @@ def distribute_items_restrictive(multiworld: MultiWorld, # "priority fill" fill_restrictive(multiworld, multiworld.state, prioritylocations, progitempool, single_player_placement=single_player, swap=False, on_place=mark_for_locking, - name="Priority", one_item_per_player=False) + name="Priority", one_item_per_player=True, allow_partial=True) + + if prioritylocations: + # retry with one_item_per_player off because some priority fills can fail to fill with that optimization + fill_restrictive(multiworld, multiworld.state, prioritylocations, progitempool, + single_player_placement=single_player, swap=False, on_place=mark_for_locking, + name="Priority Retry", one_item_per_player=False) accessibility_corrections(multiworld, multiworld.state, prioritylocations, progitempool) defaultlocations = prioritylocations + defaultlocations @@ -571,6 +577,26 @@ def distribute_items_restrictive(multiworld: MultiWorld, print_data = {"items": items_counter, "locations": locations_counter} logging.info(f"Per-Player counts: {print_data})") + more_locations = locations_counter - items_counter + more_items = items_counter - locations_counter + for player in multiworld.player_ids: + if more_locations[player]: + logging.error( + f"Player {multiworld.get_player_name(player)} had {more_locations[player]} more locations than items.") + elif more_items[player]: + logging.warning( + f"Player {multiworld.get_player_name(player)} had {more_items[player]} more items than locations.") + if unfilled: + raise FillError( + f"Unable to fill all locations.\n" + + f"Unfilled locations({len(unfilled)}): {unfilled}" + ) + else: + logging.warning( + f"Unable to place all items.\n" + + f"Unplaced items({len(unplaced)}): {unplaced}" + ) + def flood_items(multiworld: MultiWorld) -> None: # get items to distribute diff --git a/Generate.py b/Generate.py index 8a2e72d1ce..b057db25a3 100644 --- a/Generate.py +++ b/Generate.py @@ -42,7 +42,9 @@ def mystery_argparse(): help="Path to output folder. Absolute or relative to cwd.") # absolute or relative to cwd parser.add_argument('--race', action='store_true', default=defaults.race) parser.add_argument('--meta_file_path', default=defaults.meta_file_path) - parser.add_argument('--log_level', default='info', help='Sets log level') + parser.add_argument('--log_level', default=defaults.loglevel, help='Sets log level') + parser.add_argument('--log_time', help="Add timestamps to STDOUT", + default=defaults.logtime, action='store_true') parser.add_argument("--csv_output", action="store_true", help="Output rolled player options to csv (made for async multiworld).") parser.add_argument("--plando", default=defaults.plando_options, @@ -75,7 +77,7 @@ def main(args=None) -> Tuple[argparse.Namespace, int]: seed = get_seed(args.seed) - Utils.init_logging(f"Generate_{seed}", loglevel=args.log_level) + Utils.init_logging(f"Generate_{seed}", loglevel=args.log_level, add_timestamp=args.log_time) random.seed(seed) seed_name = get_seed_name(random) @@ -438,7 +440,7 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b if "linked_options" in weights: weights = roll_linked_options(weights) - valid_keys = set() + valid_keys = {"triggers"} if "triggers" in weights: weights = roll_triggers(weights, weights["triggers"], valid_keys) @@ -497,16 +499,23 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b for option_key, option in world_type.options_dataclass.type_hints.items(): handle_option(ret, game_weights, option_key, option, plando_options) valid_keys.add(option_key) - for option_key in game_weights: - if option_key in {"triggers", *valid_keys}: - continue - logging.warning(f"{option_key} is not a valid option name for {ret.game} and is not present in triggers " - f"for player {ret.name}.") + + # TODO remove plando_items after moving it to the options system + valid_keys.add("plando_items") if PlandoOptions.items in plando_options: ret.plando_items = copy.deepcopy(game_weights.get("plando_items", [])) if ret.game == "A Link to the Past": + # TODO there are still more LTTP options not on the options system + valid_keys |= {"sprite_pool", "sprite", "random_sprite_on_event"} roll_alttp_settings(ret, game_weights) + # log a warning for options within a game section that aren't determined as valid + for option_key in game_weights: + if option_key in valid_keys: + continue + logging.warning(f"{option_key} is not a valid option name for {ret.game} and is not present in triggers " + f"for player {ret.name}.") + return ret diff --git a/LinksAwakeningClient.py b/LinksAwakeningClient.py index aede742b82..e2e16922fa 100644 --- a/LinksAwakeningClient.py +++ b/LinksAwakeningClient.py @@ -560,6 +560,10 @@ class LinksAwakeningContext(CommonContext): while self.client.auth == None: await asyncio.sleep(0.1) + + # Just return if we're closing + if self.exit_event.is_set(): + return self.auth = self.client.auth await self.send_connect() diff --git a/LttPAdjuster.py b/LttPAdjuster.py index 7e33a3d5ef..963557e8da 100644 --- a/LttPAdjuster.py +++ b/LttPAdjuster.py @@ -33,10 +33,15 @@ WINDOW_MIN_HEIGHT = 525 WINDOW_MIN_WIDTH = 425 class AdjusterWorld(object): + class AdjusterSubWorld(object): + def __init__(self, random): + self.random = random + def __init__(self, sprite_pool): import random self.sprite_pool = {1: sprite_pool} self.per_slot_randoms = {1: random} + self.worlds = {1: self.AdjusterSubWorld(random)} class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter): diff --git a/Main.py b/Main.py index d105bd4ad0..d0e7a7f879 100644 --- a/Main.py +++ b/Main.py @@ -148,7 +148,8 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No else: multiworld.worlds[1].options.non_local_items.value = set() multiworld.worlds[1].options.local_items.value = set() - + + AutoWorld.call_all(multiworld, "connect_entrances") AutoWorld.call_all(multiworld, "generate_basic") # remove starting inventory from pool items. diff --git a/MultiServer.py b/MultiServer.py index 0601e17915..a310808b3a 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -28,9 +28,11 @@ ModuleUpdate.update() if typing.TYPE_CHECKING: import ssl + from NetUtils import ServerConnection -import websockets import colorama +import websockets +from websockets.extensions.permessage_deflate import PerMessageDeflate try: # ponyorm is a requirement for webhost, not default server, so may not be importable from pony.orm.dbapiprovider import OperationalError @@ -119,13 +121,14 @@ def get_saving_second(seed_name: str, interval: int = 60) -> int: class Client(Endpoint): version = Version(0, 0, 0) - tags: typing.List[str] = [] + tags: typing.List[str] remote_items: bool remote_start_inventory: bool no_items: bool no_locations: bool + no_text: bool - def __init__(self, socket: websockets.WebSocketServerProtocol, ctx: Context): + def __init__(self, socket: "ServerConnection", ctx: Context) -> None: super().__init__(socket) self.auth = False self.team = None @@ -175,6 +178,7 @@ class Context: "compatibility": int} # team -> slot id -> list of clients authenticated to slot. clients: typing.Dict[int, typing.Dict[int, typing.List[Client]]] + endpoints: list[Client] locations: LocationStore # typing.Dict[int, typing.Dict[int, typing.Tuple[int, int, int]]] location_checks: typing.Dict[typing.Tuple[int, int], typing.Set[int]] hints_used: typing.Dict[typing.Tuple[int, int], int] @@ -364,18 +368,28 @@ class Context: return True def broadcast_all(self, msgs: typing.List[dict]): - msgs = self.dumper(msgs) - endpoints = (endpoint for endpoint in self.endpoints if endpoint.auth) - async_start(self.broadcast_send_encoded_msgs(endpoints, msgs)) + msg_is_text = all(msg["cmd"] == "PrintJSON" for msg in msgs) + data = self.dumper(msgs) + endpoints = ( + endpoint + for endpoint in self.endpoints + if endpoint.auth and not (msg_is_text and endpoint.no_text) + ) + async_start(self.broadcast_send_encoded_msgs(endpoints, data)) def broadcast_text_all(self, text: str, additional_arguments: dict = {}): self.logger.info("Notice (all): %s" % text) self.broadcast_all([{**{"cmd": "PrintJSON", "data": [{ "text": text }]}, **additional_arguments}]) def broadcast_team(self, team: int, msgs: typing.List[dict]): - msgs = self.dumper(msgs) - endpoints = (endpoint for endpoint in itertools.chain.from_iterable(self.clients[team].values())) - async_start(self.broadcast_send_encoded_msgs(endpoints, msgs)) + msg_is_text = all(msg["cmd"] == "PrintJSON" for msg in msgs) + data = self.dumper(msgs) + endpoints = ( + endpoint + for endpoint in itertools.chain.from_iterable(self.clients[team].values()) + if not (msg_is_text and endpoint.no_text) + ) + async_start(self.broadcast_send_encoded_msgs(endpoints, data)) def broadcast(self, endpoints: typing.Iterable[Client], msgs: typing.List[dict]): msgs = self.dumper(msgs) @@ -389,13 +403,13 @@ class Context: await on_client_disconnected(self, endpoint) def notify_client(self, client: Client, text: str, additional_arguments: dict = {}): - if not client.auth: + if not client.auth or client.no_text: return self.logger.info("Notice (Player %s in team %d): %s" % (client.name, client.team + 1, text)) async_start(self.send_msgs(client, [{"cmd": "PrintJSON", "data": [{ "text": text }], **additional_arguments}])) def notify_client_multiple(self, client: Client, texts: typing.List[str], additional_arguments: dict = {}): - if not client.auth: + if not client.auth or client.no_text: return async_start(self.send_msgs(client, [{"cmd": "PrintJSON", "data": [{ "text": text }], **additional_arguments} @@ -444,7 +458,7 @@ class Context: self.slot_info = decoded_obj["slot_info"] self.games = {slot: slot_info.game for slot, slot_info in self.slot_info.items()} - self.groups = {slot: slot_info.group_members for slot, slot_info in self.slot_info.items() + self.groups = {slot: set(slot_info.group_members) for slot, slot_info in self.slot_info.items() if slot_info.type == SlotType.group} self.clients = {0: {}} @@ -743,23 +757,24 @@ class Context: concerns[player].append(data) if not hint.local and data not in concerns[hint.finding_player]: concerns[hint.finding_player].append(data) - # remember hints in all cases - # since hints are bidirectional, finding player and receiving player, - # we can check once if hint already exists - if hint not in self.hints[team, hint.finding_player]: - self.hints[team, hint.finding_player].add(hint) - new_hint_events.add(hint.finding_player) - for player in self.slot_set(hint.receiving_player): - self.hints[team, player].add(hint) - new_hint_events.add(player) + # only remember hints that were not already found at the time of creation + if not hint.found: + # since hints are bidirectional, finding player and receiving player, + # we can check once if hint already exists + if hint not in self.hints[team, hint.finding_player]: + self.hints[team, hint.finding_player].add(hint) + new_hint_events.add(hint.finding_player) + for player in self.slot_set(hint.receiving_player): + self.hints[team, player].add(hint) + new_hint_events.add(player) self.logger.info("Notice (Team #%d): %s" % (team + 1, format_hint(self, team, hint))) for slot in new_hint_events: self.on_new_hint(team, slot) for slot, hint_data in concerns.items(): if recipients is None or slot in recipients: - clients = self.clients[team].get(slot) + clients = filter(lambda c: not c.no_text, self.clients[team].get(slot, [])) if not clients: continue client_hints = [datum[1] for datum in sorted(hint_data, key=lambda x: x[0].finding_player != slot)] @@ -768,7 +783,7 @@ class Context: def get_hint(self, team: int, finding_player: int, seeked_location: int) -> typing.Optional[Hint]: for hint in self.hints[team, finding_player]: - if hint.location == seeked_location: + if hint.location == seeked_location and hint.finding_player == finding_player: return hint return None @@ -818,7 +833,7 @@ def update_aliases(ctx: Context, team: int): async_start(ctx.send_encoded_msgs(client, cmd)) -async def server(websocket, path: str = "/", ctx: Context = None): +async def server(websocket: "ServerConnection", path: str = "/", ctx: Context = None) -> None: client = Client(websocket, ctx) ctx.endpoints.append(client) @@ -909,6 +924,10 @@ async def on_client_joined(ctx: Context, client: Client): "If your client supports it, " "you may have additional local commands you can list with /help.", {"type": "Tutorial"}) + if not any(isinstance(extension, PerMessageDeflate) for extension in client.socket.extensions): + ctx.notify_client(client, "Warning: your client does not support compressed websocket connections! " + "It may stop working in the future. If you are a player, please report this to the " + "client's developer.") ctx.client_connection_timers[client.team, client.slot] = datetime.datetime.now(datetime.timezone.utc) @@ -1059,21 +1078,37 @@ def send_items_to(ctx: Context, team: int, target_slot: int, *items: NetworkItem def register_location_checks(ctx: Context, team: int, slot: int, locations: typing.Iterable[int], count_activity: bool = True): + slot_locations = ctx.locations[slot] new_locations = set(locations) - ctx.location_checks[team, slot] - new_locations.intersection_update(ctx.locations[slot]) # ignore location IDs unknown to this multidata + new_locations.intersection_update(slot_locations) # ignore location IDs unknown to this multidata if new_locations: if count_activity: ctx.client_activity_timers[team, slot] = datetime.datetime.now(datetime.timezone.utc) + + sortable: list[tuple[int, int, int, int]] = [] for location in new_locations: - item_id, target_player, flags = ctx.locations[slot][location] + # extract all fields to avoid runtime overhead in LocationStore + item_id, target_player, flags = slot_locations[location] + # sort/group by receiver and item + sortable.append((target_player, item_id, location, flags)) + + info_texts: list[dict[str, typing.Any]] = [] + for target_player, item_id, location, flags in sorted(sortable): new_item = NetworkItem(item_id, location, slot, flags) send_items_to(ctx, team, target_player, new_item) ctx.logger.info('(Team #%d) %s sent %s to %s (%s)' % ( team + 1, ctx.player_names[(team, slot)], ctx.item_names[ctx.slot_info[target_player].game][item_id], ctx.player_names[(team, target_player)], ctx.location_names[ctx.slot_info[slot].game][location])) - info_text = json_format_send_event(new_item, target_player) - ctx.broadcast_team(team, [info_text]) + if len(info_texts) >= 140: + # split into chunks that are close to compression window of 64K but not too big on the wire + # (roughly 1300-2600 bytes after compression depending on repetitiveness) + ctx.broadcast_team(team, info_texts) + info_texts.clear() + info_texts.append(json_format_send_event(new_item, target_player)) + ctx.broadcast_team(team, info_texts) + del info_texts + del sortable ctx.location_checks[team, slot] |= new_locations send_new_items(ctx) @@ -1100,7 +1135,7 @@ def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, st seeked_item_id = item if isinstance(item, int) else ctx.item_names_for_game(ctx.games[slot])[item] for finding_player, location_id, item_id, receiving_player, item_flags \ in ctx.locations.find_item(slots, seeked_item_id): - prev_hint = ctx.get_hint(team, slot, location_id) + prev_hint = ctx.get_hint(team, finding_player, location_id) if prev_hint: hints.append(prev_hint) else: @@ -1786,7 +1821,9 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict): ctx.clients[team][slot].append(client) client.version = args['version'] client.tags = args['tags'] - client.no_locations = 'TextOnly' in client.tags or 'Tracker' in client.tags + client.no_locations = "TextOnly" in client.tags or "Tracker" in client.tags + # set NoText for old PopTracker clients that predate the tag to save traffic + client.no_text = "NoText" in client.tags or ("PopTracker" in client.tags and client.version < (0, 5, 1)) connected_packet = { "cmd": "Connected", "team": client.team, "slot": client.slot, @@ -1859,6 +1896,9 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict): client.tags = args["tags"] if set(old_tags) != set(client.tags): client.no_locations = 'TextOnly' in client.tags or 'Tracker' in client.tags + client.no_text = "NoText" in client.tags or ( + "PopTracker" in client.tags and client.version < (0, 5, 1) + ) ctx.broadcast_text_all( f"{ctx.get_aliased_name(client.team, client.slot)} (Team #{client.team + 1}) has changed tags " f"from {old_tags} to {client.tags}.", @@ -1887,7 +1927,8 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict): for location in args["locations"]: if type(location) is not int: await ctx.send_msgs(client, - [{'cmd': 'InvalidPacket', "type": "arguments", "text": 'LocationScouts', + [{'cmd': 'InvalidPacket', "type": "arguments", + "text": 'Locations has to be a list of integers', "original_cmd": cmd}]) return @@ -1990,6 +2031,7 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict): args["cmd"] = "SetReply" value = ctx.stored_data.get(args["key"], args.get("default", 0)) args["original_value"] = copy.copy(value) + args["slot"] = client.slot for operation in args["operations"]: func = modify_functions[operation["operation"]] value = func(value, operation["value"]) diff --git a/NetUtils.py b/NetUtils.py index d58bbe81e3..f2ae2a63a0 100644 --- a/NetUtils.py +++ b/NetUtils.py @@ -5,17 +5,18 @@ import enum import warnings from json import JSONEncoder, JSONDecoder -import websockets +if typing.TYPE_CHECKING: + from websockets import WebSocketServerProtocol as ServerConnection from Utils import ByValue, Version class HintStatus(ByValue, enum.IntEnum): - HINT_FOUND = 0 - HINT_UNSPECIFIED = 1 + HINT_UNSPECIFIED = 0 HINT_NO_PRIORITY = 10 HINT_AVOID = 20 HINT_PRIORITY = 30 + HINT_FOUND = 40 class JSONMessagePart(typing.TypedDict, total=False): @@ -151,7 +152,7 @@ decode = JSONDecoder(object_hook=_object_hook).decode class Endpoint: - socket: websockets.WebSocketServerProtocol + socket: "ServerConnection" def __init__(self, socket): self.socket = socket diff --git a/OoTAdjuster.py b/OoTAdjuster.py index 9519b191e7..1581d65398 100644 --- a/OoTAdjuster.py +++ b/OoTAdjuster.py @@ -1,7 +1,6 @@ import tkinter as tk import argparse import logging -import random import os import zipfile from itertools import chain @@ -197,7 +196,6 @@ def set_icon(window): def adjust(args): # Create a fake multiworld and OOTWorld to use as a base multiworld = MultiWorld(1) - multiworld.per_slot_randoms = {1: random} ootworld = OOTWorld(multiworld, 1) # Set options in the fake OOTWorld for name, option in chain(cosmetic_options.items(), sfx_options.items()): diff --git a/Options.py b/Options.py index f4724e9747..49e82069ee 100644 --- a/Options.py +++ b/Options.py @@ -137,7 +137,7 @@ class Option(typing.Generic[T], metaclass=AssembleOptions): If this is False, the docstring is instead interpreted as plain text, and displayed as-is on the WebHost with whitespace preserved. - If this is None, it inherits the value of `World.rich_text_options_doc`. For + If this is None, it inherits the value of `WebWorld.rich_text_options_doc`. For backwards compatibility, this defaults to False, but worlds are encouraged to set it to True and use reStructuredText for their Option documentation. @@ -689,9 +689,9 @@ class Range(NumericOption): @classmethod def weighted_range(cls, text) -> Range: if text == "random-low": - return cls(cls.triangular(cls.range_start, cls.range_end, cls.range_start)) + return cls(cls.triangular(cls.range_start, cls.range_end, 0.0)) elif text == "random-high": - return cls(cls.triangular(cls.range_start, cls.range_end, cls.range_end)) + return cls(cls.triangular(cls.range_start, cls.range_end, 1.0)) elif text == "random-middle": return cls(cls.triangular(cls.range_start, cls.range_end)) elif text.startswith("random-range-"): @@ -717,11 +717,11 @@ class Range(NumericOption): f"{random_range[0]}-{random_range[1]} is outside allowed range " f"{cls.range_start}-{cls.range_end} for option {cls.__name__}") if text.startswith("random-range-low"): - return cls(cls.triangular(random_range[0], random_range[1], random_range[0])) + return cls(cls.triangular(random_range[0], random_range[1], 0.0)) elif text.startswith("random-range-middle"): return cls(cls.triangular(random_range[0], random_range[1])) elif text.startswith("random-range-high"): - return cls(cls.triangular(random_range[0], random_range[1], random_range[1])) + return cls(cls.triangular(random_range[0], random_range[1], 1.0)) else: return cls(random.randint(random_range[0], random_range[1])) @@ -739,8 +739,16 @@ class Range(NumericOption): return str(self.value) @staticmethod - def triangular(lower: int, end: int, tri: typing.Optional[int] = None) -> int: - return int(round(random.triangular(lower, end, tri), 0)) + def triangular(lower: int, end: int, tri: float = 0.5) -> int: + """ + Integer triangular distribution for `lower` inclusive to `end` inclusive. + + Expects `lower <= end` and `0.0 <= tri <= 1.0`. The result of other inputs is undefined. + """ + # Use the continuous range [lower, end + 1) to produce an integer result in [lower, end]. + # random.triangular is actually [a, b] and not [a, b), so there is a very small chance of getting exactly b even + # when a != b, so ensure the result is never more than `end`. + return min(end, math.floor(random.triangular(0.0, 1.0, tri) * (end - lower + 1) + lower)) class NamedRange(Range): @@ -1574,7 +1582,7 @@ def dump_player_options(multiworld: MultiWorld) -> None: } output.append(player_output) for option_key, option in world.options_dataclass.type_hints.items(): - if issubclass(Removed, option): + if option.visibility == Visibility.none: continue display_name = getattr(option, "display_name", option_key) player_output[display_name] = getattr(world.options, option_key).current_option_name diff --git a/Utils.py b/Utils.py index 574c006b50..0aa81af150 100644 --- a/Utils.py +++ b/Utils.py @@ -152,8 +152,15 @@ def home_path(*path: str) -> str: if hasattr(home_path, 'cached_path'): pass elif sys.platform.startswith('linux'): - home_path.cached_path = os.path.expanduser('~/Archipelago') - os.makedirs(home_path.cached_path, 0o700, exist_ok=True) + xdg_data_home = os.getenv('XDG_DATA_HOME', os.path.expanduser('~/.local/share')) + home_path.cached_path = xdg_data_home + '/Archipelago' + if not os.path.isdir(home_path.cached_path): + legacy_home_path = os.path.expanduser('~/Archipelago') + if os.path.isdir(legacy_home_path): + os.renames(legacy_home_path, home_path.cached_path) + os.symlink(home_path.cached_path, legacy_home_path) + else: + os.makedirs(home_path.cached_path, 0o700, exist_ok=True) else: # not implemented home_path.cached_path = local_path() # this will generate the same exceptions we got previously @@ -514,8 +521,8 @@ def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO, def filter(self, record: logging.LogRecord) -> bool: return self.condition(record) - file_handler.addFilter(Filter("NoStream", lambda record: not getattr(record, "NoFile", False))) - file_handler.addFilter(Filter("NoCarriageReturn", lambda record: '\r' not in record.msg)) + file_handler.addFilter(Filter("NoStream", lambda record: not getattr(record, "NoFile", False))) + file_handler.addFilter(Filter("NoCarriageReturn", lambda record: '\r' not in record.getMessage())) root_logger.addHandler(file_handler) if sys.stdout: formatter = logging.Formatter(fmt='[%(asctime)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S') @@ -933,7 +940,7 @@ def freeze_support() -> None: def visualize_regions(root_region: Region, file_name: str, *, show_entrance_names: bool = False, show_locations: bool = True, show_other_regions: bool = True, - linetype_ortho: bool = True) -> None: + linetype_ortho: bool = True, regions_to_highlight: set[Region] | None = None) -> None: """Visualize the layout of a world as a PlantUML diagram. :param root_region: The region from which to start the diagram from. (Usually the "Menu" region of your world.) @@ -949,16 +956,22 @@ def visualize_regions(root_region: Region, file_name: str, *, Items without ID will be shown in italics. :param show_other_regions: (default True) If enabled, regions that can't be reached by traversing exits are shown. :param linetype_ortho: (default True) If enabled, orthogonal straight line parts will be used; otherwise polylines. + :param regions_to_highlight: Regions that will be highlighted in green if they are reachable. Example usage in World code: from Utils import visualize_regions - visualize_regions(self.multiworld.get_region("Menu", self.player), "my_world.puml") + state = self.multiworld.get_all_state(False) + state.update_reachable_regions(self.player) + visualize_regions(self.get_region("Menu"), "my_world.puml", show_entrance_names=True, + regions_to_highlight=state.reachable_regions[self.player]) Example usage in Main code: from Utils import visualize_regions for player in multiworld.player_ids: visualize_regions(multiworld.get_region("Menu", player), f"{multiworld.get_out_file_name_base(player)}.puml") """ + if regions_to_highlight is None: + regions_to_highlight = set() assert root_region.multiworld, "The multiworld attribute of root_region has to be filled" from BaseClasses import Entrance, Item, Location, LocationProgressType, MultiWorld, Region from collections import deque @@ -1011,7 +1024,7 @@ def visualize_regions(root_region: Region, file_name: str, *, uml.append(f"\"{fmt(region)}\" : {{field}} {lock}{fmt(location)}") def visualize_region(region: Region) -> None: - uml.append(f"class \"{fmt(region)}\"") + uml.append(f"class \"{fmt(region)}\" {'#00FF00' if region in regions_to_highlight else ''}") if show_locations: visualize_locations(region) visualize_exits(region) diff --git a/WebHostLib/api/__init__.py b/WebHostLib/api/__init__.py index cf05e87374..d0b9d05c16 100644 --- a/WebHostLib/api/__init__.py +++ b/WebHostLib/api/__init__.py @@ -3,13 +3,13 @@ from typing import List, Tuple from flask import Blueprint -from ..models import Seed +from ..models import Seed, Slot api_endpoints = Blueprint('api', __name__, url_prefix="/api") def get_players(seed: Seed) -> List[Tuple[str, str]]: - return [(slot.player_name, slot.game) for slot in seed.slots] + return [(slot.player_name, slot.game) for slot in seed.slots.order_by(Slot.player_id)] from . import datapackage, generate, room, user # trigger registration diff --git a/WebHostLib/api/user.py b/WebHostLib/api/user.py index 116d3afa22..0ddb6fe83e 100644 --- a/WebHostLib/api/user.py +++ b/WebHostLib/api/user.py @@ -30,4 +30,4 @@ def get_seeds(): "creation_time": seed.creation_time, "players": get_players(seed.slots), }) - return jsonify(response) \ No newline at end of file + return jsonify(response) diff --git a/WebHostLib/customserver.py b/WebHostLib/customserver.py index a2eef108b0..76a2b8a4dc 100644 --- a/WebHostLib/customserver.py +++ b/WebHostLib/customserver.py @@ -117,6 +117,7 @@ class WebHostContext(Context): self.gamespackage = {"Archipelago": static_gamespackage.get("Archipelago", {})} # this may be modified by _load self.item_name_groups = {"Archipelago": static_item_name_groups.get("Archipelago", {})} self.location_name_groups = {"Archipelago": static_location_name_groups.get("Archipelago", {})} + missing_checksum = False for game in list(multidata.get("datapackage", {})): game_data = multidata["datapackage"][game] @@ -132,11 +133,13 @@ class WebHostContext(Context): continue else: self.logger.warning(f"Did not find game_data_package for {game}: {game_data['checksum']}") + else: + missing_checksum = True # Game rolled on old AP and will load data package from multidata self.gamespackage[game] = static_gamespackage.get(game, {}) self.item_name_groups[game] = static_item_name_groups.get(game, {}) self.location_name_groups[game] = static_location_name_groups.get(game, {}) - if not game_data_packages: + if not game_data_packages and not missing_checksum: # all static -> use the static dicts directly self.gamespackage = static_gamespackage self.item_name_groups = static_item_name_groups diff --git a/WebHostLib/static/assets/faq/en.md b/WebHostLib/static/assets/faq/en.md index e64535b42d..96e526612b 100644 --- a/WebHostLib/static/assets/faq/en.md +++ b/WebHostLib/static/assets/faq/en.md @@ -22,7 +22,7 @@ players to rely upon each other to complete their game. While a multiworld game traditionally requires all players to be playing the same game, a multi-game multiworld allows players to randomize any of the supported games, and send items between them. This allows players of different -games to interact with one another in a single multiplayer environment. Archipelago supports multi-game multiworld. +games to interact with one another in a single multiplayer environment. Archipelago supports multi-game multiworlds. Here is a list of our [Supported Games](https://archipelago.gg/games). ## Can I generate a single-player game with Archipelago? diff --git a/data/client.kv b/data/client.kv index 3455f2a236..f0f31769e4 100644 --- a/data/client.kv +++ b/data/client.kv @@ -147,3 +147,8 @@ rectangle: self.x-2, self.y-2, self.width+4, self.height+4 : pos_hint: {'center_y': 0.5, 'center_x': 0.5} + + size_hint_y: None + height: dp(30) + multiline: False + write_tab: False diff --git a/data/lua/connector_bizhawk_generic.lua b/data/lua/connector_bizhawk_generic.lua index 00021b241f..c2e8f91c0d 100644 --- a/data/lua/connector_bizhawk_generic.lua +++ b/data/lua/connector_bizhawk_generic.lua @@ -121,6 +121,14 @@ Response: Expected Response Type: `HASH_RESPONSE` +- `MEMORY_SIZE` + Returns the size in bytes of the specified memory domain. + + Expected Response Type: `MEMORY_SIZE_RESPONSE` + + Additional Fields: + - `domain` (`string`): The name of the memory domain to check + - `GUARD` Checks a section of memory against `expected_data`. If the bytes starting at `address` do not match `expected_data`, the response will have `value` @@ -216,6 +224,12 @@ Response: Additional Fields: - `value` (`string`): The returned hash +- `MEMORY_SIZE_RESPONSE` + Contains the size in bytes of the specified memory domain. + + Additional Fields: + - `value` (`number`): The size of the domain in bytes + - `GUARD_RESPONSE` The result of an attempted `GUARD` request. @@ -376,6 +390,15 @@ request_handlers = { return res end, + ["MEMORY_SIZE"] = function (req) + local res = {} + + res["type"] = "MEMORY_SIZE_RESPONSE" + res["value"] = memory.getmemorydomainsize(req["domain"]) + + return res + end, + ["GUARD"] = function (req) local res = {} local expected_data = base64.decode(req["expected_data"]) @@ -613,9 +636,11 @@ end) if bizhawk_major < 2 or (bizhawk_major == 2 and bizhawk_minor < 7) then print("Must use BizHawk 2.7.0 or newer") -elseif bizhawk_major > 2 or (bizhawk_major == 2 and bizhawk_minor > 9) then - print("Warning: This version of BizHawk is newer than this script. If it doesn't work, consider downgrading to 2.9.") else + if bizhawk_major > 2 or (bizhawk_major == 2 and bizhawk_minor > 10) then + print("Warning: This version of BizHawk is newer than this script. If it doesn't work, consider downgrading to 2.10.") + end + if emu.getsystemid() == "NULL" then print("No ROM is loaded. Please load a ROM.") while emu.getsystemid() == "NULL" do diff --git a/data/lua/connector_oot.lua b/data/lua/connector_oot.lua index 7bec37244b..9df9bdc4c9 100644 --- a/data/lua/connector_oot.lua +++ b/data/lua/connector_oot.lua @@ -1816,7 +1816,7 @@ end -- Main control handling: main loop and socket receive -function receive() +function APreceive() l, e = ootSocket:receive() -- Handle incoming message if e == 'closed' then @@ -1874,7 +1874,7 @@ function main() end if (curstate == STATE_OK) or (curstate == STATE_INITIAL_CONNECTION_MADE) or (curstate == STATE_TENTATIVELY_CONNECTED) then if (frame % 30 == 0) then - receive() + APreceive() end elseif (curstate == STATE_UNINITIALIZED) then if (frame % 60 == 0) then diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 1d70531e99..c4cb83e42f 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -99,6 +99,9 @@ # Lingo /worlds/lingo/ @hatkirby +# Links Awakening DX +/worlds/ladx/ @threeandthreee + # Lufia II Ancient Cave /worlds/lufia2ac/ @el-u /worlds/lufia2ac/docs/ @wordfcuk @el-u @@ -236,9 +239,6 @@ # Final Fantasy (1) # /worlds/ff1/ -# Links Awakening DX -# /worlds/ladx/ - # Ocarina of Time # /worlds/oot/ diff --git a/docs/entrance randomization.md b/docs/entrance randomization.md index 9e3e281bcc..0f9d764716 100644 --- a/docs/entrance randomization.md +++ b/docs/entrance randomization.md @@ -370,19 +370,13 @@ target_group_lookup = bake_target_group_lookup(world, get_target_groups) #### When to call `randomize_entrances` -The short answer is that you will almost always want to do ER in `pre_fill`. For more information why, continue reading. +The correct step for this is `World.connect_entrances`. -ER begins by collecting the entire item pool and then uses your access rules to try and prevent some kinds of failures. -This means 2 things about when you can call ER: -1. You must supply your item pool before calling ER, or call ER before setting any rules which require items. -2. If you have rules dependent on anything other than items (e.g. `Entrance`s or events), you must set your rules - and create your events before you call ER if you want to guarantee a correct output. - -If the conditions above are met, you could theoretically do ER as early as `create_regions`. However, plando is also -a consideration. Since item plando happens between `set_rules` and `pre_fill` and modifies the item pool, doing ER -in `pre_fill` is the only way to account for placements made by item plando, otherwise you risk impossible seeds or -generation failures. Obviously, if your world implements entrance plando, you will likely want to do that before ER as -well. +Currently, you could theoretically do it as early as `World.create_regions` or as late as `pre_fill`. +However, there are upcoming changes to Item Plando and Generic Entrance Randomizer to make the two features work better +together. +These changes necessitate that entrance randomization is done exactly in `World.connect_entrances`. +It is fine for your Entrances to be connected differently or not at all before this step. #### Informing your client about randomized entrances diff --git a/docs/network protocol.md b/docs/network protocol.md index 160f83031c..05a5334426 100644 --- a/docs/network protocol.md +++ b/docs/network protocol.md @@ -47,6 +47,9 @@ Packets are simple JSON lists in which any number of ordered network commands ca An object can contain the "class" key, which will tell the content data type, such as "Version" in the following example. +Websocket connections should support per-message compression. Uncompressed connections are deprecated and may stop +working in the future. + Example: ```javascript [{"cmd": "RoomInfo", "version": {"major": 0, "minor": 1, "build": 3, "class": "Version"}, "tags": ["WebHost"], ... }] @@ -261,6 +264,7 @@ Sent to clients in response to a [Set](#Set) package if want_reply was set to tr | key | str | The key that was updated. | | value | any | The new value for the key. | | original_value | any | The value the key had before it was updated. Not present on "_read" prefixed special keys. | +| slot | int | The slot that originally sent the Set package causing this change. | Additional arguments added to the [Set](#Set) package that triggered this [SetReply](#SetReply) will also be passed along. @@ -359,11 +363,11 @@ An enumeration containing the possible hint states. ```python import enum class HintStatus(enum.IntEnum): - HINT_FOUND = 0 # The location has been collected. Status cannot be changed once found. - HINT_UNSPECIFIED = 1 # The receiving player has not specified any status + HINT_UNSPECIFIED = 0 # The receiving player has not specified any status HINT_NO_PRIORITY = 10 # The receiving player has specified that the item is unneeded HINT_AVOID = 20 # The receiving player has specified that the item is detrimental HINT_PRIORITY = 30 # The receiving player has specified that the item is needed + HINT_FOUND = 40 # The location has been collected. Status cannot be changed once found. ``` - Hints for items with `ItemClassification.trap` default to `HINT_AVOID`. - Hints created with `LocationScouts`, `!hint_location`, or similar (hinting a location) default to `HINT_UNSPECIFIED`. @@ -529,9 +533,9 @@ In JSON this may look like: {"item": 3, "location": 3, "player": 3, "flags": 0} ] ``` -`item` is the item id of the item. Item ids are only supported in the range of [-253, 253 - 1], with anything ≤ 0 reserved for Archipelago use. +`item` is the item id of the item. Item ids are only supported in the range of [-253 + 1, 253 - 1], with anything ≤ 0 reserved for Archipelago use. -`location` is the location id of the item inside the world. Location ids are only supported in the range of [-253, 253 - 1], with anything ≤ 0 reserved for Archipelago use. +`location` is the location id of the item inside the world. Location ids are only supported in the range of [-253 + 1, 253 - 1], with anything ≤ 0 reserved for Archipelago use. `player` is the player slot of the world the item is located in, except when inside an [LocationInfo](#LocationInfo) Packet then it will be the slot of the player to receive the item @@ -744,6 +748,7 @@ Tags are represented as a list of strings, the common client tags follow: | HintGame | Indicates the client is a hint game, made to send hints instead of locations. Special join/leave message,¹ `game` is optional.² | | Tracker | Indicates the client is a tracker, made to track instead of sending locations. Special join/leave message,¹ `game` is optional.² | | TextOnly | Indicates the client is a basic client, made to chat instead of sending locations. Special join/leave message,¹ `game` is optional.² | +| NoText | Indicates the client does not want to receive text messages, improving performance if not needed. | ¹: When connecting or disconnecting, the chat message shows e.g. "tracking".\ ²: Allows `game` to be empty or null in [Connect](#connect). Game and version validation will then be skipped. diff --git a/docs/options api.md b/docs/options api.md index d48a56d6c7..453cbc7e2d 100644 --- a/docs/options api.md +++ b/docs/options api.md @@ -95,7 +95,7 @@ user hovers over the yellow "(?)" icon, and included in the YAML templates gener The WebHost can display Option documentation either as plain text with all whitespace preserved (other than the base indentation), or as HTML generated from the standard Python [reStructuredText] format. Although plain text is the default for backwards compatibility, world authors are encouraged to write their Option documentation as -reStructuredText and enable rich text rendering by setting `World.rich_text_options_doc = True`. +reStructuredText and enable rich text rendering by setting `WebWorld.rich_text_options_doc = True`. [reStructuredText]: https://docutils.sourceforge.io/rst.html diff --git a/docs/world api.md b/docs/world api.md index 487c5b4a36..6a45ccbf99 100644 --- a/docs/world api.md +++ b/docs/world api.md @@ -222,8 +222,8 @@ could also be progress in a research tree, or even something more abstract like Each location has a `name` and an `address` (hereafter referred to as an `id`), is placed in a Region, has access rules, and has a classification. The name needs to be unique within each game and must not be numeric (must contain least 1 -letter or symbol). The ID needs to be unique across all games, and is best kept in the same range as the item IDs. -Locations and items can share IDs, so typically a game's locations and items start at the same ID. +letter or symbol). The ID needs to be unique across all locations within the game. +Locations and items can share IDs, and locations can share IDs with other games' locations. World-specific IDs must be in the range 1 to 253-1; IDs ≤ 0 are global and reserved. @@ -243,7 +243,9 @@ progression. Progression items will be assigned to locations with higher priorit and satisfy progression balancing. The name needs to be unique within each game, meaning if you need to create multiple items with the same name, they -will all have the same ID. Name must not be numeric (must contain at least 1 letter or symbol). +will all have the same ID. Name must not be numeric (must contain at least 1 letter or symbol). +The ID thus also needs to be unique across all items with different names within the game. +Items and locations can share IDs, and items can share IDs with other games' items. Other classifications include: @@ -490,6 +492,9 @@ In addition, the following methods can be implemented and are called in this ord after this step. Locations cannot be moved to different regions after this step. * `set_rules(self)` called to set access and item rules on locations and entrances. +* `connect_entrances(self)` + by the end of this step, all entrances must exist and be connected to their source and target regions. + Entrance randomization should be done here. * `generate_basic(self)` player-specific randomization that does not affect logic can be done here. * `pre_fill(self)`, `fill_hook(self)` and `post_fill(self)` @@ -557,17 +562,13 @@ from .items import is_progression # this is just a dummy def create_item(self, item: str) -> MyGameItem: # this is called when AP wants to create an item by name (for plando) or when you call it from your own code - classification = ItemClassification.progression if is_progression(item) else - ItemClassification.filler - - -return MyGameItem(item, classification, self.item_name_to_id[item], - self.player) + classification = ItemClassification.progression if is_progression(item) else ItemClassification.filler + return MyGameItem(item, classification, self.item_name_to_id[item], self.player) def create_event(self, event: str) -> MyGameItem: # while we are at it, we can also add a helper to create events - return MyGameItem(event, True, None, self.player) + return MyGameItem(event, ItemClassification.progression, None, self.player) ``` #### create_items @@ -835,14 +836,16 @@ def generate_output(self, output_directory: str) -> None: ### Slot Data -If the game client needs to know information about the generated seed, a preferred method of transferring the data -is through the slot data. This is filled with the `fill_slot_data` method of your world by returning -a `dict` with `str` keys that can be serialized with json. -But, to not waste resources, it should be limited to data that is absolutely necessary. Slot data is sent to your client -once it has successfully [connected](network%20protocol.md#connected). +If a client or tracker needs to know information about the generated seed, a preferred method of transferring the data +is through the slot data. This is filled with the `fill_slot_data` method of your world by returning a `dict` with +`str` keys that can be serialized with json. However, to not waste resources, it should be limited to data that is +absolutely necessary. Slot data is sent to your client once it has successfully +[connected](network%20protocol.md#connected). + If you need to know information about locations in your world, instead of propagating the slot data, it is preferable -to use [LocationScouts](network%20protocol.md#locationscouts), since that data already exists on the server. The most -common usage of slot data is sending option results that the client needs to be aware of. +to use [LocationScouts](network%20protocol.md#locationscouts), since that data already exists on the server. Adding +item/location pairs is unnecessary since the AP server already retains and freely gives that information to clients +that request it. The most common usage of slot data is sending option results that the client needs to be aware of. ```python def fill_slot_data(self) -> Dict[str, Any]: diff --git a/entrance_rando.py b/entrance_rando.py index 5aa16fa0bb..b6e64002bd 100644 --- a/entrance_rando.py +++ b/entrance_rando.py @@ -378,13 +378,14 @@ def randomize_entrances( and world.multiworld.has_beaten_game(er_state.collection_state, world.player): # ensure that we have enough locations to place our progression accessible_location_count = 0 - prog_item_count = sum(er_state.collection_state.prog_items[world.player].values()) + prog_item_count = len([item for item in world.multiworld.itempool if item.advancement and item.player == world.player]) # short-circuit location checking in this case if prog_item_count == 0: return True for region in er_state.placed_regions: for loc in region.locations: - if loc.can_reach(er_state.collection_state): + if not loc.item and loc.can_reach(er_state.collection_state): + # don't count locations with preplaced items accessible_location_count += 1 if accessible_location_count >= prog_item_count: perform_validity_check = False diff --git a/kvui.py b/kvui.py index b2ab004e27..60042b00ec 100644 --- a/kvui.py +++ b/kvui.py @@ -26,6 +26,10 @@ import Utils if Utils.is_frozen(): os.environ["KIVY_DATA_DIR"] = Utils.local_path("data") +import platformdirs +os.environ["KIVY_HOME"] = os.path.join(platformdirs.user_config_dir("Archipelago", False), "kivy") +os.makedirs(os.environ["KIVY_HOME"], exist_ok=True) + from kivy.config import Config Config.set("input", "mouse", "mouse,disable_multitouch") @@ -40,7 +44,7 @@ from kivy.core.image import ImageLoader, ImageLoaderBase, ImageData from kivy.base import ExceptionHandler, ExceptionManager from kivy.clock import Clock from kivy.factory import Factory -from kivy.properties import BooleanProperty, ObjectProperty +from kivy.properties import BooleanProperty, ObjectProperty, NumericProperty from kivy.metrics import dp from kivy.effects.scroll import ScrollEffect from kivy.uix.widget import Widget @@ -64,6 +68,7 @@ from kivy.uix.recycleboxlayout import RecycleBoxLayout from kivy.uix.recycleview.layout import LayoutSelectionBehavior from kivy.animation import Animation from kivy.uix.popup import Popup +from kivy.uix.dropdown import DropDown from kivy.uix.image import AsyncImage fade_in_animation = Animation(opacity=0, duration=0) + Animation(opacity=1, duration=0.25) @@ -305,6 +310,50 @@ class SelectableLabel(RecycleDataViewBehavior, TooltipLabel): """ Respond to the selection of items in the view. """ self.selected = is_selected + +class AutocompleteHintInput(TextInput): + min_chars = NumericProperty(3) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + self.dropdown = DropDown() + self.dropdown.bind(on_select=lambda instance, x: setattr(self, 'text', x)) + self.bind(on_text_validate=self.on_message) + + def on_message(self, instance): + App.get_running_app().commandprocessor("!hint "+instance.text) + + def on_text(self, instance, value): + if len(value) >= self.min_chars: + self.dropdown.clear_widgets() + ctx: context_type = App.get_running_app().ctx + if not ctx.game: + return + item_names = ctx.item_names._game_store[ctx.game].values() + + def on_press(button: Button): + split_text = MarkupLabel(text=button.text).markup + return self.dropdown.select("".join(text_frag for text_frag in split_text + if not text_frag.startswith("["))) + lowered = value.lower() + for item_name in item_names: + try: + index = item_name.lower().index(lowered) + except ValueError: + pass # substring not found + else: + text = escape_markup(item_name) + text = text[:index] + "[b]" + text[index:index+len(value)]+"[/b]"+text[index+len(value):] + btn = Button(text=text, size_hint_y=None, height=dp(30), markup=True) + btn.bind(on_release=on_press) + self.dropdown.add_widget(btn) + if not self.dropdown.attach_to: + self.dropdown.open(self) + else: + self.dropdown.dismiss() + + class HintLabel(RecycleDataViewBehavior, BoxLayout): selected = BooleanProperty(False) striped = BooleanProperty(False) @@ -395,8 +444,11 @@ class HintLabel(RecycleDataViewBehavior, BoxLayout): if child.collide_point(*touch.pos): key = child.sort_key if key == "status": - parent.hint_sorter = lambda element: element["status"]["hint"]["status"] - else: parent.hint_sorter = lambda element: remove_between_brackets.sub("", element[key]["text"]).lower() + parent.hint_sorter = lambda element: status_sort_weights[element["status"]["hint"]["status"]] + else: + parent.hint_sorter = lambda element: ( + remove_between_brackets.sub("", element[key]["text"]).lower() + ) if key == parent.sort_key: # second click reverses order parent.reversed = not parent.reversed @@ -570,8 +622,10 @@ class GameManager(App): # show Archipelago tab if other logging is present self.tabs.add_widget(panel) - hint_panel = self.add_client_tab("Hints", HintLog(self.json_to_kivy_parser)) + hint_panel = self.add_client_tab("Hints", HintLayout()) + self.hint_log = HintLog(self.json_to_kivy_parser) self.log_panels["Hints"] = hint_panel.content + hint_panel.content.add_widget(self.hint_log) if len(self.logging_pairs) == 1: self.tabs.default_tab_text = "Archipelago" @@ -698,7 +752,7 @@ class GameManager(App): def update_hints(self): hints = self.ctx.stored_data.get(f"_read_hints_{self.ctx.team}_{self.ctx.slot}", []) - self.log_panels["Hints"].refresh_hints(hints) + self.hint_log.refresh_hints(hints) # default F1 keybind, opens a settings menu, that seems to break the layout engine once closed def open_settings(self, *largs): @@ -753,6 +807,17 @@ class UILog(RecycleView): element.height = element.texture_size[1] +class HintLayout(BoxLayout): + orientation = "vertical" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + boxlayout = BoxLayout(orientation="horizontal", size_hint_y=None, height=dp(30)) + boxlayout.add_widget(Label(text="New Hint:", size_hint_x=None, size_hint_y=None, height=dp(30))) + boxlayout.add_widget(AutocompleteHintInput()) + self.add_widget(boxlayout) + + status_names: typing.Dict[HintStatus, str] = { HintStatus.HINT_FOUND: "Found", HintStatus.HINT_UNSPECIFIED: "Unspecified", @@ -767,6 +832,13 @@ status_colors: typing.Dict[HintStatus, str] = { HintStatus.HINT_AVOID: "salmon", HintStatus.HINT_PRIORITY: "plum", } +status_sort_weights: dict[HintStatus, int] = { + HintStatus.HINT_FOUND: 0, + HintStatus.HINT_UNSPECIFIED: 1, + HintStatus.HINT_NO_PRIORITY: 2, + HintStatus.HINT_AVOID: 3, + HintStatus.HINT_PRIORITY: 4, +} class HintLog(RecycleView): diff --git a/pytest.ini b/pytest.ini index 33e0bab8a9..cd8fd8dfce 100644 --- a/pytest.ini +++ b/pytest.ini @@ -2,3 +2,6 @@ python_files = test_*.py Test*.py # TODO: remove Test* once all worlds have been ported python_classes = Test python_functions = test +testpaths = + test + worlds diff --git a/requirements.txt b/requirements.txt index 946546cb69..cd045b874b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ schema>=0.7.7 kivy>=2.3.0 bsdiff4>=1.2.4 platformdirs>=4.2.2 -certifi>=2024.8.30 +certifi>=2024.12.14 cython>=3.0.11 cymem>=2.0.8 orjson>=3.10.7 diff --git a/settings.py b/settings.py index 04d8760c3c..255c537fe0 100644 --- a/settings.py +++ b/settings.py @@ -109,7 +109,7 @@ class Group: def get_type_hints(cls) -> Dict[str, Any]: """Returns resolved type hints for the class""" if cls._type_cache is None: - if not isinstance(next(iter(cls.__annotations__.values())), str): + if not cls.__annotations__ or not isinstance(next(iter(cls.__annotations__.values())), str): # non-str: assume already resolved cls._type_cache = cls.__annotations__ else: @@ -270,15 +270,20 @@ class Group: # fetch class to avoid going through getattr cls = self.__class__ type_hints = cls.get_type_hints() + entries = [e for e in self] + if not entries: + # write empty dict for empty Group with no instance values + cls._dump_value({}, f, indent=" " * level) # validate group for name in cls.__annotations__.keys(): assert hasattr(cls, name), f"{cls}.{name} is missing a default value" # dump ordered members - for name in self: + for name in entries: attr = cast(object, getattr(self, name)) attr_cls = type_hints[name] if name in type_hints else attr.__class__ attr_cls_origin = typing.get_origin(attr_cls) - while attr_cls_origin is Union: # resolve to first type for doc string + # resolve to first type for doc string + while attr_cls_origin is Union or attr_cls_origin is types.UnionType: attr_cls = typing.get_args(attr_cls)[0] attr_cls_origin = typing.get_origin(attr_cls) if attr_cls.__doc__ and attr_cls.__module__ != "builtins": @@ -678,6 +683,8 @@ class GeneratorOptions(Group): race: Race = Race(0) plando_options: PlandoOptions = PlandoOptions("bosses, connections, texts") panic_method: PanicMethod = PanicMethod("swap") + loglevel: str = "info" + logtime: bool = False class SNIOptions(Group): @@ -785,7 +792,17 @@ class Settings(Group): if location: from Utils import parse_yaml with open(location, encoding="utf-8-sig") as f: - options = parse_yaml(f.read()) + from yaml.error import MarkedYAMLError + try: + options = parse_yaml(f.read()) + except MarkedYAMLError as ex: + if ex.problem_mark: + f.seek(0) + lines = f.readlines() + problem_line = lines[ex.problem_mark.line] + error_line = " " * ex.problem_mark.column + "^" + raise Exception(f"{ex.context} {ex.problem}\n{problem_line}{error_line}") + raise ex # TODO: detect if upgrade is required # TODO: once we have a cache for _world_settings_name_cache, detect if any game section is missing self.update(options or {}) diff --git a/test/benchmark/locations.py b/test/benchmark/locations.py index f2209eb689..857e188236 100644 --- a/test/benchmark/locations.py +++ b/test/benchmark/locations.py @@ -18,7 +18,15 @@ def run_locations_benchmark(): class BenchmarkRunner: gen_steps: typing.Tuple[str, ...] = ( - "generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill") + "generate_early", + "create_regions", + "create_items", + "set_rules", + "connect_entrances", + "generate_basic", + "pre_fill", + ) + rule_iterations: int = 100_000 if sys.version_info >= (3, 9): diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt index 927b7494da..03deb8f982 100644 --- a/test/cpp/CMakeLists.txt +++ b/test/cpp/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.16) project(ap-cpp-tests) enable_testing() @@ -7,8 +7,8 @@ find_package(GTest REQUIRED) if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_definitions("/source-charset:utf-8") - set(CMAKE_CXX_FLAGS_DEBUG "/MTd") - set(CMAKE_CXX_FLAGS_RELEASE "/MT") + # set(CMAKE_CXX_FLAGS_DEBUG "/MDd") # this is the default + # set(CMAKE_CXX_FLAGS_RELEASE "/MD") # this is the default elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # enable static analysis for gcc add_compile_options(-fanalyzer -Werror) diff --git a/test/general/__init__.py b/test/general/__init__.py index 8afd849765..6c4d5092cf 100644 --- a/test/general/__init__.py +++ b/test/general/__init__.py @@ -5,7 +5,15 @@ from BaseClasses import CollectionState, Item, ItemClassification, Location, Mul from worlds import network_data_package from worlds.AutoWorld import World, call_all -gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill") +gen_steps = ( + "generate_early", + "create_regions", + "create_items", + "set_rules", + "connect_entrances", + "generate_basic", + "pre_fill", +) def setup_solo_multiworld( diff --git a/test/general/test_entrance_rando.py b/test/general/test_entrance_rando.py index efbcf7df46..7e904d3340 100644 --- a/test/general/test_entrance_rando.py +++ b/test/general/test_entrance_rando.py @@ -311,6 +311,37 @@ class TestRandomizeEntrances(unittest.TestCase): self.assertEqual([], [exit_ for region in multiworld.get_regions() for exit_ in region.exits if not exit_.connected_region]) + def test_minimal_entrance_rando_with_collect_override(self): + """ + tests that entrance randomization can complete with minimal accessibility and unreachable exits + when the world defines a collect override that add extra values to prog_items + """ + multiworld = generate_test_multiworld() + multiworld.worlds[1].options.accessibility = Accessibility.from_any(Accessibility.option_minimal) + multiworld.completion_condition[1] = lambda state: state.can_reach("region24", player=1) + generate_disconnected_region_grid(multiworld, 5, 1) + prog_items = generate_items(10, 1, True) + multiworld.itempool += prog_items + filler_items = generate_items(15, 1, False) + multiworld.itempool += filler_items + e = multiworld.get_entrance("region1_right", 1) + set_rule(e, lambda state: False) + + old_collect = multiworld.worlds[1].collect + + def new_collect(state, item): + old_collect(state, item) + state.prog_items[item.player]["counter"] += 300 + + multiworld.worlds[1].collect = new_collect + + randomize_entrances(multiworld.worlds[1], False, directionally_matched_group_lookup) + + self.assertEqual([], [entrance for region in multiworld.get_regions() + for entrance in region.entrances if not entrance.parent_region]) + self.assertEqual([], [exit_ for region in multiworld.get_regions() + for exit_ in region.exits if not exit_.connected_region]) + def test_restrictive_region_requirement_does_not_fail(self): multiworld = generate_test_multiworld() generate_disconnected_region_grid(multiworld, 2, 1) diff --git a/test/general/test_entrances.py b/test/general/test_entrances.py new file mode 100644 index 0000000000..88362c8fa6 --- /dev/null +++ b/test/general/test_entrances.py @@ -0,0 +1,63 @@ +import unittest +from worlds.AutoWorld import AutoWorldRegister, call_all, World +from . import setup_solo_multiworld + + +class TestBase(unittest.TestCase): + def test_entrance_connection_steps(self): + """Tests that Entrances are connected and not changed after connect_entrances.""" + def get_entrance_name_to_source_and_target_dict(world: World): + return [ + (entrance.name, entrance.parent_region, entrance.connected_region) + for entrance in world.get_entrances() + ] + + gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "connect_entrances") + additional_steps = ("generate_basic", "pre_fill") + + for game_name, world_type in AutoWorldRegister.world_types.items(): + with self.subTest("Game", game_name=game_name): + multiworld = setup_solo_multiworld(world_type, gen_steps) + + original_entrances = get_entrance_name_to_source_and_target_dict(multiworld.worlds[1]) + + self.assertTrue( + all(entrance[1] is not None and entrance[2] is not None for entrance in original_entrances), + f"{game_name} had unconnected entrances after connect_entrances" + ) + + for step in additional_steps: + with self.subTest("Step", step=step): + call_all(multiworld, step) + step_entrances = get_entrance_name_to_source_and_target_dict(multiworld.worlds[1]) + + self.assertEqual( + original_entrances, step_entrances, f"{game_name} modified entrances during {step}" + ) + + def test_all_state_before_connect_entrances(self): + """Before connect_entrances, Entrance objects may be unconnected. + Thus, we test that get_all_state is performed with allow_partial_entrances if used before or during + connect_entrances.""" + + gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "connect_entrances") + + for game_name, world_type in AutoWorldRegister.world_types.items(): + with self.subTest("Game", game_name=game_name): + multiworld = setup_solo_multiworld(world_type, ()) + + original_get_all_state = multiworld.get_all_state + + def patched_get_all_state(use_cache: bool, allow_partial_entrances: bool = False): + self.assertTrue(allow_partial_entrances, ( + "Before the connect_entrances step finishes, other worlds might still have partial entrances. " + "As such, any call to get_all_state must use allow_partial_entrances = True." + )) + + return original_get_all_state(use_cache, allow_partial_entrances) + + multiworld.get_all_state = patched_get_all_state + + for step in gen_steps: + with self.subTest("Step", step=step): + call_all(multiworld, step) diff --git a/test/general/test_helpers.py b/test/general/test_helpers.py index be84739756..7e850f9744 100644 --- a/test/general/test_helpers.py +++ b/test/general/test_helpers.py @@ -1,6 +1,8 @@ import unittest from typing import Callable, Dict, Optional +from typing_extensions import override + from BaseClasses import CollectionState, MultiWorld, Region @@ -8,6 +10,7 @@ class TestHelpers(unittest.TestCase): multiworld: MultiWorld player: int = 1 + @override def setUp(self) -> None: self.multiworld = MultiWorld(self.player) self.multiworld.game[self.player] = "helper_test_game" @@ -38,15 +41,15 @@ class TestHelpers(unittest.TestCase): "TestRegion1": {"TestRegion2": "connection"}, "TestRegion2": {"TestRegion1": None}, } - + reg_exit_set: Dict[str, set[str]] = { "TestRegion1": {"TestRegion3"} } - + exit_rules: Dict[str, Callable[[CollectionState], bool]] = { "TestRegion1": lambda state: state.has("test_item", self.player) } - + self.multiworld.regions += [Region(region, self.player, self.multiworld, regions[region]) for region in regions] with self.subTest("Test Location Creation Helper"): @@ -73,7 +76,7 @@ class TestHelpers(unittest.TestCase): entrance_name = exit_name if exit_name else f"{parent} -> {exit_reg}" self.assertEqual(exit_rules[exit_reg], self.multiworld.get_entrance(entrance_name, self.player).access_rule) - + for region in reg_exit_set: current_region = self.multiworld.get_region(region, self.player) current_region.add_exits(reg_exit_set[region]) diff --git a/test/general/test_implemented.py b/test/general/test_implemented.py index 756cfa8bb6..1082a02912 100644 --- a/test/general/test_implemented.py +++ b/test/general/test_implemented.py @@ -39,7 +39,7 @@ class TestImplemented(unittest.TestCase): """Tests that if a world creates slot data, it's json serializable.""" for game_name, world_type in AutoWorldRegister.world_types.items(): # has an await for generate_output which isn't being called - if game_name in {"Ocarina of Time", "Zillion"}: + if game_name in {"Ocarina of Time"}: continue multiworld = setup_solo_multiworld(world_type) with self.subTest(game=game_name, seed=multiworld.seed): @@ -117,3 +117,12 @@ class TestImplemented(unittest.TestCase): f"\nUnexpectedly reachable locations in sphere {sphere_num}:" f"\n{reachable_only_with_explicit}") self.fail("Unreachable") + + def test_no_items_or_locations_or_regions_submitted_in_init(self): + """Test that worlds don't submit items/locations/regions to the multiworld in __init__""" + for game_name, world_type in AutoWorldRegister.world_types.items(): + with self.subTest("Game", game=game_name): + multiworld = setup_solo_multiworld(world_type, ()) + self.assertEqual(len(multiworld.itempool), 0) + self.assertEqual(len(multiworld.get_locations()), 0) + self.assertEqual(len(multiworld.get_regions()), 0) diff --git a/test/general/test_items.py b/test/general/test_items.py index 64ce1b6997..91d334e968 100644 --- a/test/general/test_items.py +++ b/test/general/test_items.py @@ -67,7 +67,7 @@ class TestBase(unittest.TestCase): def test_itempool_not_modified(self): """Test that worlds don't modify the itempool after `create_items`""" gen_steps = ("generate_early", "create_regions", "create_items") - additional_steps = ("set_rules", "generate_basic", "pre_fill") + additional_steps = ("set_rules", "connect_entrances", "generate_basic", "pre_fill") excluded_games = ("Links Awakening DX", "Ocarina of Time", "SMZ3") worlds_to_test = {game: world for game, world in AutoWorldRegister.world_types.items() if game not in excluded_games} @@ -84,7 +84,7 @@ class TestBase(unittest.TestCase): def test_locality_not_modified(self): """Test that worlds don't modify the locality of items after duplicates are resolved""" gen_steps = ("generate_early", "create_regions", "create_items") - additional_steps = ("set_rules", "generate_basic", "pre_fill") + additional_steps = ("set_rules", "connect_entrances", "generate_basic", "pre_fill") worlds_to_test = {game: world for game, world in AutoWorldRegister.world_types.items()} for game_name, world_type in worlds_to_test.items(): with self.subTest("Game", game=game_name): diff --git a/test/general/test_locations.py b/test/general/test_locations.py index 4b95ebd22c..37ae94e003 100644 --- a/test/general/test_locations.py +++ b/test/general/test_locations.py @@ -45,6 +45,12 @@ class TestBase(unittest.TestCase): self.assertEqual(location_count, len(multiworld.get_locations()), f"{game_name} modified locations count during rule creation") + call_all(multiworld, "connect_entrances") + self.assertEqual(region_count, len(multiworld.get_regions()), + f"{game_name} modified region count during rule creation") + self.assertEqual(location_count, len(multiworld.get_locations()), + f"{game_name} modified locations count during rule creation") + call_all(multiworld, "generate_basic") self.assertEqual(region_count, len(multiworld.get_regions()), f"{game_name} modified region count during generate_basic") diff --git a/test/general/test_memory.py b/test/general/test_memory.py index e352b9e875..a4b2f1bd25 100644 --- a/test/general/test_memory.py +++ b/test/general/test_memory.py @@ -1,16 +1,21 @@ import unittest +from BaseClasses import MultiWorld from worlds.AutoWorld import AutoWorldRegister from . import setup_solo_multiworld class TestWorldMemory(unittest.TestCase): - def test_leak(self): + def test_leak(self) -> None: """Tests that worlds don't leak references to MultiWorld or themselves with default options.""" import gc import weakref + refs: dict[str, weakref.ReferenceType[MultiWorld]] = {} for game_name, world_type in AutoWorldRegister.world_types.items(): - with self.subTest("Game", game_name=game_name): + with self.subTest("Game creation", game_name=game_name): weak = weakref.ref(setup_solo_multiworld(world_type)) - gc.collect() + refs[game_name] = weak + gc.collect() + for game_name, weak in refs.items(): + with self.subTest("Game cleanup", game_name=game_name): self.assertFalse(weak(), "World leaked a reference") diff --git a/test/general/test_names.py b/test/general/test_names.py index 7be76eed4b..8ad74a3354 100644 --- a/test/general/test_names.py +++ b/test/general/test_names.py @@ -3,7 +3,7 @@ from worlds.AutoWorld import AutoWorldRegister class TestNames(unittest.TestCase): - def test_item_names_format(self): + def test_item_names_format(self) -> None: """Item names must not be all numeric in order to differentiate between ID and name in !hint""" for gamename, world_type in AutoWorldRegister.world_types.items(): with self.subTest(game=gamename): @@ -11,7 +11,7 @@ class TestNames(unittest.TestCase): self.assertFalse(item_name.isnumeric(), f"Item name \"{item_name}\" is invalid. It must not be numeric.") - def test_location_name_format(self): + def test_location_name_format(self) -> None: """Location names must not be all numeric in order to differentiate between ID and name in !hint_location""" for gamename, world_type in AutoWorldRegister.world_types.items(): with self.subTest(game=gamename): diff --git a/test/general/test_reachability.py b/test/general/test_reachability.py index fafa702389..b45a2bdfc0 100644 --- a/test/general/test_reachability.py +++ b/test/general/test_reachability.py @@ -2,11 +2,11 @@ import unittest from BaseClasses import CollectionState from worlds.AutoWorld import AutoWorldRegister -from . import setup_solo_multiworld +from . import setup_solo_multiworld, gen_steps class TestBase(unittest.TestCase): - gen_steps = ["generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill"] + gen_steps = gen_steps default_settings_unreachable_regions = { "A Link to the Past": { diff --git a/test/general/test_state.py b/test/general/test_state.py new file mode 100644 index 0000000000..460fc3d608 --- /dev/null +++ b/test/general/test_state.py @@ -0,0 +1,29 @@ +import unittest + +from worlds.AutoWorld import AutoWorldRegister, call_all +from . import setup_solo_multiworld + + +class TestBase(unittest.TestCase): + gen_steps = ( + "generate_early", + "create_regions", + ) + + test_steps = ( + "create_items", + "set_rules", + "connect_entrances", + "generate_basic", + "pre_fill", + ) + + def test_all_state_is_available(self): + """Ensure all_state can be created at certain steps.""" + for game_name, world_type in AutoWorldRegister.world_types.items(): + with self.subTest("Game", game=game_name): + multiworld = setup_solo_multiworld(world_type, self.gen_steps) + for step in self.test_steps: + with self.subTest("Step", step=step): + call_all(multiworld, step) + self.assertTrue(multiworld.get_all_state(False, True)) diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index a510717920..0fcacc8ab3 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -378,6 +378,10 @@ class World(metaclass=AutoWorldRegister): """Method for setting the rules on the World's regions and locations.""" pass + def connect_entrances(self) -> None: + """Method to finalize the source and target regions of the World's entrances""" + pass + def generate_basic(self) -> None: """ Useful for randomizing things that don't affect logic but are better to be determined before the output stage. diff --git a/worlds/LauncherComponents.py b/worlds/LauncherComponents.py index d1b274c19a..41c83db419 100644 --- a/worlds/LauncherComponents.py +++ b/worlds/LauncherComponents.py @@ -87,7 +87,7 @@ class Component: processes = weakref.WeakSet() -def launch_subprocess(func: Callable, name: str = None, args: Tuple[str, ...] = ()) -> None: +def launch_subprocess(func: Callable, name: str | None = None, args: Tuple[str, ...] = ()) -> None: global processes import multiprocessing process = multiprocessing.Process(target=func, name=name, args=args) @@ -95,6 +95,14 @@ def launch_subprocess(func: Callable, name: str = None, args: Tuple[str, ...] = processes.add(process) +def launch(func: Callable, name: str | None = None, args: Tuple[str, ...] = ()) -> None: + from Utils import is_kivy_running + if is_kivy_running(): + launch_subprocess(func, name, args) + else: + func(*args) + + class SuffixIdentifier: suffixes: Iterable[str] @@ -111,7 +119,7 @@ class SuffixIdentifier: def launch_textclient(*args): import CommonClient - launch_subprocess(CommonClient.run_as_textclient, name="TextClient", args=args) + launch(CommonClient.run_as_textclient, name="TextClient", args=args) def _install_apworld(apworld_src: str = "") -> Optional[Tuple[pathlib.Path, pathlib.Path]]: diff --git a/worlds/_bizhawk/README.md b/worlds/_bizhawk/README.md index ddc70c3dd7..9058fc3061 100644 --- a/worlds/_bizhawk/README.md +++ b/worlds/_bizhawk/README.md @@ -55,6 +55,7 @@ async def lock(ctx) -> None async def unlock(ctx) -> None async def get_hash(ctx) -> str +async def get_memory_size(ctx, domain: str) -> int async def get_system(ctx) -> str async def get_cores(ctx) -> dict[str, str] async def ping(ctx) -> None @@ -168,9 +169,10 @@ select dialog and they will be associated with BizHawkClient. This does not affe associate the file extension with Archipelago. `validate_rom` is called to figure out whether a given ROM belongs to your client. It will only be called when a ROM is -running on a system you specified in your `system` class variable. In most cases, that will be a single system and you -can be sure that you're not about to try to read from nonexistent domains or out of bounds. If you decide to claim this -ROM as yours, this is where you should do setup for things like `items_handling`. +running on a system you specified in your `system` class variable. Take extra care here, because your code will run +against ROMs that you have no control over. If you're reading an address deep in ROM, you might want to check the size +of ROM before you attempt to read it using `get_memory_size`. If you decide to claim this ROM as yours, this is where +you should do setup for things like `items_handling`. `game_watcher` is the "main loop" of your client where you should be checking memory and sending new items to the ROM. `BizHawkClient` will make sure that your `game_watcher` only runs when your client has validated the ROM, and will do @@ -268,6 +270,8 @@ server connection before trying to interact with it. - By default, the player will be asked to provide their slot name after connecting to the server and validating, and that input will be used to authenticate with the `Connect` command. You can override `set_auth` in your own client to set it automatically based on data in the ROM or on your client instance. +- Use `get_memory_size` inside `validate_rom` if you need to read at large addresses, in case some other game has a +smaller ROM size. - You can override `on_package` in your client to watch raw packages, but don't forget you also have access to a subclass of `CommonContext` and its API. - You can import `BizHawkClientContext` for type hints using `typing.TYPE_CHECKING`. Importing it without conditions at diff --git a/worlds/_bizhawk/__init__.py b/worlds/_bizhawk/__init__.py index 3627f385c2..b10e33d396 100644 --- a/worlds/_bizhawk/__init__.py +++ b/worlds/_bizhawk/__init__.py @@ -10,7 +10,7 @@ import base64 import enum import json import sys -import typing +from typing import Any, Sequence BIZHAWK_SOCKET_PORT_RANGE_START = 43055 @@ -44,10 +44,10 @@ class SyncError(Exception): class BizHawkContext: - streams: typing.Optional[typing.Tuple[asyncio.StreamReader, asyncio.StreamWriter]] + streams: tuple[asyncio.StreamReader, asyncio.StreamWriter] | None connection_status: ConnectionStatus _lock: asyncio.Lock - _port: typing.Optional[int] + _port: int | None def __init__(self) -> None: self.streams = None @@ -122,12 +122,12 @@ async def get_script_version(ctx: BizHawkContext) -> int: return int(await ctx._send_message("VERSION")) -async def send_requests(ctx: BizHawkContext, req_list: typing.List[typing.Dict[str, typing.Any]]) -> typing.List[typing.Dict[str, typing.Any]]: +async def send_requests(ctx: BizHawkContext, req_list: list[dict[str, Any]]) -> list[dict[str, Any]]: """Sends a list of requests to the BizHawk connector and returns their responses. It's likely you want to use the wrapper functions instead of this.""" responses = json.loads(await ctx._send_message(json.dumps(req_list))) - errors: typing.List[ConnectorError] = [] + errors: list[ConnectorError] = [] for response in responses: if response["type"] == "ERROR": @@ -151,7 +151,7 @@ async def ping(ctx: BizHawkContext) -> None: async def get_hash(ctx: BizHawkContext) -> str: - """Gets the system name for the currently loaded ROM""" + """Gets the hash value of the currently loaded ROM""" res = (await send_requests(ctx, [{"type": "HASH"}]))[0] if res["type"] != "HASH_RESPONSE": @@ -160,6 +160,16 @@ async def get_hash(ctx: BizHawkContext) -> str: return res["value"] +async def get_memory_size(ctx: BizHawkContext, domain: str) -> int: + """Gets the size in bytes of the specified memory domain""" + res = (await send_requests(ctx, [{"type": "MEMORY_SIZE", "domain": domain}]))[0] + + if res["type"] != "MEMORY_SIZE_RESPONSE": + raise SyncError(f"Expected response of type MEMORY_SIZE_RESPONSE but got {res['type']}") + + return res["value"] + + async def get_system(ctx: BizHawkContext) -> str: """Gets the system name for the currently loaded ROM""" res = (await send_requests(ctx, [{"type": "SYSTEM"}]))[0] @@ -170,7 +180,7 @@ async def get_system(ctx: BizHawkContext) -> str: return res["value"] -async def get_cores(ctx: BizHawkContext) -> typing.Dict[str, str]: +async def get_cores(ctx: BizHawkContext) -> dict[str, str]: """Gets the preferred cores for systems with multiple cores. Only systems with multiple available cores have entries.""" res = (await send_requests(ctx, [{"type": "PREFERRED_CORES"}]))[0] @@ -223,8 +233,8 @@ async def set_message_interval(ctx: BizHawkContext, value: float) -> None: raise SyncError(f"Expected response of type SET_MESSAGE_INTERVAL_RESPONSE but got {res['type']}") -async def guarded_read(ctx: BizHawkContext, read_list: typing.Sequence[typing.Tuple[int, int, str]], - guard_list: typing.Sequence[typing.Tuple[int, typing.Sequence[int], str]]) -> typing.Optional[typing.List[bytes]]: +async def guarded_read(ctx: BizHawkContext, read_list: Sequence[tuple[int, int, str]], + guard_list: Sequence[tuple[int, Sequence[int], str]]) -> list[bytes] | None: """Reads an array of bytes at 1 or more addresses if and only if every byte in guard_list matches its expected value. @@ -252,7 +262,7 @@ async def guarded_read(ctx: BizHawkContext, read_list: typing.Sequence[typing.Tu "domain": domain } for address, size, domain in read_list]) - ret: typing.List[bytes] = [] + ret: list[bytes] = [] for item in res: if item["type"] == "GUARD_RESPONSE": if not item["value"]: @@ -266,7 +276,7 @@ async def guarded_read(ctx: BizHawkContext, read_list: typing.Sequence[typing.Tu return ret -async def read(ctx: BizHawkContext, read_list: typing.Sequence[typing.Tuple[int, int, str]]) -> typing.List[bytes]: +async def read(ctx: BizHawkContext, read_list: Sequence[tuple[int, int, str]]) -> list[bytes]: """Reads data at 1 or more addresses. Items in `read_list` should be organized `(address, size, domain)` where @@ -278,8 +288,8 @@ async def read(ctx: BizHawkContext, read_list: typing.Sequence[typing.Tuple[int, return await guarded_read(ctx, read_list, []) -async def guarded_write(ctx: BizHawkContext, write_list: typing.Sequence[typing.Tuple[int, typing.Sequence[int], str]], - guard_list: typing.Sequence[typing.Tuple[int, typing.Sequence[int], str]]) -> bool: +async def guarded_write(ctx: BizHawkContext, write_list: Sequence[tuple[int, Sequence[int], str]], + guard_list: Sequence[tuple[int, Sequence[int], str]]) -> bool: """Writes data to 1 or more addresses if and only if every byte in guard_list matches its expected value. Items in `write_list` should be organized `(address, value, domain)` where @@ -316,7 +326,7 @@ async def guarded_write(ctx: BizHawkContext, write_list: typing.Sequence[typing. return True -async def write(ctx: BizHawkContext, write_list: typing.Sequence[typing.Tuple[int, typing.Sequence[int], str]]) -> None: +async def write(ctx: BizHawkContext, write_list: Sequence[tuple[int, Sequence[int], str]]) -> None: """Writes data to 1 or more addresses. Items in write_list should be organized `(address, value, domain)` where diff --git a/worlds/_bizhawk/client.py b/worlds/_bizhawk/client.py index 415b663e60..16a8325a10 100644 --- a/worlds/_bizhawk/client.py +++ b/worlds/_bizhawk/client.py @@ -5,9 +5,9 @@ A module containing the BizHawkClient base class and metaclass from __future__ import annotations import abc -from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, ClassVar -from worlds.LauncherComponents import Component, SuffixIdentifier, Type, components, launch_subprocess +from worlds.LauncherComponents import Component, SuffixIdentifier, Type, components, launch as launch_component if TYPE_CHECKING: from .context import BizHawkClientContext @@ -15,7 +15,7 @@ if TYPE_CHECKING: def launch_client(*args) -> None: from .context import launch - launch_subprocess(launch, name="BizHawkClient", args=args) + launch_component(launch, name="BizHawkClient", args=args) component = Component("BizHawk Client", "BizHawkClient", component_type=Type.CLIENT, func=launch_client, @@ -24,9 +24,9 @@ components.append(component) class AutoBizHawkClientRegister(abc.ABCMeta): - game_handlers: ClassVar[Dict[Tuple[str, ...], Dict[str, BizHawkClient]]] = {} + game_handlers: ClassVar[dict[tuple[str, ...], dict[str, BizHawkClient]]] = {} - def __new__(cls, name: str, bases: Tuple[type, ...], namespace: Dict[str, Any]) -> AutoBizHawkClientRegister: + def __new__(cls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]) -> AutoBizHawkClientRegister: new_class = super().__new__(cls, name, bases, namespace) # Register handler @@ -54,7 +54,7 @@ class AutoBizHawkClientRegister(abc.ABCMeta): return new_class @staticmethod - async def get_handler(ctx: "BizHawkClientContext", system: str) -> Optional[BizHawkClient]: + async def get_handler(ctx: "BizHawkClientContext", system: str) -> BizHawkClient | None: for systems, handlers in AutoBizHawkClientRegister.game_handlers.items(): if system in systems: for handler in handlers.values(): @@ -65,13 +65,13 @@ class AutoBizHawkClientRegister(abc.ABCMeta): class BizHawkClient(abc.ABC, metaclass=AutoBizHawkClientRegister): - system: ClassVar[Union[str, Tuple[str, ...]]] + system: ClassVar[str | tuple[str, ...]] """The system(s) that the game this client is for runs on""" game: ClassVar[str] """The game this client is for""" - patch_suffix: ClassVar[Optional[Union[str, Tuple[str, ...]]]] + patch_suffix: ClassVar[str | tuple[str, ...] | None] """The file extension(s) this client is meant to open and patch (e.g. ".apz3")""" @abc.abstractmethod diff --git a/worlds/_bizhawk/context.py b/worlds/_bizhawk/context.py index 2a3965a54f..accb5f94c4 100644 --- a/worlds/_bizhawk/context.py +++ b/worlds/_bizhawk/context.py @@ -6,7 +6,7 @@ checking or launching the client, otherwise it will probably cause circular impo import asyncio import enum import subprocess -from typing import Any, Dict, Optional +from typing import Any from CommonClient import CommonContext, ClientCommandProcessor, get_base_parser, server_loop, logger, gui_enabled import Patch @@ -43,15 +43,15 @@ class BizHawkClientContext(CommonContext): command_processor = BizHawkClientCommandProcessor auth_status: AuthStatus password_requested: bool - client_handler: Optional[BizHawkClient] - slot_data: Optional[Dict[str, Any]] = None - rom_hash: Optional[str] = None + client_handler: BizHawkClient | None + slot_data: dict[str, Any] | None = None + rom_hash: str | None = None bizhawk_ctx: BizHawkContext watcher_timeout: float """The maximum amount of time the game watcher loop will wait for an update from the server before executing""" - def __init__(self, server_address: Optional[str], password: Optional[str]): + def __init__(self, server_address: str | None, password: str | None): super().__init__(server_address, password) self.auth_status = AuthStatus.NOT_AUTHENTICATED self.password_requested = False @@ -231,20 +231,28 @@ async def _run_game(rom: str): ) -async def _patch_and_run_game(patch_file: str): +def _patch_and_run_game(patch_file: str): try: metadata, output_file = Patch.create_rom_file(patch_file) Utils.async_start(_run_game(output_file)) + return metadata except Exception as exc: logger.exception(exc) + Utils.messagebox("Error Patching Game", str(exc), True) + return {} -def launch(*launch_args) -> None: +def launch(*launch_args: str) -> None: async def main(): parser = get_base_parser() parser.add_argument("patch_file", default="", type=str, nargs="?", help="Path to an Archipelago patch file") args = parser.parse_args(launch_args) + if args.patch_file != "": + metadata = _patch_and_run_game(args.patch_file) + if "server" in metadata: + args.connect = metadata["server"] + ctx = BizHawkClientContext(args.connect, args.password) ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop") @@ -252,9 +260,6 @@ def launch(*launch_args) -> None: ctx.run_gui() ctx.run_cli() - if args.patch_file != "": - Utils.async_start(_patch_and_run_game(args.patch_file)) - watcher_task = asyncio.create_task(_game_watcher(ctx), name="GameWatcher") try: diff --git a/worlds/adventure/Options.py b/worlds/adventure/Options.py index e6a8e4c202..4b3f30df24 100644 --- a/worlds/adventure/Options.py +++ b/worlds/adventure/Options.py @@ -1,9 +1,8 @@ from __future__ import annotations -from typing import Dict - from dataclasses import dataclass -from Options import Choice, Option, DefaultOnToggle, DeathLink, Range, Toggle, PerGameCommonOptions + +from Options import Choice, DefaultOnToggle, DeathLink, Range, Toggle, PerGameCommonOptions class FreeincarnateMax(Range): diff --git a/worlds/adventure/Regions.py b/worlds/adventure/Regions.py index 4e4dd1e7ba..a0a04be2aa 100644 --- a/worlds/adventure/Regions.py +++ b/worlds/adventure/Regions.py @@ -1,6 +1,6 @@ from BaseClasses import MultiWorld, Region, Entrance, LocationProgressType from Options import PerGameCommonOptions -from .Locations import location_table, LocationData, AdventureLocation, dragon_room_to_region +from .Locations import location_table, AdventureLocation, dragon_room_to_region def connect(world: MultiWorld, player: int, source: str, target: str, rule: callable = lambda state: True, diff --git a/worlds/adventure/Rom.py b/worlds/adventure/Rom.py index 643f7a6c76..4d56cd19e5 100644 --- a/worlds/adventure/Rom.py +++ b/worlds/adventure/Rom.py @@ -2,15 +2,15 @@ import hashlib import json import os import zipfile -from typing import Optional, Any - -import Utils -from .Locations import AdventureLocation, LocationData -from settings import get_settings -from worlds.Files import APPatch, AutoPatchRegister +from typing import Any import bsdiff4 +import Utils +from settings import get_settings +from worlds.Files import APPatch, AutoPatchRegister +from .Locations import LocationData + ADVENTUREHASH: str = "157bddb7192754a45372be196797f284" diff --git a/worlds/adventure/__init__.py b/worlds/adventure/__init__.py index 4fde1482cf..9dab2ffcef 100644 --- a/worlds/adventure/__init__.py +++ b/worlds/adventure/__init__.py @@ -1,35 +1,24 @@ -import base64 import copy -import itertools import math import os -import settings import typing -from enum import IntFlag -from typing import Any, ClassVar, Dict, List, Optional, Set, Tuple +from typing import ClassVar, Dict, Optional, Tuple -from BaseClasses import Entrance, Item, ItemClassification, MultiWorld, Region, Tutorial, \ - LocationProgressType +import settings +from BaseClasses import Item, ItemClassification, MultiWorld, Tutorial, LocationProgressType from Utils import __version__ -from Options import AssembleOptions from worlds.AutoWorld import WebWorld, World -from Fill import fill_restrictive -from worlds.generic.Rules import add_rule, set_rule -from .Options import DragonRandoType, DifficultySwitchA, DifficultySwitchB, \ - AdventureOptions -from .Rom import get_base_rom_bytes, get_base_rom_path, AdventureDeltaPatch, apply_basepatch, \ - AdventureAutoCollectLocation +from worlds.LauncherComponents import Component, components, SuffixIdentifier from .Items import item_table, ItemData, nothing_item_id, event_table, AdventureItem, standard_item_max from .Locations import location_table, base_location_id, LocationData, get_random_room_in_regions from .Offsets import static_item_data_location, items_ram_start, static_item_element_size, item_position_table, \ static_first_dragon_index, connector_port_offset, yorgle_speed_data_location, grundle_speed_data_location, \ rhindle_speed_data_location, item_ram_addresses, start_castle_values, start_castle_offset +from .Options import DragonRandoType, DifficultySwitchA, DifficultySwitchB, AdventureOptions from .Regions import create_regions +from .Rom import get_base_rom_bytes, get_base_rom_path, AdventureDeltaPatch, apply_basepatch, AdventureAutoCollectLocation from .Rules import set_rules - -from worlds.LauncherComponents import Component, components, SuffixIdentifier - # Adventure components.append(Component('Adventure Client', 'AdventureClient', file_identifier=SuffixIdentifier('.apadvn'))) diff --git a/worlds/ahit/DeathWishRules.py b/worlds/ahit/DeathWishRules.py index 1432ef5c0d..76723d3931 100644 --- a/worlds/ahit/DeathWishRules.py +++ b/worlds/ahit/DeathWishRules.py @@ -141,9 +141,12 @@ def set_dw_rules(world: "HatInTimeWorld"): add_dw_rules(world, all_clear) add_rule(main_stamp, main_objective.access_rule) add_rule(all_clear, main_objective.access_rule) - # Only set bonus stamp rules if we don't auto complete bonuses + # Only set bonus stamp rules to require All Clear if we don't auto complete bonuses if not world.options.DWAutoCompleteBonuses and not world.is_bonus_excluded(all_clear.name): add_rule(bonus_stamps, all_clear.access_rule) + else: + # As soon as the Main Objective is completed, the bonuses auto-complete. + add_rule(bonus_stamps, main_objective.access_rule) if world.options.DWShuffle: for i in range(len(world.dw_shuffle)-1): @@ -343,6 +346,7 @@ def create_enemy_events(world: "HatInTimeWorld"): def set_enemy_rules(world: "HatInTimeWorld"): no_tourist = "Camera Tourist" in world.excluded_dws or "Camera Tourist" in world.excluded_bonuses + difficulty = get_difficulty(world) for enemy, regions in hit_list.items(): if no_tourist and enemy in bosses: @@ -372,6 +376,14 @@ def set_enemy_rules(world: "HatInTimeWorld"): or state.has("Zipline Unlock - The Lava Cake Path", world.player) or state.has("Zipline Unlock - The Windmill Path", world.player)) + elif enemy == "Toilet": + if area == "Toilet of Doom": + # The boss firewall is in the way and can only be skipped on Expert logic using a cherry hover. + add_rule(event, lambda state: has_paintings(state, world, 1, allow_skip=difficulty == Difficulty.EXPERT)) + if difficulty < Difficulty.HARD: + # Hard logic and above can cross the boss arena gap with a cherry bridge. + add_rule(event, lambda state: can_use_hookshot(state, world)) + elif enemy == "Director": if area == "Dead Bird Studio Basement": add_rule(event, lambda state: can_use_hookshot(state, world)) @@ -430,7 +442,7 @@ hit_list = { # Bosses "Mafia Boss": ["Down with the Mafia!", "Encore! Encore!", "Boss Rush"], - "Conductor": ["Dead Bird Studio Basement", "Killing Two Birds", "Boss Rush"], + "Director": ["Dead Bird Studio Basement", "Killing Two Birds", "Boss Rush"], "Toilet": ["Toilet of Doom", "Boss Rush"], "Snatcher": ["Your Contract has Expired", "Breaching the Contract", "Boss Rush", @@ -454,7 +466,7 @@ triple_enemy_locations = [ bosses = [ "Mafia Boss", - "Conductor", + "Director", "Toilet", "Snatcher", "Toxic Flower", diff --git a/worlds/ahit/Locations.py b/worlds/ahit/Locations.py index 9954514e8f..b34e6bb4a7 100644 --- a/worlds/ahit/Locations.py +++ b/worlds/ahit/Locations.py @@ -264,7 +264,6 @@ ahit_locations = { required_hats=[HatType.DWELLER], paintings=3), "Subcon Forest - Tall Tree Hookshot Swing": LocData(2000324766, "Subcon Forest Area", - required_hats=[HatType.DWELLER], hookshot=True, paintings=3), @@ -323,7 +322,7 @@ ahit_locations = { "Alpine Skyline - The Twilight Path": LocData(2000334434, "Alpine Skyline Area", required_hats=[HatType.DWELLER]), "Alpine Skyline - The Twilight Bell: Wide Purple Platform": LocData(2000336478, "The Twilight Bell"), "Alpine Skyline - The Twilight Bell: Ice Platform": LocData(2000335826, "The Twilight Bell"), - "Alpine Skyline - Goat Outpost Horn": LocData(2000334760, "Alpine Skyline Area"), + "Alpine Skyline - Goat Outpost Horn": LocData(2000334760, "Alpine Skyline Area (TIHS)", hookshot=True), "Alpine Skyline - Windy Passage": LocData(2000334776, "Alpine Skyline Area (TIHS)", hookshot=True), "Alpine Skyline - The Windmill: Inside Pon Cluster": LocData(2000336395, "The Windmill"), "Alpine Skyline - The Windmill: Entrance": LocData(2000335783, "The Windmill"), @@ -407,7 +406,7 @@ act_completions = { hit_type=HitType.umbrella_or_brewing, hookshot=True, paintings=1), "Act Completion (Queen Vanessa's Manor)": LocData(2000312017, "Queen Vanessa's Manor", - hit_type=HitType.umbrella, paintings=1), + hit_type=HitType.dweller_bell, paintings=1), "Act Completion (Mail Delivery Service)": LocData(2000312032, "Mail Delivery Service", required_hats=[HatType.SPRINT]), @@ -878,7 +877,7 @@ snatcher_coins = { dlc_flags=HatDLC.death_wish), "Snatcher Coin - Top of HQ (DW: BTH)": LocData(0, "Beat the Heat", snatcher_coin="Snatcher Coin - Top of HQ", - dlc_flags=HatDLC.death_wish), + hit_type=HitType.umbrella, dlc_flags=HatDLC.death_wish), "Snatcher Coin - Top of Tower": LocData(0, "Mafia Town Area (HUMT)", snatcher_coin="Snatcher Coin - Top of Tower", dlc_flags=HatDLC.death_wish), diff --git a/worlds/ahit/Options.py b/worlds/ahit/Options.py index 17c4b95efc..b331ca5242 100644 --- a/worlds/ahit/Options.py +++ b/worlds/ahit/Options.py @@ -338,7 +338,7 @@ class MinExtraYarn(Range): There must be at least this much more yarn over the total number of yarn needed to craft all hats. For example, if this option's value is 10, and the total yarn needed to craft all hats is 40, there must be at least 50 yarn in the pool.""" - display_name = "Max Extra Yarn" + display_name = "Min Extra Yarn" range_start = 5 range_end = 15 default = 10 diff --git a/worlds/ahit/Rules.py b/worlds/ahit/Rules.py index 183248a0e6..6753b8eb81 100644 --- a/worlds/ahit/Rules.py +++ b/worlds/ahit/Rules.py @@ -414,7 +414,7 @@ def set_moderate_rules(world: "HatInTimeWorld"): # Moderate: Mystifying Time Mesa time trial without hats set_rule(world.multiworld.get_location("Alpine Skyline - Mystifying Time Mesa: Zipline", world.player), - lambda state: can_use_hookshot(state, world)) + lambda state: True) # Moderate: Goat Refinery from TIHS with Sprint only add_rule(world.multiworld.get_location("Alpine Skyline - Goat Refinery", world.player), @@ -493,9 +493,6 @@ def set_hard_rules(world: "HatInTimeWorld"): lambda state: has_paintings(state, world, 3, True)) # SDJ - add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player), - lambda state: can_use_hat(state, world, HatType.SPRINT) and has_paintings(state, world, 2), "or") - add_rule(world.multiworld.get_location("Act Completion (Time Rift - Curly Tail Trail)", world.player), lambda state: can_use_hat(state, world, HatType.SPRINT), "or") @@ -533,7 +530,10 @@ def set_expert_rules(world: "HatInTimeWorld"): # Expert: Mafia Town - Above Boats, Top of Lighthouse, and Hot Air Balloon with nothing set_rule(world.multiworld.get_location("Mafia Town - Above Boats", world.player), lambda state: True) set_rule(world.multiworld.get_location("Mafia Town - Top of Lighthouse", world.player), lambda state: True) - set_rule(world.multiworld.get_location("Mafia Town - Hot Air Balloon", world.player), lambda state: True) + # There are not enough buckets/beach balls to bucket/ball hover in Heating Up Mafia Town, so any other Mafia Town + # act is required. + add_rule(world.multiworld.get_location("Mafia Town - Hot Air Balloon", world.player), + lambda state: state.can_reach_region("Mafia Town Area", world.player), "or") # Expert: Clear Dead Bird Studio with nothing for loc in world.multiworld.get_region("Dead Bird Studio - Post Elevator Area", world.player).locations: @@ -590,7 +590,7 @@ def set_expert_rules(world: "HatInTimeWorld"): if world.is_dlc2(): # Expert: clear Rush Hour with nothing - if not world.options.NoTicketSkips: + if world.options.NoTicketSkips != NoTicketSkips.option_true: set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player), lambda state: True) else: set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player), @@ -739,7 +739,7 @@ def set_dlc1_rules(world: "HatInTimeWorld"): # This particular item isn't present in Act 3 for some reason, yes in vanilla too add_rule(world.multiworld.get_location("The Arctic Cruise - Toilet", world.player), - lambda state: state.can_reach("Bon Voyage!", "Region", world.player) + lambda state: (state.can_reach("Bon Voyage!", "Region", world.player) and can_use_hookshot(state, world)) or state.can_reach("Ship Shape", "Region", world.player)) diff --git a/worlds/ahit/__init__.py b/worlds/ahit/__init__.py index 14cf13ec34..c2fe39872f 100644 --- a/worlds/ahit/__init__.py +++ b/worlds/ahit/__init__.py @@ -12,13 +12,13 @@ from .DeathWishRules import set_dw_rules, create_enemy_events, hit_list, bosses from worlds.AutoWorld import World, WebWorld, CollectionState from worlds.generic.Rules import add_rule from typing import List, Dict, TextIO -from worlds.LauncherComponents import Component, components, icon_paths, launch_subprocess, Type +from worlds.LauncherComponents import Component, components, icon_paths, launch as launch_component, Type from Utils import local_path def launch_client(): from .Client import launch - launch_subprocess(launch, name="AHITClient") + launch_component(launch, name="AHITClient") components.append(Component("A Hat in Time Client", "AHITClient", func=launch_client, diff --git a/worlds/ahit/docs/setup_en.md b/worlds/ahit/docs/setup_en.md index 23b3490707..167c6c2faa 100644 --- a/worlds/ahit/docs/setup_en.md +++ b/worlds/ahit/docs/setup_en.md @@ -21,7 +21,7 @@ 3. Click the **Betas** tab. In the **Beta Participation** dropdown, select `tcplink`. - While it downloads, you can subscribe to the [Archipelago workshop mod.]((https://steamcommunity.com/sharedfiles/filedetails/?id=3026842601)) + While it downloads, you can subscribe to the [Archipelago workshop mod](https://steamcommunity.com/sharedfiles/filedetails/?id=3026842601). 4. Once the game finishes downloading, start it up. @@ -62,4 +62,4 @@ The level that the relic set unlocked will stay unlocked. ### When I start a new save file, the intro cinematic doesn't get skipped, Hat Kid's body is missing and the mod doesn't work! There is a bug on older versions of A Hat in Time that causes save file creation to fail to work properly -if you have too many save files. Delete them and it should fix the problem. \ No newline at end of file +if you have too many save files. Delete them and it should fix the problem. diff --git a/worlds/alttp/Bosses.py b/worlds/alttp/Bosses.py index 965a86db00..02970edb9f 100644 --- a/worlds/alttp/Bosses.py +++ b/worlds/alttp/Bosses.py @@ -119,7 +119,9 @@ def KholdstareDefeatRule(state, player: int) -> bool: def VitreousDefeatRule(state, player: int) -> bool: - return can_shoot_arrows(state, player) or has_melee_weapon(state, player) + return ((can_shoot_arrows(state, player) and can_use_bombs(state, player, 10)) + or can_shoot_arrows(state, player, 35) or state.has("Silver Bow", player) + or has_melee_weapon(state, player)) def TrinexxDefeatRule(state, player: int) -> bool: diff --git a/worlds/alttp/Client.py b/worlds/alttp/Client.py index a0b28829f4..78745f438b 100644 --- a/worlds/alttp/Client.py +++ b/worlds/alttp/Client.py @@ -464,7 +464,7 @@ async def track_locations(ctx, roomid, roomdata) -> bool: snes_logger.info(f"Discarding recent {len(new_locations)} checks as ROM Status has changed.") return False else: - await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": new_locations}]) + await ctx.check_locations(new_locations) await snes_flush_writes(ctx) return True diff --git a/worlds/alttp/ItemPool.py b/worlds/alttp/ItemPool.py index c6c1770414..77d02f9770 100644 --- a/worlds/alttp/ItemPool.py +++ b/worlds/alttp/ItemPool.py @@ -484,8 +484,7 @@ def generate_itempool(world): if multiworld.randomize_cost_types[player]: # Heart and Arrow costs require all Heart Container/Pieces and Arrow Upgrades to be advancement items for logic for item in items: - if (item.name in ("Boss Heart Container", "Sanctuary Heart Container", "Piece of Heart") - or "Arrow Upgrade" in item.name): + if item.name in ("Boss Heart Container", "Sanctuary Heart Container", "Piece of Heart"): item.classification = ItemClassification.progression else: # Otherwise, logic has some branches where having 4 hearts is one possible requirement (of several alternatives) @@ -713,7 +712,7 @@ def get_pool_core(world, player: int): pool.remove("Rupees (20)") if retro_bow: - replace = {'Single Arrow', 'Arrows (10)', 'Arrow Upgrade (+5)', 'Arrow Upgrade (+10)', 'Arrow Upgrade (50)'} + replace = {'Single Arrow', 'Arrows (10)', 'Arrow Upgrade (+5)', 'Arrow Upgrade (+10)', 'Arrow Upgrade (70)'} pool = ['Rupees (5)' if item in replace else item for item in pool] if world.small_key_shuffle[player] == small_key_shuffle.option_universal: pool.extend(diff.universal_keys) diff --git a/worlds/alttp/Items.py b/worlds/alttp/Items.py index cb44f35d58..5f081e65fc 100644 --- a/worlds/alttp/Items.py +++ b/worlds/alttp/Items.py @@ -7,7 +7,7 @@ from worlds.AutoWorld import World def GetBeemizerItem(world, player: int, item): item_name = item if isinstance(item, str) else item.name - if item_name not in trap_replaceable: + if item_name not in trap_replaceable or player in world.groups: return item # first roll - replaceable item should be replaced, within beemizer_total_chance @@ -110,9 +110,9 @@ item_table = {'Bow': ItemData(IC.progression, None, 0x0B, 'You have\nchosen the\ 'Crystal 7': ItemData(IC.progression, 'Crystal', (0x08, 0x34, 0x64, 0x40, 0x7C, 0x06), None, None, None, None, None, None, "a blue crystal"), 'Single Arrow': ItemData(IC.filler, None, 0x43, 'a lonely arrow\nsits here.', 'and the arrow', 'stick-collecting kid', 'sewing needle for sale', 'fungus for arrow', 'archer boy sews again', 'an arrow'), 'Arrows (10)': ItemData(IC.filler, None, 0x44, 'This will give\nyou ten shots\nwith your bow!', 'and the arrow pack','stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again','ten arrows'), - 'Arrow Upgrade (+10)': ItemData(IC.useful, None, 0x54, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), - 'Arrow Upgrade (+5)': ItemData(IC.useful, None, 0x53, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), - 'Arrow Upgrade (70)': ItemData(IC.useful, None, 0x4D, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), + 'Arrow Upgrade (+10)': ItemData(IC.progression_skip_balancing, None, 0x54, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), + 'Arrow Upgrade (+5)': ItemData(IC.progression_skip_balancing, None, 0x53, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), + 'Arrow Upgrade (70)': ItemData(IC.progression_skip_balancing, None, 0x4D, 'increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), 'Single Bomb': ItemData(IC.filler, None, 0x27, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), 'Bombs (3)': ItemData(IC.filler, None, 0x28, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'), 'Bombs (10)': ItemData(IC.filler, None, 0x31, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'), diff --git a/worlds/alttp/Rules.py b/worlds/alttp/Rules.py index a664f8ac9b..f13178c6c5 100644 --- a/worlds/alttp/Rules.py +++ b/worlds/alttp/Rules.py @@ -592,9 +592,9 @@ def global_rules(multiworld: MultiWorld, player: int): lambda state: can_kill_most_things(state, player, 8) and has_fire_source(state, player) and state.multiworld.get_entrance('Ganons Tower Torch Rooms', player).parent_region.dungeon.bosses['middle'].can_defeat(state)) set_rule(multiworld.get_location('Ganons Tower - Mini Helmasaur Key Drop', player), lambda state: can_kill_most_things(state, player, 1)) set_rule(multiworld.get_location('Ganons Tower - Pre-Moldorm Chest', player), - lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 7)) + lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 7) and can_use_bombs(state, player)) set_rule(multiworld.get_entrance('Ganons Tower Moldorm Door', player), - lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 8)) + lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 8) and can_use_bombs(state, player)) set_rule(multiworld.get_entrance('Ganons Tower Moldorm Gap', player), lambda state: state.has('Hookshot', player) and state.multiworld.get_entrance('Ganons Tower Moldorm Gap', player).parent_region.dungeon.bosses['top'].can_defeat(state)) set_defeat_dungeon_boss_rule(multiworld.get_location('Agahnim 2', player)) @@ -1125,7 +1125,7 @@ def set_trock_key_rules(world, player): for entrance in ['Turtle Rock Dark Room Staircase', 'Turtle Rock (Chain Chomp Room) (North)', 'Turtle Rock (Chain Chomp Room) (South)', 'Turtle Rock Entrance to Pokey Room', 'Turtle Rock (Pokey Room) (South)', 'Turtle Rock (Pokey Room) (North)', 'Turtle Rock Big Key Door']: set_rule(world.get_entrance(entrance, player), lambda state: False) - all_state = world.get_all_state(use_cache=False) + all_state = world.get_all_state(use_cache=False, allow_partial_entrances=True) all_state.reachable_regions[player] = set() # wipe reachable regions so that the locked doors actually work all_state.stale[player] = True diff --git a/worlds/alttp/Shops.py b/worlds/alttp/Shops.py index db2b5b680c..055eb2da93 100644 --- a/worlds/alttp/Shops.py +++ b/worlds/alttp/Shops.py @@ -170,7 +170,8 @@ def push_shop_inventories(multiworld): # Retro Bow arrows will already have been pushed if (not multiworld.retro_bow[location.player]) or ((item_name, location.item.player) != ("Single Arrow", location.player)): - location.shop.push_inventory(location.shop_slot, item_name, location.shop_price, + location.shop.push_inventory(location.shop_slot, item_name, + round(location.shop_price * get_price_modifier(location.item)), 1, location.item.player if location.item.player != location.player else 0, location.shop_price_type) location.shop_price = location.shop.inventory[location.shop_slot]["price"] = min(location.shop_price, diff --git a/worlds/alttp/StateHelpers.py b/worlds/alttp/StateHelpers.py index 964a77fefb..8661632b83 100644 --- a/worlds/alttp/StateHelpers.py +++ b/worlds/alttp/StateHelpers.py @@ -15,18 +15,18 @@ def can_bomb_clip(state: CollectionState, region: LTTPRegion, player: int) -> bo def can_buy_unlimited(state: CollectionState, item: str, player: int) -> bool: return any(shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(state) for - shop in state.multiworld.shops) + shop in state.multiworld.shops) def can_buy(state: CollectionState, item: str, player: int) -> bool: return any(shop.region.player == player and shop.has(item) and shop.region.can_reach(state) for - shop in state.multiworld.shops) + shop in state.multiworld.shops) -def can_shoot_arrows(state: CollectionState, player: int) -> bool: +def can_shoot_arrows(state: CollectionState, player: int, count: int = 0) -> bool: if state.multiworld.retro_bow[player]: return (state.has('Bow', player) or state.has('Silver Bow', player)) and can_buy(state, 'Single Arrow', player) - return state.has('Bow', player) or state.has('Silver Bow', player) + return (state.has('Bow', player) or state.has('Silver Bow', player)) and can_hold_arrows(state, player, count) def has_triforce_pieces(state: CollectionState, player: int) -> bool: @@ -61,13 +61,13 @@ def heart_count(state: CollectionState, player: int) -> int: # Warning: This only considers items that are marked as advancement items diff = state.multiworld.worlds[player].difficulty_requirements return min(state.count('Boss Heart Container', player), diff.boss_heart_container_limit) \ - + state.count('Sanctuary Heart Container', player) \ + + state.count('Sanctuary Heart Container', player) \ + min(state.count('Piece of Heart', player), diff.heart_piece_limit) // 4 \ - + 3 # starting hearts + + 3 # starting hearts def can_extend_magic(state: CollectionState, player: int, smallmagic: int = 16, - fullrefill: bool = False): # This reflects the total magic Link has, not the total extra he has. + fullrefill: bool = False): # This reflects the total magic Link has, not the total extra he has. basemagic = 8 if state.has('Magic Upgrade (1/4)', player): basemagic = 32 @@ -84,11 +84,18 @@ def can_extend_magic(state: CollectionState, player: int, smallmagic: int = 16, def can_hold_arrows(state: CollectionState, player: int, quantity: int): - arrows = 30 + ((state.count("Arrow Upgrade (+5)", player) * 5) + (state.count("Arrow Upgrade (+10)", player) * 10) - + (state.count("Bomb Upgrade (50)", player) * 50)) - # Arrow Upgrade (+5) beyond the 6th gives +10 - arrows += max(0, ((state.count("Arrow Upgrade (+5)", player) - 6) * 10)) - return min(70, arrows) >= quantity + if state.multiworld.worlds[player].options.shuffle_capacity_upgrades: + if quantity == 0: + return True + if state.has("Arrow Upgrade (70)", player): + arrows = 70 + else: + arrows = (30 + (state.count("Arrow Upgrade (+5)", player) * 5) + + (state.count("Arrow Upgrade (+10)", player) * 10)) + # Arrow Upgrade (+5) beyond the 6th gives +10 + arrows += max(0, ((state.count("Arrow Upgrade (+5)", player) - 6) * 10)) + return min(70, arrows) >= quantity + return quantity <= 30 or state.has("Capacity Upgrade Shop", player) def can_use_bombs(state: CollectionState, player: int, quantity: int = 1) -> bool: @@ -146,19 +153,19 @@ def can_get_good_bee(state: CollectionState, player: int) -> bool: def can_retrieve_tablet(state: CollectionState, player: int) -> bool: return state.has('Book of Mudora', player) and (has_beam_sword(state, player) or (state.multiworld.swordless[player] and - state.has("Hammer", player))) + state.has("Hammer", player))) def has_sword(state: CollectionState, player: int) -> bool: return state.has('Fighter Sword', player) \ - or state.has('Master Sword', player) \ - or state.has('Tempered Sword', player) \ - or state.has('Golden Sword', player) + or state.has('Master Sword', player) \ + or state.has('Tempered Sword', player) \ + or state.has('Golden Sword', player) def has_beam_sword(state: CollectionState, player: int) -> bool: return state.has('Master Sword', player) or state.has('Tempered Sword', player) or state.has('Golden Sword', - player) + player) def has_melee_weapon(state: CollectionState, player: int) -> bool: @@ -171,9 +178,9 @@ def has_fire_source(state: CollectionState, player: int) -> bool: def can_melt_things(state: CollectionState, player: int) -> bool: return state.has('Fire Rod', player) or \ - (state.has('Bombos', player) and - (state.multiworld.swordless[player] or - has_sword(state, player))) + (state.has('Bombos', player) and + (state.multiworld.swordless[player] or + has_sword(state, player))) def has_misery_mire_medallion(state: CollectionState, player: int) -> bool: diff --git a/worlds/alttp/docs/multiworld_es.md b/worlds/alttp/docs/multiworld_es.md index a8ed11cd32..eade0372ec 100644 --- a/worlds/alttp/docs/multiworld_es.md +++ b/worlds/alttp/docs/multiworld_es.md @@ -1,224 +1,123 @@ # Guía de instalación para A Link to the Past Randomizer Multiworld -
- -
- ## Software requerido -- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases) -- [QUsb2Snes](https://github.com/Skarsnik/QUsb2snes/releases) (Incluido en Multiworld Utilities) -- Hardware o software capaz de cargar y ejecutar archivos de ROM de SNES - - Un emulador capaz de ejecutar scripts Lua - ([snes9x rr](https://github.com/gocha/snes9x-rr/releases), +- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). +- [SNI](https://github.com/alttpo/sni/releases). Esto está incluido automáticamente en la instalación de Archipelago. +- SNI no es compatible con (Q)Usb2Snes. +- Hardware o software capaz de cargar y ejecutar archivos de ROM de SNES, por ejemplo: + - Un emulador capaz de conectarse a SNI + ([snes9x-nwa](https://github.com/Skarsnik/snes9x-emunwa/releases), [snes9x-rr](https://github.com/gocha/snes9x-rr/releases), + [BSNES-plus](https://github.com/black-sliver/bsnes-plus), [BizHawk](https://tasvideos.org/BizHawk), o - [RetroArch](https://retroarch.com?page=platforms) 1.10.1 o más nuevo). O, - - Un flashcart SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), o otro hardware compatible + [RetroArch](https://retroarch.com?page=platforms) 1.10.1 o más nuevo). + - Un SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), u otro hardware compatible. **nota: +Las SNES minis modificadas no tienen soporte de SNI. Algunos usuarios dicen haber tenido éxito con Qusb2Snes para esta consola, +pero no tiene soporte.** - Tu archivo ROM japones v1.0, probablemente se llame `Zelda no Densetsu - Kamigami no Triforce (Japan).sfc` ## Procedimiento de instalación -### Instalación en Windows - -1. Descarga e instala MultiWorld Utilities desde el enlace anterior, asegurando que instalamos la versión más reciente. - **El archivo esta localizado en la sección "assets" en la parte inferior de la información de versión**. Si tu - intención es jugar la versión normal de multiworld, necesitarás el archivo `Setup.Archipelago.exe` - - Si estas interesado en jugar la variante que aleatoriza las puertas internas de las mazmorras, necesitaras bajar ' - Setup.BerserkerMultiWorld.Doors.exe' - - Durante el proceso de instalación, se te pedirá donde esta situado tu archivo ROM japonés v1.0. Si ya habías - instalado este software con anterioridad y simplemente estas actualizando, no se te pedirá la localización del - archivo una segunda vez. - - Puede ser que el programa pida la instalación de Microsoft Visual C++. Si ya lo tienes en tu ordenador ( - posiblemente por que un juego de Steam ya lo haya instalado), el instalador no te pedirá su instalación. - -2. Si estas usando un emulador, deberías asignar la versión capaz de ejecutar scripts Lua como programa por defecto para - lanzar ficheros de ROM de SNES. - 1. Extrae tu emulador al escritorio, o cualquier sitio que después recuerdes. - 2. Haz click derecho en un fichero de ROM (ha de tener la extensión sfc) y selecciona **Abrir con...** - 3. Marca la opción **Usar siempre esta aplicación para abrir los archivos .sfc** - 4. Baja hasta el final de la lista y haz click en la opción **Buscar otra aplicación en el equipo** (Si usas Windows - 10 es posible que debas hacer click en **Más aplicaciones**) - 5. Busca el archivo .exe de tu emulador y haz click en **Abrir**. Este archivo debe estar en el directorio donde - extrajiste en el paso 1. - -### Instalación en Macintosh - -- ¡Necesitamos voluntarios para rellenar esta seccion! Contactad con **Farrak Kilhn** (en inglés) en Discord si queréis - ayudar. - -## Configurar tu archivo YAML - -### Que es un archivo YAML y por qué necesito uno? - -Tu archivo YAML contiene un conjunto de opciones de configuración que proveen al generador con información sobre como -debe generar tu juego. Cada jugador en una partida de multiworld proveerá su propio fichero YAML. Esta configuración -permite que cada jugador disfrute de una experiencia personalizada a su gusto, y cada jugador dentro de la misma partida -de multiworld puede tener diferentes opciones. - -### Donde puedo obtener un fichero YAML? - -La página "[Generate Game](/games/A%20Link%20to%20the%20Past/player-options)" en el sitio web te permite configurar tu -configuración personal y descargar un fichero "YAML". - -### Configuración YAML avanzada - -Una version mas avanzada del fichero Yaml puede ser creada usando la pagina -["Weighted settings"](/games/A Link to the Past/weighted-options), -la cual te permite tener almacenadas hasta 3 preajustes. La pagina "Weighted Settings" tiene muchas opciones -representadas con controles deslizantes. Esto permite elegir cuan probable los valores de una categoría pueden ser -elegidos sobre otros de la misma. - -Por ejemplo, imagina que el generador crea un cubo llamado "map_shuffle", y pone trozos de papel doblado en él por cada -sub-opción. Ademas imaginemos que tu valor elegido para "on" es 20 y el elegido para "off" es 40. - -Por tanto, en este ejemplo, habrán 60 trozos de papel. 20 para "on" y 40 para "off". Cuando el generador esta decidiendo -si activar o no "map shuffle" para tu partida, meterá la mano en el cubo y sacara un trozo de papel al azar. En este -ejemplo, es mucho mas probable (2 de cada 3 veces (40/60)) que "map shuffle" esté desactivado. - -Si quieres que una opción no pueda ser escogida, simplemente asigna el valor 0 a dicha opción. Recuerda que cada opción -debe tener al menos un valor mayor que cero, si no la generación fallará. - -### Verificando tu archivo YAML - -Si quieres validar que tu fichero YAML para asegurarte que funciona correctamente, puedes hacerlo en la pagina -[YAML Validator](/check). - -## Generar una partida para un jugador - -1. Navega a [la pagina Generate game](/games/A%20Link%20to%20the%20Past/player-options), configura tus opciones, haz - click en el boton "Generate game". -2. Se te redigirá a una pagina "Seed Info", donde puedes descargar tu archivo de parche. -3. Haz doble click en tu fichero de parche, y el emulador debería ejecutar tu juego automáticamente. Como el Cliente no - es necesario para partidas de un jugador, puedes cerrarlo junto a la pagina web (que tiene como titulo "Multiworld - WebUI") que se ha abierto automáticamente. - -## Unirse a una partida MultiWorld +1. Descarga e instala [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases/latest). + **El archivo del instalador se encuentra en la sección de assets al final de la información de version**. +2. La primera vez que realices una generación local o parchees tu juego, se te pedirá que ubiques tu archivo ROM base. + Este es tu archivo ROM de Link to the Past japonés. Esto sólo debe hacerse una vez. + +4. Si estás usando un emulador, deberías de asignar tu emulador con compatibilidad con Lua como el programa por defecto para abrir archivos + ROM. + 1. Extrae la carpeta de tu emulador al Escritorio, o algún otro sitio que vayas a recordar. + 2. Haz click derecho en un archivo ROM y selecciona **Abrir con...** + 3. Marca la casilla junto a **Usar siempre este programa para abrir archivos .sfc** + 4. Baja al final de la lista y haz click en el texto gris **Buscar otro programa en este PC** + 5. Busca el archivo `.exe` de tu emulador y haz click en **Abrir**. Este archivo debería de encontrarse dentro de la carpeta que + extrajiste en el paso uno. ### Obtener el fichero de parche y crea tu ROM -Cuando te unes a una partida multiworld, debes proveer tu fichero YAML a quien sea el creador de la partida. Una vez +Cuando te unas a una partida multiworld, se te pedirá enviarle tu archivo de configuración a quien quiera que esté creando. Una vez eso este hecho, el creador te devolverá un enlace para descargar el parche o un fichero zip conteniendo todos los ficheros -de parche de la partida Tu fichero de parche debe tener la extensión `.aplttp`. +de parche de la partida. Tu fichero de parche debe de tener la extensión `.aplttp`. -Pon tu fichero de parche en el escritorio o en algún sitio conveniente, y haz doble click. Esto debería ejecutar -automáticamente el cliente, y ademas creara la rom en el mismo directorio donde este el fichero de parche. +Pon tu fichero de parche en el escritorio o en algún sitio conveniente, y hazle doble click. Esto debería ejecutar +automáticamente el cliente, y además creará la rom en el mismo directorio donde este el fichero de parche. ### Conectar al cliente #### Con emulador -Cuando el cliente se lance automáticamente, QUsb2Snes debería haberse ejecutado también. Si es la primera vez que lo -ejecutas, puedes ser que el firewall de Windows te pregunte si le permites la comunicación. +Cuando el cliente se lance automáticamente, SNI debería de ejecutarse en segundo plano. Si es la +primera vez que se ejecuta, tal vez se te pida permitir que se comunique a través del firewall de Windows + +#### snes9x-nwa + +1. Haz click en el menu Network y marca 'Enable Emu Network Control +2. Carga tu archivo ROM si no lo habías hecho antes ##### snes9x-rr -1. Carga tu fichero de ROM, si no lo has hecho ya +1. Carga tu fichero ROM, si no lo has hecho ya 2. Abre el menu "File" y situa el raton en **Lua Scripting** 3. Haz click en **New Lua Script Window...** 4. En la nueva ventana, haz click en **Browse...** -5. Navega hacia el directorio donde este situado snes9x-rr, entra en el directorio `lua`, y - escoge `multibridge.lua` -6. Observa que se ha asignado un nombre al dispositivo, y el cliente muestra "SNES Device: Connected", con el mismo - nombre en la esquina superior izquierda. +5. Selecciona el archivo lua conector incluido con tu cliente + - Busca en la carpeta de Archipelago `/SNI/lua/`. +6. Si ves un error mientras carga el script que dice `socket.dll missing` o algo similar, ve a la carpeta de +el lua que estas usando en tu gestor de archivos y copia el `socket.dll` a la raíz de tu instalación de snes9x. + +##### BNES-Plus + +1. Cargue su archivo ROM si aún no se ha cargado. +2. El emulador debería conectarse automáticamente mientras SNI se está ejecutando. ##### BizHawk -1. Asegurate que se ha cargado el nucleo BSNES. Debes hacer esto en el menu Tools y siguiento estas opciones: - `Config --> Cores --> SNES --> BSNES` - Una vez cambiado el nucleo cargado, BizHawk ha de ser reiniciado. +1. Asegurate que se ha cargado el núcleo BSNES. Se hace en la barra de menú principal, bajo: + - (≤ 2.8) `Config` 〉 `Cores` 〉 `SNES` 〉 `BSNES` + - (≥ 2.9) `Config` 〉 `Preferred Cores` 〉 `SNES` 〉 `BSNESv115+` 2. Carga tu fichero de ROM, si no lo has hecho ya. -3. Haz click en el menu Tools y en la opción **Lua Console** -4. Haz click en el botón para abrir un nuevo script Lua. -5. Navega al directorio de instalación de MultiWorld Utilities, y en los siguiente directorios: - `QUsb2Snes/Qusb2Snes/LuaBridge` -6. Selecciona `luabridge.lua` y haz click en Abrir. -7. Observa que se ha asignado un nombre al dispositivo, y el cliente muestra "SNES Device: Connected", con el mismo - nombre en la esquina superior izquierda. + Si has cambiado tu preferencia de núcleo tras haber cargado la ROM, no te olvides de volverlo a cargar (atajo por defecto: Ctrl+R). +3. Arrastra el archivo `Connector.lua` que has descargado a la ventana principal de EmuHawk. + - Busca en la carpeta de Archipelago `/SNI/lua/`. + - También podrías abrir la consola de Lua manualmente, hacer click en `Script` 〉 `Open Script`, e ir a `Connector.lua` + con el selector de archivos. ##### RetroArch 1.10.1 o más nuevo -Sólo hay que segiur estos pasos una vez. +Sólo hay que seguir estos pasos una vez. 1. Comienza en la pantalla del menú principal de RetroArch. 2. Ve a Ajustes --> Interfaz de usario. Configura "Mostrar ajustes avanzados" en ON. -3. Ve a Ajustes --> Red. Configura "Comandos de red" en ON. (Se encuentra bajo Request Device 16.) Deja en 55355 (el - default) el Puerto de comandos de red. +3. Ve a Ajustes --> Red. Pon "Comandos de red" en ON. (Se encuentra bajo Request Device 16.) Deja en 55355 el valor por defecto, + el Puerto de comandos de red. ![Captura de pantalla del ajuste Comandos de red](/static/generated/docs/A%20Link%20to%20the%20Past/retroarch-network-commands-en.png) 4. Ve a Menú principal --> Actualizador en línea --> Descargador de núcleos. Desplázate y selecciona "Nintendo - SNES / SFC (bsnes-mercury Performance)". -Cuando cargas un ROM, asegúrate de seleccionar un núcleo **bsnes-mercury**. Estos son los sólos núcleos que permiten +Cuando cargas un ROM, asegúrate de seleccionar un núcleo **bsnes-mercury**. Estos son los únicos núcleos que permiten que herramientas externas lean datos del ROM. #### Con Hardware -Esta guía asume que ya has descargado el firmware correcto para tu dispositivo. Si no lo has hecho ya, hazlo ahora. Los +Esta guía asume que ya has descargado el firmware correcto para tu dispositivo. Si no lo has hecho ya, por favor hazlo ahora. Los usuarios de SD2SNES y FXPak Pro pueden descargar el firmware apropiado -[aqui](https://github.com/RedGuyyyy/sd2snes/releases). Los usuarios de otros dispositivos pueden encontrar información +[aqui](https://github.com/RedGuyyyy/sd2snes/releases). Puede que los usuarios de otros dispositivos encuentren informacion útil [en esta página](http://usb2snes.com/#supported-platforms). 1. Cierra tu emulador, el cual debe haberse autoejecutado. -2. Cierra QUsb2Snes, el cual fue ejecutado junto al cliente. -3. Ejecuta la version correcta de QUsb2Snes (v0.7.16). -4. Enciende tu dispositivo y carga la ROM. -5. Observa en el cliente que ahora muestra "SNES Device: Connected", y aparece el nombre del dispositivo. +2. Enciende tu dispositivo y carga la ROM. -### Conecta al MultiServer +### Conecta al Servidor Archipelago -El fichero de parche que ha lanzado el cliente debe haberte conectado automaticamente al MultiServer. Hay algunas -razonas por las que esto puede que no pase, incluyendo que el juego este hospedado en el sitio web pero se genero en -algún otro sitio. Si el cliente muestra "Server Status: Not Connected", preguntale al creador de la partida la dirección -del servidor, copiala en el campo "Server" y presiona Enter. +El fichero de parche que ha lanzado el cliente debería de haberte conectado automaticamente al MultiServer. Sin embargo hay algunas +razones por las que puede que esto no suceda, como que la partida este hospedada en la página web pero generada en otra parte. Si la +ventana del cliente muestra "Server Status: Not Connected", simplemente preguntale al creador de la partida la dirección +del servidor, cópiala en el campo "Server" y presiona Enter. -El cliente intentara conectarse a esta nueva dirección, y debería mostrar "Server Status: Connected" en algún momento. -Si el cliente no se conecta al cabo de un rato, puede ser que necesites refrescar la pagina web. +El cliente intentará conectarse a esta nueva dirección, y debería mostrar "Server Status: Connected" momentáneamente. -### Jugando +### Jugar al juego -Cuando ambos SNES Device and Server aparezcan como "connected", estas listo para empezar a jugar. Felicidades por unirte -satisfactoriamente a una partida de multiworld! - -## Hospedando una partida de multiworld - -La manera recomendad para hospedar una partida es usar el servicio proveído en -[el sitio web](/generate). El proceso es relativamente sencillo: - -1. Recolecta los ficheros YAML de todos los jugadores que participen. -2. Crea un fichero ZIP conteniendo esos ficheros. -3. Carga el fichero zip en el sitio web enlazado anteriormente. -4. Espera a que la seed sea generada. -5. Cuando esto acabe, se te redigirá a una pagina titulada "Seed Info". -6. Haz click en "Create New Room". Esto te llevara a la pagina del servidor. Pasa el enlace a esta pagina a los - jugadores para que puedan descargar los ficheros de parche de ahi. - **Nota:** Los ficheros de parche de esta pagina permiten a los jugadores conectarse al servidor automaticamente, - mientras que los de la pagina "Seed info" no. -7. Hay un enlace a un MultiWorld Tracker en la parte superior de la pagina de la sala. Deberías pasar también este - enlace a los jugadores para que puedan ver el progreso de la partida. A los observadores también se les puede pasar - este enlace. -8. Una vez todos los jugadores se han unido, podeis empezar a jugar. - -## Auto-Tracking - -Si deseas usar auto-tracking para tu partida, varios programas ofrecen esta funcionalidad. -El programa recomentdado actualmente es: -[OpenTracker](https://github.com/trippsc2/OpenTracker/releases). - -### Instalación - -1. Descarga el fichero de instalacion apropiado para tu ordenador (Usuarios de windows quieren el fichero ".msi"). -2. Durante el proceso de insatalación, puede que se te pida instalar Microsoft Visual Studio Build Tools. Un enlace este - programa se muestra durante la proceso, y debe ser ejecutado manualmente. - -### Activar auto-tracking - -1. Con OpenTracker ejecutado, haz click en el menu Tracking en la parte superior de la ventana, y elige ** - AutoTracker...** -2. Click the **Get Devices** button -3. Selecciona tu "SNES device" de la lista -4. Si quieres que las llaves y los objetos de mazmorra tambien sean marcados, activa la caja con nombre **Race Illegal - Tracking** -5. Haz click en el boton **Start Autotracking** -6. Cierra la ventana AutoTracker, ya que deja de ser necesaria +Cuando el cliente muestre tanto el dispositivo SNES como el servidor como conectados, estas listo para empezar a jugar. Felicidades por +haberte unido a una partida multiworld con exito! Puedes ejecutar varios comandos en tu cliente. Para mas informacion +acerca de estos comando puedes usar `/help` para comandos locales del cliente y `!help` para comandos de servidor. diff --git a/worlds/alttp/test/dungeons/TestGanonsTower.py b/worlds/alttp/test/dungeons/TestGanonsTower.py index 08274d0fe7..4b8fc4c295 100644 --- a/worlds/alttp/test/dungeons/TestGanonsTower.py +++ b/worlds/alttp/test/dungeons/TestGanonsTower.py @@ -130,19 +130,21 @@ class TestGanonsTower(TestDungeon): ["Ganons Tower - Pre-Moldorm Chest", False, []], ["Ganons Tower - Pre-Moldorm Chest", False, [], ['Progressive Bow']], + ["Ganons Tower - Pre-Moldorm Chest", False, [], ['Bomb Upgrade (50)']], ["Ganons Tower - Pre-Moldorm Chest", False, [], ['Big Key (Ganons Tower)']], ["Ganons Tower - Pre-Moldorm Chest", False, [], ['Lamp', 'Fire Rod']], - ["Ganons Tower - Pre-Moldorm Chest", True, ['Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Lamp']], - ["Ganons Tower - Pre-Moldorm Chest", True, ['Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Fire Rod']], + ["Ganons Tower - Pre-Moldorm Chest", True, ['Bomb Upgrade (50)', 'Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Lamp']], + ["Ganons Tower - Pre-Moldorm Chest", True, ['Bomb Upgrade (50)', 'Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Fire Rod']], ["Ganons Tower - Validation Chest", False, []], ["Ganons Tower - Validation Chest", False, [], ['Hookshot']], ["Ganons Tower - Validation Chest", False, [], ['Progressive Bow']], + ["Ganons Tower - Validation Chest", False, [], ['Bomb Upgrade (50)']], ["Ganons Tower - Validation Chest", False, [], ['Big Key (Ganons Tower)']], ["Ganons Tower - Validation Chest", False, [], ['Lamp', 'Fire Rod']], ["Ganons Tower - Validation Chest", False, [], ['Progressive Sword', 'Hammer']], - ["Ganons Tower - Validation Chest", True, ['Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Lamp', 'Hookshot', 'Progressive Sword']], - ["Ganons Tower - Validation Chest", True, ['Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Fire Rod', 'Hookshot', 'Progressive Sword']], - ["Ganons Tower - Validation Chest", True, ['Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Lamp', 'Hookshot', 'Hammer']], - ["Ganons Tower - Validation Chest", True, ['Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Fire Rod', 'Hookshot', 'Hammer']], + ["Ganons Tower - Validation Chest", True, ['Bomb Upgrade (50)', 'Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Lamp', 'Hookshot', 'Progressive Sword']], + ["Ganons Tower - Validation Chest", True, ['Bomb Upgrade (50)', 'Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Fire Rod', 'Hookshot', 'Progressive Sword']], + ["Ganons Tower - Validation Chest", True, ['Bomb Upgrade (50)', 'Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Lamp', 'Hookshot', 'Hammer']], + ["Ganons Tower - Validation Chest", True, ['Bomb Upgrade (50)', 'Progressive Bow', 'Big Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Fire Rod', 'Hookshot', 'Hammer']], ]) \ No newline at end of file diff --git a/worlds/alttp/test/dungeons/TestMiseryMire.py b/worlds/alttp/test/dungeons/TestMiseryMire.py index ca74e9365e..90b7055b76 100644 --- a/worlds/alttp/test/dungeons/TestMiseryMire.py +++ b/worlds/alttp/test/dungeons/TestMiseryMire.py @@ -77,5 +77,5 @@ class TestMiseryMire(TestDungeon): ["Misery Mire - Boss", False, [], ['Bomb Upgrade (+5)', 'Bomb Upgrade (+10)', 'Bomb Upgrade (50)']], ["Misery Mire - Boss", True, ['Bomb Upgrade (+5)', 'Big Key (Misery Mire)', 'Lamp', 'Cane of Somaria', 'Progressive Sword', 'Pegasus Boots']], ["Misery Mire - Boss", True, ['Bomb Upgrade (+5)', 'Big Key (Misery Mire)', 'Lamp', 'Cane of Somaria', 'Hammer', 'Pegasus Boots']], - ["Misery Mire - Boss", True, ['Bomb Upgrade (+5)', 'Big Key (Misery Mire)', 'Lamp', 'Cane of Somaria', 'Progressive Bow', 'Pegasus Boots']], + ["Misery Mire - Boss", True, ['Bomb Upgrade (+5)', 'Big Key (Misery Mire)', 'Lamp', 'Cane of Somaria', 'Progressive Bow', 'Arrow Upgrade (+5)', 'Pegasus Boots']], ]) \ No newline at end of file diff --git a/worlds/aquaria/__init__.py b/worlds/aquaria/__init__.py index 1f7b956bb3..54158b280b 100644 --- a/worlds/aquaria/__init__.py +++ b/worlds/aquaria/__init__.py @@ -93,7 +93,7 @@ class AquariaWorld(World): options: AquariaOptions "Every options of the world" - regions: AquariaRegions + regions: AquariaRegions | None "Used to manage Regions" exclude: List[str] @@ -101,10 +101,17 @@ class AquariaWorld(World): def __init__(self, multiworld: MultiWorld, player: int): """Initialisation of the Aquaria World""" super(AquariaWorld, self).__init__(multiworld, player) - self.regions = AquariaRegions(multiworld, player) + self.regions = None self.ingredients_substitution = [] self.exclude = [] + def generate_early(self) -> None: + """ + Run before any general steps of the MultiWorld other than options. Useful for getting and adjusting option + results and determining layouts for entrance rando etc. start inventory gets pushed after this step. + """ + self.regions = AquariaRegions(self.multiworld, self.player) + def create_regions(self) -> None: """ Create every Region in `regions` diff --git a/worlds/blasphemous/__init__.py b/worlds/blasphemous/__init__.py index a967fbac92..4b151f41f8 100644 --- a/worlds/blasphemous/__init__.py +++ b/worlds/blasphemous/__init__.py @@ -103,6 +103,9 @@ class BlasphemousWorld(World): if not self.options.wall_climb_shuffle: self.multiworld.push_precollected(self.create_item("Wall Climb Ability")) + if self.options.thorn_shuffle == "local_only": + self.options.local_items.value.add("Thorn Upgrade") + if not self.options.boots_of_pleading: self.disabled_locations.append("RE401") @@ -200,9 +203,6 @@ class BlasphemousWorld(World): if not self.options.skill_randomizer: self.place_items_from_dict(skill_dict) - - if self.options.thorn_shuffle == "local_only": - self.options.local_items.value.add("Thorn Upgrade") def place_items_from_set(self, location_set: Set[str], name: str): diff --git a/worlds/celeste64/docs/guide_en.md b/worlds/celeste64/docs/guide_en.md index 74ab94b913..87ebf09f75 100644 --- a/worlds/celeste64/docs/guide_en.md +++ b/worlds/celeste64/docs/guide_en.md @@ -12,6 +12,12 @@ 1. Download the above release and extract it. +## Installation Procedures (Linux and Steam Deck) + +1. Download the above release and extract it. + +2. Add Celeste64.exe to Steam as a Non-Steam Game. In the properties for it on Steam, set it to use Proton as the compatibility tool. Launch the game through Steam in order to run it. + ## Joining a MultiWorld Game 1. Before launching the game, edit the `AP.json` file in the root of the Celeste 64 install. @@ -33,5 +39,3 @@ An Example `AP.json` file: "Password": "" } ``` - - diff --git a/worlds/dark_souls_3/docs/setup_en.md b/worlds/dark_souls_3/docs/setup_en.md index 484afdce3f..4c3a6b2a7d 100644 --- a/worlds/dark_souls_3/docs/setup_en.md +++ b/worlds/dark_souls_3/docs/setup_en.md @@ -3,11 +3,13 @@ ## Required Software - [Dark Souls III](https://store.steampowered.com/app/374320/DARK_SOULS_III/) -- [Dark Souls III AP Client](https://github.com/nex3/Dark-Souls-III-Archipelago-client/releases/latest) +- [Dark Souls III AP Client] + +[Dark Souls III AP Client]: https://github.com/nex3/Dark-Souls-III-Archipelago-client/releases/latest ## Optional Software -- Map tracker not yet updated for 3.0.0 +- [Map tracker](https://github.com/TVV1GK/DS3_AP_Maptracker) ## Setting Up @@ -73,3 +75,65 @@ things to keep in mind: [.NET Runtime]: https://dotnet.microsoft.com/en-us/download/dotnet/8.0 [WINE]: https://www.winehq.org/ + +## Troubleshooting + +### Enemy randomizer issues + +The DS3 Archipelago randomizer uses [thefifthmatt's DS3 enemy randomizer], +essentially unchanged. Unfortunately, this randomizer has a few known issues, +including enemy AI not working, enemies spawning in places they can't be killed, +and, in a few rare cases, enemies spawning in ways that crash the game when they +load. These bugs should be [reported upstream], but unfortunately the +Archipelago devs can't help much with them. + +[thefifthmatt's DS3 enemy randomizer]: https://www.nexusmods.com/darksouls3/mods/484 +[reported upstream]: https://github.com/thefifthmatt/SoulsRandomizers/issues + +Because in rare cases the enemy randomizer can cause seeds to be impossible to +complete, we recommend disabling it for large async multiworlds for safety +purposes. + +### `launchmod_darksouls3.bat` isn't working + +Sometimes `launchmod_darksouls3.bat` will briefly flash a terminal on your +screen and then terminate without actually starting the game. This is usually +caused by some issue communicating with Steam either to find `DarkSoulsIII.exe` +or to launch it properly. If this is happening to you, make sure: + +* You have DS3 1.15.2 installed. This is the latest patch as of January 2025. + (Note that older versions of Archipelago required an older patch, but that + _will not work_ with the current version.) + +* You own the DS3 DLC if your randomizer config has DLC enabled. (It's possible, + but unconfirmed, that you need the DLC even when it's disabled in your config). + +* Steam is not running in administrator mode. To fix this, right-click + `steam.exe` (by default this is in `C:\Program Files\Steam`), select + "Properties", open the "Compatiblity" tab, and uncheck "Run this program as an + administrator". + +* There is no `dinput8.dll` file in your DS3 game directory. This is the old way + of installing mods, and it can interfere with the new ModEngine2 workflow. + +If you've checked all of these, you can also try: + +* Running `launchmod_darksouls3.bat` as an administrator. + +* Reinstalling DS3 or even reinstalling Steam itself. + +* Making sure DS3 is installed on the same drive as Steam and as the randomizer. + (A number of users are able to run these on different drives, but this has + helped some users.) + +If none of this works, unfortunately there's not much we can do. We use +ModEngine2 to launch DS3 with the Archipelago mod enabled, but unfortunately +it's no longer maintained and its successor, ModEngine3, isn't usable yet. + +### `DS3Randomizer.exe` isn't working + +This is almost always caused by using a version of the randomizer client that's +not compatible with the version used to generate the multiworld. If you're +generating your multiworld on archipelago.gg, you *must* use the latest [Dark +Souls III AP Client]. If you want to use a different client version, you *must* +generate the multiworld locally using the apworld bundled with the client. diff --git a/worlds/dkc3/Client.py b/worlds/dkc3/Client.py index ee2bd1dbdf..40216e81e3 100644 --- a/worlds/dkc3/Client.py +++ b/worlds/dkc3/Client.py @@ -1,5 +1,4 @@ import logging -import asyncio from NetUtils import ClientStatus, color from worlds.AutoSNIClient import SNIClient @@ -32,7 +31,7 @@ class DKC3SNIClient(SNIClient): async def validate_rom(self, ctx): - from SNIClient import snes_buffered_write, snes_flush_writes, snes_read + from SNIClient import snes_read rom_name = await snes_read(ctx, DKC3_ROMHASH_START, ROMHASH_SIZE) if rom_name is None or rom_name == bytes([0] * ROMHASH_SIZE) or rom_name[:2] != b"D3": diff --git a/worlds/dkc3/Items.py b/worlds/dkc3/Items.py index 358873cd20..e6cac91ea9 100644 --- a/worlds/dkc3/Items.py +++ b/worlds/dkc3/Items.py @@ -1,6 +1,6 @@ import typing -from BaseClasses import Item, ItemClassification +from BaseClasses import Item from .Names import ItemName diff --git a/worlds/dkc3/Options.py b/worlds/dkc3/Options.py index b114a503b9..3f220bce44 100644 --- a/worlds/dkc3/Options.py +++ b/worlds/dkc3/Options.py @@ -1,7 +1,6 @@ from dataclasses import dataclass -import typing -from Options import Choice, Range, Toggle, DeathLink, DefaultOnToggle, OptionGroup, PerGameCommonOptions +from Options import Choice, Range, Toggle, DefaultOnToggle, OptionGroup, PerGameCommonOptions class Goal(Choice): diff --git a/worlds/dkc3/Regions.py b/worlds/dkc3/Regions.py index ae505b78d8..6e968dbe1e 100644 --- a/worlds/dkc3/Regions.py +++ b/worlds/dkc3/Regions.py @@ -1,10 +1,9 @@ import typing -from BaseClasses import MultiWorld, Region, Entrance -from .Items import DKC3Item +from BaseClasses import Region, Entrance +from worlds.AutoWorld import World from .Locations import DKC3Location from .Names import LocationName, ItemName -from worlds.AutoWorld import World def create_regions(world: World, active_locations): diff --git a/worlds/dkc3/Rom.py b/worlds/dkc3/Rom.py index 0dc722a738..fb8bc2b122 100644 --- a/worlds/dkc3/Rom.py +++ b/worlds/dkc3/Rom.py @@ -2,7 +2,6 @@ import Utils from Utils import read_snes_rom from worlds.AutoWorld import World from worlds.Files import APDeltaPatch -from .Locations import lookup_id_to_name, all_locations from .Levels import level_list, level_dict USHASH = '120abf304f0c40fe059f6a192ed4f947' @@ -436,7 +435,7 @@ level_music_ids = [ class LocalRom: - def __init__(self, file, patch=True, vanillaRom=None, name=None, hash=None): + def __init__(self, file, name=None, hash=None): self.name = name self.hash = hash self.orig_buffer = None diff --git a/worlds/dkc3/Rules.py b/worlds/dkc3/Rules.py index cc45e4ef3a..3d68aefb71 100644 --- a/worlds/dkc3/Rules.py +++ b/worlds/dkc3/Rules.py @@ -1,8 +1,8 @@ import math +from worlds.AutoWorld import World +from worlds.generic.Rules import add_rule from .Names import LocationName, ItemName -from worlds.AutoWorld import LogicMixin, World -from worlds.generic.Rules import add_rule, set_rule def set_rules(world: World): diff --git a/worlds/dkc3/__init__.py b/worlds/dkc3/__init__.py index de6fb4a44a..1dabeb0539 100644 --- a/worlds/dkc3/__init__.py +++ b/worlds/dkc3/__init__.py @@ -1,15 +1,13 @@ import dataclasses -import os -import typing import math +import os import threading +import typing +import settings from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification from Options import PerGameCommonOptions -import Patch -import settings from worlds.AutoWorld import WebWorld, World - from .Client import DKC3SNIClient from .Items import DKC3Item, ItemData, item_table, inventory_table, junk_table from .Levels import level_list diff --git a/worlds/factorio/Client.py b/worlds/factorio/Client.py index 3c35c4cb09..ac58339c5e 100644 --- a/worlds/factorio/Client.py +++ b/worlds/factorio/Client.py @@ -234,8 +234,7 @@ async def game_watcher(ctx: FactorioContext): f"Connected Multiworld is not the expected one {data['seed_name']} != {ctx.seed_name}") else: data = data["info"] - research_data = data["research_done"] - research_data = {int(tech_name.split("-")[1]) for tech_name in research_data} + research_data: set[int] = {int(tech_name.split("-")[1]) for tech_name in data["research_done"]} victory = data["victory"] await ctx.update_death_link(data["death_link"]) ctx.multiplayer = data.get("multiplayer", False) @@ -249,7 +248,7 @@ async def game_watcher(ctx: FactorioContext): f"New researches done: " f"{[ctx.location_names.lookup_in_game(rid) for rid in research_data - ctx.locations_checked]}") ctx.locations_checked = research_data - await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": tuple(research_data)}]) + await ctx.check_locations(research_data) death_link_tick = data.get("death_link_tick", 0) if death_link_tick != ctx.death_link_tick: ctx.death_link_tick = death_link_tick diff --git a/worlds/factorio/Options.py b/worlds/factorio/Options.py index 72f438778b..481ed00987 100644 --- a/worlds/factorio/Options.py +++ b/worlds/factorio/Options.py @@ -3,13 +3,23 @@ from __future__ import annotations from dataclasses import dataclass import typing -from schema import Schema, Optional, And, Or +from schema import Schema, Optional, And, Or, SchemaError from Options import Choice, OptionDict, OptionSet, DefaultOnToggle, Range, DeathLink, Toggle, \ StartInventoryPool, PerGameCommonOptions, OptionGroup # schema helpers -FloatRange = lambda low, high: And(Or(int, float), lambda f: low <= f <= high) +class FloatRange: + def __init__(self, low, high): + self._low = low + self._high = high + + def validate(self, value): + if not isinstance(value, (float, int)): + raise SchemaError(f"should be instance of float or int, but was {value!r}") + if not self._low <= value <= self._high: + raise SchemaError(f"{value} is not between {self._low} and {self._high}") + LuaBool = Or(bool, And(int, lambda n: n in (0, 1))) @@ -225,6 +235,12 @@ class FactorioStartItems(OptionDict): """Mapping of Factorio internal item-name to amount granted on start.""" display_name = "Starting Items" default = {"burner-mining-drill": 4, "stone-furnace": 4, "raw-fish": 50} + schema = Schema( + { + str: And(int, lambda n: n > 0, + error="amount of starting items has to be a positive integer"), + } + ) class FactorioFreeSampleBlacklist(OptionSet): @@ -247,7 +263,8 @@ class AttackTrapCount(TrapCount): class TeleportTrapCount(TrapCount): - """Trap items that when received trigger a random teleport.""" + """Trap items that when received trigger a random teleport. + It is ensured the player can walk back to where they got teleported from.""" display_name = "Teleport Traps" @@ -294,6 +311,11 @@ class EvolutionTrapIncrease(Range): range_end = 100 +class InventorySpillTrapCount(TrapCount): + """Trap items that when received trigger dropping your main inventory and trash inventory onto the ground.""" + display_name = "Inventory Spill Traps" + + class FactorioWorldGen(OptionDict): """World Generation settings. Overview of options at https://wiki.factorio.com/Map_generator, with in-depth documentation at https://lua-api.factorio.com/latest/Concepts.html#MapGenSettings""" @@ -474,6 +496,7 @@ class FactorioOptions(PerGameCommonOptions): artillery_traps: ArtilleryTrapCount atomic_rocket_traps: AtomicRocketTrapCount atomic_cliff_remover_traps: AtomicCliffRemoverTrapCount + inventory_spill_traps: InventorySpillTrapCount attack_traps: AttackTrapCount evolution_traps: EvolutionTrapCount evolution_trap_increase: EvolutionTrapIncrease @@ -508,6 +531,7 @@ option_groups: list[OptionGroup] = [ ArtilleryTrapCount, AtomicRocketTrapCount, AtomicCliffRemoverTrapCount, + InventorySpillTrapCount, ], start_collapsed=True ), diff --git a/worlds/factorio/__init__.py b/worlds/factorio/__init__.py index 8f8abeb292..3f480527f5 100644 --- a/worlds/factorio/__init__.py +++ b/worlds/factorio/__init__.py @@ -8,7 +8,7 @@ import Utils import settings from BaseClasses import Region, Location, Item, Tutorial, ItemClassification from worlds.AutoWorld import World, WebWorld -from worlds.LauncherComponents import Component, components, Type, launch_subprocess +from worlds.LauncherComponents import Component, components, Type, launch as launch_component from worlds.generic import Rules from .Locations import location_pools, location_table from .Mod import generate_mod @@ -24,7 +24,7 @@ from .Technologies import base_tech_table, recipe_sources, base_technology_table def launch_client(): from .Client import launch - launch_subprocess(launch, name="FactorioClient") + launch_component(launch, name="FactorioClient") components.append(Component("Factorio Client", "FactorioClient", func=launch_client, component_type=Type.CLIENT)) @@ -78,6 +78,7 @@ all_items["Cluster Grenade Trap"] = factorio_base_id - 5 all_items["Artillery Trap"] = factorio_base_id - 6 all_items["Atomic Rocket Trap"] = factorio_base_id - 7 all_items["Atomic Cliff Remover Trap"] = factorio_base_id - 8 +all_items["Inventory Spill Trap"] = factorio_base_id - 9 class Factorio(World): @@ -112,6 +113,8 @@ class Factorio(World): science_locations: typing.List[FactorioScienceLocation] removed_technologies: typing.Set[str] settings: typing.ClassVar[FactorioSettings] + trap_names: tuple[str] = ("Evolution", "Attack", "Teleport", "Grenade", "Cluster Grenade", "Artillery", + "Atomic Rocket", "Atomic Cliff Remover", "Inventory Spill") def __init__(self, world, player: int): super(Factorio, self).__init__(world, player) @@ -136,15 +139,11 @@ class Factorio(World): random = self.random nauvis = Region("Nauvis", player, self.multiworld) - location_count = len(base_tech_table) - len(useless_technologies) - self.skip_silo + \ - self.options.evolution_traps + \ - self.options.attack_traps + \ - self.options.teleport_traps + \ - self.options.grenade_traps + \ - self.options.cluster_grenade_traps + \ - self.options.atomic_rocket_traps + \ - self.options.atomic_cliff_remover_traps + \ - self.options.artillery_traps + location_count = len(base_tech_table) - len(useless_technologies) - self.skip_silo + + for name in self.trap_names: + name = name.replace(" ", "_").lower()+"_traps" + location_count += getattr(self.options, name) location_pool = [] @@ -196,9 +195,8 @@ class Factorio(World): def create_items(self) -> None: self.custom_technologies = self.set_custom_technologies() self.set_custom_recipes() - traps = ("Evolution", "Attack", "Teleport", "Grenade", "Cluster Grenade", "Artillery", "Atomic Rocket", - "Atomic Cliff Remover") - for trap_name in traps: + + for trap_name in self.trap_names: self.multiworld.itempool.extend(self.create_item(f"{trap_name} Trap") for _ in range(getattr(self.options, f"{trap_name.lower().replace(' ', '_')}_traps"))) @@ -280,9 +278,6 @@ class Factorio(World): self.get_location("Rocket Launch").access_rule = lambda state: all(state.has(technology, player) for technology in victory_tech_names) - for tech_name in victory_tech_names: - if not self.multiworld.get_all_state(True).has(tech_name, player): - print(tech_name) self.multiworld.completion_condition[player] = lambda state: state.has('Victory', player) def get_recipe(self, name: str) -> Recipe: diff --git a/worlds/factorio/data/mod/lib.lua b/worlds/factorio/data/mod/lib.lua index 517a54e3d6..aa50b926f0 100644 --- a/worlds/factorio/data/mod/lib.lua +++ b/worlds/factorio/data/mod/lib.lua @@ -48,3 +48,107 @@ function fire_entity_at_entities(entity_name, entities, speed) target=target, speed=speed} end end + +local teleport_requests = {} +local teleport_attempts = {} +local max_attempts = 100 + +function attempt_teleport_player(player, attempt) + -- global attempt storage as metadata can't be stored + if attempt == nil then + attempt = teleport_attempts[player.index] + else + teleport_attempts[player.index] = attempt + end + + if attempt > max_attempts then + player.print("Teleport failed: No valid position found after " .. max_attempts .. " attempts!") + teleport_attempts[player.index] = 0 + return + end + + local surface = player.character.surface + local prototype_name = player.character.prototype.name + local original_position = player.character.position + local candidate_position = random_offset_position(original_position, 1024) + + local non_colliding_position = surface.find_non_colliding_position( + prototype_name, candidate_position, 0, 1 + ) + + if non_colliding_position then + -- Request pathfinding asynchronously + local path_id = surface.request_path{ + bounding_box = player.character.prototype.collision_box, + collision_mask = { layers = { ["player"] = true } }, + start = original_position, + goal = non_colliding_position, + force = player.force.name, + radius = 1, + pathfind_flags = {cache = true, low_priority = true, allow_paths_through_own_entities = true}, + } + + -- Store the request with the player index as the key + teleport_requests[player.index] = path_id + else + attempt_teleport_player(player, attempt + 1) + end +end + +function handle_teleport_attempt(event) + for player_index, path_id in pairs(teleport_requests) do + -- Check if the event matches the stored path_id + if path_id == event.id then + local player = game.players[player_index] + + if event.path then + if player.character then + player.character.teleport(event.path[#event.path].position) -- Teleport to the last point in the path + -- Clear the attempts for this player + teleport_attempts[player_index] = 0 + return + end + return + end + + attempt_teleport_player(player, nil) + break + end + end +end +function spill_character_inventory(character) + if not (character and character.valid) then + return false + end + + -- grab attrs once pre-loop + local position = character.position + local surface = character.surface + + local inventories_to_spill = { + defines.inventory.character_main, -- Main inventory + defines.inventory.character_trash, -- Logistic trash slots + } + + for _, inventory_type in pairs(inventories_to_spill) do + local inventory = character.get_inventory(inventory_type) + if inventory and inventory.valid then + -- Spill each item stack onto the ground + for i = 1, #inventory do + local stack = inventory[i] + if stack and stack.valid_for_read then + local spilled_items = surface.spill_item_stack{ + position = position, + stack = stack, + enable_looted = false, -- do not mark for auto-pickup + force = nil, -- do not mark for auto-deconstruction + allow_belts = true, -- do mark for putting it onto belts + } + if #spilled_items > 0 then + stack.clear() -- only delete if spilled successfully + end + end + end + end + end +end diff --git a/worlds/factorio/data/mod_template/control.lua b/worlds/factorio/data/mod_template/control.lua index 4090325046..cd0c00e987 100644 --- a/worlds/factorio/data/mod_template/control.lua +++ b/worlds/factorio/data/mod_template/control.lua @@ -134,6 +134,9 @@ end script.on_event(defines.events.on_player_changed_position, on_player_changed_position) {% endif %} +-- Handle the pathfinding result of teleport traps +script.on_event(defines.events.on_script_path_request_finished, handle_teleport_attempt) + function count_energy_bridges() local count = 0 for i, bridge in pairs(storage.energy_link_bridges) do @@ -143,9 +146,11 @@ function count_energy_bridges() end return count end + function get_energy_increment(bridge) return ENERGY_INCREMENT + (ENERGY_INCREMENT * 0.3 * bridge.quality.level) end + function on_check_energy_link(event) --- assuming 1 MJ increment and 5MJ battery: --- first 2 MJ request fill, last 2 MJ push energy, middle 1 MJ does nothing @@ -717,15 +722,15 @@ TRAP_TABLE = { game.surfaces["nauvis"].build_enemy_base(game.forces["player"].get_spawn_position(game.get_surface(1)), 25) end, ["Evolution Trap"] = function () - game.forces["enemy"].evolution_factor = game.forces["enemy"].evolution_factor + (TRAP_EVO_FACTOR * (1 - game.forces["enemy"].evolution_factor)) - game.print({"", "New evolution factor:", game.forces["enemy"].evolution_factor}) + local new_factor = game.forces["enemy"].get_evolution_factor("nauvis") + + (TRAP_EVO_FACTOR * (1 - game.forces["enemy"].get_evolution_factor("nauvis"))) + game.forces["enemy"].set_evolution_factor(new_factor, "nauvis") + game.print({"", "New evolution factor:", new_factor}) end, -["Teleport Trap"] = function () +["Teleport Trap"] = function() for _, player in ipairs(game.forces["player"].players) do - current_character = player.character - if current_character ~= nil then - current_character.teleport(current_character.surface.find_non_colliding_position( - current_character.prototype.name, random_offset_position(current_character.position, 1024), 0, 1)) + if player.character then + attempt_teleport_player(player, 1) end end end, @@ -748,6 +753,11 @@ end, fire_entity_at_entities("atomic-rocket", {cliffs[math.random(#cliffs)]}, 0.1) end end, +["Inventory Spill Trap"] = function () + for _, player in ipairs(game.forces["player"].players) do + spill_character_inventory(player.character) + end +end, } commands.add_command("ap-get-technology", "Grant a technology, used by the Archipelago Client.", function(call) diff --git a/worlds/factorio/test_file_validation.py b/worlds/factorio/test_file_validation.py new file mode 100644 index 0000000000..df56ec608c --- /dev/null +++ b/worlds/factorio/test_file_validation.py @@ -0,0 +1,39 @@ +"""Tests for error messages from YAML validation.""" + +import os +import unittest + +import WebHostLib.check + +FACTORIO_YAML=""" +game: Factorio +Factorio: + world_gen: + autoplace_controls: + coal: + richness: 1 + frequency: {} + size: 1 +""" + +def yamlWithFrequency(f): + return FACTORIO_YAML.format(f) + + +class TestFileValidation(unittest.TestCase): + def test_out_of_range(self): + results, _ = WebHostLib.check.roll_options({"bob.yaml": yamlWithFrequency(1000)}) + self.assertIn("between 0 and 6", results["bob.yaml"]) + + def test_bad_non_numeric(self): + results, _ = WebHostLib.check.roll_options({"bob.yaml": yamlWithFrequency("not numeric")}) + self.assertIn("float", results["bob.yaml"]) + self.assertIn("int", results["bob.yaml"]) + + def test_good_float(self): + results, _ = WebHostLib.check.roll_options({"bob.yaml": yamlWithFrequency(1.0)}) + self.assertIs(results["bob.yaml"], True) + + def test_good_int(self): + results, _ = WebHostLib.check.roll_options({"bob.yaml": yamlWithFrequency(1)}) + self.assertIs(results["bob.yaml"], True) diff --git a/worlds/faxanadu/__init__.py b/worlds/faxanadu/__init__.py index c4ae1ccaa1..ca17c06759 100644 --- a/worlds/faxanadu/__init__.py +++ b/worlds/faxanadu/__init__.py @@ -44,8 +44,13 @@ class FaxanaduWorld(World): location_name_to_id = {loc.name: loc.id for loc in Locations.locations if loc.id is not None} def __init__(self, world: MultiWorld, player: int): - self.filler_ratios: Dict[str, int] = {} - + self.filler_ratios: Dict[str, int] = { + item.name: item.count + for item in Items.items + if item.classification in [ItemClassification.filler, ItemClassification.trap] + } + # Remove poison by default to respect itemlinking + self.filler_ratios["Poison"] = 0 super().__init__(world, player) def create_regions(self): @@ -160,19 +165,13 @@ class FaxanaduWorld(World): for i in range(item.progression_count): itempool.append(FaxanaduItem(item.name, ItemClassification.progression, item.id, self.player)) - # Set up filler ratios - self.filler_ratios = { - item.name: item.count - for item in Items.items - if item.classification in [ItemClassification.filler, ItemClassification.trap] - } - + # Adjust filler ratios # If red potions are locked in shops, remove the count from the ratio. self.filler_ratios["Red Potion"] -= red_potion_in_shop_count - # Remove poisons if not desired - if not self.options.include_poisons: - self.filler_ratios["Poison"] = 0 + # Add poisons if desired + if self.options.include_poisons: + self.filler_ratios["Poison"] = self.item_name_to_item["Poison"].count # Randomly add fillers to the pool with ratios based on og game occurrence counts. filler_count = len(Locations.locations) - len(itempool) - prefilled_count diff --git a/worlds/ffmq/Options.py b/worlds/ffmq/Options.py index 41c397315f..4dcf1467d6 100644 --- a/worlds/ffmq/Options.py +++ b/worlds/ffmq/Options.py @@ -1,4 +1,4 @@ -from Options import Choice, FreeText, Toggle, Range, PerGameCommonOptions +from Options import Choice, FreeText, ItemsAccessibility, Toggle, Range, PerGameCommonOptions from dataclasses import dataclass @@ -324,6 +324,7 @@ class KaelisMomFightsMinotaur(Toggle): @dataclass class FFMQOptions(PerGameCommonOptions): + accessibility: ItemsAccessibility logic: Logic brown_boxes: BrownBoxes sky_coin_mode: SkyCoinMode diff --git a/worlds/ffmq/__init__.py b/worlds/ffmq/__init__.py index 3c58487265..58dc4bf13e 100644 --- a/worlds/ffmq/__init__.py +++ b/worlds/ffmq/__init__.py @@ -152,14 +152,23 @@ class FFMQWorld(World): return FFMQItem(name, self.player) def collect_item(self, state, item, remove=False): + if not item.advancement: + return None if "Progressive" in item.name: i = item.code - 256 + if remove: + if state.has(self.item_id_to_name[i+1], self.player): + if state.has(self.item_id_to_name[i+2], self.player): + return self.item_id_to_name[i+2] + return self.item_id_to_name[i+1] + return self.item_id_to_name[i] + if state.has(self.item_id_to_name[i], self.player): if state.has(self.item_id_to_name[i+1], self.player): return self.item_id_to_name[i+2] return self.item_id_to_name[i+1] return self.item_id_to_name[i] - return item.name if item.advancement else None + return item.name def modify_multidata(self, multidata): # wait for self.rom_name to be available. diff --git a/worlds/hk/Options.py b/worlds/hk/Options.py index 53dda96e2b..e76e7eba9d 100644 --- a/worlds/hk/Options.py +++ b/worlds/hk/Options.py @@ -333,7 +333,7 @@ class PlandoCharmCosts(OptionDict): continue try: self.value[key] = CharmCost.from_any(data).value - except ValueError as ex: + except ValueError: # will fail schema afterwords self.value[key] = data diff --git a/worlds/hk/__init__.py b/worlds/hk/__init__.py index bcd904521d..4a0da109fa 100644 --- a/worlds/hk/__init__.py +++ b/worlds/hk/__init__.py @@ -7,22 +7,22 @@ import itertools import operator from collections import defaultdict, Counter -logger = logging.getLogger("Hollow Knight") - -from .Items import item_table, lookup_type_to_names, item_name_groups -from .Regions import create_regions +from .Items import item_table, item_name_groups from .Rules import set_rules, cost_terms, _hk_can_beat_thk, _hk_siblings_ending, _hk_can_beat_radiance from .Options import hollow_knight_options, hollow_knight_randomize_options, Goal, WhitePalace, CostSanity, \ shop_to_option, HKOptions, GrubHuntGoal -from .ExtractedData import locations, starts, multi_locations, location_to_region_lookup, \ - event_names, item_effects, connectors, one_ways, vanilla_shop_costs, vanilla_location_costs +from .ExtractedData import locations, starts, multi_locations, event_names, item_effects, connectors, \ + vanilla_shop_costs, vanilla_location_costs from .Charms import names as charm_names -from BaseClasses import Region, Location, MultiWorld, Item, LocationProgressType, Tutorial, ItemClassification, CollectionState +from BaseClasses import Region, Location, MultiWorld, Item, LocationProgressType, Tutorial, ItemClassification, \ + CollectionState from worlds.AutoWorld import World, LogicMixin, WebWorld from settings import Group, Bool +logger = logging.getLogger("Hollow Knight") + class HollowKnightSettings(Group): class DisableMapModSpoilers(Bool): @@ -160,7 +160,7 @@ class HKWeb(WebWorld): class HKWorld(World): - """Beneath the fading town of Dirtmouth sleeps a vast, ancient kingdom. Many are drawn beneath the surface, + """Beneath the fading town of Dirtmouth sleeps a vast, ancient kingdom. Many are drawn beneath the surface, searching for riches, or glory, or answers to old secrets. As the enigmatic Knight, you’ll traverse the depths, unravel its mysteries and conquer its evils. @@ -181,6 +181,7 @@ class HKWorld(World): charm_costs: typing.List[int] cached_filler_items = {} grub_count: int + grub_player_count: typing.Dict[int, int] def __init__(self, multiworld, player): super(HKWorld, self).__init__(multiworld, player) @@ -190,7 +191,6 @@ class HKWorld(World): self.ranges = {} self.created_shop_items = 0 self.vanilla_shop_costs = deepcopy(vanilla_shop_costs) - self.grub_count = 0 def generate_early(self): options = self.options @@ -204,7 +204,14 @@ class HKWorld(World): mini.value = min(mini.value, maxi.value) self.ranges[term] = mini.value, maxi.value self.multiworld.push_precollected(HKItem(starts[options.StartLocation.current_key], - True, None, "Event", self.player)) + True, None, "Event", self.player)) + + # defaulting so completion condition isn't incorrect before pre_fill + self.grub_count = ( + 46 if options.GrubHuntGoal == GrubHuntGoal.special_range_names["all"] + else options.GrubHuntGoal.value + ) + self.grub_player_count = {self.player: self.grub_count} def white_palace_exclusions(self): exclusions = set() @@ -224,7 +231,6 @@ class HKWorld(World): def create_regions(self): menu_region: Region = create_region(self.multiworld, self.player, 'Menu') self.multiworld.regions.append(menu_region) - # wp_exclusions = self.white_palace_exclusions() # check for any goal that godhome events are relevant to all_event_names = event_names.copy() @@ -234,21 +240,17 @@ class HKWorld(World): # Link regions for event_name in sorted(all_event_names): - #if event_name in wp_exclusions: - # continue loc = HKLocation(self.player, event_name, None, menu_region) loc.place_locked_item(HKItem(event_name, - True, #event_name not in wp_exclusions, + True, None, "Event", self.player)) menu_region.locations.append(loc) for entry_transition, exit_transition in connectors.items(): - #if entry_transition in wp_exclusions: - # continue if exit_transition: # if door logic fulfilled -> award vanilla target as event loc = HKLocation(self.player, entry_transition, None, menu_region) loc.place_locked_item(HKItem(exit_transition, - True, #exit_transition not in wp_exclusions, + True, None, "Event", self.player)) menu_region.locations.append(loc) @@ -285,7 +287,10 @@ class HKWorld(World): if item_name in junk_replace: item_name = self.get_filler_item_name() - item = self.create_item(item_name) if not vanilla or location_name == "Start" or self.options.AddUnshuffledLocations else self.create_event(item_name) + item = (self.create_item(item_name) + if not vanilla or location_name == "Start" or self.options.AddUnshuffledLocations + else self.create_event(item_name) + ) if location_name == "Start": if item_name in randomized_starting_items: @@ -340,8 +345,8 @@ class HKWorld(World): randomized = True _add("Elevator_Pass", "Elevator_Pass", randomized) - for shop, locations in self.created_multi_locations.items(): - for _ in range(len(locations), getattr(self.options, shop_to_option[shop]).value): + for shop, shop_locations in self.created_multi_locations.items(): + for _ in range(len(shop_locations), getattr(self.options, shop_to_option[shop]).value): self.create_location(shop) unfilled_locations += 1 @@ -351,7 +356,7 @@ class HKWorld(World): # Add additional shop items, as needed. if additional_shop_items > 0: - shops = list(shop for shop, locations in self.created_multi_locations.items() if len(locations) < 16) + shops = [shop for shop, shop_locations in self.created_multi_locations.items() if len(shop_locations) < 16] if not self.options.EggShopSlots: # No eggshop, so don't place items there shops.remove('Egg_Shop') @@ -373,8 +378,8 @@ class HKWorld(World): self.sort_shops_by_cost() def sort_shops_by_cost(self): - for shop, locations in self.created_multi_locations.items(): - randomized_locations = list(loc for loc in locations if not loc.vanilla) + for shop, shop_locations in self.created_multi_locations.items(): + randomized_locations = [loc for loc in shop_locations if not loc.vanilla] prices = sorted( (loc.costs for loc in randomized_locations), key=lambda costs: (len(costs),) + tuple(costs.values()) @@ -398,7 +403,7 @@ class HKWorld(World): return {k: v for k, v in weights.items() if v} random = self.random - hybrid_chance = getattr(self.options, f"CostSanityHybridChance").value + hybrid_chance = getattr(self.options, "CostSanityHybridChance").value weights = { data.term: getattr(self.options, f"CostSanity{data.option}Weight").value for data in cost_terms.values() @@ -469,29 +474,28 @@ class HKWorld(World): elif goal == Goal.option_godhome_flower: multiworld.completion_condition[player] = lambda state: state.count("Godhome_Flower_Quest", player) elif goal == Goal.option_grub_hunt: - pass # will set in stage_pre_fill() + multiworld.completion_condition[player] = lambda state: self.can_grub_goal(state) else: # Any goal multiworld.completion_condition[player] = lambda state: _hk_siblings_ending(state, player) and \ - _hk_can_beat_radiance(state, player) and state.count("Godhome_Flower_Quest", player) + _hk_can_beat_radiance(state, player) and state.count("Godhome_Flower_Quest", player) and \ + self.can_grub_goal(state) set_rules(self) + def can_grub_goal(self, state: CollectionState) -> bool: + return all(state.has("Grub", owner, count) for owner, count in self.grub_player_count.items()) + @classmethod def stage_pre_fill(cls, multiworld: "MultiWorld"): - def set_goal(player, grub_rule: typing.Callable[[CollectionState], bool]): - world = multiworld.worlds[player] - - if world.options.Goal == "grub_hunt": - multiworld.completion_condition[player] = grub_rule - else: - old_rule = multiworld.completion_condition[player] - multiworld.completion_condition[player] = lambda state: old_rule(state) and grub_rule(state) - worlds = [world for world in multiworld.get_game_worlds(cls.game) if world.options.Goal in ["any", "grub_hunt"]] if worlds: grubs = [item for item in multiworld.get_items() if item.name == "Grub"] - all_grub_players = [world.player for world in worlds if world.options.GrubHuntGoal == GrubHuntGoal.special_range_names["all"]] + all_grub_players = [ + world.player + for world in worlds + if world.options.GrubHuntGoal == GrubHuntGoal.special_range_names["all"] + ] if all_grub_players: group_lookup = defaultdict(set) @@ -525,13 +529,13 @@ class HKWorld(World): for player, grub_player_count in per_player_grubs_per_player.items(): if player in all_grub_players: - set_goal(player, lambda state, g=grub_player_count: all(state.has("Grub", owner, count) for owner, count in g.items())) + multiworld.worlds[player].grub_player_count = grub_player_count for world in worlds: if world.player not in all_grub_players: world.grub_count = world.options.GrubHuntGoal.value player = world.player - set_goal(player, lambda state, p=player, c=world.grub_count: state.has("Grub", p, c)) + world.grub_player_count = {player: world.grub_count} def fill_slot_data(self): slot_data = {} @@ -666,8 +670,8 @@ class HKWorld(World): ): spoiler_handle.write(f"\n{loc}: {loc.item} costing {loc.cost_text()}") else: - for shop_name, locations in hk_world.created_multi_locations.items(): - for loc in locations: + for shop_name, shop_locations in hk_world.created_multi_locations.items(): + for loc in shop_locations: spoiler_handle.write(f"\n{loc}: {loc.item} costing {loc.cost_text()}") def get_multi_location_name(self, base: str, i: typing.Optional[int]) -> str: diff --git a/worlds/hk/test/__init__.py b/worlds/hk/test/__init__.py index c41d20127f..67591001a7 100644 --- a/worlds/hk/test/__init__.py +++ b/worlds/hk/test/__init__.py @@ -2,7 +2,6 @@ import typing from argparse import Namespace from BaseClasses import CollectionState, MultiWorld from Options import ItemLinks -from test.bases import WorldTestBase from worlds.AutoWorld import AutoWorldRegister, call_all from .. import HKWorld diff --git a/worlds/hk/test/test_grub_count.py b/worlds/hk/test/test_grub_count.py index dba15b614d..a58293c078 100644 --- a/worlds/hk/test/test_grub_count.py +++ b/worlds/hk/test/test_grub_count.py @@ -1,5 +1,6 @@ -from . import linkedTestHK, WorldTestBase +from test.bases import WorldTestBase from Options import ItemLinks +from . import linkedTestHK class test_grubcount_limited(linkedTestHK, WorldTestBase): diff --git a/worlds/kdl3/rules.py b/worlds/kdl3/rules.py index a08e99257e..828740859e 100644 --- a/worlds/kdl3/rules.py +++ b/worlds/kdl3/rules.py @@ -206,19 +206,19 @@ def set_rules(world: "KDL3World") -> None: lambda state: can_reach_needle(state, world.player)) set_rule(world.multiworld.get_location(location_name.sand_canyon_5_u2, world.player), lambda state: can_reach_ice(state, world.player) and - (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) - or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) - or can_reach_nago(state, world.player))) + (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) + or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) + or can_reach_nago(state, world.player))) set_rule(world.multiworld.get_location(location_name.sand_canyon_5_u3, world.player), lambda state: can_reach_ice(state, world.player) and - (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) - or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) - or can_reach_nago(state, world.player))) + (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) + or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) + or can_reach_nago(state, world.player))) set_rule(world.multiworld.get_location(location_name.sand_canyon_5_u4, world.player), lambda state: can_reach_ice(state, world.player) and - (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) - or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) - or can_reach_nago(state, world.player))) + (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) + or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) + or can_reach_nago(state, world.player))) set_rule(world.multiworld.get_location(location_name.cloudy_park_6_u1, world.player), lambda state: can_reach_cutter(state, world.player)) @@ -248,9 +248,9 @@ def set_rules(world: "KDL3World") -> None: for i in range(12, 18): set_rule(world.multiworld.get_location(f"Sand Canyon 5 - Star {i}", world.player), lambda state: can_reach_ice(state, world.player) and - (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) - or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) - or can_reach_nago(state, world.player))) + (can_reach_rick(state, world.player) or can_reach_coo(state, world.player) + or can_reach_chuchu(state, world.player) or can_reach_pitch(state, world.player) + or can_reach_nago(state, world.player))) for i in range(21, 23): set_rule(world.multiworld.get_location(f"Sand Canyon 5 - Star {i}", world.player), lambda state: can_reach_chuchu(state, world.player)) @@ -307,7 +307,7 @@ def set_rules(world: "KDL3World") -> None: lambda state: can_reach_coo(state, world.player) and can_reach_burning(state, world.player)) set_rule(world.multiworld.get_location(animal_friend_spawns.iceberg_4_a3, world.player), lambda state: can_reach_chuchu(state, world.player) and can_reach_coo(state, world.player) - and can_reach_burning(state, world.player)) + and can_reach_burning(state, world.player)) for boss_flag, purification, i in zip(["Level 1 Boss - Purified", "Level 2 Boss - Purified", "Level 3 Boss - Purified", "Level 4 Boss - Purified", @@ -329,6 +329,14 @@ def set_rules(world: "KDL3World") -> None: world.options.ow_boss_requirement.value, world.player_levels))) + if world.options.open_world: + for boss_flag, level in zip(["Level 1 Boss - Defeated", "Level 2 Boss - Defeated", "Level 3 Boss - Defeated", + "Level 4 Boss - Defeated", "Level 5 Boss - Defeated"], + location_name.level_names.keys()): + set_rule(world.get_location(boss_flag), + lambda state, lvl=level: state.has(f"{lvl} - Stage Completion", world.player, + world.options.ow_boss_requirement.value)) + set_rule(world.multiworld.get_entrance("To Level 6", world.player), lambda state: state.has("Heart Star", world.player, world.required_heart_stars)) diff --git a/worlds/kh1/Regions.py b/worlds/kh1/Regions.py index a6f85fe617..6189adf207 100644 --- a/worlds/kh1/Regions.py +++ b/worlds/kh1/Regions.py @@ -483,6 +483,8 @@ def create_regions(multiworld: MultiWorld, player: int, options): for name, data in regions.items(): multiworld.regions.append(create_region(multiworld, player, name, data)) + +def connect_entrances(multiworld: MultiWorld, player: int): multiworld.get_entrance("Awakening", player).connect(multiworld.get_region("Awakening", player)) multiworld.get_entrance("Destiny Islands", player).connect(multiworld.get_region("Destiny Islands", player)) multiworld.get_entrance("Traverse Town", player).connect(multiworld.get_region("Traverse Town", player)) @@ -500,6 +502,7 @@ def create_regions(multiworld: MultiWorld, player: int, options): multiworld.get_entrance("World Map", player).connect(multiworld.get_region("World Map", player)) multiworld.get_entrance("Levels", player).connect(multiworld.get_region("Levels", player)) + def create_region(multiworld: MultiWorld, player: int, name: str, data: KH1RegionData): region = Region(name, player, multiworld) if data.locations: diff --git a/worlds/kh1/__init__.py b/worlds/kh1/__init__.py index 63b4575568..ac0afca501 100644 --- a/worlds/kh1/__init__.py +++ b/worlds/kh1/__init__.py @@ -6,15 +6,15 @@ from worlds.AutoWorld import WebWorld, World from .Items import KH1Item, KH1ItemData, event_item_table, get_items_by_category, item_table, item_name_groups from .Locations import KH1Location, location_table, get_locations_by_category, location_name_groups from .Options import KH1Options, kh1_option_groups -from .Regions import create_regions +from .Regions import connect_entrances, create_regions from .Rules import set_rules from .Presets import kh1_option_presets -from worlds.LauncherComponents import Component, components, Type, launch_subprocess +from worlds.LauncherComponents import Component, components, Type, launch as launch_component def launch_client(): from .Client import launch - launch_subprocess(launch, name="KH1 Client") + launch_component(launch, name="KH1 Client") components.append(Component("KH1 Client", "KH1Client", func=launch_client, component_type=Type.CLIENT)) @@ -242,6 +242,9 @@ class KH1World(World): def create_regions(self): create_regions(self.multiworld, self.player, self.options) + + def connect_entrances(self): + connect_entrances(self.multiworld, self.player) def generate_early(self): value_names = ["Reports to Open End of the World", "Reports to Open Final Rest Door", "Reports in Pool"] diff --git a/worlds/kh2/Client.py b/worlds/kh2/Client.py index e2d2338b76..a21c8c7c55 100644 --- a/worlds/kh2/Client.py +++ b/worlds/kh2/Client.py @@ -5,8 +5,10 @@ ModuleUpdate.update() import os import asyncio import json +import requests from pymem import pymem -from . import item_dictionary_table, exclusion_item_table, CheckDupingItems, all_locations, exclusion_table, SupportAbility_Table, ActionAbility_Table, all_weapon_slot +from . import item_dictionary_table, exclusion_item_table, CheckDupingItems, all_locations, exclusion_table, \ + SupportAbility_Table, ActionAbility_Table, all_weapon_slot from .Names import ItemName from .WorldLocations import * @@ -82,6 +84,7 @@ class KH2Context(CommonContext): } self.kh2seedname = None self.kh2slotdata = None + self.mem_json = None self.itemamount = {} if "localappdata" in os.environ: self.game_communication_path = os.path.expandvars(r"%localappdata%\KH2AP") @@ -110,6 +113,7 @@ class KH2Context(CommonContext): 18: TWTNW_Checks, # 255: {}, # starting screen } + self.last_world_int = -1 # 0x2A09C00+0x40 is the sve anchor. +1 is the last saved room # self.sveroom = 0x2A09C00 + 0x41 # 0 not in battle 1 in yellow battle 2 red battle #short @@ -177,7 +181,8 @@ class KH2Context(CommonContext): self.base_accessory_slots = 1 self.base_armor_slots = 1 self.base_item_slots = 3 - self.front_ability_slots = [0x2546, 0x2658, 0x276C, 0x2548, 0x254A, 0x254C, 0x265A, 0x265C, 0x265E, 0x276E, 0x2770, 0x2772] + self.front_ability_slots = [0x2546, 0x2658, 0x276C, 0x2548, 0x254A, 0x254C, 0x265A, 0x265C, 0x265E, 0x276E, + 0x2770, 0x2772] async def server_auth(self, password_requested: bool = False): if password_requested and not self.password: @@ -339,39 +344,14 @@ class KH2Context(CommonContext): self.locations_checked |= new_locations if cmd in {"DataPackage"}: - self.kh2_loc_name_to_id = args["data"]["games"]["Kingdom Hearts 2"]["location_name_to_id"] - self.lookup_id_to_location = {v: k for k, v in self.kh2_loc_name_to_id.items()} - self.kh2_item_name_to_id = args["data"]["games"]["Kingdom Hearts 2"]["item_name_to_id"] - self.lookup_id_to_item = {v: k for k, v in self.kh2_item_name_to_id.items()} - self.ability_code_list = [self.kh2_item_name_to_id[item] for item in exclusion_item_table["Ability"]] - - if "keyblade_abilities" in self.kh2slotdata.keys(): - sora_ability_dict = self.kh2slotdata["KeybladeAbilities"] + if "Kingdom Hearts 2" in args["data"]["games"]: + self.data_package_kh2_cache(args) + if "KeybladeAbilities" in self.kh2slotdata.keys(): # sora ability to slot + self.AbilityQuantityDict.update(self.kh2slotdata["KeybladeAbilities"]) # itemid:[slots that are available for that item] - for k, v in sora_ability_dict.items(): - if v >= 1: - if k not in self.sora_ability_to_slot.keys(): - self.sora_ability_to_slot[k] = [] - for _ in range(sora_ability_dict[k]): - self.sora_ability_to_slot[k].append(self.kh2_seed_save_cache["SoraInvo"][0]) - self.kh2_seed_save_cache["SoraInvo"][0] -= 2 - donald_ability_dict = self.kh2slotdata["StaffAbilities"] - for k, v in donald_ability_dict.items(): - if v >= 1: - if k not in self.donald_ability_to_slot.keys(): - self.donald_ability_to_slot[k] = [] - for _ in range(donald_ability_dict[k]): - self.donald_ability_to_slot[k].append(self.kh2_seed_save_cache["DonaldInvo"][0]) - self.kh2_seed_save_cache["DonaldInvo"][0] -= 2 - goofy_ability_dict = self.kh2slotdata["ShieldAbilities"] - for k, v in goofy_ability_dict.items(): - if v >= 1: - if k not in self.goofy_ability_to_slot.keys(): - self.goofy_ability_to_slot[k] = [] - for _ in range(goofy_ability_dict[k]): - self.goofy_ability_to_slot[k].append(self.kh2_seed_save_cache["GoofyInvo"][0]) - self.kh2_seed_save_cache["GoofyInvo"][0] -= 2 + self.AbilityQuantityDict.update(self.kh2slotdata["StaffAbilities"]) + self.AbilityQuantityDict.update(self.kh2slotdata["ShieldAbilities"]) all_weapon_location_id = [] for weapon_location in all_weapon_slot: @@ -379,24 +359,9 @@ class KH2Context(CommonContext): self.all_weapon_location_id = set(all_weapon_location_id) try: - self.kh2 = pymem.Pymem(process_name="KINGDOM HEARTS II FINAL MIX") - if self.kh2_game_version is None: - if self.kh2_read_string(0x09A9830, 4) == "KH2J": - self.kh2_game_version = "STEAM" - self.Now = 0x0717008 - self.Save = 0x09A9830 - self.Slot1 = 0x2A23518 - self.Journal = 0x7434E0 - self.Shop = 0x7435D0 - - elif self.kh2_read_string(0x09A92F0, 4) == "KH2J": - self.kh2_game_version = "EGS" - else: - self.kh2_game_version = None - logger.info("Your game version is out of date. Please update your game via The Epic Games Store or Steam.") - if self.kh2_game_version is not None: - logger.info(f"You are now auto-tracking. {self.kh2_game_version}") - self.kh2connected = True + if not self.kh2: + self.kh2 = pymem.Pymem(process_name="KINGDOM HEARTS II FINAL MIX") + self.get_addresses() except Exception as e: if self.kh2connected: @@ -405,16 +370,25 @@ class KH2Context(CommonContext): self.serverconneced = True asyncio.create_task(self.send_msgs([{'cmd': 'Sync'}])) + def data_package_kh2_cache(self, args): + self.kh2_loc_name_to_id = args["data"]["games"]["Kingdom Hearts 2"]["location_name_to_id"] + self.lookup_id_to_location = {v: k for k, v in self.kh2_loc_name_to_id.items()} + self.kh2_item_name_to_id = args["data"]["games"]["Kingdom Hearts 2"]["item_name_to_id"] + self.lookup_id_to_item = {v: k for k, v in self.kh2_item_name_to_id.items()} + self.ability_code_list = [self.kh2_item_name_to_id[item] for item in exclusion_item_table["Ability"]] + async def checkWorldLocations(self): try: currentworldint = self.kh2_read_byte(self.Now) - await self.send_msgs([{ - "cmd": "Set", "key": "Slot: " + str(self.slot) + " :CurrentWorld", - "default": 0, "want_reply": True, "operations": [{ - "operation": "replace", - "value": currentworldint - }] - }]) + if self.last_world_int != currentworldint: + self.last_world_int = currentworldint + await self.send_msgs([{ + "cmd": "Set", "key": "Slot: " + str(self.slot) + " :CurrentWorld", + "default": 0, "want_reply": False, "operations": [{ + "operation": "replace", + "value": currentworldint + }] + }]) if currentworldint in self.worldid_to_locations: curworldid = self.worldid_to_locations[currentworldint] for location, data in curworldid.items(): @@ -443,7 +417,6 @@ class KH2Context(CommonContext): 0: ["ValorLevel", ValorLevels], 1: ["WisdomLevel", WisdomLevels], 2: ["LimitLevel", LimitLevels], 3: ["MasterLevel", MasterLevels], 4: ["FinalLevel", FinalLevels], 5: ["SummonLevel", SummonLevels] } - # TODO: remove formDict[i][0] in self.kh2_seed_save_cache["Levels"].keys() after 4.3 for i in range(6): for location, data in formDict[i][1].items(): formlevel = self.kh2_read_byte(self.Save + data.addrObtained) @@ -487,9 +460,11 @@ class KH2Context(CommonContext): if locationName in self.chest_set: if locationName in self.location_name_to_worlddata.keys(): locationData = self.location_name_to_worlddata[locationName] - if self.kh2_read_byte(self.Save + locationData.addrObtained) & 0x1 << locationData.bitIndex == 0: + if self.kh2_read_byte( + self.Save + locationData.addrObtained) & 0x1 << locationData.bitIndex == 0: roomData = self.kh2_read_byte(self.Save + locationData.addrObtained) - self.kh2_write_byte(self.Save + locationData.addrObtained, roomData | 0x01 << locationData.bitIndex) + self.kh2_write_byte(self.Save + locationData.addrObtained, + roomData | 0x01 << locationData.bitIndex) except Exception as e: if self.kh2connected: @@ -512,6 +487,9 @@ class KH2Context(CommonContext): async def give_item(self, item, location): try: # todo: ripout all the itemtype stuff and just have one dictionary. the only thing that needs to be tracked from the server/local is abilites + #sleep so we can get the datapackage and not miss any items that were sent to us while we didnt have our item id dicts + while not self.lookup_id_to_item: + await asyncio.sleep(0.5) itemname = self.lookup_id_to_item[item] itemdata = self.item_name_to_data[itemname] # itemcode = self.kh2_item_name_to_id[itemname] @@ -525,27 +503,7 @@ class KH2Context(CommonContext): if itemname not in self.kh2_seed_save_cache["AmountInvo"]["Ability"]: self.kh2_seed_save_cache["AmountInvo"]["Ability"][itemname] = [] # appending the slot that the ability should be in - # for non beta. remove after 4.3 - if "PoptrackerVersion" in self.kh2slotdata: - if self.kh2slotdata["PoptrackerVersionCheck"] < 4.3: - if (itemname in self.sora_ability_set - and len(self.kh2_seed_save_cache["AmountInvo"]["Ability"][itemname]) < self.item_name_to_data[itemname].quantity) \ - and self.kh2_seed_save_cache["SoraInvo"][1] > 0x254C: - ability_slot = self.kh2_seed_save_cache["SoraInvo"][1] - self.kh2_seed_save_cache["AmountInvo"]["Ability"][itemname].append(ability_slot) - self.kh2_seed_save_cache["SoraInvo"][1] -= 2 - elif itemname in self.donald_ability_set: - ability_slot = self.kh2_seed_save_cache["DonaldInvo"][1] - self.kh2_seed_save_cache["AmountInvo"]["Ability"][itemname].append(ability_slot) - self.kh2_seed_save_cache["DonaldInvo"][1] -= 2 - else: - ability_slot = self.kh2_seed_save_cache["GoofyInvo"][1] - self.kh2_seed_save_cache["AmountInvo"]["Ability"][itemname].append(ability_slot) - self.kh2_seed_save_cache["GoofyInvo"][1] -= 2 - if ability_slot in self.front_ability_slots: - self.front_ability_slots.remove(ability_slot) - - elif len(self.kh2_seed_save_cache["AmountInvo"]["Ability"][itemname]) < \ + if len(self.kh2_seed_save_cache["AmountInvo"]["Ability"][itemname]) < \ self.AbilityQuantityDict[itemname]: if itemname in self.sora_ability_set: ability_slot = self.kh2_seed_save_cache["SoraInvo"][0] @@ -675,7 +633,8 @@ class KH2Context(CommonContext): item_data = self.item_name_to_data[item_name] # if the inventory slot for that keyblade is less than the amount they should have, # and they are not in stt - if self.kh2_read_byte(self.Save + item_data.memaddr) != 1 and self.kh2_read_byte(self.Save + 0x1CFF) != 13: + if self.kh2_read_byte(self.Save + item_data.memaddr) != 1 and self.kh2_read_byte( + self.Save + 0x1CFF) != 13: # Checking form anchors for the keyblade to remove extra keyblades if self.kh2_read_short(self.Save + 0x24F0) == item_data.kh2id \ or self.kh2_read_short(self.Save + 0x32F4) == item_data.kh2id \ @@ -776,7 +735,8 @@ class KH2Context(CommonContext): item_data = self.item_name_to_data[item_name] amount_of_items = 0 amount_of_items += self.kh2_seed_save_cache["AmountInvo"]["Magic"][item_name] - if self.kh2_read_byte(self.Save + item_data.memaddr) != amount_of_items and self.kh2_read_byte(self.Shop) in {10, 8}: + if self.kh2_read_byte(self.Save + item_data.memaddr) != amount_of_items and self.kh2_read_byte( + self.Shop) in {10, 8}: self.kh2_write_byte(self.Save + item_data.memaddr, amount_of_items) for item_name in master_stat: @@ -835,7 +795,8 @@ class KH2Context(CommonContext): # self.kh2_write_byte(self.Save + item_data.memaddr, amount_of_items) if "PoptrackerVersionCheck" in self.kh2slotdata: - if self.kh2slotdata["PoptrackerVersionCheck"] > 4.2 and self.kh2_read_byte(self.Save + 0x3607) != 1: # telling the goa they are on version 4.3 + if self.kh2slotdata["PoptrackerVersionCheck"] > 4.2 and self.kh2_read_byte( + self.Save + 0x3607) != 1: # telling the goa they are on version 4.3 self.kh2_write_byte(self.Save + 0x3607, 1) except Exception as e: @@ -844,10 +805,59 @@ class KH2Context(CommonContext): logger.info(e) logger.info("line 840") + def get_addresses(self): + if not self.kh2connected and self.kh2 is not None: + if self.kh2_game_version is None: -def finishedGame(ctx: KH2Context, message): + if self.kh2_read_string(0x09A9830, 4) == "KH2J": + self.kh2_game_version = "STEAM" + self.Now = 0x0717008 + self.Save = 0x09A9830 + self.Slot1 = 0x2A23518 + self.Journal = 0x7434E0 + self.Shop = 0x7435D0 + elif self.kh2_read_string(0x09A92F0, 4) == "KH2J": + self.kh2_game_version = "EGS" + else: + if self.game_communication_path: + logger.info("Checking with most up to date addresses of github. If file is not found will be downloading datafiles. This might take a moment") + #if mem addresses file is found then check version and if old get new one + kh2memaddresses_path = os.path.join(self.game_communication_path, f"kh2memaddresses.json") + if not os.path.exists(kh2memaddresses_path): + mem_resp = requests.get("https://raw.githubusercontent.com/JaredWeakStrike/KH2APMemoryValues/master/kh2memaddresses.json") + if mem_resp.status_code == 200: + self.mem_json = json.loads(mem_resp.content) + with open(kh2memaddresses_path, + 'w') as f: + f.write(json.dumps(self.mem_json, indent=4)) + else: + with open(kh2memaddresses_path, 'r') as f: + self.mem_json = json.load(f) + if self.mem_json: + for key in self.mem_json.keys(): + + if self.kh2_read_string(int(self.mem_json[key]["GameVersionCheck"], 0), 4) == "KH2J": + self.Now = int(self.mem_json[key]["Now"], 0) + self.Save = int(self.mem_json[key]["Save"], 0) + self.Slot1 = int(self.mem_json[key]["Slot1"], 0) + self.Journal = int(self.mem_json[key]["Journal"], 0) + self.Shop = int(self.mem_json[key]["Shop"], 0) + self.kh2_game_version = key + + if self.kh2_game_version is not None: + logger.info(f"You are now auto-tracking {self.kh2_game_version}") + self.kh2connected = True + else: + logger.info("Your game version does not match what the client requires. Check in the " + "kingdom-hearts-2-final-mix channel for more information on correcting the game " + "version.") + self.kh2connected = False + + +def finishedGame(ctx: KH2Context): if ctx.kh2slotdata['FinalXemnas'] == 1: - if not ctx.final_xemnas and ctx.kh2_read_byte(ctx.Save + all_world_locations[LocationName.FinalXemnas].addrObtained) \ + if not ctx.final_xemnas and ctx.kh2_read_byte( + ctx.Save + all_world_locations[LocationName.FinalXemnas].addrObtained) \ & 0x1 << all_world_locations[LocationName.FinalXemnas].bitIndex > 0: ctx.final_xemnas = True # three proofs @@ -877,10 +887,12 @@ def finishedGame(ctx: KH2Context, message): elif ctx.kh2slotdata['Goal'] == 2: # for backwards compat if "hitlist" in ctx.kh2slotdata: + locations = ctx.sending for boss in ctx.kh2slotdata["hitlist"]: - if boss in message[0]["locations"]: + if boss in locations: ctx.hitlist_bounties += 1 - if ctx.hitlist_bounties >= ctx.kh2slotdata["BountyRequired"] or ctx.kh2_seed_save_cache["AmountInvo"]["Amount"]["Bounty"] >= ctx.kh2slotdata["BountyRequired"]: + if ctx.hitlist_bounties >= ctx.kh2slotdata["BountyRequired"] or ctx.kh2_seed_save_cache["AmountInvo"]["Amount"][ + "Bounty"] >= ctx.kh2slotdata["BountyRequired"]: if ctx.kh2_read_byte(ctx.Save + 0x36B3) < 1: ctx.kh2_write_byte(ctx.Save + 0x36B2, 1) ctx.kh2_write_byte(ctx.Save + 0x36B3, 1) @@ -919,35 +931,19 @@ async def kh2_watcher(ctx: KH2Context): await asyncio.create_task(ctx.verifyChests()) await asyncio.create_task(ctx.verifyItems()) await asyncio.create_task(ctx.verifyLevel()) - message = [{"cmd": 'LocationChecks', "locations": ctx.sending}] - if finishedGame(ctx, message) and not ctx.kh2_finished_game: + if finishedGame(ctx) and not ctx.kh2_finished_game: await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) ctx.kh2_finished_game = True - await ctx.send_msgs(message) + if ctx.sending: + message = [{"cmd": 'LocationChecks', "locations": ctx.sending}] + await ctx.send_msgs(message) elif not ctx.kh2connected and ctx.serverconneced: logger.info("Game Connection lost. waiting 15 seconds until trying to reconnect.") ctx.kh2 = None while not ctx.kh2connected and ctx.serverconneced: await asyncio.sleep(15) ctx.kh2 = pymem.Pymem(process_name="KINGDOM HEARTS II FINAL MIX") - if ctx.kh2 is not None: - if ctx.kh2_game_version is None: - if ctx.kh2_read_string(0x09A9830, 4) == "KH2J": - ctx.kh2_game_version = "STEAM" - ctx.Now = 0x0717008 - ctx.Save = 0x09A9830 - ctx.Slot1 = 0x2A23518 - ctx.Journal = 0x7434E0 - ctx.Shop = 0x7435D0 - - elif ctx.kh2_read_string(0x09A92F0, 4) == "KH2J": - ctx.kh2_game_version = "EGS" - else: - ctx.kh2_game_version = None - logger.info("Your game version is out of date. Please update your game via The Epic Games Store or Steam.") - if ctx.kh2_game_version is not None: - logger.info(f"You are now auto-tracking {ctx.kh2_game_version}") - ctx.kh2connected = True + ctx.get_addresses() except Exception as e: if ctx.kh2connected: ctx.kh2connected = False diff --git a/worlds/kh2/Regions.py b/worlds/kh2/Regions.py index 7fc2ad8a87..72b3c95b09 100644 --- a/worlds/kh2/Regions.py +++ b/worlds/kh2/Regions.py @@ -540,7 +540,7 @@ KH2REGIONS: typing.Dict[str, typing.List[str]] = { LocationName.SephirothFenrir, LocationName.SephiEventLocation ], - RegionName.CoR: [ + RegionName.CoR: [ #todo: make logic for getting these checks. LocationName.CoRDepthsAPBoost, LocationName.CoRDepthsPowerCrystal, LocationName.CoRDepthsFrostCrystal, @@ -1032,99 +1032,99 @@ def connect_regions(self): multiworld = self.multiworld player = self.player # connecting every first visit to the GoA - KH2RegionConnections: typing.Dict[str, typing.Set[str]] = { - "Menu": {RegionName.GoA}, - RegionName.GoA: {RegionName.Sp, RegionName.Pr, RegionName.Tt, RegionName.Oc, RegionName.Ht, + KH2RegionConnections: typing.Dict[str, typing.Tuple[str]] = { + "Menu": (RegionName.GoA,), + RegionName.GoA: (RegionName.Sp, RegionName.Pr, RegionName.Tt, RegionName.Oc, RegionName.Ht, RegionName.LoD, RegionName.Twtnw, RegionName.Bc, RegionName.Ag, RegionName.Pl, RegionName.Hb, RegionName.Dc, RegionName.Stt, RegionName.Ha1, RegionName.Keyblade, RegionName.LevelsVS1, RegionName.Valor, RegionName.Wisdom, RegionName.Limit, RegionName.Master, - RegionName.Final, RegionName.Summon, RegionName.AtlanticaSongOne}, - RegionName.LoD: {RegionName.ShanYu}, - RegionName.ShanYu: {RegionName.LoD2}, - RegionName.LoD2: {RegionName.AnsemRiku}, - RegionName.AnsemRiku: {RegionName.StormRider}, - RegionName.StormRider: {RegionName.DataXigbar}, - RegionName.Ag: {RegionName.TwinLords}, - RegionName.TwinLords: {RegionName.Ag2}, - RegionName.Ag2: {RegionName.GenieJafar}, - RegionName.GenieJafar: {RegionName.DataLexaeus}, - RegionName.Dc: {RegionName.Tr}, - RegionName.Tr: {RegionName.OldPete}, - RegionName.OldPete: {RegionName.FuturePete}, - RegionName.FuturePete: {RegionName.Terra, RegionName.DataMarluxia}, - RegionName.Ha1: {RegionName.Ha2}, - RegionName.Ha2: {RegionName.Ha3}, - RegionName.Ha3: {RegionName.Ha4}, - RegionName.Ha4: {RegionName.Ha5}, - RegionName.Ha5: {RegionName.Ha6}, - RegionName.Pr: {RegionName.Barbosa}, - RegionName.Barbosa: {RegionName.Pr2}, - RegionName.Pr2: {RegionName.GrimReaper1}, - RegionName.GrimReaper1: {RegionName.GrimReaper2}, - RegionName.GrimReaper2: {RegionName.DataLuxord}, - RegionName.Oc: {RegionName.Cerberus}, - RegionName.Cerberus: {RegionName.OlympusPete}, - RegionName.OlympusPete: {RegionName.Hydra}, - RegionName.Hydra: {RegionName.OcPainAndPanicCup, RegionName.OcCerberusCup, RegionName.Oc2}, - RegionName.Oc2: {RegionName.Hades}, - RegionName.Hades: {RegionName.Oc2TitanCup, RegionName.Oc2GofCup, RegionName.DataZexion}, - RegionName.Oc2GofCup: {RegionName.HadesCups}, - RegionName.Bc: {RegionName.Thresholder}, - RegionName.Thresholder: {RegionName.Beast}, - RegionName.Beast: {RegionName.DarkThorn}, - RegionName.DarkThorn: {RegionName.Bc2}, - RegionName.Bc2: {RegionName.Xaldin}, - RegionName.Xaldin: {RegionName.DataXaldin}, - RegionName.Sp: {RegionName.HostileProgram}, - RegionName.HostileProgram: {RegionName.Sp2}, - RegionName.Sp2: {RegionName.Mcp}, - RegionName.Mcp: {RegionName.DataLarxene}, - RegionName.Ht: {RegionName.PrisonKeeper}, - RegionName.PrisonKeeper: {RegionName.OogieBoogie}, - RegionName.OogieBoogie: {RegionName.Ht2}, - RegionName.Ht2: {RegionName.Experiment}, - RegionName.Experiment: {RegionName.DataVexen}, - RegionName.Hb: {RegionName.Hb2}, - RegionName.Hb2: {RegionName.CoR, RegionName.HBDemyx}, - RegionName.HBDemyx: {RegionName.ThousandHeartless}, - RegionName.ThousandHeartless: {RegionName.Mushroom13, RegionName.DataDemyx, RegionName.Sephi}, - RegionName.CoR: {RegionName.CorFirstFight}, - RegionName.CorFirstFight: {RegionName.CorSecondFight}, - RegionName.CorSecondFight: {RegionName.Transport}, - RegionName.Pl: {RegionName.Scar}, - RegionName.Scar: {RegionName.Pl2}, - RegionName.Pl2: {RegionName.GroundShaker}, - RegionName.GroundShaker: {RegionName.DataSaix}, - RegionName.Stt: {RegionName.TwilightThorn}, - RegionName.TwilightThorn: {RegionName.Axel1}, - RegionName.Axel1: {RegionName.Axel2}, - RegionName.Axel2: {RegionName.DataRoxas}, - RegionName.Tt: {RegionName.Tt2}, - RegionName.Tt2: {RegionName.Tt3}, - RegionName.Tt3: {RegionName.DataAxel}, - RegionName.Twtnw: {RegionName.Roxas}, - RegionName.Roxas: {RegionName.Xigbar}, - RegionName.Xigbar: {RegionName.Luxord}, - RegionName.Luxord: {RegionName.Saix}, - RegionName.Saix: {RegionName.Twtnw2}, - RegionName.Twtnw2: {RegionName.Xemnas}, - RegionName.Xemnas: {RegionName.ArmoredXemnas, RegionName.DataXemnas}, - RegionName.ArmoredXemnas: {RegionName.ArmoredXemnas2}, - RegionName.ArmoredXemnas2: {RegionName.FinalXemnas}, - RegionName.LevelsVS1: {RegionName.LevelsVS3}, - RegionName.LevelsVS3: {RegionName.LevelsVS6}, - RegionName.LevelsVS6: {RegionName.LevelsVS9}, - RegionName.LevelsVS9: {RegionName.LevelsVS12}, - RegionName.LevelsVS12: {RegionName.LevelsVS15}, - RegionName.LevelsVS15: {RegionName.LevelsVS18}, - RegionName.LevelsVS18: {RegionName.LevelsVS21}, - RegionName.LevelsVS21: {RegionName.LevelsVS24}, - RegionName.LevelsVS24: {RegionName.LevelsVS26}, - RegionName.AtlanticaSongOne: {RegionName.AtlanticaSongTwo}, - RegionName.AtlanticaSongTwo: {RegionName.AtlanticaSongThree}, - RegionName.AtlanticaSongThree: {RegionName.AtlanticaSongFour}, + RegionName.Final, RegionName.Summon, RegionName.AtlanticaSongOne), + RegionName.LoD: (RegionName.ShanYu,), + RegionName.ShanYu: (RegionName.LoD2,), + RegionName.LoD2: (RegionName.AnsemRiku,), + RegionName.AnsemRiku: (RegionName.StormRider,), + RegionName.StormRider: (RegionName.DataXigbar,), + RegionName.Ag: (RegionName.TwinLords,), + RegionName.TwinLords: (RegionName.Ag2,), + RegionName.Ag2: (RegionName.GenieJafar,), + RegionName.GenieJafar: (RegionName.DataLexaeus,), + RegionName.Dc: (RegionName.Tr,), + RegionName.Tr: (RegionName.OldPete,), + RegionName.OldPete: (RegionName.FuturePete,), + RegionName.FuturePete: (RegionName.Terra, RegionName.DataMarluxia), + RegionName.Ha1: (RegionName.Ha2,), + RegionName.Ha2: (RegionName.Ha3,), + RegionName.Ha3: (RegionName.Ha4,), + RegionName.Ha4: (RegionName.Ha5,), + RegionName.Ha5: (RegionName.Ha6,), + RegionName.Pr: (RegionName.Barbosa,), + RegionName.Barbosa: (RegionName.Pr2,), + RegionName.Pr2: (RegionName.GrimReaper1,), + RegionName.GrimReaper1: (RegionName.GrimReaper2,), + RegionName.GrimReaper2: (RegionName.DataLuxord,), + RegionName.Oc: (RegionName.Cerberus,), + RegionName.Cerberus: (RegionName.OlympusPete,), + RegionName.OlympusPete: (RegionName.Hydra,), + RegionName.Hydra: (RegionName.OcPainAndPanicCup, RegionName.OcCerberusCup, RegionName.Oc2), + RegionName.Oc2: (RegionName.Hades,), + RegionName.Hades: (RegionName.Oc2TitanCup, RegionName.Oc2GofCup, RegionName.DataZexion), + RegionName.Oc2GofCup: (RegionName.HadesCups,), + RegionName.Bc: (RegionName.Thresholder,), + RegionName.Thresholder: (RegionName.Beast,), + RegionName.Beast: (RegionName.DarkThorn,), + RegionName.DarkThorn: (RegionName.Bc2,), + RegionName.Bc2: (RegionName.Xaldin,), + RegionName.Xaldin: (RegionName.DataXaldin,), + RegionName.Sp: (RegionName.HostileProgram,), + RegionName.HostileProgram: (RegionName.Sp2,), + RegionName.Sp2: (RegionName.Mcp,), + RegionName.Mcp: (RegionName.DataLarxene,), + RegionName.Ht: (RegionName.PrisonKeeper,), + RegionName.PrisonKeeper: (RegionName.OogieBoogie,), + RegionName.OogieBoogie: (RegionName.Ht2,), + RegionName.Ht2: (RegionName.Experiment,), + RegionName.Experiment: (RegionName.DataVexen,), + RegionName.Hb: (RegionName.Hb2,), + RegionName.Hb2: (RegionName.CoR, RegionName.HBDemyx), + RegionName.HBDemyx: (RegionName.ThousandHeartless,), + RegionName.ThousandHeartless: (RegionName.Mushroom13, RegionName.DataDemyx, RegionName.Sephi), + RegionName.CoR: (RegionName.CorFirstFight,), + RegionName.CorFirstFight: (RegionName.CorSecondFight,), + RegionName.CorSecondFight: (RegionName.Transport,), + RegionName.Pl: (RegionName.Scar,), + RegionName.Scar: (RegionName.Pl2,), + RegionName.Pl2: (RegionName.GroundShaker,), + RegionName.GroundShaker: (RegionName.DataSaix,), + RegionName.Stt: (RegionName.TwilightThorn,), + RegionName.TwilightThorn: (RegionName.Axel1,), + RegionName.Axel1: (RegionName.Axel2,), + RegionName.Axel2: (RegionName.DataRoxas,), + RegionName.Tt: (RegionName.Tt2,), + RegionName.Tt2: (RegionName.Tt3,), + RegionName.Tt3: (RegionName.DataAxel,), + RegionName.Twtnw: (RegionName.Roxas,), + RegionName.Roxas: (RegionName.Xigbar,), + RegionName.Xigbar: (RegionName.Luxord,), + RegionName.Luxord: (RegionName.Saix,), + RegionName.Saix: (RegionName.Twtnw2,), + RegionName.Twtnw2: (RegionName.Xemnas,), + RegionName.Xemnas: (RegionName.ArmoredXemnas, RegionName.DataXemnas), + RegionName.ArmoredXemnas: (RegionName.ArmoredXemnas2,), + RegionName.ArmoredXemnas2: (RegionName.FinalXemnas,), + RegionName.LevelsVS1: (RegionName.LevelsVS3,), + RegionName.LevelsVS3: (RegionName.LevelsVS6,), + RegionName.LevelsVS6: (RegionName.LevelsVS9,), + RegionName.LevelsVS9: (RegionName.LevelsVS12,), + RegionName.LevelsVS12: (RegionName.LevelsVS15,), + RegionName.LevelsVS15: (RegionName.LevelsVS18,), + RegionName.LevelsVS18: (RegionName.LevelsVS21,), + RegionName.LevelsVS21: (RegionName.LevelsVS24,), + RegionName.LevelsVS24: (RegionName.LevelsVS26,), + RegionName.AtlanticaSongOne: (RegionName.AtlanticaSongTwo,), + RegionName.AtlanticaSongTwo: (RegionName.AtlanticaSongThree,), + RegionName.AtlanticaSongThree: (RegionName.AtlanticaSongFour,), } for source, target in KH2RegionConnections.items(): diff --git a/worlds/kh2/Rules.py b/worlds/kh2/Rules.py index 0f26b56d0e..a59fbfd8ab 100644 --- a/worlds/kh2/Rules.py +++ b/worlds/kh2/Rules.py @@ -194,8 +194,8 @@ class KH2WorldRules(KH2Rules): RegionName.Oc: lambda state: self.oc_unlocked(state, 1), RegionName.Oc2: lambda state: self.oc_unlocked(state, 2), + #twtnw1 is actually the roxas fight region thus roxas requires 1 way to the dawn RegionName.Twtnw2: lambda state: self.twtnw_unlocked(state, 2), - # These will be swapped and First Visit lock for twtnw is in development. # RegionName.Twtnw1: lambda state: self.lod_unlocked(state, 2), RegionName.Ht: lambda state: self.ht_unlocked(state, 1), @@ -263,7 +263,10 @@ class KH2WorldRules(KH2Rules): weapon_region = self.multiworld.get_region(RegionName.Keyblade, self.player) for location in weapon_region.locations: - add_rule(location, lambda state: state.has(exclusion_table["WeaponSlots"][location.name], self.player)) + if location.name in exclusion_table["WeaponSlots"]: # shop items and starting items are not in this list + exclusion_item = exclusion_table["WeaponSlots"][location.name] + add_rule(location, lambda state, e_item=exclusion_item: state.has(e_item, self.player)) + if location.name in Goofy_Checks: add_item_rule(location, lambda item: item.player == self.player and item.name in GoofyAbility_Table.keys()) elif location.name in Donald_Checks: @@ -919,8 +922,8 @@ class KH2FightRules(KH2Rules): # normal:both gap closers,limit 5,reflera,guard,both 2 ground finishers,3 dodge roll,finishing plus # hard:1 gap closers,reflect, guard,both 1 ground finisher,2 dodge roll,finishing plus sephiroth_rules = { - "easy": self.kh2_dict_count(easy_sephiroth_tools, state) and self.kh2_can_reach(LocationName.Limitlvl5, state) and self.kh2_list_any_sum([donald_limit], state) >= 1, - "normal": self.kh2_dict_count(normal_sephiroth_tools, state) and self.kh2_can_reach(LocationName.Limitlvl5, state) and self.kh2_list_any_sum([donald_limit, gap_closer], state) >= 2, + "easy": self.kh2_dict_count(easy_sephiroth_tools, state) and self.kh2_can_reach(LocationName.Limitlvl5, state), + "normal": self.kh2_dict_count(normal_sephiroth_tools, state) and self.kh2_can_reach(LocationName.Limitlvl5, state) and self.kh2_list_any_sum([gap_closer], state) >= 1, "hard": self.kh2_dict_count(hard_sephiroth_tools, state) and self.kh2_list_any_sum([gap_closer, ground_finisher], state) >= 2, } return sephiroth_rules[self.fight_logic] diff --git a/worlds/kh2/__init__.py b/worlds/kh2/__init__.py index 59c77627ee..edc4305acc 100644 --- a/worlds/kh2/__init__.py +++ b/worlds/kh2/__init__.py @@ -3,7 +3,7 @@ from typing import List from BaseClasses import Tutorial, ItemClassification from Fill import fast_fill -from worlds.LauncherComponents import Component, components, Type, launch_subprocess +from worlds.LauncherComponents import Component, components, Type, launch as launch_component from worlds.AutoWorld import World, WebWorld from .Items import * from .Locations import * @@ -17,7 +17,7 @@ from .Subclasses import KH2Item def launch_client(): from .Client import launch - launch_subprocess(launch, name="KH2Client") + launch_component(launch, name="KH2Client") components.append(Component("KH2 Client", "KH2Client", func=launch_client, component_type=Type.CLIENT)) diff --git a/worlds/kh2/docs/setup_en.md b/worlds/kh2/docs/setup_en.md index cb80ec6098..2e1022f3ef 100644 --- a/worlds/kh2/docs/setup_en.md +++ b/worlds/kh2/docs/setup_en.md @@ -10,7 +10,7 @@ Kingdom Hearts II Final Mix from the [Epic Games Store](https://store.epicgames.com/en-US/discover/kingdom-hearts) or [Steam](https://store.steampowered.com/app/2552430/KINGDOM_HEARTS_HD_1525_ReMIX/) - Follow this Guide to set up these requirements [KH2Rando.com](https://tommadness.github.io/KH2Randomizer/setup/Panacea-ModLoader/) - 1. Version 3.4.0 or greater OpenKH Mod Manager with Panacea + 1. Version 25.01.26.0 or greater OpenKH Mod Manager with Panacea 2. Lua Backend from the OpenKH Mod Manager 3. Install the mod `KH2FM-Mods-Num/GoA-ROM-Edition` using OpenKH Mod Manager - Needed for Archipelago @@ -52,7 +52,7 @@ After Installing the seed click "Mod Loader -> Build/Build and Run". Every slot

What the Mod Manager Should Look Like.

-![image](https://i.imgur.com/Si4oZ8w.png) +![image](https://i.imgur.com/N0WJ8Qn.png)

Using the KH2 Client

diff --git a/worlds/ladx/LADXR/generator.py b/worlds/ladx/LADXR/generator.py index d017621eb0..da5812e1ef 100644 --- a/worlds/ladx/LADXR/generator.py +++ b/worlds/ladx/LADXR/generator.py @@ -103,6 +103,7 @@ def generateRom(args, world: "LinksAwakeningWorld"): assembler.const("wGoldenLeaves", 0xDB42) # New memory location where to store the golden leaf counter assembler.const("wCollectedTunics", 0xDB6D) # Memory location where to store which tunic options are available (and boots) assembler.const("wCustomMessage", 0xC0A0) + assembler.const("wOverworldRoomStatus", 0xD800) # We store the link info in unused color dungeon flags, so it gets preserved in the savegame. assembler.const("wLinkSyncSequenceNumber", 0xDDF6) diff --git a/worlds/ladx/LADXR/itempool.py b/worlds/ladx/LADXR/itempool.py index 5031488337..68f3e54ecb 100644 --- a/worlds/ladx/LADXR/itempool.py +++ b/worlds/ladx/LADXR/itempool.py @@ -68,10 +68,12 @@ DEFAULT_ITEM_POOL = { class ItemPool: - def __init__(self, logic, settings, rnd): + def __init__(self, logic, settings, rnd, stabilize_item_pool: bool): self.__pool = {} self.__setup(logic, settings) - self.__randomizeRupees(settings, rnd) + + if not stabilize_item_pool: + self.__randomizeRupees(settings, rnd) def add(self, item, count=1): self.__pool[item] = self.__pool.get(item, 0) + count diff --git a/worlds/ladx/LADXR/locations/itemInfo.py b/worlds/ladx/LADXR/locations/itemInfo.py index dcd4205f4c..cd0f355149 100644 --- a/worlds/ladx/LADXR/locations/itemInfo.py +++ b/worlds/ladx/LADXR/locations/itemInfo.py @@ -2,6 +2,10 @@ import typing from ..checkMetadata import checkMetadataTable from .constants import * +custom_name_replacements = { + '"':"'", + '_':' ', +} class ItemInfo: MULTIWORLD = True @@ -23,6 +27,11 @@ class ItemInfo: def setLocation(self, location): self._location = location + def setCustomItemName(self, name): + for key, val in custom_name_replacements.items(): + name = name.replace(key, val) + self.custom_item_name = name + def getOptions(self): return self.OPTIONS diff --git a/worlds/ladx/LADXR/logic/overworld.py b/worlds/ladx/LADXR/logic/overworld.py index ed8fab3cc8..86e076fabe 100644 --- a/worlds/ladx/LADXR/logic/overworld.py +++ b/worlds/ladx/LADXR/logic/overworld.py @@ -11,7 +11,7 @@ class World: mabe_village = Location("Mabe Village") Location().add(HeartPiece(0x2A4)).connect(mabe_village, r.bush) # well - Location().add(FishingMinigame()).connect(mabe_village, AND(r.bush, COUNT("RUPEES", 20))) # fishing game, heart piece is directly done by the minigame. + Location().add(FishingMinigame()).connect(mabe_village, AND(r.can_farm, COUNT("RUPEES", 20))) # fishing game, heart piece is directly done by the minigame. Location().add(Seashell(0x0A3)).connect(mabe_village, r.bush) # bushes below the shop Location().add(Seashell(0x0D2)).connect(mabe_village, PEGASUS_BOOTS) # smash into tree next to lv1 Location().add(Song(0x092)).connect(mabe_village, OCARINA) # Marins song @@ -23,7 +23,7 @@ class World: papahl_house.connect(mamasha_trade, TRADING_ITEM_YOSHI_DOLL) trendy_shop = Location("Trendy Shop") - trendy_shop.connect(Location().add(TradeSequenceItem(0x2A0, TRADING_ITEM_YOSHI_DOLL)), FOUND("RUPEES", 50)) + trendy_shop.connect(Location().add(TradeSequenceItem(0x2A0, TRADING_ITEM_YOSHI_DOLL)), AND(r.can_farm, FOUND("RUPEES", 50))) outside_trendy = Location() outside_trendy.connect(mabe_village, r.bush) @@ -44,8 +44,8 @@ class World: shop = Location("Shop") if options.steal == "inlogic": - Location().add(ShopItem(0)).connect(shop, OR(COUNT("RUPEES", 500), SWORD)) - Location().add(ShopItem(1)).connect(shop, OR(COUNT("RUPEES", 1480), SWORD)) + Location().add(ShopItem(0)).connect(shop, OR(AND(r.can_farm, COUNT("RUPEES", 500)), SWORD)) + Location().add(ShopItem(1)).connect(shop, OR(AND(r.can_farm, COUNT("RUPEES", 1480)), SWORD)) else: Location().add(ShopItem(0)).connect(shop, COUNT("RUPEES", 500)) Location().add(ShopItem(1)).connect(shop, COUNT("RUPEES", 1480)) @@ -168,7 +168,7 @@ class World: self._addEntrance("prairie_left_cave2", ukuku_prairie, prairie_left_cave2, BOMB) self._addEntranceRequirementExit("prairie_left_cave2", None) # if exiting, you do not need bombs - mamu = Location().connect(Location().add(Song(0x2FB)), AND(OCARINA, COUNT("RUPEES", 1480))) + mamu = Location().connect(Location().add(Song(0x2FB)), AND(OCARINA, r.can_farm, COUNT("RUPEES", 1480))) self._addEntrance("mamu", ukuku_prairie, mamu, AND(OR(AND(FEATHER, PEGASUS_BOOTS), ROOSTER), OR(HOOKSHOT, ROOSTER), POWER_BRACELET)) dungeon3_entrance = Location().connect(ukuku_prairie, OR(FEATHER, ROOSTER, FLIPPERS)) @@ -381,7 +381,7 @@ class World: # Raft game. raft_house = Location("Raft House") - Location().add(KeyLocation("RAFT")).connect(raft_house, AND(r.bush, COUNT("RUPEES", 100))) # add bush requirement for farming in case player has to try again + Location().add(KeyLocation("RAFT")).connect(raft_house, AND(r.can_farm, COUNT("RUPEES", 100))) raft_return_upper = Location() raft_return_lower = Location().connect(raft_return_upper, None, one_way=True) outside_raft_house = Location().connect(below_right_taltal, HOOKSHOT).connect(below_right_taltal, FLIPPERS, one_way=True) diff --git a/worlds/ladx/LADXR/logic/requirements.py b/worlds/ladx/LADXR/logic/requirements.py index fa01627a15..8d637ecfe9 100644 --- a/worlds/ladx/LADXR/logic/requirements.py +++ b/worlds/ladx/LADXR/logic/requirements.py @@ -253,7 +253,8 @@ def isConsumable(item) -> bool: class RequirementsSettings: def __init__(self, options): - self.bush = OR(SWORD, MAGIC_POWDER, MAGIC_ROD, POWER_BRACELET, BOOMERANG) + self.can_farm = OR(SWORD, MAGIC_POWDER, MAGIC_ROD, BOOMERANG, BOMB, HOOKSHOT, BOW) + self.bush = OR(SWORD, MAGIC_POWDER, MAGIC_ROD, POWER_BRACELET, BOOMERANG, BOMB) self.pit_bush = OR(SWORD, MAGIC_POWDER, MAGIC_ROD, BOOMERANG, BOMB) # unique self.attack = OR(SWORD, BOMB, BOW, MAGIC_ROD, BOOMERANG) self.attack_hookshot = OR(SWORD, BOMB, BOW, MAGIC_ROD, BOOMERANG, HOOKSHOT) # hinox, shrouded stalfos diff --git a/worlds/ladx/LADXR/patches/core.py b/worlds/ladx/LADXR/patches/core.py index f4752c82e3..d9fcd62e30 100644 --- a/worlds/ladx/LADXR/patches/core.py +++ b/worlds/ladx/LADXR/patches/core.py @@ -716,9 +716,7 @@ def addWarpImprovements(rom, extra_warps): # Allow cursor to move over black squares # This allows warping to undiscovered areas - a fine cheat, but needs a check for wOverworldRoomStatus in the warp code - CHEAT_WARP_ANYWHERE = False - if CHEAT_WARP_ANYWHERE: - rom.patch(0x01, 0x1AE8, None, ASM("jp $5AF5")) + rom.patch(0x01, 0x1AE8, None, ASM("jp $5AF5")) # This disables the arrows around the selection bubble #rom.patch(0x01, 0x1B6F, None, ASM("ret"), fill_nop=True) @@ -797,8 +795,14 @@ def addWarpImprovements(rom, extra_warps): TeleportHandler: ld a, [$DBB4] ; Load the current selected tile - ; TODO: check if actually revealed so we can have free movement - ; Check cursor against different tiles to see if we are selecting a warp + ld hl, wOverworldRoomStatus + ld e, a ; $5D38: $5F + ld d, $00 ; $5D39: $16 $00 + add hl, de ; $5D3B: $19 + ld a, [hl] + and $80 + jr z, exit + ld a, [$DBB4] ; Load the current selected tile {warp_jump} jr exit diff --git a/worlds/ladx/Locations.py b/worlds/ladx/Locations.py index 8670738e08..45fa99adc5 100644 --- a/worlds/ladx/Locations.py +++ b/worlds/ladx/Locations.py @@ -110,15 +110,6 @@ class LinksAwakeningLocation(Location): add_item_rule(self, filter_item) -def has_free_weapon(state: CollectionState, player: int) -> bool: - return state.has("Progressive Sword", player) or state.has("Magic Rod", player) or state.has("Boomerang", player) or state.has("Hookshot", player) - - -# If the player has access to farm enough rupees to afford a game, we assume that they can keep beating the game -def can_farm_rupees(state: CollectionState, player: int) -> bool: - return has_free_weapon(state, player) and (state.has("Can Play Trendy Game", player=player) or state.has("RAFT", player=player)) - - class LinksAwakeningRegion(Region): dungeon_index = None ladxr_region = None @@ -154,9 +145,7 @@ class GameStateAdapater: def get(self, item, default): # Don't allow any money usage if you can't get back wasted rupees if item == "RUPEES": - if can_farm_rupees(self.state, self.player): - return self.state.prog_items[self.player]["RUPEES"] - return 0 + return self.state.prog_items[self.player]["RUPEES"] elif item.endswith("_USED"): return 0 else: diff --git a/worlds/ladx/Options.py b/worlds/ladx/Options.py index 36a769ef8a..0bfe850130 100644 --- a/worlds/ladx/Options.py +++ b/worlds/ladx/Options.py @@ -534,6 +534,13 @@ class InGameHints(DefaultOnToggle): display_name = "In-game Hints" +class StabilizeItemPool(DefaultOffToggle): + """ + By default, rupees in the item pool may be randomly swapped with bombs, arrows, powders, or capacity upgrades. This option disables that swapping, which is useful for plando. + """ + display_name = "Stabilize Item Pool" + + class ForeignItemIcons(Choice): """ Choose how to display foreign items. @@ -570,6 +577,7 @@ ladx_option_groups = [ TrendyGame, InGameHints, NagMessages, + StabilizeItemPool, Quickswap, HardMode, BootsControls @@ -640,6 +648,7 @@ class LinksAwakeningOptions(PerGameCommonOptions): no_flash: NoFlash in_game_hints: InGameHints overworld: Overworld + stabilize_item_pool: StabilizeItemPool warp_improvements: Removed additional_warp_points: Removed diff --git a/worlds/ladx/__init__.py b/worlds/ladx/__init__.py index b8de6da812..a887638e37 100644 --- a/worlds/ladx/__init__.py +++ b/worlds/ladx/__init__.py @@ -9,7 +9,7 @@ import re import bsdiff4 import settings -from BaseClasses import Entrance, Item, ItemClassification, Location, Tutorial, MultiWorld +from BaseClasses import CollectionState, Entrance, Item, ItemClassification, Location, Tutorial, MultiWorld from Fill import fill_restrictive from worlds.AutoWorld import WebWorld, World from .Common import * @@ -138,7 +138,30 @@ class LinksAwakeningWorld(World): world_setup = LADXRWorldSetup() world_setup.randomize(self.ladxr_settings, self.random) self.ladxr_logic = LADXRLogic(configuration_options=self.ladxr_settings, world_setup=world_setup) - self.ladxr_itempool = LADXRItemPool(self.ladxr_logic, self.ladxr_settings, self.random).toDict() + self.ladxr_itempool = LADXRItemPool(self.ladxr_logic, self.ladxr_settings, self.random, bool(self.options.stabilize_item_pool)).toDict() + + + def generate_early(self) -> None: + self.dungeon_item_types = { + } + for dungeon_item_type in ["maps", "compasses", "small_keys", "nightmare_keys", "stone_beaks", "instruments"]: + option_name = "shuffle_" + dungeon_item_type + option: DungeonItemShuffle = getattr(self.options, option_name) + + self.dungeon_item_types[option.ladxr_item] = option.value + + # The color dungeon does not contain an instrument + num_items = 8 if dungeon_item_type == "instruments" else 9 + + # For any and different world, set item rule instead + if option.value == DungeonItemShuffle.option_own_world: + self.options.local_items.value |= { + ladxr_item_to_la_item_name[f"{option.ladxr_item}{i}"] for i in range(1, num_items + 1) + } + elif option.value == DungeonItemShuffle.option_different_world: + self.options.non_local_items.value |= { + ladxr_item_to_la_item_name[f"{option.ladxr_item}{i}"] for i in range(1, num_items + 1) + } def create_regions(self) -> None: # Initialize @@ -185,32 +208,9 @@ class LinksAwakeningWorld(World): def create_items(self) -> None: exclude = [item.name for item in self.multiworld.precollected_items[self.player]] - dungeon_item_types = { - - } - self.prefill_original_dungeon = [ [], [], [], [], [], [], [], [], [] ] self.prefill_own_dungeons = [] self.pre_fill_items = [] - # For any and different world, set item rule instead - - for dungeon_item_type in ["maps", "compasses", "small_keys", "nightmare_keys", "stone_beaks", "instruments"]: - option_name = "shuffle_" + dungeon_item_type - option: DungeonItemShuffle = getattr(self.options, option_name) - - dungeon_item_types[option.ladxr_item] = option.value - - # The color dungeon does not contain an instrument - num_items = 8 if dungeon_item_type == "instruments" else 9 - - if option.value == DungeonItemShuffle.option_own_world: - self.options.local_items.value |= { - ladxr_item_to_la_item_name[f"{option.ladxr_item}{i}"] for i in range(1, num_items + 1) - } - elif option.value == DungeonItemShuffle.option_different_world: - self.options.non_local_items.value |= { - ladxr_item_to_la_item_name[f"{option.ladxr_item}{i}"] for i in range(1, num_items + 1) - } # option_original_dungeon = 0 # option_own_dungeons = 1 # option_own_world = 2 @@ -226,7 +226,7 @@ class LinksAwakeningWorld(World): for _ in range(count): if item_name in exclude: exclude.remove(item_name) # this is destructive. create unique list above - self.multiworld.itempool.append(self.create_item("Nothing")) + self.multiworld.itempool.append(self.create_item(self.get_filler_item_name())) else: item = self.create_item(item_name) @@ -238,7 +238,7 @@ class LinksAwakeningWorld(World): if isinstance(item.item_data, DungeonItemData): item_type = item.item_data.ladxr_id[:-1] - shuffle_type = dungeon_item_types[item_type] + shuffle_type = self.dungeon_item_types[item_type] if item.item_data.dungeon_item_type == DungeonItemType.INSTRUMENT and shuffle_type == ShuffleInstruments.option_vanilla: # Find instrument, lock @@ -315,8 +315,6 @@ class LinksAwakeningWorld(World): # Set up filter rules - # The list of items we will pass to fill_restrictive, contains at first the items that go to all dungeons - all_dungeon_items_to_fill = list(self.prefill_own_dungeons) # set containing the list of all possible dungeon locations for the player all_dungeon_locs = set() @@ -327,9 +325,6 @@ class LinksAwakeningWorld(World): for item in self.prefill_original_dungeon[dungeon_index]: allowed_locations_by_item[item] = locs - # put the items for this dungeon in the list to fill - all_dungeon_items_to_fill.extend(self.prefill_original_dungeon[dungeon_index]) - # ...and gather the list of all dungeon locations all_dungeon_locs |= locs # ...also set the rules for the dungeon @@ -369,16 +364,27 @@ class LinksAwakeningWorld(World): if allowed_locations_by_item[item] is all_dungeon_locs: i += 3 return i + all_dungeon_items_to_fill = self.get_pre_fill_items() all_dungeon_items_to_fill.sort(key=priority) # Set up state - all_state = self.multiworld.get_all_state(use_cache=False) - # Remove dungeon items we are about to put in from the state so that we don't double count - for item in all_dungeon_items_to_fill: - all_state.remove(item) + partial_all_state = CollectionState(self.multiworld) + # Collect every item from the item pool and every pre-fill item like MultiWorld.get_all_state, except not our own pre-fill items. + for item in self.multiworld.itempool: + partial_all_state.collect(item, prevent_sweep=True) + for player in self.multiworld.player_ids: + if player == self.player: + # Don't collect the items we're about to place. + continue + subworld = self.multiworld.worlds[player] + for item in subworld.get_pre_fill_items(): + partial_all_state.collect(item, prevent_sweep=True) + + # Sweep to pick up already placed items that are reachable with everything but the dungeon items. + partial_all_state.sweep_for_advancements() - # Finally, fill! - fill_restrictive(self.multiworld, all_state, all_dungeon_locs_to_fill, all_dungeon_items_to_fill, lock=True, single_player_placement=True, allow_partial=False) + fill_restrictive(self.multiworld, partial_all_state, all_dungeon_locs_to_fill, all_dungeon_items_to_fill, lock=True, single_player_placement=True, allow_partial=False) + name_cache = {} # Tries to associate an icon from another game with an icon we have @@ -439,7 +445,7 @@ class LinksAwakeningWorld(World): # Otherwise, use a cute letter as the icon elif self.options.foreign_item_icons == 'guess_by_name': loc.ladxr_item.item = self.guess_icon_for_other_world(loc.item) - loc.ladxr_item.custom_item_name = loc.item.name + loc.ladxr_item.setCustomItemName(loc.item.name) else: if loc.item.advancement: @@ -500,8 +506,14 @@ class LinksAwakeningWorld(World): state.prog_items[self.player]["RUPEES"] -= self.rupees[item.name] return change + # Same fill choices and weights used in LADXR.itempool.__randomizeRupees + filler_choices = ("Bomb", "Single Arrow", "10 Arrows", "Magic Powder", "Medicine") + filler_weights = ( 10, 5, 10, 10, 1) + def get_filler_item_name(self) -> str: - return "Nothing" + if self.options.stabilize_item_pool: + return "Nothing" + return self.random.choices(self.filler_choices, self.filler_weights)[0] def fill_slot_data(self): slot_data = {} diff --git a/worlds/lingo/__init__.py b/worlds/lingo/__init__.py index 2a61a71f5f..141fca0743 100644 --- a/worlds/lingo/__init__.py +++ b/worlds/lingo/__init__.py @@ -128,6 +128,9 @@ class LingoWorld(World): pool.append(self.create_item("Puzzle Skip")) if traps: + if self.options.speed_boost_mode: + self.options.trap_weights.value["Slowness Trap"] = 0 + total_weight = sum(self.options.trap_weights.values()) if total_weight == 0: @@ -171,7 +174,7 @@ class LingoWorld(World): "death_link", "victory_condition", "shuffle_colors", "shuffle_doors", "shuffle_paintings", "shuffle_panels", "enable_pilgrimage", "sunwarp_access", "mastery_achievements", "level_2_requirement", "location_checks", "early_color_hallways", "pilgrimage_allows_roof_access", "pilgrimage_allows_paintings", "shuffle_sunwarps", - "group_doors" + "group_doors", "speed_boost_mode" ] slot_data = { @@ -188,5 +191,8 @@ class LingoWorld(World): return slot_data def get_filler_item_name(self) -> str: - filler_list = [":)", "The Feeling of Being Lost", "Wanderlust", "Empty White Hallways"] - return self.random.choice(filler_list) + if self.options.speed_boost_mode: + return "Speed Boost" + else: + filler_list = [":)", "The Feeling of Being Lost", "Wanderlust", "Empty White Hallways"] + return self.random.choice(filler_list) diff --git a/worlds/lingo/data/generated.dat b/worlds/lingo/data/generated.dat index 8b159d4ae4ac7c565e2372b1cc43d7a349b2ca7c..646ce3b5d7430dad51aa01a3a3f0e73b62106884 100644 GIT binary patch delta 2672 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 diff --git a/worlds/lingo/data/ids.yaml b/worlds/lingo/data/ids.yaml index 13b77145ea..0a43592d3f 100644 --- a/worlds/lingo/data/ids.yaml +++ b/worlds/lingo/data/ids.yaml @@ -17,6 +17,7 @@ special_items: Iceland Trap: 444411 Atbash Trap: 444412 Puzzle Skip: 444413 + Speed Boost: 444680 panels: Starting Room: HI: 444400 diff --git a/worlds/lingo/items.py b/worlds/lingo/items.py index 78b288e7c2..7e75cc76c7 100644 --- a/worlds/lingo/items.py +++ b/worlds/lingo/items.py @@ -85,6 +85,7 @@ def load_item_data(): "The Feeling of Being Lost": ItemClassification.filler, "Wanderlust": ItemClassification.filler, "Empty White Hallways": ItemClassification.filler, + "Speed Boost": ItemClassification.filler, **{trap_name: ItemClassification.trap for trap_name in TRAP_ITEMS}, "Puzzle Skip": ItemClassification.useful, } diff --git a/worlds/lingo/options.py b/worlds/lingo/options.py index 2d6e9967df..f9d04f68fc 100644 --- a/worlds/lingo/options.py +++ b/worlds/lingo/options.py @@ -232,6 +232,14 @@ class TrapWeights(OptionDict): default = {trap_name: 1 for trap_name in TRAP_ITEMS} +class SpeedBoostMode(Toggle): + """ + If on, the player's default speed is halved, as if affected by a Slowness Trap. Speed Boosts are added to + the item pool, which temporarily return the player to normal speed. Slowness Traps are removed from the pool. + """ + display_name = "Speed Boost Mode" + + class PuzzleSkipPercentage(Range): """Replaces junk items with puzzle skips, at the specified rate.""" display_name = "Puzzle Skip Percentage" @@ -260,6 +268,7 @@ lingo_option_groups = [ Level2Requirement, TrapPercentage, TrapWeights, + SpeedBoostMode, PuzzleSkipPercentage, ]) ] @@ -287,6 +296,7 @@ class LingoOptions(PerGameCommonOptions): shuffle_postgame: ShufflePostgame trap_percentage: TrapPercentage trap_weights: TrapWeights + speed_boost_mode: SpeedBoostMode puzzle_skip_percentage: PuzzleSkipPercentage death_link: DeathLink start_inventory_from_pool: StartInventoryPool diff --git a/worlds/lingo/test/TestOptions.py b/worlds/lingo/test/TestOptions.py index bd8ed81d7a..224dbe0f75 100644 --- a/worlds/lingo/test/TestOptions.py +++ b/worlds/lingo/test/TestOptions.py @@ -59,4 +59,11 @@ class TestShuffleSunwarpsAccess(LingoTestBase): "victory_condition": "pilgrimage", "shuffle_sunwarps": "true", "sunwarp_access": "individual" - } \ No newline at end of file + } + + +class TestSpeedBoostMode(LingoTestBase): + options = { + "location_checks": "insanity", + "speed_boost_mode": "true", + } diff --git a/worlds/lingo/utils/assign_ids.rb b/worlds/lingo/utils/assign_ids.rb index f7de3d03f5..bcb8018ebc 100644 --- a/worlds/lingo/utils/assign_ids.rb +++ b/worlds/lingo/utils/assign_ids.rb @@ -216,3 +216,6 @@ config.each do |room_name, room_data| end File.write(outputpath, old_generated.to_yaml) + +puts "Next item ID: #{next_item_id}" +puts "Next location ID: #{next_location_id}" diff --git a/worlds/meritous/__init__.py b/worlds/meritous/__init__.py index 7a21b19ef2..2263478ff5 100644 --- a/worlds/meritous/__init__.py +++ b/worlds/meritous/__init__.py @@ -136,6 +136,12 @@ class MeritousWorld(World): def set_rules(self): set_rules(self.multiworld, self.player) + if self.goal == 0: + self.multiworld.completion_condition[self.player] = lambda state: state.has_any( + ["Victory", "Full Victory"], self.player) + else: + self.multiworld.completion_condition[self.player] = lambda state: state.has( + "Full Victory", self.player) def generate_basic(self): self.multiworld.get_location("Place of Power", self.player).place_locked_item( @@ -166,13 +172,6 @@ class MeritousWorld(World): self.multiworld.get_location(boss, self.player).place_locked_item( self.create_item("Evolution Trap")) - if self.goal == 0: - self.multiworld.completion_condition[self.player] = lambda state: state.has_any( - ["Victory", "Full Victory"], self.player) - else: - self.multiworld.completion_condition[self.player] = lambda state: state.has( - "Full Victory", self.player) - def fill_slot_data(self) -> dict: return { "goal": self.goal, diff --git a/worlds/mm2/client.py b/worlds/mm2/client.py index aaa0813c76..96c477757d 100644 --- a/worlds/mm2/client.py +++ b/worlds/mm2/client.py @@ -214,10 +214,19 @@ class MegaMan2Client(BizHawkClient): last_wily: Optional[int] = None # default to wily 1 async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: - from worlds._bizhawk import RequestFailedError, read + from worlds._bizhawk import RequestFailedError, read, get_memory_size from . import MM2World try: + if (await get_memory_size(ctx.bizhawk_ctx, "PRG ROM")) < 0x3FFB0: + if "pool" in ctx.command_processor.commands: + ctx.command_processor.commands.pop("pool") + if "request" in ctx.command_processor.commands: + ctx.command_processor.commands.pop("request") + if "autoheal" in ctx.command_processor.commands: + ctx.command_processor.commands.pop("autoheal") + return False + game_name, version = (await read(ctx.bizhawk_ctx, [(0x3FFB0, 21, "PRG ROM"), (0x3FFC8, 3, "PRG ROM")])) if game_name[:3] != b"MM2" or version != bytes(MM2World.world_version): diff --git a/worlds/mm2/options.py b/worlds/mm2/options.py index 2d90395cac..f333348982 100644 --- a/worlds/mm2/options.py +++ b/worlds/mm2/options.py @@ -175,7 +175,7 @@ class WeaknessPlando(OptionDict): display_name = "Plando Weaknesses" schema = Schema({ Optional(And(str, Use(str.title), lambda s: s in bosses)): { - And(str, Use(str.title), lambda s: s in weapons_to_id): And(int, lambda i: i in range(-1, 14)) + And(str, Use(str.title), lambda s: s in weapons_to_id): And(int, lambda i: i in range(-1, 15)) } }) default = {} diff --git a/worlds/mm2/rules.py b/worlds/mm2/rules.py index 7e2ce1f3c7..7e03edf3a2 100644 --- a/worlds/mm2/rules.py +++ b/worlds/mm2/rules.py @@ -135,41 +135,47 @@ def set_rules(world: "MM2World") -> None: world.weapon_damage[weapon][i] = 0 for p_boss in world.options.plando_weakness: + boss = bosses[p_boss] for p_weapon in world.options.plando_weakness[p_boss]: - if world.options.plando_weakness[p_boss][p_weapon] < minimum_weakness_requirement[p_weapon] \ - and not any(w != p_weapon - and world.weapon_damage[w][bosses[p_boss]] > minimum_weakness_requirement[w] - for w in world.weapon_damage): + weapon = weapons_to_id[p_weapon] + if world.options.plando_weakness[p_boss][p_weapon] < minimum_weakness_requirement[weapon] \ + and not any(w != weapon + and world.weapon_damage[w][boss] >= minimum_weakness_requirement[w] + for w in world.weapon_damage): # we need to replace this weakness - weakness = world.random.choice([key for key in world.weapon_damage if key != p_weapon]) - world.weapon_damage[weakness][bosses[p_boss]] = minimum_weakness_requirement[weakness] - world.weapon_damage[weapons_to_id[p_weapon]][bosses[p_boss]] \ - = world.options.plando_weakness[p_boss][p_weapon] + weakness = world.random.choice([key for key in world.weapon_damage if key != weapon]) + world.weapon_damage[weakness][boss] = minimum_weakness_requirement[weakness] + world.weapon_damage[weapon][boss] = world.options.plando_weakness[p_boss][p_weapon] # handle special cases for boss in range(14): for weapon in (1, 2, 3, 6, 8): if (0 < world.weapon_damage[weapon][boss] < minimum_weakness_requirement[weapon] and - not any(world.weapon_damage[i][boss] >= minimum_weakness_requirement[weapon] + not any(world.weapon_damage[i][boss] >= minimum_weakness_requirement[i] for i in range(9) if i != weapon)): # Weapon does not have enough possible ammo to kill the boss, raise the damage - if boss == 9: - if weapon in (1, 6): - # Atomic Fire and Crash Bomber cannot be Picopico-kun's only weakness - world.weapon_damage[weapon][boss] = 0 - weakness = world.random.choice((2, 3, 4, 5, 7, 8)) - world.weapon_damage[weakness][boss] = minimum_weakness_requirement[weakness] - elif boss == 11: - if weapon == 1: - # Atomic Fire cannot be Boobeam Trap's only weakness - world.weapon_damage[weapon][boss] = 0 - weakness = world.random.choice((2, 3, 4, 5, 6, 7, 8)) - world.weapon_damage[weakness][boss] = minimum_weakness_requirement[weakness] - else: - world.weapon_damage[weapon][boss] = minimum_weakness_requirement[weapon] + world.weapon_damage[weapon][boss] = minimum_weakness_requirement[weapon] + + for weapon in (1, 6): + if (world.weapon_damage[weapon][9] >= minimum_weakness_requirement[weapon] and + not any(world.weapon_damage[i][9] >= minimum_weakness_requirement[i] + for i in range(9) if i not in (1, 6))): + # Atomic Fire and Crash Bomber cannot be Picopico-kun's only weakness + world.weapon_damage[weapon][9] = 0 + weakness = world.random.choice((2, 3, 4, 5, 7, 8)) + world.weapon_damage[weakness][9] = minimum_weakness_requirement[weakness] + + if (world.weapon_damage[1][11] >= minimum_weakness_requirement[1] and + not any(world.weapon_damage[i][11] >= minimum_weakness_requirement[i] + for i in range(9) if i != 1)): + # Atomic Fire cannot be Boobeam Trap's only weakness + world.weapon_damage[1][11] = 0 + weakness = world.random.choice((2, 3, 4, 5, 6, 7, 8)) + world.weapon_damage[weakness][11] = minimum_weakness_requirement[weakness] if world.weapon_damage[0][world.options.starting_robot_master.value] < 1: - world.weapon_damage[0][world.options.starting_robot_master.value] = weapon_damage[0][world.options.starting_robot_master.value] + world.weapon_damage[0][world.options.starting_robot_master.value] = \ + weapon_damage[0][world.options.starting_robot_master.value] # final special case # There's a vanilla crash if Time Stopper kills Wily phase 1 @@ -218,9 +224,10 @@ def set_rules(world: "MM2World") -> None: # we are out of weapons that can actually damage the boss # so find the weapon that has the most uses, and apply that as an additional weakness # it should be impossible to be out of energy, simply because even if every boss took 1 from - # Quick Boomerang and no other, it would only be 28 off from defeating all 9, which Metal Blade should - # be able to cover - wp, max_uses = max((weapon, weapon_energy[weapon] // weapon_costs[weapon]) for weapon in weapon_weight + # Quick Boomerang and no other, it would only be 28 off from defeating all 9, + # which Metal Blade should be able to cover + wp, max_uses = max((weapon, weapon_energy[weapon] // weapon_costs[weapon]) + for weapon in weapon_weight if weapon != 0 and (weapon != 8 or boss != 12)) # Wily Machine cannot under any circumstances take damage from Time Stopper, prevent this world.weapon_damage[wp][boss] = minimum_weakness_requirement[wp] diff --git a/worlds/mmbn3/Items.py b/worlds/mmbn3/Items.py index 30ec311ecb..7e3458c913 100644 --- a/worlds/mmbn3/Items.py +++ b/worlds/mmbn3/Items.py @@ -85,7 +85,7 @@ keyItemList: typing.List[ItemData] = [ ] subChipList: typing.List[ItemData] = [ - ItemData(0xB31018, ItemName.Unlocker, ItemClassification.useful, ItemType.SubChip, 117), + ItemData(0xB31018, ItemName.Unlocker, ItemClassification.progression, ItemType.SubChip, 117), ItemData(0xB31019, ItemName.Untrap, ItemClassification.filler, ItemType.SubChip, 115), ItemData(0xB3101A, ItemName.LockEnmy, ItemClassification.filler, ItemType.SubChip, 116), ItemData(0xB3101B, ItemName.MiniEnrg, ItemClassification.filler, ItemType.SubChip, 112), @@ -290,7 +290,9 @@ programList: typing.List[ItemData] = [ ItemData(0xB31099, ItemName.WpnLV_plus_Yellow, ItemClassification.filler, ItemType.Program, 35, ProgramColor.Yellow), ItemData(0xB3109A, ItemName.Press, ItemClassification.progression, ItemType.Program, 20, ProgramColor.White), - ItemData(0xB310B7, ItemName.UnderSht, ItemClassification.useful, ItemType.Program, 30, ProgramColor.White) + ItemData(0xB310B7, ItemName.UnderSht, ItemClassification.useful, ItemType.Program, 30, ProgramColor.White), + ItemData(0xB310E0, ItemName.Humor, ItemClassification.progression, ItemType.Program, 45, ProgramColor.Pink), + ItemData(0xB310E1, ItemName.BlckMnd, ItemClassification.progression, ItemType.Program, 46, ProgramColor.White) ] zennyList: typing.List[ItemData] = [ @@ -338,8 +340,29 @@ item_frequencies: typing.Dict[str, int] = { ItemName.zenny_800z: 2, ItemName.zenny_1000z: 2, ItemName.zenny_1200z: 2, - ItemName.bugfrag_01: 5, + ItemName.bugfrag_01: 10, + ItemName.bugfrag_10: 5 } + +item_groups: typing.Dict[str, typing.Set[str]] = { + "Key Items": {loc.itemName for loc in keyItemList}, + "Subchips": {loc.itemName for loc in subChipList}, + "Programs": {loc.itemName for loc in programList}, + "BattleChips": {loc.itemName for loc in chipList}, + "Zenny": {loc.itemName for loc in zennyList}, + "BugFrags": {loc.itemName for loc in bugFragList}, + "Navi Chips": { + ItemName.Roll_R, ItemName.RollV2_R, ItemName.RollV3_R, ItemName.GutsMan_G, ItemName.GutsManV2_G, + ItemName.GutsManV3_G, ItemName.ProtoMan_B, ItemName.ProtoManV2_B, ItemName.ProtoManV3_B, ItemName.FlashMan_F, + ItemName.FlashManV2_F, ItemName.FlashManV3_F, ItemName.BeastMan_B, ItemName.BeastManV2_B, ItemName.BeastManV3_B, + ItemName.BubblMan_B, ItemName.BubblManV2_B, ItemName.BubblManV3_B, ItemName.DesertMan_D, ItemName.DesertManV2_D, + ItemName.DesertManV3_D, ItemName.PlantMan_P, ItemName.PlantManV2_P, ItemName.PlantManV3_P, ItemName.FlamMan_F, + ItemName.FlamManV2_F, ItemName.FlamManV3_F, ItemName.DrillMan_D, ItemName.DrillManV2_D, ItemName.DrillManV3_D, + ItemName.MetalMan_M, ItemName.MetalManV2_M, ItemName.MetalManV3_M, ItemName.KingMan_K, ItemName.KingManV2_K, + ItemName.KingManV3_K, ItemName.BowlMan_B, ItemName.BowlManV2_B, ItemName.BowlManV3_B + } +} + all_items: typing.List[ItemData] = keyItemList + subChipList + chipList + programList + zennyList + bugFragList item_table: typing.Dict[str, ItemData] = {item.itemName: item for item in all_items} items_by_id: typing.Dict[int, ItemData] = {item.code: item for item in all_items} diff --git a/worlds/mmbn3/Locations.py b/worlds/mmbn3/Locations.py index 0e2a1c51d1..bc16c99a58 100644 --- a/worlds/mmbn3/Locations.py +++ b/worlds/mmbn3/Locations.py @@ -221,7 +221,8 @@ overworlds = [ LocationData(LocationName.Hades_Boat_Dock, 0xb310ab, 0x200024c, 0x10, 0x7519B0, 223, [3]), LocationData(LocationName.WWW_Control_Room_1_Screen, 0xb310ac, 0x200024d, 0x40, 0x7596C4, 222, [3, 4]), LocationData(LocationName.WWW_Wilys_Desk, 0xb310ad, 0x200024d, 0x2, 0x759384, 229, [3]), - LocationData(LocationName.Undernet_4_Pillar_Prog, 0xb310ae, 0x2000161, 0x1, 0x7746C8, 191, [0, 1]) + LocationData(LocationName.Undernet_4_Pillar_Prog, 0xb310ae, 0x2000161, 0x1, 0x7746C8, 191, [0, 1]), + LocationData(LocationName.Serenade, 0xb3110f, 0x2000178, 0x40, 0x7B3C74, 1, [0]) ] jobs = [ @@ -240,7 +241,8 @@ jobs = [ # LocationData(LocationName.Gathering_Data, 0xb310bb, 0x2000300, 0x10, 0x739580, 193, [0]), LocationData(LocationName.Somebody_please_help, 0xb310bc, 0x2000301, 0x4, 0x73A14C, 193, [0]), LocationData(LocationName.Looking_for_condor, 0xb310bd, 0x2000301, 0x2, 0x749444, 203, [0]), - LocationData(LocationName.Help_with_rehab, 0xb310be, 0x2000301, 0x1, 0x762CF0, 192, [3]), + LocationData(LocationName.Help_with_rehab, 0xb310be, 0x2000301, 0x1, 0x762CF0, 192, [0]), + LocationData(LocationName.Help_with_rehab_bonus, 0xb3110e, 0x2000301, 0x1, 0x762CF0, 192, [3]), LocationData(LocationName.Old_Master, 0xb310bf, 0x2000302, 0x80, 0x760E80, 193, [0]), LocationData(LocationName.Catching_gang_members, 0xb310c0, 0x2000302, 0x40, 0x76EAE4, 193, [0]), LocationData(LocationName.Please_adopt_a_virus, 0xb310c1, 0x2000302, 0x20, 0x76A4F4, 193, [0]), @@ -250,7 +252,7 @@ jobs = [ LocationData(LocationName.Hide_and_seek_Second_Child, 0xb310c5, 0x2000188, 0x2, 0x75ADA8, 191, [0]), LocationData(LocationName.Hide_and_seek_Third_Child, 0xb310c6, 0x2000188, 0x1, 0x75B5EC, 191, [0]), LocationData(LocationName.Hide_and_seek_Fourth_Child, 0xb310c7, 0x2000189, 0x80, 0x75BEB0, 191, [0]), - LocationData(LocationName.Hide_and_seek_Completion, 0xb310c8, 0x2000302, 0x8, 0x7406A0, 193, [0]), + LocationData(LocationName.Hide_and_seek_Completion, 0xb310c8, 0x2000302, 0x8, 0x742D40, 193, [0]), LocationData(LocationName.Finding_the_blue_Navi, 0xb310c9, 0x2000302, 0x4, 0x773700, 192, [0]), LocationData(LocationName.Give_your_support, 0xb310ca, 0x2000302, 0x2, 0x752D80, 192, [0]), LocationData(LocationName.Stamp_collecting, 0xb310cb, 0x2000302, 0x1, 0x756074, 193, [0]), @@ -329,10 +331,7 @@ chocolate_shop = [ LocationData(LocationName.Chocolate_Shop_32, 0xb3110d, 0x20001c3, 0x01, 0x73F8FC, 181, [0]), ] -always_excluded_locations = [ - LocationName.Undernet_7_PMD, - LocationName.Undernet_7_Northeast_BMD, - LocationName.Undernet_7_Northwest_BMD, +secret_locations = { LocationName.Secret_1_Northwest_BMD, LocationName.Secret_1_Northeast_BMD, LocationName.Secret_1_South_BMD, @@ -341,19 +340,23 @@ always_excluded_locations = [ LocationName.Secret_2_Island_BMD, LocationName.Secret_3_Island_BMD, LocationName.Secret_3_BugFrag_BMD, - LocationName.Secret_3_South_BMD -] + LocationName.Secret_3_South_BMD, + LocationName.Serenade +} +location_groups: typing.Dict[str, typing.Set[str]] = { + "BMDs": {loc.name for loc in bmds}, + "PMDs": {loc.name for loc in pmds}, + "Jobs": {loc.name for loc in jobs}, + "Number Trader": {loc.name for loc in number_traders}, + "Bugfrag Trader": {loc.name for loc in chocolate_shop}, + "Secret Area": {LocationName.Secret_1_Northwest_BMD, LocationName.Secret_1_Northeast_BMD, + LocationName.Secret_1_South_BMD, LocationName.Secret_2_Upper_BMD, LocationName.Secret_2_Lower_BMD, + LocationName.Secret_2_Island_BMD, LocationName.Secret_3_Island_BMD, + LocationName.Secret_3_BugFrag_BMD, LocationName.Secret_3_South_BMD, LocationName.Serenade}, +} all_locations: typing.List[LocationData] = bmds + pmds + overworlds + jobs + number_traders + chocolate_shop scoutable_locations: typing.List[LocationData] = [loc for loc in all_locations if loc.hint_flag is not None] location_table: typing.Dict[str, int] = {locData.name: locData.id for locData in all_locations} location_data_table: typing.Dict[str, LocationData] = {locData.name: locData for locData in all_locations} - - -""" -def setup_locations(world, player: int): - # If we later include options to change what gets added to the random pool, - # this is where they would be changed - return {locData.name: locData.id for locData in all_locations} -""" diff --git a/worlds/mmbn3/Names/ItemName.py b/worlds/mmbn3/Names/ItemName.py index 677eff22b3..af645db90c 100644 --- a/worlds/mmbn3/Names/ItemName.py +++ b/worlds/mmbn3/Names/ItemName.py @@ -173,6 +173,8 @@ class ItemName(): WpnLV_plus_White = "WpnLV+1 (White)" Press = "Press" UnderSht = "UnderSht" + Humor = "Humor" + BlckMnd = "BlckMnd" ## Currency zenny_200z = "200z" diff --git a/worlds/mmbn3/Names/LocationName.py b/worlds/mmbn3/Names/LocationName.py index 36060b12ec..61c64faa9d 100644 --- a/worlds/mmbn3/Names/LocationName.py +++ b/worlds/mmbn3/Names/LocationName.py @@ -210,6 +210,7 @@ class LocationName(): WWW_Control_Room_1_Screen = "WWW Control Room 1 Screen" WWW_Wilys_Desk = "WWW Wily's Desk" Undernet_4_Pillar_Prog = "Undernet 4 Pillar Prog" + Serenade = "Serenade" ## Numberman Codes Numberman_Code_01 = "Numberman Code 01" @@ -261,6 +262,7 @@ class LocationName(): Somebody_please_help = "Job: Somebody, please help!" Looking_for_condor = "Job: Looking for condor" Help_with_rehab = "Job: Help with rehab" + Help_with_rehab_bonus = "Job: Help with rehab bonus" Old_Master = "Job: Old Master" Catching_gang_members = "Job: Catching gang members" Please_adopt_a_virus = "Job: Please adopt a virus!" diff --git a/worlds/mmbn3/Options.py b/worlds/mmbn3/Options.py index 4ed64e3d9d..a127d25dda 100644 --- a/worlds/mmbn3/Options.py +++ b/worlds/mmbn3/Options.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from Options import Choice, Range, DefaultOnToggle, PerGameCommonOptions +from Options import Choice, Range, DefaultOnToggle, Toggle, PerGameCommonOptions class ExtraRanks(Range): @@ -17,10 +17,17 @@ class ExtraRanks(Range): class IncludeJobs(DefaultOnToggle): """ - Whether Jobs can be included in logic. + Whether Jobs can contain progression or useful items. """ display_name = "Include Jobs" + +class IncludeSecretArea(Toggle): + """ + Whether the Secret Area (including Serenade) can contain progression or useful items. + """ + display_name = "Include Secret Area" + # Possible logic options: # - Include Number Trader # - Include Secret Area @@ -46,5 +53,6 @@ class TradeQuestHinting(Choice): class MMBN3Options(PerGameCommonOptions): extra_ranks: ExtraRanks include_jobs: IncludeJobs + include_secret: IncludeSecretArea trade_quest_hinting: TradeQuestHinting \ No newline at end of file diff --git a/worlds/mmbn3/Regions.py b/worlds/mmbn3/Regions.py index 1dc58600cb..286e95a1c2 100644 --- a/worlds/mmbn3/Regions.py +++ b/worlds/mmbn3/Regions.py @@ -135,6 +135,7 @@ regions = [ LocationName.Somebody_please_help, LocationName.Looking_for_condor, LocationName.Help_with_rehab, + LocationName.Help_with_rehab_bonus, LocationName.Old_Master, LocationName.Catching_gang_members, LocationName.Please_adopt_a_virus, @@ -349,6 +350,7 @@ regions = [ LocationName.Secret_2_Upper_BMD, LocationName.Secret_3_Island_BMD, LocationName.Secret_3_South_BMD, - LocationName.Secret_3_BugFrag_BMD + LocationName.Secret_3_BugFrag_BMD, + LocationName.Serenade ]) ] diff --git a/worlds/mmbn3/__init__.py b/worlds/mmbn3/__init__.py index 6d28b101c3..08165a7df6 100644 --- a/worlds/mmbn3/__init__.py +++ b/worlds/mmbn3/__init__.py @@ -9,14 +9,14 @@ from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification, Region, from worlds.AutoWorld import WebWorld, World from .Rom import MMBN3DeltaPatch, LocalRom, get_base_rom_path -from .Items import MMBN3Item, ItemData, item_table, all_items, item_frequencies, items_by_id, ItemType +from .Items import MMBN3Item, ItemData, item_table, all_items, item_frequencies, items_by_id, ItemType, item_groups from .Locations import Location, MMBN3Location, all_locations, location_table, location_data_table, \ - always_excluded_locations, jobs + secret_locations, jobs, location_groups from .Options import MMBN3Options from .Regions import regions, RegionName from .Names.ItemName import ItemName from .Names.LocationName import LocationName -from worlds.generic.Rules import add_item_rule +from worlds.generic.Rules import add_item_rule, add_rule class MMBN3Settings(settings.Group): @@ -57,12 +57,16 @@ class MMBN3World(World): settings: typing.ClassVar[MMBN3Settings] topology_present = False + item_name_to_id = {name: data.code for name, data in item_table.items()} location_name_to_id = {loc_data.name: loc_data.id for loc_data in all_locations} - excluded_locations: typing.List[str] + excluded_locations: typing.Set[str] item_frequencies: typing.Dict[str, int] + location_name_groups = location_groups + item_name_groups = item_groups + web = MMBN3Web() def generate_early(self) -> None: @@ -74,10 +78,11 @@ class MMBN3World(World): if self.options.extra_ranks > 0: self.item_frequencies[ItemName.Progressive_Undernet_Rank] = 8 + self.options.extra_ranks + self.excluded_locations = set() + if not self.options.include_secret: + self.excluded_locations |= secret_locations if not self.options.include_jobs: - self.excluded_locations = always_excluded_locations + [job.name for job in jobs] - else: - self.excluded_locations = always_excluded_locations + self.excluded_locations |= {job.name for job in jobs} def create_regions(self) -> None: """ @@ -140,19 +145,19 @@ class MMBN3World(World): if connection == RegionName.SciLab_Cyberworld: entrance.access_rule = lambda state: \ state.has(ItemName.CSciPas, self.player) or \ - state.can_reach(RegionName.SciLab_Overworld, "Region", self.player) + state.can_reach_region(RegionName.SciLab_Overworld, self.player) self.multiworld.register_indirect_condition(self.get_region(RegionName.SciLab_Overworld), entrance) if connection == RegionName.Yoka_Cyberworld: entrance.access_rule = lambda state: \ state.has(ItemName.CYokaPas, self.player) or \ ( - state.can_reach(RegionName.SciLab_Overworld, "Region", self.player) and + state.can_reach_region(RegionName.SciLab_Overworld, self.player) and state.has(ItemName.Press, self.player) ) self.multiworld.register_indirect_condition(self.get_region(RegionName.SciLab_Overworld), entrance) if connection == RegionName.Beach_Cyberworld: entrance.access_rule = lambda state: state.has(ItemName.CBeacPas, self.player) and\ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) self.multiworld.register_indirect_condition(self.get_region(RegionName.Yoka_Overworld), entrance) if connection == RegionName.Undernet: entrance.access_rule = lambda state: self.explore_score(state) > 8 and\ @@ -198,122 +203,138 @@ class MMBN3World(World): # Set WWW ID requirements def has_www_id(state): return state.has(ItemName.WWW_ID, self.player) - self.multiworld.get_location(LocationName.ACDC_1_PMD, self.player).access_rule = has_www_id - self.multiworld.get_location(LocationName.SciLab_1_WWW_BMD, self.player).access_rule = has_www_id - self.multiworld.get_location(LocationName.Yoka_1_WWW_BMD, self.player).access_rule = has_www_id - self.multiworld.get_location(LocationName.Undernet_1_WWW_BMD, self.player).access_rule = has_www_id + add_rule(self.multiworld.get_location(LocationName.ACDC_1_PMD, self.player), has_www_id) + add_rule(self.multiworld.get_location(LocationName.SciLab_1_WWW_BMD, self.player), has_www_id) + add_rule(self.multiworld.get_location(LocationName.Yoka_1_WWW_BMD, self.player), has_www_id) + add_rule(self.multiworld.get_location(LocationName.Undernet_1_WWW_BMD, self.player), has_www_id) # Set Press Program requirements def has_press(state): return state.has(ItemName.Press, self.player) - self.multiworld.get_location(LocationName.Yoka_1_PMD, self.player).access_rule = has_press - self.multiworld.get_location(LocationName.Yoka_2_Upper_BMD, self.player).access_rule = has_press - self.multiworld.get_location(LocationName.Beach_2_East_BMD, self.player).access_rule = has_press - self.multiworld.get_location(LocationName.Hades_South_BMD, self.player).access_rule = has_press - self.multiworld.get_location(LocationName.Secret_3_BugFrag_BMD, self.player).access_rule = has_press - self.multiworld.get_location(LocationName.Secret_3_Island_BMD, self.player).access_rule = has_press + add_rule(self.multiworld.get_location(LocationName.Yoka_1_PMD, self.player), has_press) + add_rule(self.multiworld.get_location(LocationName.Yoka_2_Upper_BMD, self.player), has_press) + add_rule(self.multiworld.get_location(LocationName.Beach_2_East_BMD, self.player), has_press) + add_rule(self.multiworld.get_location(LocationName.Hades_South_BMD, self.player), has_press) + add_rule(self.multiworld.get_location(LocationName.Secret_3_BugFrag_BMD, self.player), has_press) + add_rule(self.multiworld.get_location(LocationName.Secret_3_Island_BMD, self.player), has_press) + + # Set Purple Mystery Data Unlocker access + def can_unlock(state): return state.can_reach_region(RegionName.SciLab_Overworld, self.player) or \ + state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) or \ + state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) or \ + state.has(ItemName.Unlocker, self.player, 8) # There are 8 PMDs that aren't in one of the above areas + add_rule(self.multiworld.get_location(LocationName.ACDC_1_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Yoka_1_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Beach_1_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Undernet_7_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Mayls_HP_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.SciLab_Dads_Computer_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Zoo_Panda_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Beach_DNN_Security_Panel_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Beach_DNN_Main_Console_PMD, self.player), can_unlock) + add_rule(self.multiworld.get_location(LocationName.Tamakos_HP_PMD, self.player), can_unlock) # Set Job additional area access self.multiworld.get_location(LocationName.Please_deliver_this, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.ACDC_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.ACDC_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ + state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) self.multiworld.get_location(LocationName.My_Navi_is_sick, self.player).access_rule =\ lambda state: \ state.has(ItemName.Recov30_star, self.player) self.multiworld.get_location(LocationName.Help_me_with_my_son, self.player).access_rule =\ lambda state:\ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.ACDC_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ + state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) self.multiworld.get_location(LocationName.Transmission_error, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) self.multiworld.get_location(LocationName.Chip_Prices, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.ACDC_Cyberworld, "Region", self.player) and \ - state.can_reach(RegionName.SciLab_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) and \ + state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) self.multiworld.get_location(LocationName.Im_broke, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.Yoka_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ + state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) self.multiworld.get_location(LocationName.Rare_chips_for_cheap, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.ACDC_Overworld, "Region", self.player) + state.can_reach_region(RegionName.ACDC_Overworld, self.player) self.multiworld.get_location(LocationName.Be_my_boyfriend, self.player).access_rule =\ lambda state: \ - state.can_reach(RegionName.Beach_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.Beach_Cyberworld, self.player) self.multiworld.get_location(LocationName.Will_you_deliver, self.player).access_rule=\ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.ACDC_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ + state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ + state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) self.multiworld.get_location(LocationName.Somebody_please_help, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.ACDC_Overworld, "Region", self.player) + state.can_reach_region(RegionName.ACDC_Overworld, self.player) self.multiworld.get_location(LocationName.Looking_for_condor, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.ACDC_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ + state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ + state.can_reach_region(RegionName.ACDC_Overworld, self.player) self.multiworld.get_location(LocationName.Help_with_rehab, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Beach_Overworld, self.player) self.multiworld.get_location(LocationName.Old_Master, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.ACDC_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) + state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ + state.can_reach_region(RegionName.Beach_Overworld, self.player) self.multiworld.get_location(LocationName.Catching_gang_members, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Cyberworld, "Region", self.player) and \ + state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) and \ state.has(ItemName.Press, self.player) self.multiworld.get_location(LocationName.Please_adopt_a_virus, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.SciLab_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) self.multiworld.get_location(LocationName.Legendary_Tomes, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.Undernet, "Region", self.player) and \ - state.can_reach(RegionName.Deep_Undernet, "Region", self.player) and \ + state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ + state.can_reach_region(RegionName.Undernet, self.player) and \ + state.can_reach_region(RegionName.Deep_Undernet, self.player) and \ state.has_all({ItemName.Press, ItemName.Magnum1_A}, self.player) self.multiworld.get_location(LocationName.Legendary_Tomes_Treasure, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.ACDC_Overworld, "Region", self.player) and \ - state.can_reach(LocationName.Legendary_Tomes, "Location", self.player) + state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ + state.can_reach_location(LocationName.Legendary_Tomes, self.player) self.multiworld.get_location(LocationName.Hide_and_seek_First_Child, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) self.multiworld.get_location(LocationName.Hide_and_seek_Second_Child, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) self.multiworld.get_location(LocationName.Hide_and_seek_Third_Child, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) self.multiworld.get_location(LocationName.Hide_and_seek_Fourth_Child, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) self.multiworld.get_location(LocationName.Hide_and_seek_Completion, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Yoka_Overworld, self.player) self.multiworld.get_location(LocationName.Finding_the_blue_Navi, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Undernet, "Region", self.player) + state.can_reach_region(RegionName.Undernet, self.player) self.multiworld.get_location(LocationName.Give_your_support, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) + state.can_reach_region(RegionName.Beach_Overworld, self.player) self.multiworld.get_location(LocationName.Stamp_collecting, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.ACDC_Cyberworld, "Region", self.player) and \ - state.can_reach(RegionName.SciLab_Cyberworld, "Region", self.player) and \ - state.can_reach(RegionName.Yoka_Cyberworld, "Region", self.player) and \ - state.can_reach(RegionName.Beach_Cyberworld, "Region", self.player) + state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ + state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) and \ + state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) and \ + state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) and \ + state.can_reach_region(RegionName.Beach_Cyberworld, self.player) self.multiworld.get_location(LocationName.Help_with_a_will, self.player).access_rule = \ lambda state: \ - state.can_reach(RegionName.ACDC_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.ACDC_Cyberworld, "Region", self.player) and \ - state.can_reach(RegionName.Yoka_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.Yoka_Cyberworld, "Region", self.player) and \ - state.can_reach(RegionName.Beach_Overworld, "Region", self.player) and \ - state.can_reach(RegionName.Undernet, "Region", self.player) + state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ + state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) and \ + state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ + state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) and \ + state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ + state.can_reach_region(RegionName.Undernet, self.player) # Set Trade quests self.multiworld.get_location(LocationName.ACDC_SonicWav_W_Trade, self.player).access_rule =\ @@ -390,6 +411,11 @@ class MMBN3World(World): self.multiworld.get_location(LocationName.Numberman_Code_31, self.player).access_rule =\ lambda state: self.explore_score(state) > 10 + #miscellaneous locations with extra requirements + add_rule(self.multiworld.get_location(LocationName.Comedian, self.player), + lambda state: state.has(ItemName.Humor, self.player)) + add_rule(self.multiworld.get_location(LocationName.Villain, self.player), + lambda state: state.has(ItemName.BlckMnd, self.player)) def not_undernet(item): return item.code != item_table[ItemName.Progressive_Undernet_Rank].code or item.player != self.player self.multiworld.get_location(LocationName.WWW_1_Central_BMD, self.player).item_rule = not_undernet self.multiworld.get_location(LocationName.WWW_1_East_BMD, self.player).item_rule = not_undernet @@ -500,24 +526,24 @@ class MMBN3World(World): Determine roughly how much of the game you can explore to make certain checks not restrict much movement """ score = 0 - if state.can_reach(RegionName.WWW_Island, "Region", self.player): + if state.can_reach_region(RegionName.WWW_Island, self.player): return 999 - if state.can_reach(RegionName.SciLab_Overworld, "Region", self.player): + if state.can_reach_region(RegionName.SciLab_Overworld, self.player): score += 3 - if state.can_reach(RegionName.SciLab_Cyberworld, "Region", self.player): + if state.can_reach_region(RegionName.SciLab_Cyberworld, self.player): score += 1 - if state.can_reach(RegionName.Yoka_Overworld, "Region", self.player): + if state.can_reach_region(RegionName.Yoka_Overworld, self.player): score += 2 - if state.can_reach(RegionName.Yoka_Cyberworld, "Region", self.player): + if state.can_reach_region(RegionName.Yoka_Cyberworld, self.player): score += 1 - if state.can_reach(RegionName.Beach_Overworld, "Region", self.player): + if state.can_reach_region(RegionName.Beach_Overworld, self.player): score += 3 - if state.can_reach(RegionName.Beach_Cyberworld, "Region", self.player): + if state.can_reach_region(RegionName.Beach_Cyberworld, self.player): score += 1 - if state.can_reach(RegionName.Undernet, "Region", self.player): + if state.can_reach_region(RegionName.Undernet, self.player): score += 2 - if state.can_reach(RegionName.Deep_Undernet, "Region", self.player): + if state.can_reach_region(RegionName.Deep_Undernet, self.player): score += 1 - if state.can_reach(RegionName.Secret_Area, "Region", self.player): + if state.can_reach_region(RegionName.Secret_Area, self.player): score += 1 return score diff --git a/worlds/mmbn3/data/bn3-ap-patch.bsdiff b/worlds/mmbn3/data/bn3-ap-patch.bsdiff index d3548b4c949a459da53701090d5f6fa5f565b7f8..d55fecad80641b372bc7752600f335d6961f9185 100644 GIT binary patch literal 61276 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�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 literal 59914 zcmaI7V{j$R6YzWDb(0+uYc8?(=`|t$M%R{?aquJyX+F zT|G5bzY$Rtla`QRXZ{NX_&>5l^8ae_e?k9eAfjW%!y>Frsj7_?&GHKX%MkeepL~9Q zKmSi(e|HC7Utdc;_Wp0S@wx36X!xxJiJOdtZ#9)=G)D{q4N&HngA&cmkZB47Dia^s z0X`9n5Q~Tq!iDU3_IO!{0H2__qCx;WLOj6A3PMpi5nx4_ov%b17q+-=<6|$iF5*L2 zd0O%KQwc93Kgt-99jpZrC!1L!iyhDEksVr2R3d0>)(Rn1XqFuhkA2MgzpW6#iqKKS z%*spGf2oR!E?NQXh2}uPr+8pzRX01!JF@D+nk}gU_ z1WN<}{yQcB03Gx{FCK)%|IuJ)|E*w$&IX4N`kxtK_1~)hVuYgr09*hb01PA%oQOaf z^k0nGfA(}@_ZS`dKInMrJh#lWZtEu+VgJr48dp^Z1H^=Fi+SY5FTt z&lR6n{Syg-O62$n?r88NNn!^ztRe`)ek8VzNP!dUFG8h`U zP*ho5R21e@FT>IbXC?KJWJAgyZ-e1fvn`2F8uu#9E{>nbdUu4l9>Y~aB#EY#v9a%5 z(R8ps(KuFzm;Al$YB<%fn_mL{NN*~9pFIRRV`UVi` zb?3xw7E8m4Q%{45B~AcAm=#k0)u|F1VDUzM_bf}@eRRKLU{=X_>gErnOo)yM4gNk( zfb;jU9xg??k6fcwq>0!cNuE<;x<+2Zg?MOfmv;)};84abA!mVqWHMB{)f6&WFIi2U zdEpRVRj=;Em8gxE7e^q3k#A+t6`ew zkW52?mo!*0@#3kvRKJqGGy=M;k1<5N23QHSu|79>oX#|_dtbx@i0cvtL~$@;E9Vf! zS!!mKf(RKP7_lDbudQ3{zg#!WiQOhRw_#PZ^=r?azoqZ!v>B)Kamb-iVTsXT0pMX6 zBw^t~r6@uaVALVcpUw}+p)Jb%*|wxJsnE?a`kjh5GGDG~26Y$!Q-NSm1r zmm-&66(G;SQfw0d0zC>S(r|()TFdjx%ay(4i{FLPDKJtnjtgQKSI9aUL{BrV=VK(-7W{P-OoS-6%G0JRkMG4AmE715J#=7-M zwvmn8;+-+aPqj}pdk*%e5Tg{cU-F9bh2`O#<>3NUAvQkw<*5Rqi^j-upxFpTpicx` z^WqfAKRh4NMIXu3M>c8!s>(An+I-3=GdwFqZ~>H|@I~ zlX<%s!r6Jw=xo%Gg3?F+%D3$N{BVIYv0KFn0f}F#a~wbB__L|EOCN^D7M6aBkxj{y zNuFRBL#llOf+WJmpp~FQF-9mut=9vvxxvuyyD{GlQM|r2*jZXw3o|VKrNvJ<*1HxmWR!y;`tc3}vs=womP{Zl zNS|4anOQxsM#M9dad4{QWwW!ISy>nU5M!T$D;zTOVa+5dkwBR{MP#3~Vzn-6K?uUL zG6Ar|rY3@5t@6X!zz}{(%?aSKW}4%IQszp>9y0N)*`yl*@|?khAUQ=cG@LOjGSp0Y zGI>ybg+-LvkdHMpgjhdk)B-zP;(8WVkHR5wV0a}rhhUC`oAK{{S?|@!H}P8OUy!F6 z4_jI4$uAn5L4lme>iU|UfeEHTz44ZrBX6FFNp3EId|yl_0h}Ue?YX;8Zun@+%^K%z z2s@jB-JE${Aj6 zN$e)`JC}@;cY}{@s;hV9_ewS6JhS(EO7%hC8MeEV(Mb~GV<@o@L}rfT0HI9T=vP2w z1(~7yPzyEFo1IRdL>4E#_@{ASO*AH5$;4>$n?}PMdP;k%wgbka-RsszFWksyZVumX z{bAJlx?29c*9P2~hrb>_ht;^M2Hh!Qdd*645jC>W+qCcYkRcA_J(H&thZ!|IDEB)& zp1Xop8Z~Avn+4-wFvPAq-B5XPRAY#q7d<8YYIUeSXqHdO>3+p3f~TI zw}fb>mzoARKc0FcB9QkPE)hK{F`=y5pFfFW&cpcxCMB*Id0MR}W!7*I7N!X5|2f!E zb!zbkdDi!wJodPy#Ah0}Uz)d0>tE7iTep4Y3i8+Oh7#hHkoAO6MXJ1}dHVTHbcL(F z)Z*bMSkM!{Co>`B*d*J(7PZv3DK#c%mHG2Fe=w2CzgatEkE5z0gr8v6#^%KISDz_e zx#=3)!Pb{;Ej=?@u*m(sYIb_fiRodWO`rH61V)Cv>v^6u zqj5`z3uXs9tfD*{kNrv)HC??27t)p|lY&RSZYZ~C_ZU&&%J6w1uC8{1Iy%ezMcIN_YUT1cOV->nZ;E^%AfX#?Pj_wos%{^0&JUs=?roB)?qM= zPu4jJG@7qSJ%FBErT#;U)IXsyu^{5HXfKQJ*gJe~!s$x*dnW=d={7is!~QHUfvsb; z#Cj~wJVI>K%E}7-VJBVi7Mfm)_@Vr^>h{j(Xg!Y zq&WYAV-~>X4B)XM85t&&fGP-A=%7l$UW)d8)1XCn&HF1431b#TpoguFeIYKI6|ylT z(j}Lx@hVu`Cah9(=iv;00k|WMa$-Ti5IZaObMlPBIbpoSWVvTRC2XXzM4>MZJ{EaL z3HU(a`2*b+^=O0AKdK5qZ1qb#Gi~gX@9L5*fi&}coX}}^ zC0-*$q%U8UpL>UkZzl2v$q)~k+D z!+5^3#n>mz!zDOh!jv%M3aArI4k9y-j9+)aZPrY>_+$K2C%Dgzc1=2wpLQG?T5P-ishoYe7!13L{7h4aqx6eI^BN6`N_x{b9O7qa@^XPp3aF0mQ z(8&oB%u;y`k%iu#^+n%``0(G>{LtRfwxEqcCeKE4 z#T{ifOfaaZX=r+Amx>K)dWgfBbCU(3}`ET2~g*x5Ipof@n z5kbxxLKtvLRf&8Fk@;#>=a2L&xO@r<{sBSm=VAjl{kBTk*rw9Z5HjO@c&frOP&4>q z)I7!;7if6YmQ@(hL$bb7lD%2kkN{ylV#>VqdA%V1^iK)Nlt|1s^HL`p`WoP@%!Goz z8D&)b!Yq5CutKM)ugzBh(_LI_^N#SUabh6T#^5mlQ(UxvDmuA%t_v>{yuf>B`4uPAKLCDHDsNQzP?=CKrw?Zv;~F))&W6d zc_}$JrojR&_+zhj`0vt>AMs}h6|cuOE_YTYvm*2$)`?yxAvLHwLxuSfORCO^mAN!Au3`|oZ4ltjM zj*8t-6u_a@;WB^q0t@RzIp!15mH|*vKzkO(!iXJgbwmX9B}KBFVh|QA$;BuK#)1%1 zt(TLiDhA@VdxNMh3ja$a6}B-3d}er;E6b#~{2A>Z>N+N`!jqyKA-B(Xu-0EUQ7RO< z1{zfUBXjtF`TpQaK~+O2^H}K^SqaD?(^9_T$2r`vHz0oDV@SpYJ0s^2wT#TF{z{Oc zHR^~F91>#Y?tp$KG=MXqgeHub5)Dg0gZc|o5cwG7jK_;3Mfse4QFTD<&GJmrp~yPBm<2r^l^NZP)J4 z7HDX=_4{V87o6B>w8EE*`$v+Zt_4Yqr$StBry=JXi#~W>BgGY!^JTPh0fA>S;H^0s zFYWd_+$tq#wBw@iHXuWKmyh35mXmRi_0$_n(*}%&%=pr(aDq~PbD+aXh=i4*pos)V z*Gdq_Y=0>Q#hsr@-0N?$To9l!ceH3JUO{tcTD=4sW+6CjL}`9L1V|}AL%nn-^YJFN8Ign*Zt;| zX96cWXQ#rLfo9<5CFuN7*F1P+`oOVhd;=lebr6b_v`cw7ft5}yM?6Z6ogp#g^DHq@ zgBT@v+L;mhs_lY(D}1uM6BjBv!+p}4h?}!oi`2`;=0sTUC^tzG@nZ3VQu?+ep4^j! zt~*&+@iw+EjQB&uOA`!&{1?yuiyW7J+ZtvYrnE_yrX=w-mM!GjQOO}YA-{T5Qq#~- zeY!iNfcwZ(1*zdUH;AK|FyM#g1V_~heqVKbtrvzzMXGHz`+wY*KeVhsp?nNan1D(!~@d@fUwW%T9c z9GUCj7n3duFFgz|^OEu@jFr5~|5vxWB zuHn`g3C~m!do*bi(D3mEsQ`MP7s#ffjNSCgIka+(n>gRVfW@)GSM@ zBTa60n!jF98kp|TitAJoO-v|w#en%1HzOD&i5s$Epm*R4KfATnw-ciiJ~O%?wz0sn z`6qx!RkC6E6tgydJ(U1YqwL5?YGUNqxR1Ye7Th!_%G|E|t**6p(5f>l*yY&pZ1je0 z8Al1i+hwyAt0wIl4RC4<{LJ6?BWOuH0S5M^qPqPXvJw$W zED4KbdEg2foH>+OIKJ(}@E6?QUWtpQQC>N18{-|_{R)#m$R>$(9)5ZzFX9`6$p5vbDx>wgT%|q#_BxP7 zB98CE$kd45(u(jAA;&sX#?g5j}{pi1_MdT12c$2d#j>Sgwa8pQ|0(Hb#xJ}GZ3 z#h);6h*=cbsGr+|PTzQ&N2SkRh9^=@PDXC4RIz6_5WY0J=XHu5yGQQ3!cHvVZ`1W( zjak`~V6B%H&>s}uUJ%;~w>xW?cU_T!?Yhs1U%E@Gd?A5V$ek{$w0)}rA+}49lZxUT z0#V8>>ZId-YuwqX=A%ChA>sYC03YyQik`%)6?LEXn9hq-Mx6FN@AWFGS+h zEeRLo80maEbDx0LvC9;NT+(Qi;668eb3V#xd3OW0^tr1E!zkVy?G?c;rxxiqfAk*= ziVnEgvUCQh>cW`F%nJf89Hcp4y@tg_VZ|Dx<(-^_E|Nk~ST`D3Dv;@$MLJW?ySbr2 zmDrIjO~2_|qyF&D1lodeCc*KHY+q$Tgh`X0%0M&xzy^p2(J6AT)p~F7!U^&AAHzi` z2U+<<$q-q??8Xa}n7h!@xVuF)m#>!OI58?_s0AG^g8;2h15ZpE6-mTQYMud`ub1{E zh`F4U6$Do~q=2DM;=eDq;z3oSFJC)M9!>(o@ZjkMraxZC3|;HHSy9#UL%fyxgDEoq zAO=dcxt{VA42P9Ybsz-U!$P6C9tmu9Y-YmR!Eo!_>U!4qMzX}!;*a#e_p-}%4z zYPPU%d~@pNi`9RxIfZ)bQj@F*l5b1r`#_aTgF= z@p(x~tTAbs#?9oUD^{9KW4_+=UCMyUYUjfW5zq#t-ySt+r(ta8+0QwqsCUqX{E(|( zt3&E|k68WXEU!*(D-36KvCh zM3$CISj~=X-p5}EA8AOKXvP0J&}4%@XATY2Mw;ljv-wfXZzRZMBs>^ri?2B&>C~C+ zX*ms)7&m*Ag)Uu&UW*>mg~E>z6bF#$I$F*CF){)y$vxTbc0LxY3Gx;aZ~bsPfTN+a zN8?Yir@^DO{PdtOMZHj{&ag$QlpHaf2mnJT{^BvwK-qke5=IO3Mu$QRTACi^)Z{RW zs)xJpES;?!5X)|~)TCT;iTGqrkRMv{kxup!o%RDaA*0}W4h@ferWWu_1t;hW9j(GC z<(Dr%vz~%`^P&8@K6_%M8S>?a9?S}z)GY4~r{WawH%qAzqwFUh&^O79BxtoMY_x6R zsTpt6t0SY{_#FwS^2jo!nPC#0;5gpj&2eM(rh~A;yCVQ}Q-zV!M(~qFU|}f;u*as6 zf5`HNz)a?*i0)^autTTNHsdKCPqRHD@X~jk$Yl0w!j^6~0y&1VpNmRL_Gpj|hbeU+ zl)?o5efyY9fS72~MMsMVUQEH8PcBKP13;80W#Ha zOeojXS%hZAjUS(`K}{FzCQyg1O!_b6B)^sESy;7F!I*aIyTRh1vKuQdfqR)svabbwciG1HEj!9z0GOuotbc&>c#eGuA(+IMFszRc6 z-P#l5yQeo2@>lrNGa!02%S780P4oI<*U+wCOf= zjjrvX*KagKO4^Q5&ee4k>=3B))Vch ziacA7ZmFciiB@aO+bzr0&Jm-+WM+cG@--IY5oxZ(F7h3r_r&;u(Qz8*Q`Wecym)cT zO|^eG=Uc;-D2Ia)Q$~Brx()H+scycS*~r*mwd`7Bgzhkm_}K}!I6nORFpWQ`E*oot zK|v$*?07_{KnY1k`yC7w+ilpgWb7F?kw`c6g9ki0nVLvTNJpD9oV+Y@vXLJyz|ui2r&A|A?9g?W7Q|o9k64cnV7u>48Ef zBEqB!8MS^Ym?v_c&>S3XQ=#8uLyj0xOtO#RDbmMov`h>Kk8m)5tW- ztRmDz1N=xT0b8SamSW)bk$D}J^F|bQY5}6s_n$8A*wkH>X+_4u9*R~Xh+H7$dj@WB zh>E}jHpf)1&1a3=&%GTNI@T^(bFry!)+`_xcfqlk1a;J&_lQt9xww>2>P6SZ*p-OAX%I zB;lY^-zFCeUr(Jnd+i>*-5)>CP>SI-?`08vnT*}(fZo$T|IYU!**@n}VR86%wOi3F z?ZQ_56@5&Sg!UAp+g7EK=#45K!pHZ`JHiO12DB_^fX{ZYEPwnqCA~~0Cuji2`>~vM z8%3|4!}q0yB&oYrV`>(440iex0vpIvPO#+c>3?T6uYm4s$_`sAXo~7A0LbG9VTQ0OWSub)uzkl5lHu*eR4$mLdV%8AgJ!K*`(?G!M|MbTOR|H zSB(q5_WXzbb9tWr*)l~eW58+Dw>30OKRXdnMYgD$#4>So>FP25M=hpy+D>>%q4Sq8 z({r|tMbg33E4`7{FZWULq_JULOW_0Q%(MyKoh&%c_1~+A)?^;>Z85oF3Qz2iGr^}36+-jIYE?B_uSwqEqjCBPrGOjK1~91 zY&S2Jlj%l*tF$#Y@booPk(ms=iF=m_uJP?vQkOqRzpJ4w>mL!li@los-B6OmB* za%`d_eTEo?W03#_mDneq0BiTX!o`M%#rp}72ERAo^6LXL(Oa!L_$q2*;6Iy4G?d$I zS*k0i9#Dsh1opPx^xHg_P*Q)Bijp^c9w+Lj6n?Q#32Zyy;z-7-Oss8v)OB7M``^a- z1oH`+3mzs=z1ZM@;Jo090y@2Fw~n)sPEE;f+Ch+*J9MDzye&bX<)o2;>c;4R7ZS~J{tm1k+pJ}=|uyqcf zqXCe~{P+BI!!@t9P0-S9aCyP98OZ{vlPg^(QE=(`1SR>HwfkOiYeZUzF-v9na)bMX z<$mVc4Qgf5;(N+`(fEdw++4CksxZk52q*=G6Y8_}QmvL|*SYoha4}VuP&%e|taW@~OVtARAx#|}6 zpnyo@Uvv}ba1xA9L&}Stvy6x#n^@=0w;84NY%55}!aBV&E*3sOTaqbxY~19ocEQ$i zz~)wq5*2p_ItOSb|MZhVwmKcD#}M~At{Rl!3I-v&{@B?s`a3W5X2`nWIHAy1mL_6~ zdSFizcj>`XD;Xt+27cQ5M`IY6=FdSV`NB%e*5e?t6f^fg_5$zVipM>&jMCX6yBBNo?bez&X9Jv(urPtNd=5ju&9nzKNzTa1SM32x+?<*uo5SVmMbTb zp+?EyF81nu$9QGpR#&4jHZi#mcYA3#_K?C*nk#Ck>HJ4DIIe|xNRw@Ygs+2;EZGn- z;bn`%c7e86{&J0P@y!xvYQ{l7St6~g-fZw1F;A%cKn{V)7Fm3PQ<;>r#6;Q<=+_Ev-FOLplHVjVW zaW?~BPx|vz#@mjz!=vxP`O_HRO3o|_}__?h&1dN2~AJ@ayz@M&!!FZ)t}uh!_w z-$UGY+PJ@jlJ}Mc+xg((;EJ&Wrc}fQzSBoa$<9aPfra%_{khBFyzMTb!+08BVhcUb zWrcMEoGnvVi!_$O5&2MMmORPmO+uS}U(({sPq#0rap~dwHooL)LyW_&MKR)pO;Dz7 zd5|K*`kf;L!(w4t7R{|c;*f=-&Wxwpa%KYm`l>rt&UO($lH}Q=aS~xQ6d{5+WN7q!L{>z>zEv7c1f7QEQUz< z{F=R@(*$*uda+D|G?lTj#PZLY*~!w~5|y^W6%4JdTA>ov+UaO}f`027c`H}9KiIX- zjL(j*AxzKPR?pRY(?sNkU}yK^v*&1QtNL>Skvh8<& znoEY}B}0#M9f;c8i>+e+v{bG(rPMlLi~H&^g>3cKc4yDtgSz+Q8Lhvxxs-4*)v2)!5k3|Hl=ALuV5ANx-F0#>vGA znf1wmn;F64fu)E-jsXLL=8aS25y3=h4grvTa;RZeV+-gg?EixfUXpVhhSd=yZ{6AU|f--0p z0EUS7A3K@FOeQA>2a2HJ$M{5)0L(GN4%m1}fX4r$cvy|1PtOn)$z*(qtt-!btmMel zzG<>iQ$%TT6#S0l|20|Y@DktDLi1v3N4VCM=EB!VFO z*yjq-0dkb=l<}+x=;#s=a^)e=mEDMV>l@vW1N7?A7QguNw z_+TnjkixfOM67+7v(4zCH|UvB218(xN#bBHrF593!m6QPWUCWy9$6u86yBOVC!@qE zJ~55oL{kDjpBcD_izvR+b~ibqhZ5WwqE@$&!KQ2hU{2K*=N6K z)JJDq@b+`82e9SUo!2jfgh?2|*M^5S0;>&LMotyKZRz2VB&pL}R(*8oa5Dl7G zopY;aS%vid3kbUKDHz^Q^tW?0W#32H?SmCXFAie{4r3g0hehxQ1IC*3Ykuk62D5S< z+kNfkgW)Na{j6kHgnf|nGaTKO+YXR# z_8a}-!1L?Ijhf+C?O!;y9Q5v>orNiRy1aE~fy{$!y3&4TD4%@<%e6;4+ZnGmo zIROP)qp?f63mQjq0Yt7b`-1pqDQJpl@J^sKo+zuC7e{Cy(-?n$t!#RA?iN&s&~h>d zXavOeK&in-KL1nNlx)lKBO*+QEgVe!7j3?axcxxutDMfy?2jXrGKanDr4pwR$`giX zIUVk^y-gj|hTPtS0Eyn`6z)73R|t_+(t^TFowpG!=XSrM5274_{UgL}efrNoT8+O&qRXUd#@w+dNHzODFFhdG4PGeMX4{wW6^$nECeZJQHIW+UICtR@2k4nz`U472^%qx zXr*rs)hd~l0i~~F`@a`D40=vn2Y_!V(=*>Al&y$uV=|~T+?ucvyzvS5SgdiTjf@kg z<-V>Do7WPF%p_5~mUlGYx)?Ih-~MFGKW^w1KmkBf{aJnW27|6Z-uDPlL;27KgXLJoR-2twehwbfJEEE z59h9Jn4V2!I7P-dn6_F=dE-9q5YL*VL;IO}DKf>>}O%21~ox5)^7VRJBNeR8LrnJs776kFldQ%6PkArhNJm0v3y zu*ZB|^!yCawZWGXIZv9Z8JV3!*V)S~d$zBb@RM2#FRiJ|NBw*`J}~1cpekIvhnN<_ zPyC7gVUnWFRxEEEz+QRztLe2z{|t zwbxS)G2|SSj9r!-Q@(eacP~>~%2=d`t%VE<2`Rso%zmec#?oM-Aob;)1C_yLLuvho z-y~&B$T9SIn@Ed2VgnP@kjKAN?7x~>A`E0QMG5sZ95C z)%Y?FKo?)uRoY)SM$=NJs&!lJ=U1?@uPP=tog4`BPyH;63N}Mrh$2q4gJULdQGV|G zHWKS76oq`)54B9p%zv5w-44XQtOwzMcL60l+;Jwf69P^r&MJ|AawSQ+7E!*fjAbuM z*buhAnsUac1cz|W>$MjVtJsw-7hiq+0&@`}Ex2K{{E=Q;v<;i%>>gPbnlaHrdYLwN zMR?p@P=w=J6KbDIGd`R*kv87wMhpSE!A_>Hlb2NRjrIBWrQZ0@&u4zXK<(KnGZpR? z9oo={0XNOdWEyPE4uvu3MH0BQ8!g+>ljD?)lN&Sq@gm2xX zGK7qOIe3;bz&%*tndHWrE$XjEtj!K9G-=syLqyGn*E4^{BNp=Bc{)FB2&@JOV)l96 zELb`)3986uqDP}R*>b#>fY-Mr`V88oRoc^s7On5R9jY3{SXV--wF2xm;YJG58gQ=Z zR@T~~*EO$VqK{0K3<1$^^}|Ua5#l(spBZgF>6HXJVNzaaR&j>k%Kz|p?K9>A)4@G0 z?ZpxS0jJvVgZoAJ3l-n|>23Pt;y&YtqXe1#=KCQGtZOP^_@wo3*P z?^}q+D}1jspUaErXPR8FP(1HD(^wJN-x}5t)}voG9@y(1%k2y)siE9VY%Yuskt2b( zNH)m0ZM9xk)wbT=3kQpA8kCWqT_%WT?AwU^^x*LCo~Qt5dd41by)gFv4^%SP-WfTPBuCV8YA318f#-!f68Bq7mHf)(AE#BEJXt%rxi1eF44z%g| zH^P;|p`?&jwxLLBobFw+m$eur}G!5=Ikiv>)#_Y^$ ziargis={49)Q1T*MQ)>#yglDMRp6{xDg6ZPe)81h`t<_eUz!!pmzk0sDtFC9k_M&h zQlMf#iz2>$bpHlhpo`d)XJ^}-xlT|t5OXK5#@=!=`FXTIzV+(cdfUBCkv73U>p-8! zvB7qKJ$^d!DrY%psXo5+FwC_Po*ZLqY12chJ_!Hvo z>bt(J<7d~Wk0yAdqCuV!x3m55i_`1?+^{5W3kchk|F8bgpZxP5jKJ3yApJHq!+s(XFvhnV1?Dt5?kB{>wX zq>lh&>Qs_$dk~D|C>SHlon<&*Nyt z#4FoGic3fMhkQ$h=NNb@DlbeN)WS3XjxBpR^FQeo&-p3X+rSXX469sK8ms!lXWT-b zg_FB7a~zTp%RgcZN~j7LE$$59#K8l+=rN~lYF(6QwN z?OXX8Z<3q1zkTU0~T2U=gHOOQwO4sOHnj^l5Yuf#Hlr6V1d|RIc_-umNlvx>2 zX-7`x7ZB2wKu7gA$>mG}hsyKi#xnEy(Z!^^v-UF-&;rzdwWgI-Cp$j}9>lGa@HTZV z=}J!A(nq`K*pu++aNH$znuAs%xv(K|U1_B)AzKuBjt}sB=})8*r;D9ggViBIRX{eURNn2Qqo>EHf#ndG(;#xNns6@blThz0?RoWdS_6v1U1>4}nQKv>=XCqNhc=uiM4->LDeBzOpP@ ztFkxgk2g=G(v~+yTN9QMI7?Mr88i5Ki+HrvD|q6g`ggBD(f6!q-@v&QxX~-HMCa*> zl|^^Q?|C$U_Ny&o0FpbtRgvsv!|abbzrawuj2aF`CaxCR6|<$hu)~VMq^=eYzE~IK z?Tt>dVJXp`6FrMsNr*k*YZ+$E)?h}UD>k4x1bi21@fReUbUcJl00={fyOS7|M|oWw%ePp4eEI8`|*{ zEdR;-ABtGZF2EF|@7__$aP1l5fTuyV@J0o`nuoOK{c}1eys<=RzTPNY!3OI(q!c-% z8(^|`{Xu8G*CP5xM+W=*eVV{U)nSLPBi+E4srM$9O`v7u*w*C@zc#wb(A7WId^PrT zb?oba6zuroVe|KPJ;#|!sO7{rUGYBzC;$&JRi$U9dIL5V7CI2&Q*}NP5=nApHDl>b zVz(3c9X3UPY+IGZ?a7W8NiSHI3-$2*&rxM!S>HaQkaRR`QJm8|W?sC(fNz4XLn*z;3x;f5cr$Ysqvxm1`V%kTJl=MD! zJr2CMtq^{F7Kt`R!WRPuc$Y+k1`b)f)MMrQ)ucn7K(^aiiB+65*g_jLp}cR`@o^YG zn^Fkcg15A^aY9$uadO<=;!+3ZNxT};U#jXEPSTFi65scq8D>a1g%l4SE2d{xg~Q`8 zZIKqf-7i8f|C#|LzUx|9|G+SvM7rq#GJ>4Q%YbX((6;C6?+qzi2U}2g->sBx={vcm zmhv17)QuUULz}UMBHYN(x8MntgA=un=uzXZungZ+s|INGTw`gYWXL+?X4ewx4i(>_ zjp9YDrP~fjL7vUu*xtX}M#%%L@-q=rNmOU`LvCe1d7uU@&*i(im117}GkEc!+X)2= z<2C-l5UXW+Dt?U{UM$ej_5@OSugu-GDz|Axcf96?d3Hp_++3;Z7=6@vp)|DESqa6r z4a#Is2K0?P)zMfStq(R`Z&7_$D>}>*xG1 zKG1BjH;vP!MTs|dJLO;e%)y_UWkMoZa_o!fsAw#h)W|)M7gApK^51iv`Oh4a^Kg$s zExT@(u}LwWv5UJE!BIO4!e{^-czCi>EqkVc14~+7JYlE(e7|la8~$))J|^U}dvKPI zv_+mg@BfYQEoqFW6c7c{3S?Uj@oYx%1x+zO)AVscL@f32ednYNeJx@W^^Zkve4>Kz#JacK%JWmj3lqhaUu9~aH z8GTa7a;L_G(F7e=%Zg zW{@!s8rCpo@)VzU3wKm?>*cj#A-z)Fsf1H;ySM?HGhEgWn@B73Ukr)BEa)*!6mT^_ zkF$4Ad*O+0Y9tbQRmL6xzYYt9{v*X0?%RbK(;L!LTEQWo_p*FC^Syf9V@4M0(5kmI zpx5e)MGb!Zvi8amPg0ocN;Qs^n67reQ?01k85uWzji4o#Wj^>l(z9X_8)O6o$V;cc zHNc`XAV9rNx;is=GU!Inz^h}Y{{mNyjujW)d_TQ`I322iW=I^Va^j5I23ZN8OMA}L zTrV>s@(7=jp$rK2)dkQuZP?0D58*DxcH>Qv(d>^k`Brdcl`tR)RUB>_TP>|Ab6d^wA(wReE8yUuC3W+e53u}5LNtf@9l0GwC}=# zO{N!l2F9ZCn)Zgc;}nU_9a&tbTRPH`_o96t+d>byz|_*h6t1|WzRQETlo#?OGZE0s ziR`U-P5z7K+9vkqYR@u>}E;WNPkPf$J5mte%iIop2$W^P4ic7wl4u_p$`MVmkXqXKW^)y z7MMs?{CGZwirR(xq)uA!eYZmY{1QNh`t{pzJdz$E?$5#UwORpu&JQxBmY*4xd`rzN zY4!DY*yi?!KpsbwUcPZI3DJ6JbMWr?B(1ZzcxOXrR5eX(|Eb%yYJ1%;jC~QZOpAQ%55?o zpK@6c#iAb_uG8H>_e5`<6J4sY21A}ef9LB)^@vqQd(KK$YW?axoY>N>fiAZjiAM-k zYUHz=2%-QF01o9Ft_yo+pTIo*N3KMDM|H6&n!jS;*Ao&HRh$Qigak-q0LXa!0je5n z9mlh7Jd>vN2MxpxVb~i2DwRZ$10zamCSZt=P804^prJ^)4Om%3;d7wjCw})E)d{C! z0?Tt$1GaCHSRh#iTy}YWaHB&K5`%6Kp|Tj>FO8VMztcr8(jd=#HCUAG*Fd*0I7KaE z01~|z&Y2}!jJ8mNJYz%8qsYuVz~&hQP#Vl#bZ}}oA*mee8GA9HYiUAst5>7otLkGB z)|q5VI=Q)ALiy!Z!suj@e~-^sJZppy-;F1E-=c}GE=ZT$tU2W~97mf)Va6n!j&DEB95xl>S z(1mtX5L#adY}o2gkBD@^ighF6bq>o(RINkMHc8q^YBpora4NsN$)*_};@Qr?a6EXee|2H^*uKg4}hb z8RiEjZ|kaJN_2ooG!g|dFR%FMDoh12G^t6ri^~l zHCZjyt%BJM76*BuqL|qdOO4D1i;oi`nk@>`ykZEQ#tKXBwwsZmjRVQaf77pR_W!Mw zLLAastM(JVn_Vr-T|{on!fCah%ldujt%*t#R>7Mk84_LYaSOjPJXVl!AJ8AIfc6t> z`4RyMF2I8rf83N2h0J%e%$huN-9AW&l%Cm=q~O*^eIs+|1WJ3&Xh+gX`I%D=U3(y{ zaw^QViS-lU=6t?=OjSlJyagN;w8Ii005j{QM9Y6}IoFMc`lV%GnJO-?L*W>oH_%Pt z@%WO&KW2s;;!MbfK8pAuvAg9m0+#E`&S`clgxmpzr|w1{|28xf1k(M3sn_skBbwLR z$1E7};mQZ)FqfE#+_pKwP6}X&UURQi4e+Aa`20{R8vDmC^JIm7N(|M|JP}L26 zbZvy2xF5`aj~bZU$pzY#G6GEuc|>D5t}3W0X|#BQfmm{7H0B6XvCDX>KaA1O+O?b! z{F`3P7~WO0` zD@5Wpqwv(5F+erV{K}S?GjP}C9=?T=haV+Gu5x3Czh{d}Fhqr#>LWf<4lw1;3=@VDp0 zdHG$XEM9CjobNGnrB9>qw*M~+o{fAK{`aKgC5roO%_++~m>DB!C*qQ4!5hnqWuIo^ z*k8L)cGaDoP{#KF0+%6Iwy<8^{Kgv#muTZgGhb;8hmg72?$BS!Ns7gRv8Ns?>;$R; z0SKJFVI!bwG)pW80bhU;%d9&x7W;f8$q=0Z`c5Idh&D#Qn;knM8Y{LkC7v$p5qTdq zAN`cf>%0Sg8^g-%vTQw3PmRlkRXgWx7B|<>)Qbx|wn2>e#<0%nCfnrw--Dy|ISngf zE&ggaErPK0t~#NVgL&XjR2~Q8=<4XzRQaVU+y5y#F2!|mCjP@QDeW4zgi>2af~V@|_qa-%q~_H=R?R>GLsBX?g@e zyTg^JdGXL3hT=_o``IX!`(Dll2imgqizH7`$^YK&PU2BEFsnf5gs1gU4C9Q8ZTCdb zd)o=a&Eozo7PY>R9UbtS7+UTB@~2Ow`jsJ4O7dt>AEj=4wggp3O`vV8GqC#%0LktY zo!>nycjE7C?m*jth{ih#*>#5@40mna#6Yt^anA?+Rl>6)@X-q&VPUn$a1oKWrKG`+ zkqR^xAQylT)QEy?l}x8{;a&6fx&y}z#0JbWo<>S&XE=Tn*;|XT3#1{DEVZ$FG+o}A zQ2L+42tY@D6$Cp$H&bodRkU7et+R-QEPxZzxwa9~D0_!vFU=O&Jqi8+KuctKnmWVa#=NI**H_Z*RE0(=$-JN;}kp~qz31mi_XuM z4YcMSbAfl=7~w|pXbNnBn`jBwqHh^@O0L~LTYt5>D6?#7=jU*i*E?o7E3^^G(|=S1 zeQvc6d=e~$ji9Y5h&Fk4#>j+rKbzQFJu=5t7Az<_G_T*#RG_-UIy2IelcoAHq|QrN zRYInx=>PKaX&>%tA^-bRyWosj01;7-Y-r{uHk!6xQY2$0tSO#UwCSlbmBp8E^Y30y z4z`^QJ+rj1myt)_8ufng>a>tY=Hml5cE$H#!K&IYEPg&uT9N?nt9kPS7fW7i6ynE! z+f%C_p4H_?N@2v_$2ISMUN6GKk@{PPGm!n-BeJ5|MVpFW(VM7pnZ_ipGE5>}1)74|=CWUgdFQaxR1G_?M!tUcQR8qZ;y zvKzZlY2j||!X5{#pRh8BJivI}&NXeNkO6g^qGa}qIz-Hg{&Xf&mBsI~cd3>)aAl(7 z`LIcV!v?8%UDi$KoQ*Ih7YybRJXvlG>ODGxGLilnOU^UK;-++z+6}dXr;YL5kHyBB zRI(ANkW$lqiz7IO5M1T{*pK0AL<`nybjg=%;e*KPk?TCU-SG0|+clW>InG226hIKY5SFtX*<&7B4zWPn~Ct zdtp)$bix>)!BB>#5yUS-D>_IZ6+gp)q_OV{v8Vn0mH9d9q1N`KFDGpz}_#yHjB zsyTn2UA}F>jlS+J^o|597MDbgW(T9;gU3pZx(8#}E4k^5bmn?9YblQ#?u9G0(r;ZO z=cni(G1V>>loRVdR~D5~fP3p(wJK#;x`1r7#%P6p!Qv4`7?-QBWx8+DFOkYKbi-UT zy|uftl26YH65V$f=aqmfg(@r#-T_83MqPx_(lXhgIN;kwKFO(yniF{U0|{rpYL z;uG9$4`XYyx{~^E5@5y51i+F!$!$dY0yqxtyOKT+`8J7BXwfZ5^?VamXL}e}(n|{B zEosvhy(h^3I>`35_54>HT4S{xyDk}EXp_*dGt z=`O$mv6H^1%Srz6$L{_dOO3_76k`AP&~);jAV^@6 zB9mNr58=K6UU!u$1p_S9GbMRW=Gac}#uM0_TDaBhC>_gSts4;=6NH##WIt))uOUt+ zUC7E+%6W>_^_4FmdExhT4D~!8+ORH;9yXBVKTl<{(Scl@8P~2;z>mf7oUrCfly+P@ zT)z?bi#hUdM*z4H_5A9eONd;TfYM2f^)WtI;?J_SY~3!tf>p=C@1E&2 zC8mChJS8^WK{xy5Ev?Zrrwx^~Jsr2kpxNw7Ys+gdR8Z1?H&-83%opAbuU6r%r73^z zd5zNxY_kBmrXlXD<;p~`*Lp#f0p$Dg^-%LWXwFOA`1Tl~9#m$(eh zX5?1k6kBT`5<<1Cv~d&|!EnXpBUg{})=T0?wCJw)G8Vj6AyCKY<#`z`hp4l?9mnS+ z?dxx9i{H%X2%*fy-b9>V1leQkt9IpsdlpxuHlV^-rF55!iux_M8}4yCv(CiB)Be}- zo?N+Us_`a-vqtA_U>XCsHxx?ZW^}RLbK6#ZRlI(+GdjLQBaR zRz6X7cH+(Y$G5Ky`+#&EPH7jz)!=7>Ed}VcWE$7lt!dyB{(fU~i0`><=;@j#q@+gy zPfoiNA&LIhQqb^DE6;S+|Jh$RU&irI^C6My^iSj4I$Y$jwLx|oZjMWIx?o*g?`xTJ zxtQ-}B4fE%`9`9w<5~OtEwgkDLu}l6Ho58)3iB5aG9TN1I}GMO6Q6AqwPntc`hVzS zk@8W=|0%_177d~d_Vv;8ojw~-ndavG+BS?19kyTob)x4DhsF=KjQ;^5lrf4T}%%*p%<&XKli#Pdb+4O!rAR@ZXwyhy8LF2+z zTOp2HwqYxQ*kfjGb{89C>}X@GUiL>L=v8%N>V1zWG4Hp0^qe(&6vmqFkfFfiwK5AvARC6DuKFA$USNQ_JIkQ- zqa{HwcrPgZn;r8%8`g7_mpm0hI)Sd7q=;4ST-f2cxF zCl`bGGfm2{`mTGH^J2!aQTPh{dO>+PAtS@wxhv_|qB|nxQg5%yNrLfILb!lBjvx{{b40V3eek57kD9WD5Jhofq0<;{bMHUmPhWshk7CD z2fk#;LObiY3^|oBbaSE|SxNeux{tD(j&~7KJQ8V&c)eK9rw;9Md;>S9O{p0Ipnlr_ zgV(yr*fU*e8Th7@_*!fc5$KR}IFpKm>tIW7 zD1R(@3q@6H4C&TeFhCWKIP%Tm9`jpCR)(ua#kL~-buExq{l$=U>yE{DaF$|c;?Z@$ zD$D&^HYUg1pIEh}$Igl;fDVaw(NPm8~?5}y4 zeZNf4QIz!v)vABb{v9DFOX%RK_vlVEuffy7{^V5nW{d6^k?e+huC3X)c4VPhpKDO~ z-ggt(PiCSx%^Erv+4KyXp~u}k8O(kEtG@S?n<;3;%J1YiWZq3FU;(<=EwA3m5kjNB z)!IB;^9JLr)H3gM(}bclz^B~z2mUruw$iqT93&)VJkuz^yVK99nQFY2slJGugA-d$ zjSo30HhEVQ-^O%AF0Kz%s9F4@7lgMHZ8cP{QX7J+s9b-iLwnFb{r`p1vUw-;jwlX% z<1pU;?_W+UwQ_+kX&Bsg{M~qcQomy#mrF|Khl_6k@16Dj+^Gv&3RnGhHU|I)xvVa% zce*ODvO|v$;fvI9?crfh;m2+M4$JOw-}zm%@53W>2HN0x0`UKta%rm#R!bQwJ0Lrm zihOM^@K6y6oSdqDjjhL(2(`##oxgE$iL-Wup~%(RtzPL$H5!`sZ*L*#GnN0O7}V-` zxBNOTt4Sti*5enFitc%EOb!7_n1xlp7J- zKkY2802d0{*c%iSN&5V{ifyrO)F(-~axs}b{t3g*hEXe$@^`@bakKh6)p)NoZ4|QC zSAozp24eL?7nKcXqqjv;yIe$u@<0ILmR~1?fbU#TXW$5Ph|Tgu=KGN6En|ESEg?`6 zd~-=RgPBHp+uq+x8xfrsFhfuwO3&ym?`5KZaD81w3E7n+e_htRTJ1;`f(ME&p14ac zhv-I?yjodIK}+bRWS}Uo`RLW!rJ3T4tTXj2K7V5S#~WRRzp$j>LadU{|9s%SV0AZ( zcFk$Xj`mi@-V;fyv(v9?L?Bau^=jb_onk~=~!dFBz?!?p19rO6+ z8?0bCjEt^oA4jttnlFkL(cX-q_sL^Yfe=k;N+TJ2ppa7BWf=X!iSRLQP_rC$7+{E1 z4z61uvrGlUXHkhDdr$H&;g*?!S2G_2?W)D zTwq|xpmmKT!*o7Epylq7`Yi(}h6Zo>c>%!ow8xx@(M8&r?gFpF+v0R!aR+QaMADeL z$V3IJ6temY_p#?0D3CV0LJTt}1nOhhBn*C6Z0fXg)pr;*W0^d3!+l~|nIND#(lc>S zEg&=31>IM7g*GGtzUcB4Q2eTW|IJsU(M7hd@^4BA{P6Q5{XPd4^+ufd0j43HvXmt( z*e;n=NZZofMRftg{v(>WaJzj(79Amp{oG^s!uhj4g(a~b5C5MWR&_lerq+|UArHM^ zMhnuqnpuOuP&KXbn`B^M-5GehD>|yJd^cqt44A?bMNbm_zMZw>=ZJu^pLS~72SaYv z80PZ_blOJP!w_8>V99s6!a&vuEn~A4GXx6;$Y!^Wn0H2WH1$1j%3G)cce?2@W*=l5 zk042IoJfY)f~>xYP@_Y|9TMATnkihQXTv+nAZln&VQxvoY~zs1?R9<0gf;S;36}sK z4viM&KslUvpudMHJG3)G(y(F2?{pj2_|fF{UD)-3!ZnvPOj|+}Ks~e^qGC8WFro=E z{jRVLOSrJnh{$qJ*zxCQhTY5>*GV>E>6@M_T^po07BAXEX^=#!L(Tb+LeK0IrSp}c zF(1@kB`h;j!hgdS&4{38rf6`6b%n}v8K1z)qn14guTD{zC%GGz!y-GS=}yPR&a!V8 zgAPa80V@1gh@6kN86->sR3D`OFJK=RNrzCG4Lh?{TMJlKA1ha9WNh86cU65AE~4nM zC0<~Tm5K5Q$Ld~0c#?V=>lDXuAHbyEb&O)^<{}hC}Gm@O_ zcXbq?jk}>~we@33&qS#Ie3c7|Dij%?@6-sHYeb@qS6v=E^)-Zndk4Elbl+ zXnQa%Y>Fp<*DI8h0fatOz5!xN_(AdSK}K}}uJY9dZod_g$`OFH=%2prXVcL49_w6d zf+5uDqs!;uHIHo||QcYNf8|VZm4@jxgQ$nQ7A}}(0&tE^7jWCO^d)--5;|QB;r?1 z#@e&fOfN;% z#i7%znZ`6ih6RlzS}!4Bns;>1OpuDExL}jZ*gY~HZ+zQ>X0V$<%3r7Jxw`o}8xHpi3U0-x%?SV)cJpL(BAEHmC8M<^S$qA=#@%_a zJjD+cNtULeKS>np;2Y<#`z8M`4T)cN~ne%PR`aO z8v|cD;d=gbqdCA}1OWMV#P_vZ(Oh%&jGnlf^GXSG3k*R>;HLNJz4fe9(opvg+)q;> zmChFt_p6nLtYzn%%l?=Cc6Ohg(y|U3ixk|FO&l&W1N|r1SGdMGpAlU(iW>{aj2$!p zd5lKk)sz$Tq#bJOFCnqC?{O8it^1}j-Cp)BUIO%P(Bx<${?rs=R z`y}};6Ub{0!)0v{Rs423jHpEKHffq(eE$RtxZga9r(btWQR9?r)U@FSaC|7{Ysv<; zz;LT_+koaCzfEQDJQ&$s7i=+8OGg|ke0Y({*$U~dpm8{1uXV_ILghI+L*>27*tBZS zhTb^*>l&{ZC{Fkkp-D4UpzjtU@_V4kX3STNjF#C{I?0B(euOFrhxMgxxst~mKkKX4 z9vs?oO&_mr4*l!7TA9hY@&OJo!C(0vRxIy7xv@WPWkV)zT|CA~QygR2go=58yCgHV za;QPPqc+=zzc5ztcNZqN0}cOc@$7!5rp&2mZ;}%V3S0Y*v)1l)GwMO$#42UvK2GC5 z5L$$}-PCikx_A36(&Y=_-5auZt9oc| zkoW`gdo?QG08!pO1z5ak)I?mJ8ve#$fUpZ2(;C1~!oGvLgjd-f}ME z#TN#Q7YHi=(Lls8&j0L1LI_YGp|*p*9xJLTIyD;%5fmWP8!`7g%5433di@7N@tlWv zl%0x2oe5u?EiaagW3Dgf%Fnxayv3LE@;QBkT!h=BiVaCeKVvgpLbv{#A3&$hU}{%E z@ zjH*FG%;|?+m#Cb;A2tl9y&moW#AyNdAYDga+n}-&%3LMd*quUAV{;v65Go(J!&ENg zSJW2w*c^+VJnu-pv*?}d3IDTic7=cdMFdY~febAu*%8e2LQmB~jb5^hNq;tu)avM& z2xrgnM=k`M6NeF=q^Jd%0s-rLc}^uX`(e=dtx(nJorjU?%y{k}yYBp~cNrpf4z_hr zS_$EIH+Os_*w-HYTVo#&2%OZ9TU}kD-MwD%p_{1d5>ZYyO%A?VqZqdPgEj)zKGCX- zK0Y%FJntI+TcWjQ%eV3UzC9?9JVg10uOzM0#P;|uTtOU(JKfZQ@dZFD{DQ`$8@0T)} z`A2P!LX7Wec4N6e&TH>>@;pwvOg0VqE}aa%UIaOB10u65&BZX26s}cpn>}7#-3qc8 zeW7>azOP(g?iaDw{X*&zr2;*12>Cru&@OGM9bH|5=1P)-)9Z52y?*R!;wywj7eJS8 z|8aF*NHb&^Ve(g_yf|g zzJ%R2h|72maCrw^K5tyjt106r8BlMH5|z~Rkob!CZ($fmbH4fr)ryaEr}Xv25n|ZE zZ+Naz#r@Aejl(;)Oe)#R>C>pRc^@Fj!BBq3p{h$AMrJ6F0}qBu2Q4~=;1}<~YK}}r zj@Nt}T+FCz30zE`6{Vj8He)!@>Wcik+_4OsxBSnki!a7(tVrOA=HG#x-i@3P&3C}# zLf)Qt8>$E*v-E22gd=oJLkSrEnTViKhlbo{#Sjf=EG%#`(liaW#5}097zLG+(lQW% zH_M5>`eS!KQWTwe;&Z|9RNo;QV;{x6H`Mu@2j<#LIs#H{4yWD1MQtSkU2vsNi&5T^ z2RD#|DC)dp2wK?#U7w>deXQd!45Z+Mk^}4y_8vAhlgeF~v8aU!GV%U;s^}O&*9{jw zOJN?X2P9{_oN$26)34{V&e=l%%qtXQ??DLH*})2n$00}Es3C6%?OE%=vRy?A@quMI$;EOMqp7GzJ8|>mybi+VwtG0ob~irLq5)3oVNNb% z0h57|HRM}LP9IyBV{_Sv>vX9#s`Y%OGd8~OF+5h2^Uy!$&MC}X7mKfl!R*~hk zv##Y}Wk`pV;2XOWotE}-yO(X4*c`Ci(SbH&KHC(KeF#!XZA+8W8#|wrj@wM}T9*AtQ6 z{#pK&-0I4_`^a~c)I6{3L^#5&(Tw3h*K`STJSUJB8BeC9GLqxNLeuNu<2zRU@-J*N zb)Q9#s7Ef>By7;hFeL7u18*{-&{Ml?ehp4j&K1gnUxDAqr>m8F_dZj&8#g5rr)ZMG z$Y#&TQdVc)J3?=nMNT@oyKwqL9+GFo#us<+<>t1m#-vxpV)E`h&%7LLiI36hs$ddX zeS8SBw&luYIZRY`@*gWF3VLoCd%t&TO;op>Hv$^#hy3g`hGW4|S^Vbl?zJ3qi0SI5 zJ9_n=XZi-l%w|bT$B_*dALo9QQz$zO@qlX|_7I80TJYnmt5g_;4NKj&{N5fcGWCwB zTG>tt$QS{eI^sNuIbX_3*dB?c$q6IRa_iY_#}kY-DTdbIza0YJanO=`O9wp9#_Xid z{Sc%n83i{6mHO}KO%$!P;d{s6QRt~QHPHE+Fr2?`^X(6>(|)>`d77~)Iez>x8Qo<) zCw~lZBYBejR{s7f@~vie`wX1Rg#fGQ{ie-V{M>z{*C>sD-xK+c>bTNfz&3Tt;3j{0 zN+L!(QbqIBx|SBNaiP4Q#NV}SIj`;KZ1Z@&9s3D5@Av5yJT~?JqD80GPSmuy-DmK>@EiuO%_@hzRkgb+a5ek|Z-?hI zan8fO*_Yf_tbs__MJ0D+MoAy2Dig+DVB?C3aeQgW;|Rj#lL9uXF=3l}GIo3pC~x1a z<0no$0(w>becB~=Zp9&)*PBOm$P~jT{jmU)_BaD z0{dgf(WY)DL!st|9r_;X1SI6}jCH})I6$T{heS@WkB{wtImNm)WB?84 zvOMZJ4Z97-?7_^Sif{odX)U(!)!k~YJD`BWiWYysEpULN?OoJyOB?Dv6YzbT z2%a!b(+^lk+*}0F1jE<_;oR8FHW*-{rxp(43)<8i={9kuV3g^#X~qFDOcRm%U|f%- z>k7fxBPNC&u)+T{6v+6y@LEHDz>E|gvQ(tm_tcxWmoIAa|=?Z$2*H#+pG#6%ywtlvz+8+w7&IvzX zk>dRlqVrZ2pAG?sz+<_NGqCplPRmf*&*<(_3Xvj1CUy?-8L$syaGxtf$?N?atgzj^ zG#MIxY{9)wQ#r`sSgk?*hidBIzToMbkaPvN#LBZK!Ttv-r=WW2Kx zdb>A{p0blCu(8y4AF-NpRh)Ktq)p?oIlJGD)(zQ>&wTtVPKjCRsvOBKB^?ZRUh>V8 zCOv*Tl&}?RlhsB)8>;J6zX8Wq;kg&%JsZ$KwQF3B#e9YcT|WrT|8Vq9{7<@h+m`z& z;wi%P!6f2cveCWZugpsCmH20`Lvw`5HU$v=>Q{deza?(>-%8h47``mZ?l(ua(1Drf zw{iOGk6tSq=<3M?K|_g0U1fGWyn^8cyv zC(W#(!YL3q2|ME>TAItzQvJj}N2)llX(x=YW*)sR_83AT6?4Sc6$ENTHp@<~>M4QET?+`G}=``oc1EwlmB7JR9rz>i?k<;4hd^Xn@>1H*Hg4bibSz z&3_9U5u~1S<+)T^>wEn#V9Ae+T0!P!{f;dozu|b$-eKR7lHL~6cRz(azm9WfA0e+P z841dR$6@?k`ujIko{wzj_Faf=PLFHJ7bGW#&1u%E=({{Bf9W3QytM4?mh5OaGar|d zH>NfH0jCA4L+M{Q0o3M-^`okYntC0D#?(8ImH$bT=e5@a>ZfRzO(k>`3`SB)+{$5k zPjkC*{hjnoZ;MVy$36! zUI_6#-GZhCAh5s0Lc};+9mBG7`_Ighm{MaaS%PlNKL2m@)Q9AANZ_Y>NlC$k`9NW+ zx4}EV^GZ)NbDrLR=*7|ayE$=+YAPN9nWQoN@>;TeU*M*y(T*1OLk5| zr_mg*SwQ$swefVL3;m8Bg36}*>*Q%H@t@J#e!87G?sSv2@@}lP4a{aqCN;p*54ct9 z&?L#95M0n`=d6FfdQ8P1Nf~v9U3bm;cHGkb)*2eq{@Dxc3eiwqFF`H(>uz5^V2l75 zC*SL3`N`aK4*MwBJ5djWb`|0J|JRGxc{NmD0C)sN|KK*1Eo<+iy%i@~z4g4bzSJb>Alm+vbTB46;$bdklWoxs;;pE(x!p(EwNe0&aXq6*#6x~LGlKD4Yx2+(u=Oi zu8jY&8Lz~LqwB)aco;X`a&+hgrCx9@6DPGEQuPZfCi%R$#T0D|XcJS#`E64odZ~RD z{ZmtO2g9xcv$a)K85&Py zF!w=8>6+NiSh+}hM4hg8ju(agHz~_UXVG=D;det=GOOQhrU##wY?} z_k(5|+(HI6l!xJ{vi2$D8-KR%Yu%sYAig$hT@COuvZ&-&OxqGVd~o#@z-jG)5UKBY@{{43!N~kJ68wkDqouwtBbmP zSxxi>m|2xCa~qY+nsFGc3N2-aCP7TSoKJ^Sk79&rDz=rIK3a7m7ZZrY<^>OJaO(*= zjx2hR4DkYPLu>js?!o|GO=-lP`cc_ zH$2x`nZAiz%BFwlH?cFBtVc?j$>kJ*nZe1hdt`-0!rXe;wDC1gF=^`bdYCN#4d>=; zv5}{X^*ftHdR^0+qk#Zi-e(HM56aE;TcDD&O|a)aCq9~4v^s1FZ)F2d70%I$>dy>Q z3*5W&3@RoLg}kxqw1z$5|CXYjDHD^)#dXNjr2oaqYa4}n)x;`SSb4^~{NF~0$G-pv zTBKXVJnBXSUe+L|K;I zi)^DmH=xFR3BRuOn^!fWLYl4?eOfFs@bvite+X&K)^IWZ!yoS*HaJKFreieJd#**K zEM0N%kXzf%zIU1b7>uEDW~LnQ^RBk^vvhv@9+ouv8tE=mg#dO?0}W#gmCknJ8Fe2Y zSR-!I;MP&Mh;dd|RVyuzQiY|0!T+gz6=@bDktb@;VrX4e?vh(g{HSKbK)eYGDT7*V zX)zqu5+@ZR%p^P=n>UHO6#$YJu+f?kj^+}$oo{jiy>G~PNlE$U?FIPMVRs{f+||Rp zsHnqQ-o(-=t`b=NRQ%x(XTbc1uylDJ&2is?!KC?rv#;rA)NPo>Q?@OV(l#N1b%!rg`E1rh_xLW6?3wUfi z7Yo*5s6=2kiE=W0o$PdKB0{$W6ci#On$!s4^D!G}76h3m2tb6S{*hB%B`4+N69|WV z%8hU+0qhXdAc0@b9(k0CS?@bkS{AZOChb(eKMOOAeGakWR#gT^UiL(P4oaJoFuxnP z<723mdC(W#2SNbs5-XG~99JwF0o=vg)W9}i#^8g8hqS`)vW_ceH-hdR%t%q5mWS~B zAN2|)8dOMc2|FbIxM7jSyCFToi|DL}e+N~3%iEv3xn4J`sy|Dv++BPPoJsxoCW`4# zu}C;JM5KB|2Bx<<#EK@6N~i3nK#&>$xYN422iaO?-2>$lXcOxoqADm=ZvqG{VEFrQ z4w(|DV}JtfX{&%I&^A(YRJDS+2Ub71eSG zQG`a85Fy7U?#6qT5Ha7=hYZ<1B37-r4?qcGg3ds~ z_-6$lpw4{=alnWw(x1e3#}@iTjU1s14J=S($Bg#1O_lk(Cc(INxY)yZb*!u4c-JV- zVYEmXi3FF6KU&|xJl(LWpcaayjn;`&^U&CvHb#&f`BKaIk7lZ3-w24-P$dIk@xXSP z*6U5M7ZEeDk}2OoA0%=G087vBE0-7N^s~-Fp$^<(XAL1B16@z{8zP!%^tlsIl#>N%30!z*#XEd-2)072UJ4uGCWNc@r@q7hc@$It1S1%H*%0L z9eEw16x$jcoi&GFMWa%YeA@apj7T#4QkU#QgrO5cCUin#irxSZ1KAW!zm5&^nA=0g z?`4R5LlL>Ufo0;l=Or~r2);%~eh8mMD`2qfyuC1$V0J|McqT-~Oqr?S!s}*4wvOnq zsbbX>GS`&{Af1NsTG!qX{=_S_i!->E2qiAzi6aSaU^C{u`D&&h1_5Yy`VJq(?S^}@ z+W)I~l2k*s`5xXDIWa%5B@!TF8!GO4-us4GFCBnTfjP0(T=3IE($P-{3eq!PfU;LY zQL&|;r^mn^S=LFm+Tp!K0QXgt3PBwAl_MeD#(df1fXtNR16gwq`a!sJ#ihOPy#r2X zkjf0t>}q~#BtnT<*bx=LxoJA#+GTRlU>`UD0j>*;?R(RGBRpm|6#uyYwhG{2z8!Dd zZ^7EupwFF$hv3!qqhBiJQH;Vm>cjAb(+$IA}u7{`+Fl00@GFAm5iORc8tDy31mh4@xciQf>Hp2_qI1* z!W&x8q8Kc9pSe+Z$gCC)?u3No@83aig&eSI<&IL0Rue)8(R+G?^IgnsXEDm}rWGf} ztv5bPU5L~`jsvaj+_3)OB)dX0=@8ra$HS=|?9c--2?HSskr)J%68*iRl_P+hLX$ks zA>IEJndA=~=^)$-c0-eWrtH05JLF4(;k|$UdG`Kv(TaUy3nCg95N#Sp#OrQ9q^eih zi-_MarrjSrFes_vDE{sGBx7aB9Sqz6E|bk7I@lB5k+g_P09HDt%lOoAfh8^s{`QyC z8nl_tF-T)=afA=~ZpljO7ySFgF4b2x+gs1yz|_t7DWfj%b^k^!SS>-b^L$L3*gdX1 zv4t#Ji!Zr#E$y@@JuP)7m08b;AFU5lfL);d7`ohqYPN2gB;tywyY>r0|L=@5aEK>LJEDQWM6Kq zr~B?hPIC;nElz+#za2ZB?W(2E4W;}(1B&VTWMxB~ljjVB^;QrrcbnC=`*=Ns{s5}Ivuw9B-e#~%g7QfO6v%Cciops+5P~8 z7&&bqnfdV2!XQ!oQgH;#jXFip$)Y8)nt(n(@)nPdNBQbfdo?YFc01%3U^2rd5hN+d zPb#B(PAu^(l*tR{bxaFJyxlk=K11LKv&7J)yKQ(a&C!>Tzf7kgj(aMyzr0;lWe3Tab$I0{h0I_4p_XLVG$G}VJWP=l zhop=#hcq_#d}s{e2#XLH8i~;zUzAF$2%reQiR>#N8ez+$_=H=Ni@r>4%ALnu%R|HO zG*o_n5Y6bKa*k|uoPAI3gOZV~UI28N+Lg{K9U+Y|ssad*PbxA291a1z0YU&5(z(y- z403&WE^R*EhWP@^M6U+s)*fq#$D30e5xDf3boSwo8t?<)5DW@wDxDb8)(e)q``J76R$86X~b0IpDpYGS@*{l5$SSwZAmVnY0FMt0qG?@k`I0B4(`AQ-J_m8pi=w90*%_r^88 z0ke2jf`nvWnYEUgM-{Wd#=i(~@KBdSOV($40F%Oy46}0mxMT#or%jx9C^Xx7|jFZ?Iz^S@oi&npP7-L-k-7p z3E)%BZQYvTuax`Q;iAtkY^#;T7NvunYKhmN=r~az+rL=#f`xLkOT76P?2k>{-3*bI z#0q6#Lec@MZrBIOHqWQ*$d)N<(u;87e_4OWsE0Rwv z=h7e&%rMM0b`oI(FmQn}45F8@YYI2CFJU(rENLemtZ%NqZ?3oXl*4wlmt^1U_1O{7 zlHTc+4+;r^at}|j-?J+~C~oN~11zCpU)q29v(aWLnvdmVAT}Rc*=invPXtgM0eFbsElD_smJK!-xS;E` z|EG@?$nuP47y%L7mj}A?vQa#K~^_ATD27 zH8Jw1s&!4W*EelupwHk{x3s02>mlL@GQx?|3?T1mzbX{c@&>#>xbB8$Fv2Qwvo9j> z!Khwi8>P5tmRYJ*enIBKwOHA_fP~E%S>M)s!?j-6l>1GH8-Ase*OaWL%*U5<6`So@ zCmna*A#G-`Q&$peQLb6=3U+!G!Y#Kj3+_KzGt!+B%V`6iSJ9gA;|E_8S8{`yF^RK# zLdC@AyoT{M|5+`mN9q1)oc6*4PC4-A!iG!R`*a%QGZVbWTxva4#<{X?0jU7#K8ZeT zC&M9i5dr6HBb+?Wp+DA{_52@Kk*@!`mQT3baCxBcfgt9Idr>s#ehEP?&#vKYMEpbL zIZy?%)YL3APU=|ASm4Btd;;@=H!8c6WG(UNez_U!+!-b=C;W~auUqUClsvUY*)B&; z7T2Z9vAd=5JO4sk(1gFI>+Dk1p|zB{v2cB6J8Fm-_TK|;V_@$7NsUmLd0v#!hmWN% zk1^2?iZ3c#Q`3W+6f2)JeO(AyS{}`Izc`6usW1Ww(2~S$B0mU z<4b#$Dt^r;d-I@w%E4j8@@Zq=y&vKht)6iIJRzfTG=gfAT+zqnkt>0_FHxA>otwvl zpLP5#P{>@O?<$`m``vy_h5v2KT!$cIhV`^AAWBi|aKP{XhU@0?*Mq7n$4h6ai7zGU zZWeA6duf*8=*S@FHV_k3-7o72&8HG@k19-mc*JFtQYj!B03d%c$OLyb+427X3?TR zYVd*YrjIPambUnFu5WV4rT{InFWH~_?^}E6!bBb3N&)fE62;OwU;V;(vEd0Eg#(-2 zd%#FS0D&aLAc$?6?O+2fqs+xWI*vLyl6_M}aUQ@TO%RyGX~ z!<&8*jWcxj0^_d$|IoBrzE>yFJ76?C$V}XN_4wu)oqK_pOAc6?ZXuNrFbMn?qlQh% zGoS9wt!O0spy1_#6s{s`TP%~kW=y+(Srgn(bWa&6a&u9g2!)ft^Q8@HINe%Lw%X78 z?2G<>my-pf3p!&$0Z@`yjy6!1xnXh>ES3V$Lkr#`?BC6&M@pt#E6?t*yo!0^i`b@< zKsLJ`sTX3$@4)M#M*8%)JAxgEV{o?usCRPJu=!HCaC3sa3{#XBMS-N;^lN5Yvf>0`ny2?tkIm zq|FD)5xd%Ds`Uw$P~0%9WQp*}w^E=_Fei|gV_EtVBFKksex7}A#M4y%pTF51$*77ds~6!!VQ0AF9}kXk&3ad`^bJUxUMAK}E%t#42b5h+Fjv>Is8ZJ@4~7 z+Qu9(%H(KjQ??&ne|w_O#)i?xMw!wVXJYEm!6DVc_T2SkO-K$=f1r3y;i}5&>iG5NKCBtZN{DiT(Lefy=2+%Nnc532-N5 zCIbQ72INO|a`*I2fq)MNz|a~K*q`7qWXokN3REx0+EcZCXwQ`|?IfXzV?ti@OwY?f zm(cqM;8u&)Qfb?Tn`czim;c^R6Meb78wTGH*xVk~0@BzSm`(~v2!J9|7aAwZ;zkG^ znT-y=s5eo*?k$Eu7>w?{bLX7>j_i{?3F0rZcHx877AgmP{QWj~km}Mh!^ob;`;x~b zvKKq1vcFxQhhxk5@xIl)Mbh$(n8S(NEMrk4GC9w3<}G?4cxaO%UueCJ9dZGkknp0} zMUijpXAz&9Jqp(jgOrvaqylENP5Uwv&KGZK$SxtH25BfZr_Z^#@wt@^)Vx1ZfP@mj z*u|PF_114*#VD^klKN_#`(pgR1adK(s@8WXdaJYy$>3_!@%fiNG+39_Pczb#>zYuu zVq75Ph`xYEF8ie`W57d{*O;)ClR))0m!q>heufk zs8`&Q#p6dy$9MHcTfdf90&*NS{}HKy-L|MRq?=c#>3p1974{urp1*kx%+Ge?U#$*$ z_xp=@yFo6+7$E+BxY-C-Nem2U^ z3;l-;#hh&g)W>0f+%B`Dg$=9~u&=Og7-y?XayGPVf3tGNv!nk`Qc%}ohYn$*Tp4Em zaONj@F70=FxygROP*Xg3nL@3GdKftqs8jylj>Hi30Q`3kd-Q?oVf9Ofdv)Jr|Idp8 zmz|~tfT+5uuhc7Ck|xr%-s}2g3=dbbM!tv8!yA zqX7Y<#$+G&;0LW#&pzcr4Oq+{$fiK>QjvSHn!2>REXxr$myZnr$9chhz@g2R_&vSf z^X(y*1**^t0N&srFH63Qc7bk6_Wwf~hVKXcK%Y6;2nbqyc72MVsD<4kD-x<#fW4|I zQb7~im4H=zN7Vvi6D2@NJVik`vU-!Ub|it}mZ+o}4{y%;$CqM#5(V+ExeC?#=}I*b z99zueF>c;-q0iT{v0#KF;K4Ki(CR$|biuD;-b5!GG)PTlV$-A!3xx1%o@Q$rHbr04h7{}aQ`(L`7rpxF~|M$x8gEa!{men z0dLXW7xBoOH5WuC29d&=5%0&a_bn+Y11QBkaV7n+QgDd${KN@=_flyX@r zzsudqrq*rMmv&>mi`}Rt(diBluFiJFs_Xgnp3_$n3UPIgM8sip8q0br#=H`D(F?%E zxne>q@&^(7BmfWxC35xBG_QHbjUUY4aU8&}R;celSrwEshzSxcY9ABM=p`7U+AW7@ z%`&9ZUY2JvyRd`7KeGl3D;^y2_Y3wnTY@fekhCRpEG9`p1^d&NG*TOX`8Zhm4MdDt zkJj$p7%9~^{dwg8piA+e^~Z`r&}e}!pI^cWvK@8B1yKp8`v9cc_HetoaVmLA?8{Rk zwcrV0TRPSQI~r=~gE6=8DF96CI_ky6q7U&D&F`$){S9#u`SVIy>RQF2eBeooNlVn* zi>$A-tQfy>jP-UqHZi-f4a4rwrt+NFpr9bop1s>pJV%OA*$Cq#>)#;m-ZxK4$c3Z( zHBpV&Cz{CTpU-CBrOn>sWIv8?(|N@0&R4g_i_%&;(UnzOA{NKLM_-TP;N=cD9Y!ad zy;Dm*|CaA6)^lg>xz0Lf%%wGAqz(~JPz^8n9$5Nc)mvl11nXzu8Z=Vu5;R+5BGCM^ zvAUOlPo_1e?UG>byp^`T-w42%e)yfgmLU0nGy#0xV(z2R%@r<;x2!O5Kry)iJyn#& zr%~E{*+I@zJtI=>n2plX?qgwgkAM!wzWhdrbf(BI?n(H(D!qRAA{usf3}y0X@bYBy z_k7UW{oxgl>Mip1`Yq-C1j)+6E5AWxGV$)Fjaz*|Dsj;2^IJKh32COE(#75HRbSrz zi8~qsaaX$EHV#a6T~8Lsx8EQ`QmG5?Ye0y|F&G>r=((oQAvi;7aha_BhMoQhBqZnWRD`q!}tlKc`qoDJtY*C z#@6}2Y4Sc|jRkY_tiU?FBUOo~+4jpEQ-}eZ7uKv#7eXEWn$qUeCZHxg!6s;gw$j!x zSXE$9+Z#_u^ts<27EBcn*mBPPEwq*!v zu~q`qw&gSia}j0F$j&Nc3M3HM6Gu1Cx@4XPPyc-RM+V$FC}CX{QUSyyaUKdBlhBNJ zYkEDVe$vBk;BrAwnj+loLMY&ugjMLffQ_jaAA9T)Hh1E@hAmasFh^gwdR$tLvsn|s( z%?WHxRIRBw0|^#UfRuosQ{9@G0%kA!n%9YW=2bcUqh!oV7XmasvgK|P(hin2=(#Ak z7evp<(@R$tvuF$q%fK6zLnP*Z)E7eemQF#arX?Z+%f}Hn=V!qW@qcKix;h3H-XuCC zkP!ylvWGeq%E9(899ZmmR72@wetOPnt3?Uqyqju(KWM){xI2SAGT=uRT@pFN^A8*V zXGV!*$d=<0Mo;0&B)O*=|D$Z{$}z#ad~c#qDGAEx6HZmI*$8Gzls8AC!$Uk^CRyg}Su+e~GoGJ$txGS#o<(apd_6MM@lLeN8G#uo*l^xV1p=Xhd z$j1?YWIFMUl0jfaTtLPi2qYv3@odOvhWqj3{`8wo4dxo`1+sF({llF>swxxbXz7qz zOz!|1Iw`=J!AF%0~b>PxM(+ z+0tl|2V*SuE}<}JEem>U6x2x>emA7Sx>zPgmAwf{BJ%%W}Wl$I-%& z+@i~~>0>d8CAtsz!uf*9$D&q20&3cJ>9GaK1NH)&JB&_~5d0mqCzI3;qB3Nh75!NH$WtiP%+a-mJF5S0r24^kcQVt4XG;@5FWEDmCAIKfr=jWaJj6( zt&{<{8ex*+(?L`L6+M!@9xQ?3Nd-E$WvPca!3gH*QxJ(stAWKXf@h*P#zaWOtxTM5 zf_KP)d$e!!J>r${`g{E^y>7ADs)X<`*H1EaUjf@RVwyR`zw&`NP^W_e2eawi%Xec_ zdjOH9!L3I{*IRRW`Bls?{UVct-~8HH6m zW#LB3blr_5Ok+qFsbkzpWqrua_r2h$+vmcCS>6Jed0G~JY|vS@m$Fb1xiCnDYTdGc zKyP%N4+=tglr1{*C3z0uU*g@p0VaQG5T%0$9j!sWHf~WZ#WHw_+X?)gC-2(Gktaer zTNsqTMC@Mr(mJ6()J?e=970rl#t>1y zR|=XcMi8Xlzx0zp?-%2TSNWr!jhKKz*bZxtlSxc# zfY&xYUHZHB^v01-uZK{`pP<&5$x#-a+Iz-Fw<1F@a6KVgp-+Ke$iRXtMg{m(vrlao z!#y~_qWlSen{I}$LJm`S_l@@k!}I z*|46p?cXMC4sm8P_E!gb44@Mj^Lw7c(|1ZC=j`6jvD;LjvjZQg}l=_ z5v8?hws$n+k8Mx!Cs$s@@7uv8;Z(Cru=o&^>vghbWrI|CTmBgEZzyN_;#4Hdg4@zi zs|h8#E(S|J(>#H`hi!wi=X@MaICmS`pYc5Xz@Ty0HLbr|4s~O$zK1%pe=cI*Lk&;aW zlMl4uMJ&BpM@?lzmmm4GyH5_fCgs`7rkil;w({Qp#ta+?5CH`kfd~Ox3T>hCn+?>@ z=z4)kGlOG7%Q(ounXATds#lY$lFqzLi!9rBjQL%lk=8MxLx;^X>)kDhRj)E(V)%G0 zFH{~N&gQ&oD@@3bWbjc%{N#_px8b1{K=IV-9Z%~pAcXz)$AL{*J5D|kFM1++{Kjk; z{=FUreN=^_pnGV3jNKuNovrd2-Krq zIP2R{>WX6Tth3%n!u>msp0qgym?U!3{}Y(hcn?*HjtEZvv3&s0Ic^_>2ghoZ!A#d^ zS-vjQqA+%Ssj~jGto7JhS`!TqiQblq861b{Eq9)kFqiINSpSUGshDhDToF z_#nVt?d4{6ELp}wtoG&S4?kliAPvt0%Y-JrWXPL#CBl&4%JNan^(6Ol$A|Fti3TT; z`8kfH8XY|)S-zQ+atO3$G^h|zVxOSX?Mic&!exeqnr!pj-)BJ#Ko0v}u#hJYib!sMEUmrOp#i|MQ9 z;%R(1W$3Pzgx9!2m9+5)@cd?310sitI85K>d}|UqDPgukgvGLc(HjIP?c$Gu3CcnWm0)O^aQk`!?RR15wTBvRVVcG~1F5#eV7$=#--a zt$v^%;nj|eLA%L#bc$@(zqIMt;?+T3jJND7*#r^5hcpW|rCKotf6-uEj4f+OEYxvT zoqn^PLlDfv+o8PhQhrmAnM)syW{jq>VeToYfXbq<89w`)ssD2I6!P3vM z06h&X^$zTMdwfpihVP-Qfcb-*M4>XN`}O`;oTII?Jjs29fs-L8_J7S5_NvXPabx<3 zB^oNnfLL`9rVu~SB(o7%g+Kefn3Z)g4nzjTBf|r`JAji;OKQ%3D;FS;4-qMB$QO)% zB2Wxu2B#wv4G;F0yjX)U#F?p7dJm7~GY=fI`Qik%j?vr0qL6l7?c|*n?Xa=(Q5M^Y zQ-kI0Jq-@c1VKU2QfrSTbDK}GKH>++el2J~4C*NyG>bqA^g(?IBuiaeGDKcIFK+`= zMq74?A+m;HK}$_6qzO^@PN@yO^${r-Kx_Px zYAiKD$y=Z7@$S(d#&6H2N^z{qp{aSt?#_p`S{*i5LLQ0Ap7s7MZGrtc=iURzjidDD zO)NeQ>X9wOeIvpI@bE)3gdOncjTlnGQ5ZHF!49Y2K_T4IE4=)WPh0d`^IA}#yjE+L zP^&ak!aLTGhNBXY0_qV_Oi@4xVnY&b(2r8*EYujZO>-CRBs2c(xsYe=J&NNg3a66Q zX6wmgE}3M~dJ}0p?g#viS%_wF%@VOd|I7iXP$yAi+AOC1)_5@ldbj3^A;3fWgeQ+{ z*yM;fIs`OfqGyG{`-3tt;ehFKp<;e902g-K&*>i{QCwhca<#2CPEjAzrHo5)d08J5 z9mU7o1rOM7*`~WEd(+Rx68NwmE+@z^aGpGu3MfE>f$#UQ2sKAu)4DrTE{J_i5dn}i z3Vc2ZJOS$A`{%`Hx5xlzmVWn^@tj^=cmQLAuv6VBxOkFZs_>L-Gvi7%2Gg+90z?Qn z{#KTB{9vKnf)BJ;;T0}(Oj}Z(YU}plSeKp=BnOP{8k(rCv}390$i}P zFkdYTs#QKRfGhwf0)Nffl0e?xo4a)CW~poMmZPpbD)^U8$R`DFh99NBzakz(KL&}c zkS_)w&$}ja|6!387tR_@Z7;m%($k<9xw*B}Zqj(g1OL`Mt;8FoL{YZZ8}mVCf+mMA zbWR}C2K(vW}`4Ux@qzMU^0WSexOSftUgcq7JGZ_hYMvX*LNRy zNF|!W0HZYd$j62k0G<_4&LEMX4ryBChQ#lYcnLMy))PKl*9Y$|Kgd(~(#NShabor< zT>p%)9ngErg49m`f_?G`6}OS}^kG}a70oCR5TN6W_h`)dW5lfSdkNW*07xWa&Lj?r zuH5)gLR=Y~hK=5Z0rgZdB`rYss?!yGd^k2|Urq@~Gl_ zK^UAAI_(L+Ky(6Q5YksTjR|6O({RT|d2r^Ei1o0wHJ3p9Oq>?5wq$bMpTEp_-AEs= z$?aqDwn=F0gTu6IE@(r^v2p~?2q7mZ6cztLR%Wa`yFQ#03VAUaitebH&D#W^2TTwg ztSVF?0(Ktm()Ota1BVAeo|9xtu%H4j*lh+~=nQh8+@Xb;T{;--??L&P#gJq|ZhRUl zRmlJvDXbyyDUhAK3Vz7{q4p2J)%HKThAfnB(PkbGBJ@xN?B^AUN-LZXu+tCbOe`j6 zD+~rS6U35Nt4GWOpEGSf!}+mF%l|Tz05CeOa15P@GxoiThad(Zi@;x^e`wgcVA;vi zm&U_YP%&)9l#cz~QWG`4luNU>e(J%nnh&7@)F2{Adttzyr0P&Ki)MfQM&|Pn zB68CWR$0jTXx#v;K|}LTH6)r4*6^Ehzt>cjdelHLQyy8JyMxb4nH>i8oykSy&US$^ zXeRyBx@=3g9lbiN(TvIzr8Q8FTLlU6$ka03mub;Wc|uWBpXy(>j4Kcy``PiZ`mlFV zCXA|%^(k>D^HSGkJ!Psq>z6uUoUE_ZNO@jxlG4T<6K zoUR<4NMExBioIyE%HWGcu9XHXyh;Tk!hgxd?PSh1HNQN7)=cw$#8 z`X279n2;5S?G(({2D}OdlqFP8OsMmnF+*P&3?NDtK%nmLx0ez&yN}&@O@s6gS%#;?#E_C!{np7Ts-JDgg?WY8TkccMPnN8AmIbh<#lHb~2Y|=d zr<^cTY+TG$jaEqkVFq`%N`%@s@Wgz5jZON z*~PuT2Mx>g8Y}qnb!G46G;J%<&E|X%lmrO zey^2Urb+VYVA{{dOFY#gLX?6s_!YD;h-+Y^(vEZ##pRGm z+AqgV_Vtx9e4gsSmKy2h-oO)dH`>{ThcZQJ&yLs-D0+o6JjH3?5*dHdn4+PyFMry*Da9fotZ= zH96_j`ixEkcf4But|suWgxqjlx)1UFs@O?!gd=p#Ovu!KeCSWT`(8kbLNknepC!I3 zadD{dgs`nu=q|VKLgu?k-{S;lm^pTlzblSrMBlY9=+pln4z*P`yi$$(48)o}#V1?G zH^!NVK0>sDLVFIwbJiT(nKyiBkeSm&gw_5Nh#wpzx1Z3n*w$;Fyt24vqynB<>^2T{ zzuMGy@UnJDT9+@RGbX<}%PA&DUESrhMX}hoE&u{3N%n~_M`wUGIx1e08I#1*Xke)& zLbssLJ}H&HS9!!WmNQ zb;wPsRWy$us_X9_dIl^f^v>gm5){3u?o!qi_!qQcFj7=bX?%6&ikBOBz&i)T@I+n5 z@=(yc!7E=81yW6Zbi_xDAp^v%}>_w216#7d47(&JZQraH) zq>oqA5;HuqsF*ngg{5Ot=(Bj=jNWSe{`#S!dUieQ@^J*Z7&2Ns<3lX2K3S3bO?jnsD@%&R)?g904WWj6Eo@ePrdZf@7GDw*(55t*tM1{rM+BkfvJqUPB>Uw+Jg>>a z+18L>I_1Ilt~dR#o);_ji^ch>gBtpDPu`N;j#!~2$&5uW0&LK3fEeJa3JnNO-!=$W8rM`0 zqD6BWMs?P~7Ky~^6(-RiTNe^!3gOlV6kCa=(;AnNC#pJ>ncApN@X}t*suEQQ{EG|c zz+uR-w#8&|Fjn82*AAQG=GTZGvCwm~^BJCQfDWLL%IokSvP=e(CY~mFrp^6AVGBm9 zUjLrs!)%>K0h7o1FJh*S9$vfATbwN6;$bOHMo%A@_0@A8JE4NI?>#&G!QA8%ykMrO z&;1x+-zWakyL=NA2JhO?Ya5eols6XIg9P{8VVuBl|$^;U`fv84H@C znD~Tax%-%YYeS$ia@BrQj{*QYs{%9**CQT)ySM~w5563SxM(?Pkn#dOU8ZQ)he7pM zG^6<>d*o_&dAE4A)SOew^>?1ljR$a0_H)oFsFoN5wV$XPY2y}hDve6!n8%($mZ@q| z=B0!&T9GT_0if4kxN@1Jfv6pf#*ymCjbBg3G$TkUnE~spChB6~RM)Hd7U`@!M;Ns{ zdmzk&T;`PjR{Vt&d85Fmu(K~Z!?;`k!|xJT@*drZR!I;89nm9lE##jS1pY9>*LYM) zd?p57x6+Hip8cQtXDUZlbOHP>ALV?7=wD9lqlGgj&G*tbP>4}}-a$eDJV5PItIb$% zB-&!tY`v}xm7ZavI6ZfF7A|%+xAYRIV&BnUQH}S94|((Qtyh}i(ld*UvDGGaGy}Vh zp%j*#fmP*CFv}|Kje+%yNA+=gS)Jl)aM!@0ShP#RNByv6-oTf|$QzXSnXckzxKKm9>Km$=HKudlry~LTz;AD0e792)qQ}LxNI^F*d^jpK?d{qLmOm5 zhuQyr;g^yx1iY3uL9X~BXXa;#+VE0to$daMw@(UrD(|L;yGCe6IYPps7@g9XlED+NTKj&LH__G_`g!o3ZtdK{}SD5WE|x zO;bQf@r;@@K51l56}B<(Vcn3x$r6$fzYT=tm1USx8=K-}d+6u-)jJB_!ejXrgB-iF zlj9=Tij$55ZBRHEZF<<|X=1Khvi@7Uzj7#jg?#>;Jh=L{BdAXg!N#H75Lr5$Wx$c` z)r@i8K6&I+t$VRDFRMK=B(Nk;JMag9K9*?~_0U5sbd!BIL#qj_6?EdKB7EFjVZ0&2 z;A5}QCF735B*L04TtIq;G(=lfa8s>CwDZXlgST;HOWercElc)LEz4+e*IzH@dyTXr z0VQ&YjhEwPm>zTNUWNiSzt#}!rlZ!6sYD#osf(j;6)kd#D?Wh#sDW}L@x^BDQBFz~WPiU*3Nb-l$8_fKBWQrH+2vHegJ+D~Q;^EO1 zZZz+*+;~nEJ&)M-*TvXZMc?rxHne za<4TL_PonPisrwS|4um?pNDq0T7GJ``eXcQOfk7`y$RUGEK!rk8K@YI!sNT)5R3Z< z{2ceJDza4%mI>04>f~&|FB?m~_-(-s1iw#OJ(ASE9O#F;#|I{yFkBP!Hr?D=TxG{p z5cG|FRA-D<>+|JSD)DM+udyyvV>c&+r|-S7Y0=j|*`=S+Dqt9OJT5H!oDuy{Zm84D zP^7QlYF=*>-PqgK{l5>|C7BFg4`}iYz{1{Hy2Xe0muXyK-Pu=b27yXdOWSip_%8Jf zY%;cMqyQ^HRRR93qw5^s6btrh#sv{`wKeg?ps-fG^8%0NkM|$9jUqIn8^krnk&1I+ zdtwUyLGEtA(L-w$dP54d)G27$-5mWqjwkN90DcDFr9Hm+v=2;&GE9W>+8w+$n1eY@zd0e@LHhg_0ZDHE`0h~1HuZ{`yZsyDVl z#-Mts`cEaa8oCP?>i-G`2c;zbH7rKbIxfYB35Wjk;U=K{?%rz?=k(a`t23;ukGsN< zy%T@}uH}}Y zv)7LGm>R z(Ad)d4IT*|DKIH0X$vJ@NrCu=cLJ@2GaSgbx#ND4=Y;yZE=2Li)!|v{58Gt!QhEXJ zW{3b>SC0O%K*21;jz#gSjXjDeKq>s2Oa~2MkUs4d4liQK9bQJqw?ZisL}kZavO8m} zKiRUd)lQ|G^Y5Iml3TI)($?R{{EvC~$=ZB*{BRmNyZ&UE#UDEkW72u3>M2X54vcg? zX=*ExIImReL!)^%(0@0$b2X*lXJ1xq<8Kr98a3mEjHxm%?^dR@7(9}2i4ar7Dz*Ba zYi|JQkwZq=%LM!fmWdHJ4?Z}=`7O6ub`>>{kdlCRecXxY%jP@*gaAi9!Ld9+zyvs1z6yu?9@Ox6!ISuCjc7 z<%v3ctkqG&v3vYOP*bL!x`SrcxC~yd*aZ#y%@ z(=X7ZS||xi>hMOx=v1ma?bboZzuMI*r6e`MOWT`%m{9h@=0gQ849JnLVXnm80NA*h zz+HId$#*Sd)hTi}&VcF2)+Y&J!6JDtSfRCNAMzbV=XtpVS^s->U0|Nph^x5U^4)KS zb9L*Q+Fs|Nk77?hLyEz%)W>T0=DlR^L|EVp$m^Yi8IxVMX?$i2&PlwaN%^9ws3=Ob zxC5DJiWyOj-6K%Z@7HnY^QFA?@alXdt0q?(N@w?a)S$gyqW9q=4R~3_EowQJx+1GH zDC_qZ+ujVF;E|fL{!MZep9BMNwgJZUQ>{}t1KR`QmP*6mJQ|Z~b8bi>rD$5v_(V@5v~AuquV722{o}|#c7;g3+-064JFy+z6wi7Xw~*z4*gP}wXJK$ zLCF**3GA`knDRlwqGs_SF&;dF*Q)j0m=WMuwC{1~$g#V4TNG}#sGHJd6_HML9)q;Wh0ER%#E}R)ImF<#8sH|RBtBr1< zp`7E`bWHBg7mGl6#SMM2_{hNh#syNwSQec+w&|n+9jQ-hbZPZu=aROlY)^5o`j+|> zwV1HnPR$BLf&A3w$)PwSYSLo?ZET@pso&=}q63dzl^oY8H)DxlZD#*t{5b{WufD2e zq^o?FWB{k@hP$ul&LF4(O%~d(EA4q-N2u50xE)1I*|}omH?8#djmv8hG5g9jVIkIL zx!KE+?RY!~wB+O3ZEo}$Y9%VxGk6;Qp#%{3IJ+I-SWUvKij3-8U9!Na)Njs)?g=Mj zEZo490%kx+$dfu@nZXtG$ZHL!T4$Q5ILj{%55~OOAcx4uF3AhH)Q0Ldue@!}k+{AnA8uctN%Z{g=C=u~DuQp7D>kfIPWRS)1Yt>h);^HI&}j1vjt{-W)i zu|h7m$S+^3JS|xFe<=wtZjbG)uo1K!Q@VmWN!3ky%_z>b{t5#QvjtsiU%Mc@3_j}5 z(e7-_{?6~xGK0{HQ7z_v?Fe@Pz0}SpNTV4XlIBwtoMz%BZcM-ezC{ok+EgpaAcbTD-=R&f4^RdJGY%D7y>i&{s6?dG`@Az!iA&pqTB3Wyf) zpPFUplRSVZQ4>&5LmAOW)H4MK1(@a0Q%}k&l)t(#yq-^Hitx`STgN+!+fPTy{~4Du z8CUPNp?^g_SU)|D*q=kRp#_IoH@FH8WjsclRYx*!kAA859{<>K7$9gtlw4AhZ*ZLL zI&i9hE(OOi6q6U*8*b7~*IB(=j9iWpryQEIyrgUP`?J6r4C!n**Qoq?8b8>(D$?hyD3;a60#Td2R;_7rZBy5I z`{u*UfRU*e>4~^802VD5EX;5BT_=nc@toj(d1gE;?eb!{%MOr#@=d{z5+SvkpivwO zW@$wAx?!hZOwMWDU?-mN_D_#K%y=TS29bl9s??FcjavuhO0Fg0mz^<-Ug2=&mqrk3 zZc6$g%;R^%i?gE+MRfSDG_Lvj_1huLzA_nU4jMRCq#9}K?J1#JnI_}&lhlM!rx&5- zY6~!er!xS1LXU$<9?j-pHjt|qtu<3t16n8^fjZl^n*lG%Zz&NcT?S4pvaBC9hhB+= z>iiSp(U9H-U;qJ(5kV?Ot}c0$31AYw_B2MQfrW-Nf|>+i4)BiuYQmb;KN5^6M%`_s zD}cT}&`qjRoM`QPWv|fdv+XG6DEd&$ zdg!a52{xy`kk>@3VY~UL<^9j^I1kL`1vjXSi|Z|6T>;fQ!EOPWdPxUBO$%toZDJY0 zB635f94%ZTL*!TId7B#rbQ6UxGR0XPlVy+S$4YA@o1-v=_{{zP1{#Jl=6X;wG9C?`G-an)WnCUa-q-Q0{m?Gx&UzC`4=q?J zt}?6J-Pg-pdfg*7hdV~h^r;G`67`8n9!oEpzi<|aIv}*hmxiIU(8y_I(6DN&eM)tc z7g)-2<}Ni2jPb2}wL8kB6&A(ppI-WsT`_SQgj;ahiad79#_p@zQJn>*y(50jk|z`l zP@~j|o9x;4yFJHJFI>{n4g|$wvP!po*4GeQIja^^S?9%H8pg(^okw|g z5sI_hR_l~t-_e_J`CKH{PQ2JWm3uAnuHo&FDwx`<%iy<>pdQz-VO%(`My7jZJ(roz zSiE4fGyx)r3E^zr9CUh>&1Y%9f!OJw}#cOHIK z>YiFssjIkX2SQ~(^I&#(0)`lz%p?f(V_C&(J*M+=tuuEDu&6+<03?B~Cm4qr7MV{< zPAUxEV%Db$sgT`Ur#_SfUD>jqpMQyq^}a@sF(F}~0tPiNJ*+%LB_eu{mBz6^>B%qs zc4QQPX63;w++XT`k}J`>{#)v;cf zJlG>-@-T{46IaltV!(ybaR086Gjfj7S$o3u4d=TS*guy3c<+k{7sfUUJO}3q)2zY? zO(I_XmM=u4R1;o+VdzC=)x@>l6-KM?Q_ilob>UAwqup*gT@i|80Q@R-*1?F)_f!-| zAJyvV?5!}h_3W%Ze_A?(b=*UdMFdq~DgAX>e@Aw?Hw%9fun09UsQo`@66?cL&<8CV z6*A*jhqe_QRxXzGd{}|7t3**H4P}?<>M0;=Cc+OC=I!BYF>+iQ**oRs`z9n>tWmbb ztgz<#ULi&OB}36g*cS@@nfyH9d*7(Y?7@5Ep*yQ&dI1@R5!cQ|L!`gp4 z=80YSFu^FYe8w;ZcCmmPXr?zMonp|65(C$M;O1Dsa^nUX+5UEk?PB#MUCm+3x|3p* z%dBB3H9e_@?z8&tIEXu)Jb>%H`CJ)`9JI6qC|Ob*!4dV#uL`^~|CH7jLu*!=;fgYRq3YkL(SE&6D!Mv; zljc661$O9c)`7H66%wr;DEA<*w=5=_zgBoqI}N9^@iDv2 z2n2w=X8J;?7&#(j480`CC;)6Rvh_*xgWuSPCcYPUO5N&oq_F7N=BAjC!#ox>U4%@P z8(o<2bEac&b<|!%?Gv-N4(T7923BnuGhnr21Z8xF(jr+0w)A(T=-vWC8meIiFcB=X z-5J{wTcgWAH2q<8%%2lh>S@ zAl}kaf$ADbb_U!a7|f#jP3|cy^O@Gsj6jIwqcasQ&%MnLd1Ra?NW$&227AMwD2WN8 zOl?Q$U_JDPHA!ZQl<1-HsnJ+Vr#}dY0t!x0z#(3ws{;ebjdyx`W z!#u>1yhk>NZ-uF4%_Qe!YXR~m>#{9xBWz^0GU|+fq);xbCRpnFc9mzF>S18~0g47( zEgP@7Mn0i0KuaW|+Mvh%1O=_oO`L4ek^%pkON)bCHnbXG9P8<(FEz~6K;#visLAIe z|B7((6E5n|$RvD==MV0{X=P-gHTn)oK{A(#9_)7=bm4&QZ3im2(@N@wHxCaqvS+AJ z3SB=!A%JU#O!M4H^3brAu%X9GK<=&(BsBaU0QuuA0(ekbwGdKPUzx^ZZVf<@3_3;p=^-ac>o)iH+>1?Vb9w1$}eUKG%xaoKQMIB3-rc-91X% z85G&;cXaW3$)lfeH44*64j7?|L+)yFxhuz_WMjwc)(GsG>1rgP7iT4JvSl#MyCPni z*WpgJhpbD6eVpMv8BTQeN4TTN%_~2)Tm}eWlDicM(jzHi|HWIZeg}UuJ&r-Sr9kql zm#Uz7B1%A6!l?Nzio8N=SSvn4#$=lYvM@6%kJPzl^4Pq}mNQ}3!Sw1d6*athDy9{I zBe+Q~!Li#+&-Z9#z$&yPdEt<5_{44y*S#-JS0FXE?&zQEm@jXYfBLvJvbiTnnt-Z! zM1&8`Y_J7XiWEIMg&OHbi!)l|V;j~!wOn$$isxBtKXl(6d1unH;{p!3V4JB53{217 ztSXEtU!2B(5_56|)vEWk$&J2Ykw~e1e!>8wymn9?%pXup{HH%#hC=^$ z{IX7Op+hM7TaukDWPgH54Pv(g?xREVNqwY+beg#*8gh~LP2or@eO%8G9g38al!e;T zx=UK)S!42Mi4QrRxm&xnK#L4kQET(37I{yhS#-N;V%pj2;58K^n32$~+uLQ)$fifx zgO}5b_;BY`DH{|J^RqR?o&B{#GZp%83i_u&7KZO2gjnZ-mGHZu+>-8Gxk@dj&|4Vc zonkhCS!&%}hJRE>>VJMHk$9@(sk%<CGVq^<`n0Kn;B3j-l)ri1L}ra1oTukh~~ zJ3QWt(x|#Ka0fp8c{nk?6pE&yRc7u}=sf9xeC-gs!qs87nA9$O_DC~zPf_<2TRm8> zRzaJ=>Ht#tHv{a4s@LwE`o7T3d2uhY=II6|PjLO3ZKJ-S5mHvq!k!7gZ<3*WS2!yd#@ z1Y@4mQAt{TZNB2cnKJRC&Q`#)dzx_&7c1e6ls1S*X?SNHZ7XI6iUOXA!~#A!pj5-U z6_&!oXJ0HzG7vAvsDNWBCX$JnucgF=Y_8noR7w=~MNE<>)#ImPx^j`3feiV;07rZ(#*nSw_a#OTfpm0%T?v^w<{ z^>?!5o>ad%zHH1bgaP6x9oHjARQ?%pz>=&SUodK-m_loddl(|bY&x*)xe!E3tL-7Hd+;k?kM?2bTmnM#=c( zHB97V$eX6v3;7g1F)O#M^U;dA`rO8LWw82uK8sT%yLnGW;45POtvrba9V(q}|0kU? z1Xxs~Y$TpXnLtrOO}y-;&v9LaJis72%W~_(~_K<^@$pnazBcWxN z+P%~cGMzZ$B}7d*m3KgS3#y7kQ_4GJ1H9Go(`v&RWQQZ1rzTF|wSm_pl(L7BsbnUK zhelH0&wrqtW4aqn0srX<)!DbDsI7YWP3De_Lna7zEf-%&GwclYPoQS5Kb779`3PF4 zPafG4@=ej~q=9uzvlzf0@P~&kl=0J55C~xOw80*-8TS^_qOX8?b{RtW59sO_@+*Y( z!hf%DQ!Qzvy}Ct2!Ig?-{=)kH^H3ngVs{SAO_Hq%X;tJ!$MGPvHQ9Sqr7Zo;ggrU)@VNZK8IL%*LtOIbrC3cNNki9@4|>lStay zExLwq=s1XF+ozH7d#Xy=Y&^Fj^s3;Ze(`OzxCyACDh!ZNwE14(5`)iH2V$=LHvOzQ z_X``KSRujgXT(}I+0??bgD?$J8!t{+q79y@gw3m}t8cjy;?QnotgjFcRHi1cCkuY@ zHx-Z_hSk+N4)3Vi{(kktU_MA2q-#wH$#u%>kAudXD(7|s{h`Q4{gy$tS#QexA@cBI z8mEA@{%|UJsV8Jvf1i-bhIrTc5?fHS^rtm9fmF^AITA(lfz`)wm`E zasu7=PUhH}BIrq|=Ak2<0nl5gMo}lnS27dm!8R+~X61Eqfsj6Qc^#ix>BKDJiq_9m z`i!;a78grVHhtEoOw=$X7=enYkqzy_gp8{U zabvey@*et8^U>&v4Vh(DCKmUBV4`+(%7e{J2|!`lm#Fy}=tq*ciu;H`p`E+=2?^4; zA2b>d+VsnR0MG4UV8fE$WrDF3%>`q7ScKj`uTy#g{Q#X8tfQilE<%xEG6j`iHF(y! zZSey`jkK!H90gCr-E_5sONHgVz&O5KD1L3}2YAJn4yA&%S*lVnIutQX zmkJguFq??bg68P;;PZxuqdmwkr$P?GmdjI3utqW$60i z1`gvHU)8V`<(f&liyC7NmNHjR>CGWpg1n0ZZUN}om`KsGEs9}{{gJKSxT2W4=EKjy z3T;3pzUQAAmI5C1>$kC}Dg$=7tB9r;&}gUtdfBEOSx2Vn=B9f^W^1qU8ii@-Tin)) z$lGY>PFLhZqfW2U8|Y~Id~P?&cNZmg($2RCO!YIy-nB37U^crk37%>cR-g@A!u)XKpgkvsSH4XMYR)uR;FdMUE_Rs*(4p_BRGX`&pfI(g4@;>O^~CV^YFOODs+)q@mFGu`Hr} ziV^CIZXGtMz?Oj@vG_c>pm+K!xFE~1Z-xW83(O(}XH6Bu2^m5f2K^g{-b7dJhTy$` z5m}36CvQO?6moz%))ZWmimf;*VYH9El7=ED%AIlaokP;b(DoizDCPcZ{F}7i#YOXF z3gLtM5}GwRX%$i>0>&RwE_I{C(kCY`7v;#jmBX}Q%^5WtRL4o!6ptFvvB|~&$k+RG zNn)hw`vfolV+5FJRI~ywpa!7!%>o8KOiA{<76^NlJIC6v@1|i+rtv;BD+rZCO*v{Gi&W~`?W9SP z)*x4ebA@fGhN4e9RWAgC|{$hZd=SzY@i)9Y+3hEW#@T47C9O(d2^p7*}RA>3^!9r zIFJ3$xvc|6`twh9*n;CemE00y#vDZyPPAUY-h2s#z>0lzWY!B`L`8_3v3?Zb9Jo>t z31xY}zPrg_KO45jj*cnC-W%h1!&Ec~5i|%AWr6KdiKk3~oV?*lCi= zR}fb2F%WQSmo^GKOXz|fO#lm1viMxp42U+0Xbk3>_WuL+di{^z2Oug zeVw;T;aeA2;?;JZFb|0n5G#7ob;u+s=2tA$?Dkgls|{Cd1T)kce!7;Z8LIJ|5f*Y~ znq(NP;>VbZcAh1^a^lV|@ME=&oB;SG&GY;vy~=1D6Q0|S(vGqyiAiUqpRMM(e;;i_ zY?0*$iF}$ojec&>#Y_C>i^`-9g750|sVaeLiG^PRdvt-1P$cN|=S1SnE-dC^q5lhO zK54mm@~01ZyKzgwC|ntYjV4LpPtAx{xL9RZ`Wd$RvL)&dMyg{0?6K$3l%!ei_!69r zG1^{Ha1mBm)8=(@?H5>?m&Zw10ac>F8Tb^?*&&D}*ft3IlGh-62BD?rOB8GTEH0O+ z_t)v0k5t2y9lw^2?d?0m4ON-b=AR)12MyE=qfIsS0NnN85qJqlymR6K$$*b=s9LW> zgzEW_5JzkD?e`*F9U!^8pY@wqt|K|v7*JX}tEmm)pd{?9yx zN2wXe=xOBqx;h@;gcXEx(@i*VSjERqJuEQR z8n8%_h>i_~4(`exsQX9-Xx7y$SNeR&6Q3`&^0I10)iPG8Xcz*xsi&oF$UzCqEu4O` z8j9mQ2IO*dKB=t~^yAMoT2?d4eylb_g#{jtEgQ2+?Un1tpi~&5!wy&Wl#jxZM#P1- z6r+_lVGN?8%M4Hf2~=JAea6bqqa+KK){;-MWF7Hh(gN3{0#<3+AHa46>z~1u!`%}2mQvbMH}3?Bp+A1)IdVfF zwbh2dS%1@DGi||lru+x7}1NC z1rmdxsXrz$VTb{b=Cvn2-UC%hHHJEBuH%Nj>VZST7*yO8V!_kq@)8ORP22ie2B6G0 z4FWyccTBzvW(ldL#`e~J(JXgmbe!?vk#vL3vt*U0uUwt3fG;t=j5PBH(QmK#cG8@; zUU4-N4;SBRWoGLicdC9n+_E$$yo$IFhK*NmuL6Zx7OrZI$G36g`W~HKU%t7}VX6dB z@+;FLl~T)%&Yrn!(8XjODO}~n95m$s26&5njoViZq~a*1AtqAv9&yH8{)xhx|uaBiNe6byAf*A4mtz+nQ zf#Ouui$}Ns;53?Bg9`177#iW33iwOT&TkGIeJm` z`iR1Nyq^Ejc4yxlHOD=x6rYddAv>CUf4nuFrSDwjt*c|4AT_Fqvu>bS!eSqSM_5HI z8rsJ+%1wL6q6S81WhC$;wrS=lT#QB`rjrCamVGl6g5mAG{e2B>_X+yh?UQEA0NfA{ zq;ciRlcJ*OT*$*j#yIm3D)zgHZhzBVPMH42?RmpyP4*o|jx-5~WN0C9-O+W}zDc15 zMsS{&Uet^fS6HIA#9da3hY`u<3BQUt1;fqhc67PPs9ovZ>F8>M)tN*jJQO0mEo$nu zv`Wsbv76RX-IPTtty{vZ^Dd?_XTdfK02@x?^|0w- z8}1F$74ry9XUwOqleM0og3Jm?ZtFNLTM3)+h>|Xwi2+ zQ2*{e=AxRdQL%_f^xF=5(VYl(L1e=~AI|Q8)G=s6it+)f4w%s(%*;z9*S2lJD;)dS z+Z`xsP0=kl`L#w&i0|4*{=@(lm|dWHNavWhEgJb^<%H(2Mg$4E6L(wIwCAzmQquh) zG_`vI#W{GGCR~D+Y@_6LIsu*-@sE<95LHM|Fdwn>@F7pEgJ@Dsz}}0;AU& z!xb|O*H%(gr7TKQG-?OlI7*4L&4ShVAkQf?TE8bOxdKYIZb{-*oOavDGP^9HO5)3-& z54$f7_6YPmya}J&89qwg!5;5SMx|dZ9Dl zGVkQ3qd7*=?G^oMDyirCbLkrf2MH->KyBuEW*9zT`@(Q+ga8UB9c&;6a#?0KJ-F~9 z{yP8%XE69n@9b;dzKqcn)fQXSEZN=K=6r=I7Nn(%+HeM0Gud`*$m2b{f>Jn( z#1oFMOI9EYVdjO-q{Ytl$j2B|oSn%uTf^eWozDT=L8&4*VgB**)h?H^Yn?cSYX;{}*9 zMMHBGB~%I$Z1!$rHrl#rU(3NCqLGt}%?1UEmBq_qmkBj-nm8$&_?cmetfw-9;Hp;Hqa|b1GI#BIcEN#EUp;dgQ$2 zbo*i;J2A*5I^_JP2M)D1ZD8DzUsB7oft1ZMTH~8Wl`L@~I}7*8u3n~riNJ8+%FjoI zpg$)a@+W1kpGdL~Ha_!lJC5Rhn`K)K3jJ#oQyau#Bw-JR>`m3tXqBIHNeh&X@oRJn z+@eUU{26St{d4cBIek)g@(t+ZH#KStUUI=^*&M0z3CXgdvh=Adkf!IXUGw)TwV8*+ zt*iKL^eu1W?WWY6ITbW6%!C_jZ4mlc3N2!CbmLAyS2Hc&v4dJ;#o>`ve!cy*RWjE} zycBqoXotiFv*a2Qmc>pO&0WLWp}>`~S^F zLB;^Dl9?if_0>VjXd#e+-;jN^dso=37MdO**u(C=zE)#e>srCXJmF463H%@aE&^f$ zEei(7v#74p5ou3HfVuDp_31uh#Ufm-wCrN`7zM|R%CvKmKZ^OdGl3Mb19OQdF+;sc zgy*bkT}?+oP+1YW-`cv}O?I_BPmj(%j?rX0aw{{Nio|jVomnsFkBZ>1;Ft?4C{kvO z54nHqjHjJmi_DF+1pO>lKJb8<%lsX3!2V~O7iL~N8UW2Mc|L7^^@|6NXgZ7)JgTYo zlpiV?kyO@V%#S8iX2LJoQ^6ufoeO}ZULy|UYGvX=^(MwkHYtE; zie)Lo#P$$Usa!^zUWrUtR%ifv`)#0-wo-}$HCwE@mv3SY>TlGKRo1Cu8_x9Uvy&h| zkZ}c6zTB7~PJfU>hSm!q{G2P!!(`>Wm%a=B1R7zMF)ha8(@EYsGb@M)h{1b28l>cT zB?b#(9T&TIM}O^zC_gwL(aWLg37TdS4K=rkge}HRqrkl$Gq<;4_i&XD5vCP*fB^Eo zuH9`nd0nBo+87iw&f@n!pXj*DV{tY^ z_yEo2m5Xf?n}dZ3Og(Z))R$-J&3vZcnNKv|5smrwcnz9tze(#WpLd?((4vdV)}w{Q z3yHUmq0>$yrIll32jZvvv&tgknalaw`G}xsn2P95nxH)=-J}j*T-f-4>Wc|m5B)lS zzLaq(vB@r<2NS!Zi-qJCY~o1Et-NtCuTyillv9lq8yo}k#knp8L-Zl`(Q8e&E9U-D z)tZin=b!tP6S|?k-n!mcGt)b&RJ^gepjK^}8}fDd=A@gJ-}abSwIp<5$REC=&u*07 zdtnp1rSXjO-eq|qKXoJ>uq-P$srDlYRv;T$0vVt96;z1io`yqbap_BByf=!>TM(${ zHos``9co6_51>k^$Iqf(2>}X`l~3XvYG4xtF#cU@$5n8*?D2LR%hK@DOymXQT58q1 z8kiIPkG8XzTMdm`cL~JXX(2WFc5Av~w}h6A!#l>ll>x$rB?{mGosDC>(IP!Xwq-eH6(p`~ znlFDTnWB(c53L|2K%3C4dTyKi3}@>XdiYQ#AnE@#?r9k6v$v|cDp1?p=Wh<=0~Ye{ zjpsuLyQd?OT-N)*>vy~Ii-nyit_@gBMaQ;sV2cAc z@OxBwiXY&~_krwFwlpW}-tw#l`Ek7e&E1^mi4Xi^1K?dXR3D|)G>_~M;geW=c>?TWqLR67ElK#cRQ#&c&>Ku)#i#F!#w)egu(!w5)oMl5r+t{h6B2^L&kMm`*D<#U?S zi%2g*zm&7T`!kq~0U7H%@d80-60Ch=&;7?Skt*t*yiou=l0h)7?a7kvkW}zBN2GgM zq&IRruJ%bvo@&Y8;T>cVFOm@C7(G8P7je{L;@&sN54pti-g?!l@duJIPM*U70#Ntc zB!R5L*FC?!%r?ouLvVpvF4*IMvZEJIh5rSVF!`4Sc110ZTdR2#eCj2~Op^;L zxw%?%3PGih*-qWQWgcJS71}~~XA)AvRjNkT#WAF$3|G~mzXEl01`hxX+>JQEG`3>r z9lOq)a&|jRO6^F+g+lL%GYW>uGAcUCe05gdZ-qD!*_Bp3!mcC)s-Z)s{vnw@inAjP z6szqnCNSsRPKz`JVxTWd=>An`vm&Vwua3MUE(3g|f{gOQdHiv{bpRC;qFdNe$)%!cQ_W3zNo9&@5igZvRa7sl#rv5e z_`-5?$vWw=?Tq6z{am_xD#c{h5)lA9`c^%-jB*sK zT67HcGl-JU;1|l~CKbT{jkj0IwRXT-T04OIN8?i!vd&N3SyEU6Q0?t5>D|A#0a4;vbh1*_1J=g$w z&X9F{8w!Ua9p7V>AO_IS+R;gza|gCq3H7R@ z_yXEj2`7TBf-iXe+ssy&Jmn7Y#18Gu;!vcNgoxl2$RXoea6;`8lQ=n-Qv?-0Rs|2^ zQ=)5=q!m4~&FEUg?^_-Ds^WQ6F>uScexDBshr(Lh-C3Odpcu>!vFKq7o>7(sI4s*N7Geh9iY zhTB*5wQH$zRlG~1D6X>y2xT|0X}Y`j>!~>J90)?}AfE36F*p040NcIy_75PHcS59m zmbxy2$7@A2;+`gA8L5N`^w{h81@yUqKKEGj3LbM<5Btl(!eoj+cGqdu)Ho(!P|rKk z+XZBRE^jvtbhx(AOGJ=KN)ZPTBleY}m>)3~iKs6(P-b!n(o zyPVB&V@v}FPqXoHh@eDV?5SqC0D}Cz05F2v;>He)N3Wg(;FOh>ydjT|@*m-P+&ZUHQ^Kpp`H!Z=vk z0a8jm>RNN9;(ZJYVYK*MXKm2{(!g3Cra{Ynar<-tT_XW$^au9#Q%4r^ z>4){wIvY8-Sb~}390}QYbqD}QrsU;=TnZ3C*oX!1GcoC_yhD}p@YTxA5#-9?9_2LB z&=CWKW&B^U>9EWQa9`NIoZjI*i)nM9knQN*k(`#WW8w}b{t-jO9k|fQ>s1lu}DuX@w5pZxDLeul+JAU^2JLh%4VWk}@hCIng$I4GU*O#PhSn<4h}4`$^yFBcMuii)CVFfi27 zw$Y!?rHoIGk6Xq}<}nJ-z4z^+!f1N0oFAtw1n&x-v<;7?}0$f%z*pdQj{4=rUo z1aF!_%+~p!^CAQGRe6ooi+!!(6uC%?n}2H8dfkkE5r(etU}(WMJEUN6o;0-&_GNrq z3QJIN{6A)jLqo;yF6lXLV9H<}HB6KK&8>WKL*^FFWZSolRd$$4P`T8yBLP6L!?U+1 zc^@^#gzt)_MOIPzlo2-$uS2`fL_B-U!J*S-f8=x|xxOj8ij_FsI5* zSB^sU-K}pW6y9ch1`mdJ0b8Ss@ESoa%9Ip90W<@5AiFppw}qvX^yb@2^y+7(eea5z z@2Hlin!q0>;mk!;lN#nbrmZV$l^~zZQrK37t!eMHaY9=8T)W_`&+dD@xDYSF5jQL;uplmC*L zzH=pp0s*vV9}le7u7;6C!sHR+>wT}Nsw9XWKR1Wq+(N?H!qV^|xHdR(lh+SznjtJR z$TD@G_v?BIIu~@*dLB!}J>k+1E0+`C=X<%i{uH$|0;?IBvlL$w(v5yC8tme9m)G6X zt_eVErPfNSw&~lhfxSk@d=nnqgcoE5sUMSr=Yp9TKPNqd+FWQ6I2+cDXMZb7g?LvC zEp$Eom1-)dS`p!aiVgo#O0@R z&Mep1_;c!lfgZi`z5XTqK>z>@|B%7R7z5xBz?0N3ypmOdb)=jVVMvHm5@1g?o-K<5 j2!^xij=fBMKhMRYPy#B8Q{}Zg|Ha&qP81{{t54Q|)AB3| diff --git a/worlds/musedash/Items.py b/worlds/musedash/Items.py index 63fd3aa51b..027a9002d5 100644 --- a/worlds/musedash/Items.py +++ b/worlds/musedash/Items.py @@ -6,6 +6,7 @@ class SongData(NamedTuple): """Special data container to contain the metadata of each song to make filtering work.""" code: Optional[int] + uid: str album: str streamer_mode: bool easy: Optional[int] diff --git a/worlds/musedash/MuseDashCollection.py b/worlds/musedash/MuseDashCollection.py index 9e8c9214a1..64aa6ca49a 100644 --- a/worlds/musedash/MuseDashCollection.py +++ b/worlds/musedash/MuseDashCollection.py @@ -1,13 +1,9 @@ -from .Items import SongData, AlbumData -from typing import Dict, List, Set, Optional +from .Items import SongData +from .MuseDashData import SONG_DATA +from typing import Dict, List, Set from collections import ChainMap -def load_text_file(name: str) -> str: - import pkgutil - return pkgutil.get_data(__name__, name).decode() - - class MuseDashCollections: """Contains all the data of Muse Dash, loaded from MuseDashData.txt.""" STARTING_CODE = 2900000 @@ -33,15 +29,6 @@ class MuseDashCollections: "Rin Len's Mirrorland", # Paid DLC not included in Muse Plus ] - DIFF_OVERRIDES: List[str] = [ - "MuseDash ka nanika hi", - "Rush-Hour", - "Find this Month's Featured Playlist", - "PeroPero in the Universe", - "umpopoff", - "P E R O P E R O Brother Dance", - ] - REMOVED_SONGS = [ "CHAOS Glitch", "FM 17314 SUGAR RADIO", @@ -50,9 +37,7 @@ class MuseDashCollections: "Tsukuyomi Ni Naru Replaced", ] - album_items: Dict[str, AlbumData] = {} - album_locations: Dict[str, int] = {} - song_items: Dict[str, SongData] = {} + song_items = SONG_DATA song_locations: Dict[str, int] = {} trap_items: Dict[str, int] = { @@ -65,7 +50,7 @@ class MuseDashCollections: "Gray Scale Trap": STARTING_CODE + 7, "Nyaa SFX Trap": STARTING_CODE + 8, "Error SFX Trap": STARTING_CODE + 9, - "Focus Line Trap": STARTING_CODE + 10, + "Focus Line Trap": STARTING_CODE + 10, } sfx_trap_items: List[str] = [ @@ -85,65 +70,13 @@ class MuseDashCollections: "Extra Life": 1, } - item_names_to_id: ChainMap = ChainMap({}, filler_items, trap_items) - location_names_to_id: ChainMap = ChainMap(song_locations, album_locations) + item_names_to_id: ChainMap = ChainMap({k: v.code for k, v in SONG_DATA.items()}, filler_items, trap_items) + location_names_to_id: ChainMap = ChainMap(song_locations) def __init__(self) -> None: self.item_names_to_id[self.MUSIC_SHEET_NAME] = self.MUSIC_SHEET_CODE - item_id_index = self.STARTING_CODE + 50 - full_file = load_text_file("MuseDashData.txt") - seen_albums = set() - for line in full_file.splitlines(): - line = line.strip() - sections = line.split("|") - - album = sections[2] - if album not in seen_albums: - seen_albums.add(album) - self.album_items[album] = AlbumData(item_id_index) - item_id_index += 1 - - # Data is in the format 'Song|UID|Album|StreamerMode|EasyDiff|HardDiff|MasterDiff|SecretDiff' - song_name = sections[0] - # [1] is used in the client copy to make sure item id's match. - steamer_mode = sections[3] == "True" - - if song_name in self.DIFF_OVERRIDES: - # These songs use non-standard difficulty values. Which are being overriden with standard values. - # But also avoid filling any missing difficulties (i.e. 0s) with a difficulty value. - if sections[4] != '0': - diff_of_easy = 4 - else: - diff_of_easy = None - - if sections[5] != '0': - diff_of_hard = 7 - else: - diff_of_hard = None - - if sections[6] != '0': - diff_of_master = 10 - else: - diff_of_master = None - else: - diff_of_easy = self.parse_song_difficulty(sections[4]) - diff_of_hard = self.parse_song_difficulty(sections[5]) - diff_of_master = self.parse_song_difficulty(sections[6]) - - self.song_items[song_name] = SongData(item_id_index, album, steamer_mode, - diff_of_easy, diff_of_hard, diff_of_master) - item_id_index += 1 - - self.item_names_to_id.update({name: data.code for name, data in self.song_items.items()}) - self.item_names_to_id.update({name: data.code for name, data in self.album_items.items()}) - location_id_index = self.STARTING_CODE - for name in self.album_items.keys(): - self.album_locations[f"{name}-0"] = location_id_index - self.album_locations[f"{name}-1"] = location_id_index + 1 - location_id_index += 2 - for name in self.song_items.keys(): self.song_locations[f"{name}-0"] = location_id_index self.song_locations[f"{name}-1"] = location_id_index + 1 @@ -157,7 +90,7 @@ class MuseDashCollections: for songKey, songData in self.song_items.items(): if not self.song_matches_dlc_filter(songData, dlc_songs): continue - + if songKey in self.REMOVED_SONGS: continue @@ -193,18 +126,3 @@ class MuseDashCollections: return True return False - - def parse_song_difficulty(self, difficulty: str) -> Optional[int]: - """Attempts to parse the song difficulty.""" - if len(difficulty) <= 0 or difficulty == "?" or difficulty == "¿": - return None - - # 0 is used as a filler and no songs actually have a 0 difficulty song. - if difficulty == "0": - return None - - # Curse the 2023 april fools update. Used on 3rd Avenue. - if difficulty == "〇": - return 10 - - return int(difficulty) diff --git a/worlds/musedash/MuseDashData.py b/worlds/musedash/MuseDashData.py new file mode 100644 index 0000000000..1700f956aa --- /dev/null +++ b/worlds/musedash/MuseDashData.py @@ -0,0 +1,615 @@ +from .Items import SongData +from typing import Dict + + +# Auto Generated +SONG_DATA: Dict[str, SongData] = { + "Magical Wonderland": SongData(2900051, "0-48", "Default Music", True, 1, 3, None), + "Iyaiya": SongData(2900052, "0-0", "Default Music", True, 1, 4, None), + "Wonderful Pain": SongData(2900053, "0-2", "Default Music", False, 1, 3, None), + "Breaking Dawn": SongData(2900054, "0-3", "Default Music", True, 2, 4, None), + "One-Way Subway": SongData(2900055, "0-4", "Default Music", True, 1, 4, None), + "Frost Land": SongData(2900056, "0-1", "Default Music", False, 1, 3, 6), + "Heart-Pounding Flight": SongData(2900057, "0-5", "Default Music", True, 2, 5, None), + "Pancake is Love": SongData(2900058, "0-29", "Default Music", True, 2, 4, 7), + "Shiguang Tuya": SongData(2900059, "0-6", "Default Music", True, 2, 5, None), + "Evolution": SongData(2900060, "0-37", "Default Music", False, 2, 4, 7), + "Dolphin and Broadcast": SongData(2900061, "0-7", "Default Music", True, 2, 5, None), + "Yuki no Shizuku Ame no Oto": SongData(2900062, "0-8", "Default Music", True, 2, 4, 6), + "Best One feat.tooko": SongData(2900063, "0-43", "Default Music", False, 3, 5, None), + "Candy-coloured Love Theory": SongData(2900064, "0-31", "Default Music", False, 2, 4, 6), + "Night Wander": SongData(2900065, "0-38", "Default Music", False, 3, 5, 7), + "Dohna Dohna no Uta": SongData(2900066, "0-46", "Default Music", False, 2, 4, 6), + "Spring Carnival": SongData(2900067, "0-9", "Default Music", False, 2, 4, 7), + "DISCO NIGHT": SongData(2900068, "0-30", "Default Music", True, 2, 4, 7), + "Koi no Moonlight": SongData(2900069, "0-49", "Default Music", False, 2, 5, 8), + "Lian Ai Audio Navigation": SongData(2900070, "0-10", "Default Music", False, 3, 5, 7), + "Lights of Muse": SongData(2900071, "0-11", "Default Music", True, 4, 6, 8), + "midstream jam": SongData(2900072, "0-12", "Default Music", False, 2, 5, 8), + "Nihao": SongData(2900073, "0-40", "Default Music", False, 3, 5, 7), + "Confession": SongData(2900074, "0-13", "Default Music", False, 3, 5, 8), + "Galaxy Striker": SongData(2900075, "0-32", "Default Music", False, 4, 7, 9), + "Departure Road": SongData(2900076, "0-14", "Default Music", True, 2, 5, 8), + "Bass Telekinesis": SongData(2900077, "0-15", "Default Music", False, 2, 5, 8), + "Cage of Almeria": SongData(2900078, "0-16", "Default Music", True, 3, 5, 7), + "Ira": SongData(2900079, "0-17", "Default Music", True, 4, 6, 8), + "Blackest Luxury Car": SongData(2900080, "0-18", "Default Music", True, 3, 6, 8), + "Medicine of Sing": SongData(2900081, "0-19", "Default Music", False, 3, 6, 8), + "irregulyze": SongData(2900082, "0-20", "Default Music", True, 3, 6, 8), + "I don't care about Christmas though": SongData(2900083, "0-47", "Default Music", False, 4, 6, 8), + "Imaginary World": SongData(2900084, "0-21", "Default Music", True, 4, 6, 8), + "Dysthymia": SongData(2900085, "0-22", "Default Music", True, 4, 7, 9), + "From the New World": SongData(2900086, "0-42", "Default Music", False, 2, 5, 7), + "NISEGAO": SongData(2900087, "0-33", "Default Music", True, 4, 7, 9), + "Say! Fanfare!": SongData(2900088, "0-44", "Default Music", False, 4, 6, 9), + "Star Driver": SongData(2900089, "0-34", "Default Music", True, 5, 7, 9), + "Formation": SongData(2900090, "0-23", "Default Music", True, 4, 6, 9), + "Shinsou Masui": SongData(2900091, "0-24", "Default Music", True, 4, 6, 10), + "Mezame Eurythmics": SongData(2900092, "0-50", "Default Music", False, 4, 6, 9), + "Shenri Kuaira -repeat-": SongData(2900093, "0-51", "Default Music", False, 5, 7, 9), + "Latitude": SongData(2900094, "0-25", "Default Music", True, 3, 6, 9), + "Aqua Stars": SongData(2900095, "0-39", "Default Music", False, 5, 7, 10), + "Funkotsu Saishin Casino": SongData(2900096, "0-26", "Default Music", False, 5, 7, 10), + "Clock Room & Spiritual World": SongData(2900097, "0-27", "Default Music", True, 4, 6, 9), + "INTERNET OVERDOSE": SongData(2900098, "0-52", "Default Music", False, 3, 6, 9), + "Tu Hua": SongData(2900099, "0-35", "Default Music", True, 4, 7, 9), + "Mujinku-Vacuum": SongData(2900100, "0-28", "Default Music", False, 5, 7, 11), + "MilK": SongData(2900101, "0-36", "Default Music", False, 5, 7, 9), + "umpopoff": SongData(2900102, "0-41", "Default Music", False, None, 7, None), + "Mopemope": SongData(2900103, "0-45", "Default Music", False, 4, 7, 9), + "The Happycore Idol": SongData(2900105, "43-0", "MD Plus Project", True, 2, 5, 7), + "Amatsumikaboshi": SongData(2900106, "43-1", "MD Plus Project", True, 4, 6, 8), + "ARIGA THESIS": SongData(2900107, "43-2", "MD Plus Project", True, 3, 6, 10), + "Night of Nights": SongData(2900108, "43-3", "MD Plus Project", False, 4, 7, 10), + "#Psychedelic_Meguro_River": SongData(2900109, "43-4", "MD Plus Project", False, 3, 6, 8), + "can you feel it": SongData(2900110, "43-5", "MD Plus Project", False, 4, 6, 8), + "Midnight O'clock": SongData(2900111, "43-6", "MD Plus Project", True, 3, 6, 8), + "Rin": SongData(2900112, "43-7", "MD Plus Project", True, 5, 7, 10), + "Smile-mileS": SongData(2900113, "43-8", "MD Plus Project", False, 6, 8, 10), + "Believing and Being": SongData(2900114, "43-9", "MD Plus Project", True, 4, 6, 9), + "Catalyst": SongData(2900115, "43-10", "MD Plus Project", False, 5, 7, 9), + "don't!stop!eroero!": SongData(2900116, "43-11", "MD Plus Project", True, 5, 7, 9), + "pa pi pu pi pu pi pa": SongData(2900117, "43-12", "MD Plus Project", False, 6, 8, 10), + "Sand Maze": SongData(2900118, "43-13", "MD Plus Project", True, 6, 8, 10), + "Diffraction": SongData(2900119, "43-14", "MD Plus Project", True, 5, 8, 10), + "AKUMU": SongData(2900120, "43-15", "MD Plus Project", False, 4, 6, 8), + "Queen Aluett": SongData(2900121, "43-16", "MD Plus Project", True, 7, 9, 11), + "DROPS": SongData(2900122, "43-17", "MD Plus Project", False, 2, 5, 8), + "Frightfully-insane Flan-chan's frightful song": SongData(2900123, "43-18", "MD Plus Project", False, 5, 7, 10), + "snooze": SongData(2900124, "43-19", "MD Plus Project", False, 5, 7, 10), + "Kuishinbo Hacker feat.Kuishinbo Akachan": SongData(2900125, "43-20", "MD Plus Project", True, 5, 7, 9), + "Inu no outa": SongData(2900126, "43-21", "MD Plus Project", True, 3, 5, 7), + "Prism Fountain": SongData(2900127, "43-22", "MD Plus Project", True, 7, 9, 11), + "Gospel": SongData(2900128, "43-23", "MD Plus Project", False, 4, 6, 9), + "East Ai Li Lovely": SongData(2900130, "62-0", "Happy Otaku Pack Vol.17", False, 2, 4, 7), + "Mori Umi no Fune": SongData(2900131, "62-1", "Happy Otaku Pack Vol.17", True, 5, 7, 9), + "Ooi": SongData(2900132, "62-2", "Happy Otaku Pack Vol.17", True, 5, 7, 10), + "Numatta!!": SongData(2900133, "62-3", "Happy Otaku Pack Vol.17", True, 5, 7, 9), + "SATELLITE": SongData(2900134, "62-4", "Happy Otaku Pack Vol.17", False, 5, 7, 9), + "Fantasia Sonata Colorful feat. V!C": SongData(2900135, "62-5", "Happy Otaku Pack Vol.17", True, 6, 8, 11), + "MuseDash ka nanika hi": SongData(2900137, "61-0", "Ola Dash", True, 4, 7, 10), + "Aleph-0": SongData(2900138, "61-1", "Ola Dash", True, 7, 9, 11), + "Buttoba Supernova": SongData(2900139, "61-2", "Ola Dash", False, 5, 7, 10), + "Rush-Hour": SongData(2900140, "61-3", "Ola Dash", False, 4, 7, 10), + "3rd Avenue": SongData(2900141, "61-4", "Ola Dash", False, 3, 5, 10), + "WORLDINVADER": SongData(2900142, "61-5", "Ola Dash", True, 5, 8, 10), + "N3V3R G3T OV3R": SongData(2900144, "60-0", "maimai DX Limited-time Suite", True, 4, 7, 10), + "Oshama Scramble!": SongData(2900145, "60-1", "maimai DX Limited-time Suite", True, 5, 7, 10), + "Valsqotch": SongData(2900146, "60-2", "maimai DX Limited-time Suite", True, 5, 9, 11), + "Paranormal My Mind": SongData(2900147, "60-3", "maimai DX Limited-time Suite", True, 5, 7, 9), + "Flower, snow and Drum'n'bass.": SongData(2900148, "60-4", "maimai DX Limited-time Suite", True, 5, 8, 10), + "Amenohoakari": SongData(2900149, "60-5", "maimai DX Limited-time Suite", True, 6, 8, 10), + "Boiling Blood": SongData(2900151, "59-0", "MSR Anthology", True, 5, 8, 10), + "ManiFesto": SongData(2900152, "59-1", "MSR Anthology", True, 4, 6, 9), + "Operation Blade": SongData(2900153, "59-2", "MSR Anthology", True, 3, 5, 7), + "Radiant": SongData(2900154, "59-3", "MSR Anthology", True, 3, 5, 8), + "Renegade": SongData(2900155, "59-4", "MSR Anthology", True, 3, 5, 8), + "Speed of Light": SongData(2900156, "59-5", "MSR Anthology", False, 1, 4, 7), + "Dossoles Holiday": SongData(2900157, "59-6", "MSR Anthology", True, 5, 7, 9), + "Autumn Moods": SongData(2900158, "59-7", "MSR Anthology", True, 3, 5, 7), + "People People": SongData(2900160, "58-0", "Nanahira Paradise", True, 5, 7, 9), + "Endless Error Loop": SongData(2900161, "58-1", "Nanahira Paradise", True, 4, 7, 9), + "Forbidden Pizza!": SongData(2900162, "58-2", "Nanahira Paradise", True, 5, 7, 9), + "Don't Make the Vocalist do Anything Insane": SongData(2900163, "58-3", "Nanahira Paradise", True, 5, 8, 9), + "Tokimeki*Meteostrike": SongData(2900165, "57-0", "Happy Otaku Pack Vol.16", True, 3, 6, 8), + "Down Low": SongData(2900166, "57-1", "Happy Otaku Pack Vol.16", True, 4, 6, 8), + "LOUDER MACHINE": SongData(2900167, "57-2", "Happy Otaku Pack Vol.16", True, 5, 7, 9), + "Sorewa mo Lovechu": SongData(2900168, "57-3", "Happy Otaku Pack Vol.16", True, 5, 7, 10), + "Rave_Tech": SongData(2900169, "57-4", "Happy Otaku Pack Vol.16", True, 5, 8, 10), + "Brilliant & Shining!": SongData(2900170, "57-5", "Happy Otaku Pack Vol.16", False, 5, 8, 10), + "Psyched Fevereiro": SongData(2900172, "56-0", "Give Up TREATMENT Vol.11", False, 5, 8, 10), + "Inferno City": SongData(2900173, "56-1", "Give Up TREATMENT Vol.11", False, 6, 8, 10), + "Paradigm Shift": SongData(2900174, "56-2", "Give Up TREATMENT Vol.11", False, 4, 7, 10), + "Snapdragon": SongData(2900175, "56-3", "Give Up TREATMENT Vol.11", False, 5, 7, 10), + "Prestige and Vestige": SongData(2900176, "56-4", "Give Up TREATMENT Vol.11", True, 6, 8, 11), + "Tiny Fate": SongData(2900177, "56-5", "Give Up TREATMENT Vol.11", False, 7, 9, 11), + "Tsuki ni Murakumo Hana ni Kaze": SongData(2900179, "55-0", "Touhou Mugakudan -II-", False, 3, 5, 7), + "Patchouli's - Best Hit GSK": SongData(2900180, "55-1", "Touhou Mugakudan -II-", False, 3, 5, 8), + "Monosugoi Space Shuttle de Koishi ga Monosugoi uta": SongData(2900181, "55-2", "Touhou Mugakudan -II-", False, 3, 5, 7), + "Kakoinaki Yo wa Ichigo no Tsukikage": SongData(2900182, "55-3", "Touhou Mugakudan -II-", False, 3, 6, 8), + "Psychedelic Kizakura Doumei": SongData(2900183, "55-4", "Touhou Mugakudan -II-", False, 4, 7, 10), + "Mischievous Sensation": SongData(2900184, "55-5", "Touhou Mugakudan -II-", False, 5, 7, 9), + "White Canvas": SongData(2900186, "54-0", "MEGAREX THE FUTURE", False, 3, 6, 8), + "Gloomy Flash": SongData(2900187, "54-1", "MEGAREX THE FUTURE", False, 5, 8, 10), + "Find this Month's Featured Playlist": SongData(2900188, "54-2", "MEGAREX THE FUTURE", False, 4, 7, 10), + "Sunday Night": SongData(2900189, "54-3", "MEGAREX THE FUTURE", False, 3, 6, 9), + "Goodbye Goodnight": SongData(2900190, "54-4", "MEGAREX THE FUTURE", False, 4, 6, 9), + "ENDLESS CIDER": SongData(2900191, "54-5", "MEGAREX THE FUTURE", False, 4, 6, 8), + "On And On!!": SongData(2900193, "53-0", "Happy Otaku Pack Vol.15", True, 4, 7, 9), + "Trip!": SongData(2900194, "53-1", "Happy Otaku Pack Vol.15", True, 3, 5, 7), + "Hoshi no otoshimono": SongData(2900195, "53-2", "Happy Otaku Pack Vol.15", False, 5, 7, 9), + "Plucky Race": SongData(2900196, "53-3", "Happy Otaku Pack Vol.15", True, 5, 8, 10), + "Fantasia Sonata Destiny": SongData(2900197, "53-4", "Happy Otaku Pack Vol.15", True, 3, 7, 10), + "Run through": SongData(2900198, "53-5", "Happy Otaku Pack Vol.15", False, 5, 8, 10), + "marooned night": SongData(2900200, "52-0", "MUSE RADIO FM103", False, 2, 4, 6), + "daydream girl": SongData(2900201, "52-1", "MUSE RADIO FM103", False, 3, 6, 8), + "Not Ornament": SongData(2900202, "52-2", "MUSE RADIO FM103", True, 3, 5, 8), + "Baby Pink": SongData(2900203, "52-3", "MUSE RADIO FM103", False, 3, 5, 8), + "I'm Here": SongData(2900204, "52-4", "MUSE RADIO FM103", False, 4, 6, 8), + "Masquerade Diary": SongData(2900206, "51-0", "Virtual Idol Production", True, 2, 5, 8), + "Reminiscence": SongData(2900207, "51-1", "Virtual Idol Production", True, 5, 7, 9), + "DarakuDatenshi": SongData(2900208, "51-2", "Virtual Idol Production", True, 3, 6, 9), + "D.I.Y.": SongData(2900209, "51-3", "Virtual Idol Production", False, 4, 6, 9), + "Boys in Virtual Land": SongData(2900210, "51-4", "Virtual Idol Production", False, 4, 7, 9), + "kui": SongData(2900211, "51-5", "Virtual Idol Production", True, 5, 7, 9), + "Nyan Cat": SongData(2900213, "50-0", "Nyanya Universe!", False, 4, 7, 9), + "PeroPero in the Universe": SongData(2900214, "50-1", "Nyanya Universe!", True, 4, 7, 10), + "In-kya Yo-kya Onmyoji": SongData(2900215, "50-2", "Nyanya Universe!", False, 6, 8, 10), + "KABOOOOOM!!!!": SongData(2900216, "50-3", "Nyanya Universe!", True, 4, 6, 8), + "Doppelganger": SongData(2900217, "50-4", "Nyanya Universe!", True, 5, 7, 9), + "Pray a LOVE": SongData(2900219, "49-0", "DokiDoki! Valentine!", False, 2, 5, 8), + "Love-Avoidance Addiction": SongData(2900220, "49-1", "DokiDoki! Valentine!", False, 3, 5, 7), + "Daisuki Dayo feat.Wotoha": SongData(2900221, "49-2", "DokiDoki! Valentine!", False, 5, 7, 10), + "glory day": SongData(2900223, "48-0", "DJMAX Reflect", False, 2, 5, 7), + "Bright Dream": SongData(2900224, "48-1", "DJMAX Reflect", False, 2, 4, 7), + "Groovin Up": SongData(2900225, "48-2", "DJMAX Reflect", False, 4, 6, 8), + "I Want You": SongData(2900226, "48-3", "DJMAX Reflect", False, 3, 6, 8), + "OBLIVION": SongData(2900227, "48-4", "DJMAX Reflect", False, 3, 6, 9), + "Elastic STAR": SongData(2900228, "48-5", "DJMAX Reflect", False, 4, 6, 8), + "U.A.D": SongData(2900229, "48-6", "DJMAX Reflect", False, 4, 6, 8), + "Jealousy": SongData(2900230, "48-7", "DJMAX Reflect", False, 3, 5, 7), + "Memory of Beach": SongData(2900231, "48-8", "DJMAX Reflect", False, 3, 6, 8), + "Don't Die": SongData(2900232, "48-9", "DJMAX Reflect", False, 6, 8, 10), + "Y CE Ver.": SongData(2900233, "48-10", "DJMAX Reflect", False, 4, 6, 9), + "Fancy Night": SongData(2900234, "48-11", "DJMAX Reflect", False, 4, 6, 8), + "Can We Talk": SongData(2900235, "48-12", "DJMAX Reflect", False, 4, 6, 8), + "Give Me 5": SongData(2900236, "48-13", "DJMAX Reflect", False, 2, 6, 8), + "Nightmare": SongData(2900237, "48-14", "DJMAX Reflect", False, 7, 9, 11), + "Haze of Autumn": SongData(2900239, "47-0", "Arcaea", True, 3, 6, 9), + "GIMME DA BLOOD": SongData(2900240, "47-1", "Arcaea", False, 3, 6, 9), + "Libertas": SongData(2900241, "47-2", "Arcaea", False, 4, 7, 10), + "Cyaegha": SongData(2900242, "47-3", "Arcaea", False, 5, 7, 9), + "Bang!!": SongData(2900244, "46-0", "Happy Otaku Pack Vol.14", False, 4, 6, 8), + "Paradise 2": SongData(2900245, "46-1", "Happy Otaku Pack Vol.14", False, 4, 6, 8), + "Symbol": SongData(2900246, "46-2", "Happy Otaku Pack Vol.14", False, 5, 7, 9), + "Nekojarashi": SongData(2900247, "46-3", "Happy Otaku Pack Vol.14", False, 5, 8, 10), + "A Philosophical Wanderer": SongData(2900248, "46-4", "Happy Otaku Pack Vol.14", False, 4, 6, 10), + "Isouten": SongData(2900249, "46-5", "Happy Otaku Pack Vol.14", True, 6, 8, 10), + "ONOMATO Pairing!!!": SongData(2900251, "45-0", "WACCA Horizon", False, 4, 6, 9), + "with U": SongData(2900252, "45-1", "WACCA Horizon", False, 6, 8, 10), + "Chariot": SongData(2900253, "45-2", "WACCA Horizon", False, 3, 6, 9), + "GASHATT": SongData(2900254, "45-3", "WACCA Horizon", False, 5, 7, 10), + "LIN NE KRO NE feat. lasah": SongData(2900255, "45-4", "WACCA Horizon", False, 6, 8, 10), + "ANGEL HALO": SongData(2900256, "45-5", "WACCA Horizon", False, 5, 8, 11), + "Party in the HOLLOWood": SongData(2900258, "44-0", "Happy Otaku Pack Vol.13", False, 3, 6, 8), + "Ying Ying da Zuozhan": SongData(2900259, "44-1", "Happy Otaku Pack Vol.13", True, 5, 7, 9), + "Howlin' Pumpkin": SongData(2900260, "44-2", "Happy Otaku Pack Vol.13", True, 4, 6, 8), + "Bad Apple!! feat. Nomico": SongData(2900262, "42-0", "Touhou Mugakudan -I-", False, 1, 3, 6), + "Iro wa Nioedo, Chirinuru wo": SongData(2900263, "42-1", "Touhou Mugakudan -I-", False, 2, 4, 7), + "Cirno's Perfect Math Class": SongData(2900264, "42-2", "Touhou Mugakudan -I-", False, 4, 7, 9), + "Hiiro Gekka Kyousai no Zetsu": SongData(2900265, "42-3", "Touhou Mugakudan -I-", False, 4, 6, 8), + "Flowery Moonlit Night": SongData(2900266, "42-4", "Touhou Mugakudan -I-", False, 3, 6, 8), + "Unconscious Requiem": SongData(2900267, "42-5", "Touhou Mugakudan -I-", False, 3, 6, 8), + "Super Battleworn Insomniac": SongData(2900269, "41-0", "7th Beat Games", True, 4, 7, 9), + "Bomb-Sniffing Pomeranian": SongData(2900270, "41-1", "7th Beat Games", True, 4, 6, 8), + "Rollerdisco Rumble": SongData(2900271, "41-2", "7th Beat Games", True, 4, 6, 9), + "Rose Garden": SongData(2900272, "41-3", "7th Beat Games", False, 5, 8, 9), + "EMOMOMO": SongData(2900273, "41-4", "7th Beat Games", True, 4, 7, 10), + "Heracles": SongData(2900274, "41-5", "7th Beat Games", False, 6, 8, 10), + "Rush-More": SongData(2900276, "40-0", "Happy Otaku Pack Vol.12", False, 4, 7, 9), + "Kill My Fortune": SongData(2900277, "40-1", "Happy Otaku Pack Vol.12", False, 5, 7, 10), + "Yosari Tsukibotaru Suminoborite": SongData(2900278, "40-2", "Happy Otaku Pack Vol.12", False, 5, 7, 9), + "JUMP! HardCandy": SongData(2900279, "40-3", "Happy Otaku Pack Vol.12", False, 3, 6, 8), + "Hibari": SongData(2900280, "40-4", "Happy Otaku Pack Vol.12", False, 3, 5, 8), + "OCCHOCO-REST-LESS": SongData(2900281, "40-5", "Happy Otaku Pack Vol.12", True, 4, 7, 9), + "See-Saw Day": SongData(2900283, "39-0", "MUSE RADIO FM102", True, 1, 3, 6), + "happy hour": SongData(2900284, "39-1", "MUSE RADIO FM102", True, 2, 4, 7), + "Seikimatsu no Natsu": SongData(2900285, "39-2", "MUSE RADIO FM102", True, 4, 6, 8), + "twinkle night": SongData(2900286, "39-3", "MUSE RADIO FM102", False, 3, 6, 8), + "ARUYA HARERUYA": SongData(2900287, "39-4", "MUSE RADIO FM102", False, 2, 5, 7), + "Blush": SongData(2900288, "39-5", "MUSE RADIO FM102", False, 2, 4, 7), + "Naked Summer": SongData(2900289, "39-6", "MUSE RADIO FM102", True, 4, 6, 8), + "BLESS ME": SongData(2900290, "39-7", "MUSE RADIO FM102", True, 2, 5, 7), + "FM 17314 SUGAR RADIO": SongData(2900291, "39-8", "MUSE RADIO FM102", True, None, None, None), + "NO ONE YES MAN": SongData(2900293, "38-0", "Phigros", False, 5, 7, 9), + "Snowfall, Merry Christmas": SongData(2900294, "38-1", "Phigros", False, 5, 8, 10), + "Igallta": SongData(2900295, "38-2", "Phigros", False, 6, 8, 10), + "Colored Glass": SongData(2900297, "37-0", "Cute Is Everything Vol.7", False, 1, 4, 7), + "Neonlights": SongData(2900298, "37-1", "Cute Is Everything Vol.7", False, 4, 7, 9), + "Hope for the flowers": SongData(2900299, "37-2", "Cute Is Everything Vol.7", False, 4, 7, 9), + "Seaside Cycling on May 30": SongData(2900300, "37-3", "Cute Is Everything Vol.7", False, 3, 6, 8), + "SKY HIGH": SongData(2900301, "37-4", "Cute Is Everything Vol.7", False, 2, 4, 6), + "Mousou Chu!!": SongData(2900302, "37-5", "Cute Is Everything Vol.7", False, 4, 7, 8), + "NightTheater": SongData(2900304, "36-0", "Give Up TREATMENT Vol.10", True, 6, 8, 11), + "Cutter": SongData(2900305, "36-1", "Give Up TREATMENT Vol.10", False, 4, 7, 10), + "bamboo": SongData(2900306, "36-2", "Give Up TREATMENT Vol.10", False, 6, 8, 10), + "enchanted love": SongData(2900307, "36-3", "Give Up TREATMENT Vol.10", False, 2, 6, 9), + "c.s.q.n.": SongData(2900308, "36-4", "Give Up TREATMENT Vol.10", False, 5, 8, 11), + "Booouncing!!": SongData(2900309, "36-5", "Give Up TREATMENT Vol.10", False, 5, 7, 10), + "PeroPeroGames goes Bankrupt": SongData(2900311, "35-0", "Happy Otaku Pack SP", True, 6, 8, 10), + "MARENOL": SongData(2900312, "35-1", "Happy Otaku Pack SP", False, 4, 7, 10), + "I am really good at Japanese style": SongData(2900313, "35-2", "Happy Otaku Pack SP", True, 6, 8, 10), + "Rush B": SongData(2900314, "35-3", "Happy Otaku Pack SP", True, 4, 7, 9), + "DataErr0r": SongData(2900315, "35-4", "Happy Otaku Pack SP", False, 5, 7, 9), + "Burn": SongData(2900316, "35-5", "Happy Otaku Pack SP", True, 4, 7, 9), + "ALiVE": SongData(2900318, "34-0", "HARDCORE TANO*C", False, 5, 7, 10), + "BATTLE NO.1": SongData(2900319, "34-1", "HARDCORE TANO*C", False, 5, 8, 10), + "Cthugha": SongData(2900320, "34-2", "HARDCORE TANO*C", False, 6, 8, 10), + "TWINKLE*MAGIC": SongData(2900321, "34-3", "HARDCORE TANO*C", False, 4, 7, 10), + "Comet Coaster": SongData(2900322, "34-4", "HARDCORE TANO*C", False, 6, 8, 10), + "XODUS": SongData(2900323, "34-5", "HARDCORE TANO*C", False, 7, 9, 11), + "Fireflies": SongData(2900325, "33-0", "cyTus", True, 1, 4, 7), + "Light up my love!!": SongData(2900326, "33-1", "cyTus", True, 3, 5, 7), + "Happiness Breeze": SongData(2900327, "33-2", "cyTus", True, 4, 6, 8), + "Chrome VOX": SongData(2900328, "33-3", "cyTus", True, 6, 8, 10), + "CHAOS": SongData(2900329, "33-4", "cyTus", True, 3, 6, 9), + "Saika": SongData(2900330, "33-5", "cyTus", True, 3, 5, 8), + "Standby for Action": SongData(2900331, "33-6", "cyTus", True, 4, 6, 8), + "Hydrangea": SongData(2900332, "33-7", "cyTus", True, 5, 7, 9), + "Amenemhat": SongData(2900333, "33-8", "cyTus", True, 6, 8, 10), + "Santouka": SongData(2900334, "33-9", "cyTus", True, 2, 5, 8), + "HEXENNACHTROCK-katashihaya-": SongData(2900335, "33-10", "cyTus", True, 4, 8, 10), + "Blah!!": SongData(2900336, "33-11", "cyTus", True, 5, 8, 11), + "CHAOS Glitch": SongData(2900337, "33-12", "cyTus", True, None, None, None), + "Preparara": SongData(2900339, "32-0", "Let's Do Bad Things Together", False, 1, 4, 6), + "Whatcha;Whatcha Doin'": SongData(2900340, "32-1", "Let's Do Bad Things Together", False, 3, 6, 9), + "Madara": SongData(2900341, "32-2", "Let's Do Bad Things Together", False, 4, 6, 9), + "pICARESq": SongData(2900342, "32-3", "Let's Do Bad Things Together", False, 4, 6, 8), + "Desastre": SongData(2900343, "32-4", "Let's Do Bad Things Together", False, 4, 6, 8), + "Shoot for the Moon": SongData(2900344, "32-5", "Let's Do Bad Things Together", False, 2, 5, 8), + "The 90's Decision": SongData(2900346, "31-0", "Happy Otaku Pack Vol.11", True, 5, 7, 9), + "Medusa": SongData(2900347, "31-1", "Happy Otaku Pack Vol.11", False, 4, 6, 8), + "Final Step!": SongData(2900348, "31-2", "Happy Otaku Pack Vol.11", False, 5, 7, 10), + "MAGENTA POTION": SongData(2900349, "31-3", "Happy Otaku Pack Vol.11", False, 4, 7, 9), + "Cross Ray": SongData(2900350, "31-4", "Happy Otaku Pack Vol.11", False, 3, 6, 9), + "Square Lake": SongData(2900351, "31-5", "Happy Otaku Pack Vol.11", False, 6, 8, 9), + "Girly Cupid": SongData(2900353, "30-0", "Cute Is Everything Vol.6", False, 3, 6, 8), + "sheep in the light": SongData(2900354, "30-1", "Cute Is Everything Vol.6", False, 2, 5, 8), + "Breaker city": SongData(2900355, "30-2", "Cute Is Everything Vol.6", False, 4, 6, 9), + "heterodoxy": SongData(2900356, "30-3", "Cute Is Everything Vol.6", False, 4, 6, 8), + "Computer Music Girl": SongData(2900357, "30-4", "Cute Is Everything Vol.6", False, 3, 5, 7), + "Focus Point": SongData(2900358, "30-5", "Cute Is Everything Vol.6", True, 2, 5, 7), + "Groove Prayer": SongData(2900360, "29-0", "Let' s GROOVE!", True, 3, 5, 7), + "FUJIN Rumble": SongData(2900361, "29-1", "Let' s GROOVE!", True, 5, 7, 10), + "Marry me, Nightmare": SongData(2900362, "29-2", "Let' s GROOVE!", False, 6, 8, 11), + "HG Makaizou Polyvinyl Shounen": SongData(2900363, "29-3", "Let' s GROOVE!", True, 4, 7, 9), + "Seizya no Ibuki": SongData(2900364, "29-4", "Let' s GROOVE!", True, 6, 8, 10), + "ouroboros -twin stroke of the end-": SongData(2900365, "29-5", "Let' s GROOVE!", True, 4, 6, 9), + "Heisha Onsha": SongData(2900367, "28-0", "Happy Otaku Pack Vol.10", False, 4, 6, 8), + "Ginevra": SongData(2900368, "28-1", "Happy Otaku Pack Vol.10", True, 5, 7, 10), + "Paracelestia": SongData(2900369, "28-2", "Happy Otaku Pack Vol.10", False, 5, 8, 10), + "un secret": SongData(2900370, "28-3", "Happy Otaku Pack Vol.10", False, 2, 4, 6), + "Good Life": SongData(2900371, "28-4", "Happy Otaku Pack Vol.10", False, 4, 6, 8), + "nini-nini-": SongData(2900372, "28-5", "Happy Otaku Pack Vol.10", False, 4, 7, 9), + "Can I friend you on Bassbook? lol": SongData(2900374, "27-0", "Nanahira Festival", False, 3, 6, 8), + "Gaming*Everything": SongData(2900375, "27-1", "Nanahira Festival", False, 5, 8, 11), + "Renji de haochi": SongData(2900376, "27-2", "Nanahira Festival", False, 5, 7, 9), + "You Make My Life 1UP": SongData(2900377, "27-3", "Nanahira Festival", False, 4, 6, 8), + "Newbies, Geeks, Internets": SongData(2900378, "27-4", "Nanahira Festival", False, 6, 8, 10), + "Onegai!Kon kon Oinarisama": SongData(2900379, "27-5", "Nanahira Festival", False, 3, 6, 9), + "Legend of Eastern Rabbit -SKY DEFENDER-": SongData(2900381, "26-0", "Give Up TREATMENT Vol.9", False, 4, 6, 9), + "ENERGY SYNERGY MATRIX": SongData(2900382, "26-1", "Give Up TREATMENT Vol.9", False, 6, 8, 10), + "Punai Punai Genso": SongData(2900383, "26-2", "Give Up TREATMENT Vol.9", False, 2, 7, 11), + "Better Graphic Animation": SongData(2900384, "26-3", "Give Up TREATMENT Vol.9", False, 5, 8, 11), + "Variant Cross": SongData(2900385, "26-4", "Give Up TREATMENT Vol.9", False, 4, 7, 10), + "Ultra Happy Miracle Bazoooooka!!": SongData(2900386, "26-5", "Give Up TREATMENT Vol.9", False, 7, 9, 11), + "tape/stop/night": SongData(2900388, "25-0", "MUSE RADIO FM101", True, 3, 5, 7), + "Pixel Galaxy": SongData(2900389, "25-1", "MUSE RADIO FM101", False, 2, 5, 8), + "Notice": SongData(2900390, "25-2", "MUSE RADIO FM101", False, 4, 7, 10), + "Strawberry Godzilla": SongData(2900391, "25-3", "MUSE RADIO FM101", True, 2, 5, 7), + "OKIMOCHI EXPRESSION": SongData(2900392, "25-4", "MUSE RADIO FM101", False, 4, 6, 10), + "Kimi to pool disco": SongData(2900393, "25-5", "MUSE RADIO FM101", False, 4, 6, 8), + "The Last Page": SongData(2900395, "24-0", "Happy Otaku Pack Vol.9", False, 3, 5, 7), + "IKAROS": SongData(2900396, "24-1", "Happy Otaku Pack Vol.9", False, 4, 7, 10), + "Tsukuyomi": SongData(2900397, "24-2", "Happy Otaku Pack Vol.9", False, 3, 6, 9), + "Future Stream": SongData(2900398, "24-3", "Happy Otaku Pack Vol.9", False, 4, 6, 8), + "FULi AUTO SHOOTER": SongData(2900399, "24-4", "Happy Otaku Pack Vol.9", True, 4, 7, 9), + "GOODFORTUNE": SongData(2900400, "24-5", "Happy Otaku Pack Vol.9", False, 5, 7, 9), + "The Dessert After Rain": SongData(2900402, "23-0", "Cute Is Everything Vol.5", True, 2, 4, 6), + "Confession Support Formula": SongData(2900403, "23-1", "Cute Is Everything Vol.5", False, 3, 5, 7), + "Omatsuri": SongData(2900404, "23-2", "Cute Is Everything Vol.5", False, 1, 3, 6), + "FUTUREPOP": SongData(2900405, "23-3", "Cute Is Everything Vol.5", True, 2, 5, 7), + "The Breeze": SongData(2900406, "23-4", "Cute Is Everything Vol.5", False, 1, 4, 6), + "I LOVE LETTUCE FRIED RICE!!": SongData(2900407, "23-5", "Cute Is Everything Vol.5", False, 3, 7, 9), + "The NightScape": SongData(2900409, "22-0", "Give Up TREATMENT Vol.8", False, 4, 7, 9), + "FREEDOM DiVE": SongData(2900410, "22-1", "Give Up TREATMENT Vol.8", False, 6, 8, 10), + "Phi": SongData(2900411, "22-2", "Give Up TREATMENT Vol.8", False, 5, 8, 10), + "Lueur de la nuit": SongData(2900412, "22-3", "Give Up TREATMENT Vol.8", False, 6, 8, 11), + "Creamy Sugary OVERDRIVE!!!": SongData(2900413, "22-4", "Give Up TREATMENT Vol.8", True, 4, 7, 10), + "Disorder": SongData(2900414, "22-5", "Give Up TREATMENT Vol.8", False, 5, 7, 11), + "Glimmer": SongData(2900416, "21-0", "Budget Is Burning: Nano Core", False, 2, 5, 8), + "EXIST": SongData(2900417, "21-1", "Budget Is Burning: Nano Core", False, 3, 5, 8), + "Irreplaceable": SongData(2900418, "21-2", "Budget Is Burning: Nano Core", False, 4, 6, 8), + "Moonlight Banquet": SongData(2900420, "20-0", "Happy Otaku Pack Vol.8", True, 2, 5, 8), + "Flashdance": SongData(2900421, "20-1", "Happy Otaku Pack Vol.8", False, 3, 6, 9), + "INFiNiTE ENERZY -Overdoze-": SongData(2900422, "20-2", "Happy Otaku Pack Vol.8", False, 4, 7, 9), + "One Way Street": SongData(2900423, "20-3", "Happy Otaku Pack Vol.8", False, 3, 6, 10), + "This Club is Not 4 U": SongData(2900424, "20-4", "Happy Otaku Pack Vol.8", False, 4, 7, 9), + "ULTRA MEGA HAPPY PARTY!!!": SongData(2900425, "20-5", "Happy Otaku Pack Vol.8", False, 5, 7, 10), + "INFINITY": SongData(2900427, "19-0", "Give Up TREATMENT Vol.7", True, 5, 8, 10), + "Punai Punai Senso": SongData(2900428, "19-1", "Give Up TREATMENT Vol.7", False, 2, 7, 11), + "Maxi": SongData(2900429, "19-2", "Give Up TREATMENT Vol.7", False, 5, 8, 10), + "YInMn Blue": SongData(2900430, "19-3", "Give Up TREATMENT Vol.7", False, 6, 8, 10), + "Plumage": SongData(2900431, "19-4", "Give Up TREATMENT Vol.7", False, 4, 7, 10), + "Dr.Techro": SongData(2900432, "19-5", "Give Up TREATMENT Vol.7", False, 7, 9, 11), + "SWEETSWEETSWEET": SongData(2900434, "18-0", "Cute Is Everything Vol.4", True, 2, 5, 7), + "Deep Blue and the Breaths of the Night": SongData(2900435, "18-1", "Cute Is Everything Vol.4", True, 2, 4, 6), + "Joy Connection": SongData(2900436, "18-2", "Cute Is Everything Vol.4", False, 3, 6, 8), + "Self Willed Girl Ver.B": SongData(2900437, "18-3", "Cute Is Everything Vol.4", True, 4, 6, 8), + "Just Disobedient": SongData(2900438, "18-4", "Cute Is Everything Vol.4", False, 3, 6, 8), + "Holy Sh*t Grass Snake": SongData(2900439, "18-5", "Cute Is Everything Vol.4", False, 2, 6, 9), + "Cotton Candy Wonderland": SongData(2900441, "17-0", "Happy Otaku Pack Vol.7", False, 2, 5, 8), + "Punai Punai Taiso": SongData(2900442, "17-1", "Happy Otaku Pack Vol.7", False, 2, 7, 10), + "Fly High": SongData(2900443, "17-2", "Happy Otaku Pack Vol.7", False, 3, 5, 7), + "prejudice": SongData(2900444, "17-3", "Happy Otaku Pack Vol.7", True, 4, 6, 9), + "The 89's Momentum": SongData(2900445, "17-4", "Happy Otaku Pack Vol.7", True, 5, 7, 9), + "energy night": SongData(2900446, "17-5", "Happy Otaku Pack Vol.7", True, 5, 7, 10), + "Future Dive": SongData(2900448, "16-0", "Give Up TREATMENT Vol.6", True, 4, 6, 9), + "Re End of a Dream": SongData(2900449, "16-1", "Give Up TREATMENT Vol.6", False, 5, 8, 11), + "Etude -Storm-": SongData(2900450, "16-2", "Give Up TREATMENT Vol.6", True, 6, 8, 10), + "Unlimited Katharsis": SongData(2900451, "16-3", "Give Up TREATMENT Vol.6", False, 4, 6, 10), + "Magic Knight Girl": SongData(2900452, "16-4", "Give Up TREATMENT Vol.6", False, 4, 7, 9), + "Eeliaas": SongData(2900453, "16-5", "Give Up TREATMENT Vol.6", False, 6, 9, 11), + "Magic Spell": SongData(2900455, "15-0", "Cute Is Everything Vol.3", True, 2, 5, 7), + "Colorful Star, Colored Drawing, Travel Poem": SongData(2900456, "15-1", "Cute Is Everything Vol.3", False, 3, 4, 6), + "Satell Knight": SongData(2900457, "15-2", "Cute Is Everything Vol.3", False, 3, 6, 8), + "Black River Feat.Mes": SongData(2900458, "15-3", "Cute Is Everything Vol.3", True, 1, 4, 6), + "I am sorry": SongData(2900459, "15-4", "Cute Is Everything Vol.3", False, 2, 5, 8), + "Ueta Tori Tachi": SongData(2900460, "15-5", "Cute Is Everything Vol.3", False, 3, 6, 8), + "Elysion's Old Mans": SongData(2900462, "14-0", "Happy Otaku Pack Vol.6", False, 3, 5, 8), + "AXION": SongData(2900463, "14-1", "Happy Otaku Pack Vol.6", False, 4, 5, 8), + "Amnesia": SongData(2900464, "14-2", "Happy Otaku Pack Vol.6", True, 3, 6, 9), + "Onsen Dai Sakusen": SongData(2900465, "14-3", "Happy Otaku Pack Vol.6", True, 4, 6, 8), + "Gleam stone": SongData(2900466, "14-4", "Happy Otaku Pack Vol.6", False, 4, 7, 9), + "GOODWORLD": SongData(2900467, "14-5", "Happy Otaku Pack Vol.6", False, 4, 7, 10), + "Instant Soluble Neon": SongData(2900469, "13-0", "Cute Is Everything Vol.2", True, 2, 4, 7), + "Retrospective Poem on the Planet": SongData(2900470, "13-1", "Cute Is Everything Vol.2", False, 3, 5, 7), + "I'm Gonna Buy! Buy! Buy!": SongData(2900471, "13-2", "Cute Is Everything Vol.2", True, 4, 6, 8), + "Dating Manifesto": SongData(2900472, "13-3", "Cute Is Everything Vol.2", True, 2, 4, 6), + "First Snow": SongData(2900473, "13-4", "Cute Is Everything Vol.2", True, 2, 3, 6), + "Xin Shang Huahai": SongData(2900474, "13-5", "Cute Is Everything Vol.2", False, 3, 6, 8), + "Gaikan Chrysalis": SongData(2900476, "12-0", "Give Up TREATMENT Vol.5", False, 4, 6, 8), + "Sterelogue": SongData(2900477, "12-1", "Give Up TREATMENT Vol.5", True, 5, 7, 10), + "Cheshire's Dance": SongData(2900478, "12-2", "Give Up TREATMENT Vol.5", True, 4, 7, 10), + "Skrik": SongData(2900479, "12-3", "Give Up TREATMENT Vol.5", True, 5, 7, 11), + "Soda Pop Canva5!": SongData(2900480, "12-4", "Give Up TREATMENT Vol.5", False, 5, 8, 10), + "RUBY LINTe": SongData(2900481, "12-5", "Give Up TREATMENT Vol.5", False, 5, 8, 11), + "Brave My Heart": SongData(2900483, "11-0", "Happy Otaku Pack Vol.5", True, 3, 5, 7), + "Sakura Fubuki": SongData(2900484, "11-1", "Happy Otaku Pack Vol.5", False, 4, 7, 10), + "8bit Adventurer": SongData(2900485, "11-2", "Happy Otaku Pack Vol.5", False, 6, 8, 10), + "Suffering of screw": SongData(2900486, "11-3", "Happy Otaku Pack Vol.5", False, 3, 5, 8), + "tiny lady": SongData(2900487, "11-4", "Happy Otaku Pack Vol.5", True, 4, 6, 9), + "Power Attack": SongData(2900488, "11-5", "Happy Otaku Pack Vol.5", False, 5, 7, 10), + "Destr0yer": SongData(2900490, "10-0", "Give Up TREATMENT Vol.4", False, 4, 7, 9), + "Noel": SongData(2900491, "10-1", "Give Up TREATMENT Vol.4", False, 5, 8, 10), + "Kyoukiranbu": SongData(2900492, "10-2", "Give Up TREATMENT Vol.4", False, 7, 9, 11), + "Two Phace": SongData(2900493, "10-3", "Give Up TREATMENT Vol.4", True, 4, 7, 10), + "Fly Again": SongData(2900494, "10-4", "Give Up TREATMENT Vol.4", False, 5, 7, 10), + "ouroVoros": SongData(2900495, "10-5", "Give Up TREATMENT Vol.4", False, 7, 9, 11), + "Leave It Alone": SongData(2900497, "9-0", "Happy Otaku Pack Vol.4", True, 2, 5, 8), + "Tsubasa no Oreta Tenshitachi no Requiem": SongData(2900498, "9-1", "Happy Otaku Pack Vol.4", False, 4, 7, 9), + "Chronomia": SongData(2900499, "9-2", "Happy Otaku Pack Vol.4", False, 5, 7, 10), + "Dandelion's Daydream": SongData(2900500, "9-3", "Happy Otaku Pack Vol.4", True, 5, 7, 8), + "Lorikeet Flat design": SongData(2900501, "9-4", "Happy Otaku Pack Vol.4", True, 5, 7, 10), + "GOODRAGE": SongData(2900502, "9-5", "Happy Otaku Pack Vol.4", False, 6, 9, 11), + "Altale": SongData(2900504, "8-0", "Give Up TREATMENT Vol.3", False, 3, 5, 7), + "Brain Power": SongData(2900505, "8-1", "Give Up TREATMENT Vol.3", False, 4, 7, 10), + "Berry Go!!": SongData(2900506, "8-2", "Give Up TREATMENT Vol.3", False, 3, 6, 9), + "Sweet* Witch* Girl*": SongData(2900507, "8-3", "Give Up TREATMENT Vol.3", False, 6, 8, 10), + "trippers feeling!": SongData(2900508, "8-4", "Give Up TREATMENT Vol.3", True, 5, 7, 9), + "Lilith ambivalence lovers": SongData(2900509, "8-5", "Give Up TREATMENT Vol.3", False, 5, 8, 10), + "Brave My Soul": SongData(2900511, "7-0", "Give Up TREATMENT Vol.2", False, 4, 6, 8), + "Halcyon": SongData(2900512, "7-1", "Give Up TREATMENT Vol.2", False, 4, 7, 10), + "Crimson Nightingale": SongData(2900513, "7-2", "Give Up TREATMENT Vol.2", True, 4, 7, 10), + "Invader": SongData(2900514, "7-3", "Give Up TREATMENT Vol.2", True, 3, 7, 11), + "Lyrith": SongData(2900515, "7-4", "Give Up TREATMENT Vol.2", False, 5, 7, 10), + "GOODBOUNCE": SongData(2900516, "7-5", "Give Up TREATMENT Vol.2", False, 4, 6, 9), + "Out of Sense": SongData(2900518, "6-0", "Budget Is Burning Vol.1", False, 3, 5, 8), + "My Life Is For You": SongData(2900519, "6-1", "Budget Is Burning Vol.1", False, 2, 4, 7), + "Etude -Sunset-": SongData(2900520, "6-2", "Budget Is Burning Vol.1", True, 5, 7, 9), + "Goodbye Boss": SongData(2900521, "6-3", "Budget Is Burning Vol.1", False, 4, 6, 8), + "Stargazer": SongData(2900522, "6-4", "Budget Is Burning Vol.1", True, 2, 5, 8), + "Lys Tourbillon": SongData(2900523, "6-5", "Budget Is Burning Vol.1", True, 4, 6, 8), + "Thirty Million Persona": SongData(2900525, "5-0", "Happy Otaku Pack Vol.3", False, 2, 4, 6), + "conflict": SongData(2900526, "5-1", "Happy Otaku Pack Vol.3", False, 2, 6, 9), + "Enka Dance Music": SongData(2900527, "5-2", "Happy Otaku Pack Vol.3", False, 3, 5, 7), + "XING": SongData(2900528, "5-3", "Happy Otaku Pack Vol.3", True, 4, 6, 8), + "Amakakeru Soukyuu no Serenade": SongData(2900529, "5-4", "Happy Otaku Pack Vol.3", False, 3, 6, 9), + "Gift box": SongData(2900530, "5-5", "Happy Otaku Pack Vol.3", False, 5, 7, 10), + "MUSEDASH!!!!": SongData(2900532, "4-0", "Happy Otaku Pack Vol.2", False, 2, 6, 9), + "Imprinting": SongData(2900533, "4-1", "Happy Otaku Pack Vol.2", False, 3, 6, 9), + "Skyward": SongData(2900534, "4-2", "Happy Otaku Pack Vol.2", True, 4, 7, 10), + "La nuit de vif": SongData(2900535, "4-3", "Happy Otaku Pack Vol.2", True, 2, 5, 8), + "Bit-alize": SongData(2900536, "4-4", "Happy Otaku Pack Vol.2", False, 3, 6, 8), + "GOODTEK": SongData(2900537, "4-5", "Happy Otaku Pack Vol.2", False, 4, 6, 9), + "Maharajah": SongData(2900539, "3-0", "Happy Otaku Pack Vol.1", False, 1, 3, 6), + "keep on running": SongData(2900540, "3-1", "Happy Otaku Pack Vol.1", False, 5, 7, 9), + "Kafig": SongData(2900541, "3-2", "Happy Otaku Pack Vol.1", True, 4, 6, 8), + "-+": SongData(2900542, "3-3", "Happy Otaku Pack Vol.1", True, 4, 6, 8), + "Tenri Kaku Jou": SongData(2900543, "3-4", "Happy Otaku Pack Vol.1", True, 3, 6, 9), + "Adjudicatorz-DanZai-": SongData(2900544, "3-5", "Happy Otaku Pack Vol.1", False, 3, 7, 10), + "Oriens": SongData(2900546, "2-0", "Give Up TREATMENT Vol.1", True, 3, 7, 9), + "PUPA": SongData(2900547, "2-1", "Give Up TREATMENT Vol.1", False, 6, 8, 11), + "Luna Express 2032": SongData(2900548, "2-2", "Give Up TREATMENT Vol.1", False, 4, 6, 8), + "Ukiyoe Yokochou": SongData(2900549, "2-3", "Give Up TREATMENT Vol.1", False, 6, 7, 9), + "Alice in Misanthrope": SongData(2900550, "2-4", "Give Up TREATMENT Vol.1", False, 5, 7, 10), + "GOODMEN": SongData(2900551, "2-5", "Give Up TREATMENT Vol.1", False, 5, 7, 10), + "Sunshine and Rainbow after August Rain": SongData(2900553, "1-0", "Cute Is Everything Vol.1", False, 2, 5, 8), + "Magical Number": SongData(2900554, "1-1", "Cute Is Everything Vol.1", False, 2, 5, 8), + "Dreaming Girl": SongData(2900555, "1-2", "Cute Is Everything Vol.1", False, 2, 5, 6), + "Daruma-san Fell Over": SongData(2900556, "1-3", "Cute Is Everything Vol.1", False, 3, 4, 6), + "Different": SongData(2900557, "1-4", "Cute Is Everything Vol.1", False, 1, 3, 6), + "The Future of the Phantom": SongData(2900558, "1-5", "Cute Is Everything Vol.1", False, 1, 3, 5), + "Doki Doki Jump!": SongData(2900560, "63-0", "MUSE RADIO FM104", True, 3, 5, 7), + "Centennial Streamers High": SongData(2900561, "63-1", "MUSE RADIO FM104", False, 4, 7, 9), + "Love Patrol": SongData(2900562, "63-2", "MUSE RADIO FM104", True, 3, 5, 7), + "Mahorova": SongData(2900563, "63-3", "MUSE RADIO FM104", True, 3, 5, 8), + "Yoru no machi": SongData(2900564, "63-4", "MUSE RADIO FM104", True, 1, 4, 7), + "INTERNET YAMERO": SongData(2900565, "63-5", "MUSE RADIO FM104", True, 6, 8, 10), + "Abracadabra": SongData(2900566, "43-24", "MD Plus Project", False, 6, 8, 10), + "Squalldecimator feat. EZ-Ven": SongData(2900567, "43-25", "MD Plus Project", True, 5, 7, 9), + "Amateras Rhythm": SongData(2900568, "43-26", "MD Plus Project", True, 6, 8, 11), + "Record one's Dream": SongData(2900569, "43-27", "MD Plus Project", False, 4, 7, 10), + "Lunatic": SongData(2900570, "43-28", "MD Plus Project", True, 5, 8, 10), + "Jiumeng": SongData(2900571, "43-29", "MD Plus Project", True, 3, 6, 8), + "The Day We Become Family": SongData(2900572, "43-30", "MD Plus Project", True, 3, 5, 8), + "Sutori ma FIRE!?!?": SongData(2900574, "64-0", "COSMIC RADIO PEROLIST", True, 3, 5, 8), + "Tanuki Step": SongData(2900575, "64-1", "COSMIC RADIO PEROLIST", True, 5, 7, 10), + "Space Stationery": SongData(2900576, "64-2", "COSMIC RADIO PEROLIST", True, 5, 7, 10), + "Songs Are Judged 90% by Chorus feat. Mameko": SongData(2900577, "64-3", "COSMIC RADIO PEROLIST", True, 6, 8, 10), + "Kawai Splendid Space Thief": SongData(2900578, "64-4", "COSMIC RADIO PEROLIST", False, 6, 8, 10), + "Night City Runway": SongData(2900579, "64-5", "COSMIC RADIO PEROLIST", True, 4, 6, 8), + "Chaos Shotgun feat. ChumuNote": SongData(2900580, "64-6", "COSMIC RADIO PEROLIST", True, 6, 8, 10), + "mew mew magical summer": SongData(2900581, "64-7", "COSMIC RADIO PEROLIST", False, 5, 8, 10), + "BrainDance": SongData(2900583, "65-0", "NeonAbyss", True, 3, 6, 9), + "My Focus!": SongData(2900584, "65-1", "NeonAbyss", True, 5, 7, 10), + "ABABABA BURST": SongData(2900585, "65-2", "NeonAbyss", True, 5, 7, 9), + "ULTRA HIGHER": SongData(2900586, "65-3", "NeonAbyss", True, 4, 7, 10), + "Silver Bullet": SongData(2900587, "43-31", "MD Plus Project", True, 5, 7, 10), + "Random": SongData(2900588, "43-32", "MD Plus Project", True, 4, 7, 9), + "OTOGE-BOSS-KYOKU-CHAN": SongData(2900589, "43-33", "MD Plus Project", False, 6, 8, 10), + "Crow Rabbit": SongData(2900590, "43-34", "MD Plus Project", True, 7, 9, 11), + "SyZyGy": SongData(2900591, "43-35", "MD Plus Project", True, 6, 8, 10), + "Mermaid Radio": SongData(2900592, "43-36", "MD Plus Project", True, 3, 5, 7), + "Helixir": SongData(2900593, "43-37", "MD Plus Project", False, 6, 8, 10), + "Highway Cruisin'": SongData(2900594, "43-38", "MD Plus Project", False, 3, 5, 8), + "JACK PT BOSS": SongData(2900595, "43-39", "MD Plus Project", False, 6, 8, 10), + "Time Capsule": SongData(2900596, "43-40", "MD Plus Project", False, 7, 9, 11), + "39 Music!": SongData(2900598, "66-0", "Miku in Museland", False, 3, 5, 8), + "Hand in Hand": SongData(2900599, "66-1", "Miku in Museland", False, 1, 3, 6), + "Cynical Night Plan": SongData(2900600, "66-2", "Miku in Museland", False, 4, 6, 8), + "God-ish": SongData(2900601, "66-3", "Miku in Museland", False, 4, 7, 10), + "Darling Dance": SongData(2900602, "66-4", "Miku in Museland", False, 4, 7, 9), + "Hatsune Creation Myth": SongData(2900603, "66-5", "Miku in Museland", False, 6, 8, 10), + "The Vampire": SongData(2900604, "66-6", "Miku in Museland", False, 4, 6, 9), + "Future Eve": SongData(2900605, "66-7", "Miku in Museland", False, 4, 8, 11), + "Unknown Mother Goose": SongData(2900606, "66-8", "Miku in Museland", False, 4, 8, 10), + "Shun-ran": SongData(2900607, "66-9", "Miku in Museland", False, 4, 7, 9), + "NICE TYPE feat. monii": SongData(2900608, "43-41", "MD Plus Project", True, 3, 6, 8), + "Rainy Angel": SongData(2900610, "67-0", "Happy Otaku Pack Vol.18", True, 4, 6, 9), + "Gullinkambi": SongData(2900611, "67-1", "Happy Otaku Pack Vol.18", True, 4, 7, 10), + "RakiRaki Rebuilders!!!": SongData(2900612, "67-2", "Happy Otaku Pack Vol.18", True, 5, 7, 10), + "Laniakea": SongData(2900613, "67-3", "Happy Otaku Pack Vol.18", False, 5, 8, 10), + "OTTAMA GAZER": SongData(2900614, "67-4", "Happy Otaku Pack Vol.18", True, 5, 8, 10), + "Sleep Tight feat.Macoto": SongData(2900615, "67-5", "Happy Otaku Pack Vol.18", True, 3, 5, 8), + "New York Back Raise": SongData(2900617, "68-0", "Gambler's Tricks", True, 6, 8, 10), + "slic.hertz": SongData(2900618, "68-1", "Gambler's Tricks", True, 5, 7, 9), + "Fuzzy-Navel": SongData(2900619, "68-2", "Gambler's Tricks", True, 6, 8, 10), + "Swing Edge": SongData(2900620, "68-3", "Gambler's Tricks", True, 4, 8, 10), + "Twisted Escape": SongData(2900621, "68-4", "Gambler's Tricks", True, 5, 8, 10), + "Swing Sweet Twee Dance": SongData(2900622, "68-5", "Gambler's Tricks", False, 4, 7, 10), + "Sanyousei SAY YA!!!": SongData(2900623, "43-42", "MD Plus Project", False, 4, 6, 8), + "YUKEMURI TAMAONSEN II": SongData(2900624, "43-43", "MD Plus Project", False, 3, 6, 9), + "Samayoi no mei Amatsu": SongData(2900626, "69-0", "Touhou Mugakudan -III-", False, 4, 6, 9), + "INTERNET SURVIVOR": SongData(2900627, "69-1", "Touhou Mugakudan -III-", False, 5, 8, 10), + "Shuki*RaiRai": SongData(2900628, "69-2", "Touhou Mugakudan -III-", False, 5, 7, 9), + "HELLOHELL": SongData(2900629, "69-3", "Touhou Mugakudan -III-", False, 4, 7, 10), + "Calamity Fortune": SongData(2900630, "69-4", "Touhou Mugakudan -III-", True, 6, 8, 10), + "Tsurupettan": SongData(2900631, "69-5", "Touhou Mugakudan -III-", True, 2, 5, 8), + "Twilight Poems": SongData(2900632, "43-44", "MD Plus Project", True, 3, 6, 8), + "All My Friends feat. RANASOL": SongData(2900633, "43-45", "MD Plus Project", True, 4, 7, 9), + "Heartache": SongData(2900634, "43-46", "MD Plus Project", True, 5, 7, 10), + "Blue Lemonade": SongData(2900635, "43-47", "MD Plus Project", True, 3, 6, 8), + "Haunted Dance": SongData(2900636, "43-48", "MD Plus Project", False, 6, 9, 11), + "Hey Vincent.": SongData(2900637, "43-49", "MD Plus Project", True, 6, 8, 10), + "Meteor feat. TEA": SongData(2900638, "43-50", "MD Plus Project", True, 3, 6, 9), + "Narcissism Angel": SongData(2900639, "43-51", "MD Plus Project", True, 1, 3, 6), + "AlterLuna": SongData(2900640, "43-52", "MD Plus Project", True, 6, 8, 11), + "Niki Tousen": SongData(2900641, "43-53", "MD Plus Project", True, 6, 8, 10), + "Rettou Joutou": SongData(2900643, "70-0", "Rin Len's Mirrorland", False, 4, 7, 9), + "Telecaster B-Boy": SongData(2900644, "70-1", "Rin Len's Mirrorland", False, 5, 7, 10), + "Iya Iya Iya": SongData(2900645, "70-2", "Rin Len's Mirrorland", False, 2, 4, 7), + "Nee Nee Nee": SongData(2900646, "70-3", "Rin Len's Mirrorland", False, 4, 6, 8), + "Chaotic Love Revolution": SongData(2900647, "70-4", "Rin Len's Mirrorland", False, 4, 6, 8), + "Dance of the Corpses": SongData(2900648, "70-5", "Rin Len's Mirrorland", False, 2, 5, 8), + "Bitter Choco Decoration": SongData(2900649, "70-6", "Rin Len's Mirrorland", False, 3, 6, 9), + "Dance Robot Dance": SongData(2900650, "70-7", "Rin Len's Mirrorland", False, 4, 7, 10), + "Sweet Devil": SongData(2900651, "70-8", "Rin Len's Mirrorland", False, 5, 7, 9), + "Someday'z Coming": SongData(2900652, "70-9", "Rin Len's Mirrorland", False, 5, 7, 9), + "Yume Ou Mono Yo Secret": SongData(2900653, "0-53", "Default Music", True, 6, 8, 10), + "Yume Ou Mono Yo": SongData(2900654, "0-54", "Default Music", True, 1, 4, None), + "Sweet Dream VIVINOS": SongData(2900656, "71-0", "Valentine Stage", False, 1, 4, 7), + "Ruler Of My Heart VIVINOS": SongData(2900657, "71-1", "Valentine Stage", False, 2, 4, 6), + "Reality Show": SongData(2900658, "71-2", "Valentine Stage", False, 5, 7, 10), + "SIG feat.Tobokegao": SongData(2900659, "71-3", "Valentine Stage", True, 3, 6, 8), + "Rose Love": SongData(2900660, "71-4", "Valentine Stage", True, 2, 4, 7), + "Euphoria": SongData(2900661, "71-5", "Valentine Stage", True, 1, 3, 6), + "P E R O P E R O Brother Dance": SongData(2900663, "72-0", "Legends of Muse Warriors", True, None, 7, None), + "PA PPA PANIC": SongData(2900664, "72-1", "Legends of Muse Warriors", False, 4, 8, 10), + "How To Make Music Game Song!": SongData(2900665, "72-2", "Legends of Muse Warriors", True, 6, 8, 10), + "Re Re": SongData(2900666, "72-3", "Legends of Muse Warriors", True, 7, 9, 11), + "Marmalade Twins": SongData(2900667, "72-4", "Legends of Muse Warriors", True, 5, 8, 10), + "DOMINATOR": SongData(2900668, "72-5", "Legends of Muse Warriors", True, 7, 9, 11), + "Teshikani TESHiKANi": SongData(2900669, "72-6", "Legends of Muse Warriors", True, 5, 7, 9), + "Urban Magic": SongData(2900671, "73-0", "Happy Otaku Pack Vol.19", True, 3, 5, 7), + "Maid's Prank": SongData(2900672, "73-1", "Happy Otaku Pack Vol.19", True, 5, 7, 10), + "Dance Dance Good Night Dance": SongData(2900673, "73-2", "Happy Otaku Pack Vol.19", True, 2, 4, 7), + "Ops Limone": SongData(2900674, "73-3", "Happy Otaku Pack Vol.19", True, 5, 8, 11), + "NOVA": SongData(2900675, "73-4", "Happy Otaku Pack Vol.19", True, 6, 8, 10), + "Heaven's Gradius": SongData(2900676, "73-5", "Happy Otaku Pack Vol.19", True, 6, 8, 10), + "Ray Tuning": SongData(2900678, "74-0", "CHUNITHM COURSE MUSE", True, 6, 8, 10), + "World Vanquisher": SongData(2900679, "74-1", "CHUNITHM COURSE MUSE", True, 6, 8, 10), + "Tsukuyomi Ni Naru Replaced": SongData(2900680, "74-2", "CHUNITHM COURSE MUSE", True, 5, 7, 9), + "The wheel to the right": SongData(2900681, "74-3", "CHUNITHM COURSE MUSE", True, 5, 7, 9), + "Climax": SongData(2900682, "74-4", "CHUNITHM COURSE MUSE", True, 4, 8, 11), + "Spider's Thread": SongData(2900683, "74-5", "CHUNITHM COURSE MUSE", True, 5, 8, 10), + "HIT ME UP": SongData(2900684, "43-54", "MD Plus Project", True, 4, 6, 8), + "Test Me feat. Uyeon": SongData(2900685, "43-55", "MD Plus Project", True, 3, 5, 9), + "Assault TAXI": SongData(2900686, "43-56", "MD Plus Project", True, 4, 7, 10), + "No": SongData(2900687, "43-57", "MD Plus Project", False, 4, 6, 9), + "Pop it": SongData(2900688, "43-58", "MD Plus Project", True, 1, 3, 6), + "HEARTBEAT! KyunKyun!": SongData(2900689, "43-59", "MD Plus Project", True, 4, 6, 9), + "SUPERHERO": SongData(2900691, "75-0", "Novice Rider Pack", False, 2, 4, 7), + "Highway_Summer": SongData(2900692, "75-1", "Novice Rider Pack", True, 2, 4, 6), + "Mx. Black Box": SongData(2900693, "75-2", "Novice Rider Pack", True, 5, 7, 9), + "Sweet Encounter": SongData(2900694, "75-3", "Novice Rider Pack", True, 2, 4, 7), + "Echo over you... Secret": SongData(2900695, "0-55", "Default Music", False, 6, 8, 10), + "Echo over you...": SongData(2900696, "0-56", "Default Music", False, 1, 4, None), + "Tsukuyomi Ni Naru": SongData(2900697, "74-6", "CHUNITHM COURSE MUSE", True, 5, 8, 10), + "disco light": SongData(2900699, "76-0", "MUSE RADIO FM105", True, 5, 7, 9), + "room light feat.chancylemon": SongData(2900700, "76-1", "MUSE RADIO FM105", True, 3, 5, 7), + "Invisible": SongData(2900701, "76-2", "MUSE RADIO FM105", True, 3, 5, 8), + "Christmas Season-LLABB": SongData(2900702, "76-3", "MUSE RADIO FM105", True, 1, 4, 7), + "Hyouryu": SongData(2900704, "77-0", "Let's Rhythm Jam!", False, 6, 8, 10), + "The Whole Rest": SongData(2900705, "77-1", "Let's Rhythm Jam!", False, 5, 8, 10), + "Hydra": SongData(2900706, "77-2", "Let's Rhythm Jam!", False, 4, 7, 11), + "Pastel Lines": SongData(2900707, "77-3", "Let's Rhythm Jam!", False, 3, 6, 9), + "LINK x LIN#S": SongData(2900708, "77-4", "Let's Rhythm Jam!", False, 3, 6, 9), + "Arcade ViruZ": SongData(2900709, "77-5", "Let's Rhythm Jam!", False, 6, 8, 11), + "Eve Avenir": SongData(2900711, "78-0", "Endless Pirouette", True, 6, 8, 10), + "Silverstring": SongData(2900712, "78-1", "Endless Pirouette", True, 5, 7, 10), + "Melusia": SongData(2900713, "78-2", "Endless Pirouette", False, 5, 7, 10), + "Devil's Castle": SongData(2900714, "78-3", "Endless Pirouette", True, 4, 7, 10), + "Abatement": SongData(2900715, "78-4", "Endless Pirouette", True, 6, 8, 10), + "Azalea": SongData(2900716, "78-5", "Endless Pirouette", False, 4, 8, 10), + "Brightly World": SongData(2900717, "78-6", "Endless Pirouette", True, 6, 8, 10), + "We'll meet in every world ***": SongData(2900718, "78-7", "Endless Pirouette", True, 7, 9, 11), + "Collapsar": SongData(2900719, "78-8", "Endless Pirouette", True, 7, 9, 10), + "Parousia": SongData(2900720, "78-9", "Endless Pirouette", False, 6, 8, 10), + "Gunners in the Rain": SongData(2900722, "79-0", "Ensemble Arcanum", False, 5, 8, 10), + "Halzion": SongData(2900723, "79-1", "Ensemble Arcanum", False, 2, 5, 8), + "SHOWTIME!!": SongData(2900724, "79-2", "Ensemble Arcanum", False, 6, 8, 10), + "Achromic Riddle": SongData(2900725, "79-3", "Ensemble Arcanum", False, 6, 8, 10), + "karanosu": SongData(2900726, "79-4", "Ensemble Arcanum", False, 3, 6, 8), + "Necromantic": SongData(2900727, "43-60", "MD Plus Project", False, 6, 8, 10), + "Saishuu kichiku imouto Flandre-S": SongData(2900729, "80-0", "Touhou Mugakudan -IV-", False, 6, 8, 10), + "Kachoufuugetsu": SongData(2900730, "80-1", "Touhou Mugakudan -IV-", False, 2, 6, 8), + "Maid heart is a puppet": SongData(2900731, "80-2", "Touhou Mugakudan -IV-", False, 5, 7, 9), + "Trance dance anarchy": SongData(2900732, "80-3", "Touhou Mugakudan -IV-", False, 4, 7, 10), + "fairy stage": SongData(2900733, "80-4", "Touhou Mugakudan -IV-", False, 4, 6, 9), + "Scarlet Police on Ghetto Patrol": SongData(2900734, "80-5", "Touhou Mugakudan -IV-", False, 5, 7, 10), + "Unwelcome School": SongData(2900735, "81-0", "MD-level Tactical Training Blu-ray", False, 6, 8, 10), + "Usagi Flap": SongData(2900736, "81-1", "MD-level Tactical Training Blu-ray", False, 3, 6, 8), + "RE Aoharu": SongData(2900737, "81-2", "MD-level Tactical Training Blu-ray", False, 3, 5, 8), + "Operation*DOTABATA!": SongData(2900738, "81-3", "MD-level Tactical Training Blu-ray", False, 5, 7, 10), +} diff --git a/worlds/musedash/MuseDashData.txt b/worlds/musedash/MuseDashData.txt deleted file mode 100644 index d913449ed5..0000000000 --- a/worlds/musedash/MuseDashData.txt +++ /dev/null @@ -1,597 +0,0 @@ -Magical Wonderland|0-48|Default Music|True|1|3|0| -Iyaiya|0-0|Default Music|True|1|4|0| -Wonderful Pain|0-2|Default Music|False|1|3|0| -Breaking Dawn|0-3|Default Music|True|2|4|0| -One-Way Subway|0-4|Default Music|True|1|4|0| -Frost Land|0-1|Default Music|False|1|3|6| -Heart-Pounding Flight|0-5|Default Music|True|2|5|0| -Pancake is Love|0-29|Default Music|True|2|4|7| -Shiguang Tuya|0-6|Default Music|True|2|5|0| -Evolution|0-37|Default Music|False|2|4|7| -Dolphin and Broadcast|0-7|Default Music|True|2|5|0| -Yuki no Shizuku Ame no Oto|0-8|Default Music|True|2|4|6| -Best One feat.tooko|0-43|Default Music|False|3|5|0| -Candy-coloured Love Theory|0-31|Default Music|False|2|4|6| -Night Wander|0-38|Default Music|False|3|5|7| -Dohna Dohna no Uta|0-46|Default Music|False|2|4|6| -Spring Carnival|0-9|Default Music|False|2|4|7| -DISCO NIGHT|0-30|Default Music|True|2|4|7| -Koi no Moonlight|0-49|Default Music|False|2|5|8| -Lian Ai Audio Navigation|0-10|Default Music|False|3|5|7| -Lights of Muse|0-11|Default Music|True|4|6|8|10 -midstream jam|0-12|Default Music|False|2|5|8| -Nihao|0-40|Default Music|False|3|5|7| -Confession|0-13|Default Music|False|3|5|8| -Galaxy Striker|0-32|Default Music|False|4|7|9| -Departure Road|0-14|Default Music|True|2|5|8| -Bass Telekinesis|0-15|Default Music|False|2|5|8| -Cage of Almeria|0-16|Default Music|True|3|5|7| -Ira|0-17|Default Music|True|4|6|8| -Blackest Luxury Car|0-18|Default Music|True|3|6|8| -Medicine of Sing|0-19|Default Music|False|3|6|8| -irregulyze|0-20|Default Music|True|3|6|8| -I don't care about Christmas though|0-47|Default Music|False|4|6|8| -Imaginary World|0-21|Default Music|True|4|6|8|10 -Dysthymia|0-22|Default Music|True|4|7|9| -From the New World|0-42|Default Music|False|2|5|7| -NISEGAO|0-33|Default Music|True|4|7|9| -Say! Fanfare!|0-44|Default Music|False|4|6|9| -Star Driver|0-34|Default Music|True|5|7|9| -Formation|0-23|Default Music|True|4|6|9| -Shinsou Masui|0-24|Default Music|True|4|6|10| -Mezame Eurythmics|0-50|Default Music|False|4|6|9| -Shenri Kuaira -repeat-|0-51|Default Music|False|5|7|9| -Latitude|0-25|Default Music|True|3|6|9| -Aqua Stars|0-39|Default Music|False|5|7|10| -Funkotsu Saishin Casino|0-26|Default Music|False|5|7|10| -Clock Room & Spiritual World|0-27|Default Music|True|4|6|9| -INTERNET OVERDOSE|0-52|Default Music|False|3|6|9| -Tu Hua|0-35|Default Music|True|4|7|9| -Mujinku-Vacuum|0-28|Default Music|False|5|7|11| -MilK|0-36|Default Music|False|5|7|9| -umpopoff|0-41|Default Music|False|0|?|0| -Mopemope|0-45|Default Music|False|4|7|9|11 -The Happycore Idol|43-0|MD Plus Project|True|2|5|7| -Amatsumikaboshi|43-1|MD Plus Project|True|4|6|8|10 -ARIGA THESIS|43-2|MD Plus Project|True|3|6|10| -Night of Nights|43-3|MD Plus Project|False|4|7|10| -#Psychedelic_Meguro_River|43-4|MD Plus Project|False|3|6|8| -can you feel it|43-5|MD Plus Project|False|4|6|8|9 -Midnight O'clock|43-6|MD Plus Project|True|3|6|8| -Rin|43-7|MD Plus Project|True|5|7|10| -Smile-mileS|43-8|MD Plus Project|False|6|8|10| -Believing and Being|43-9|MD Plus Project|True|4|6|9| -Catalyst|43-10|MD Plus Project|False|5|7|9| -don't!stop!eroero!|43-11|MD Plus Project|True|5|7|9| -pa pi pu pi pu pi pa|43-12|MD Plus Project|False|6|8|10| -Sand Maze|43-13|MD Plus Project|True|6|8|10|11 -Diffraction|43-14|MD Plus Project|True|5|8|10| -AKUMU|43-15|MD Plus Project|False|4|6|8| -Queen Aluett|43-16|MD Plus Project|True|7|9|11| -DROPS|43-17|MD Plus Project|False|2|5|8| -Frightfully-insane Flan-chan's frightful song|43-18|MD Plus Project|False|5|7|10| -snooze|43-19|MD Plus Project|False|5|7|10| -Kuishinbo Hacker feat.Kuishinbo Akachan|43-20|MD Plus Project|True|5|7|9| -Inu no outa|43-21|MD Plus Project|True|3|5|7| -Prism Fountain|43-22|MD Plus Project|True|7|9|11| -Gospel|43-23|MD Plus Project|False|4|6|9| -East Ai Li Lovely|62-0|Happy Otaku Pack Vol.17|False|2|4|7| -Mori Umi no Fune|62-1|Happy Otaku Pack Vol.17|True|5|7|9| -Ooi|62-2|Happy Otaku Pack Vol.17|True|5|7|10| -Numatta!!|62-3|Happy Otaku Pack Vol.17|True|5|7|9| -SATELLITE|62-4|Happy Otaku Pack Vol.17|False|5|7|9|10 -Fantasia Sonata Colorful feat. V!C|62-5|Happy Otaku Pack Vol.17|True|6|8|11| -MuseDash ka nanika hi|61-0|Ola Dash|True|?|?|¿| -Aleph-0|61-1|Ola Dash|True|7|9|11| -Buttoba Supernova|61-2|Ola Dash|False|5|7|10|11 -Rush-Hour|61-3|Ola Dash|False|IG|Jh|a2|Eh -3rd Avenue|61-4|Ola Dash|False|3|5|〇| -WORLDINVADER|61-5|Ola Dash|True|5|8|10|11 -N3V3R G3T OV3R|60-0|maimai DX Limited-time Suite|True|4|7|10| -Oshama Scramble!|60-1|maimai DX Limited-time Suite|True|5|7|10| -Valsqotch|60-2|maimai DX Limited-time Suite|True|5|9|11| -Paranormal My Mind|60-3|maimai DX Limited-time Suite|True|5|7|9| -Flower, snow and Drum'n'bass.|60-4|maimai DX Limited-time Suite|True|5|8|10|? -Amenohoakari|60-5|maimai DX Limited-time Suite|True|6|8|10| -Boiling Blood|59-0|MSR Anthology|True|5|8|10| -ManiFesto|59-1|MSR Anthology|True|4|6|9| -Operation Blade|59-2|MSR Anthology|True|3|5|7| -Radiant|59-3|MSR Anthology|True|3|5|8| -Renegade|59-4|MSR Anthology|True|3|5|8| -Speed of Light|59-5|MSR Anthology|False|1|4|7| -Dossoles Holiday|59-6|MSR Anthology|True|5|7|9| -Autumn Moods|59-7|MSR Anthology|True|3|5|7| -People People|58-0|Nanahira Paradise|True|5|7|9|11 -Endless Error Loop|58-1|Nanahira Paradise|True|4|7|9| -Forbidden Pizza!|58-2|Nanahira Paradise|True|5|7|9| -Don't Make the Vocalist do Anything Insane|58-3|Nanahira Paradise|True|5|8|9| -Tokimeki*Meteostrike|57-0|Happy Otaku Pack Vol.16|True|3|6|8| -Down Low|57-1|Happy Otaku Pack Vol.16|True|4|6|8| -LOUDER MACHINE|57-2|Happy Otaku Pack Vol.16|True|5|7|9| -Sorewa mo Lovechu|57-3|Happy Otaku Pack Vol.16|True|5|7|10| -Rave_Tech|57-4|Happy Otaku Pack Vol.16|True|5|8|10| -Brilliant & Shining!|57-5|Happy Otaku Pack Vol.16|False|5|8|10| -Psyched Fevereiro|56-0|Give Up TREATMENT Vol.11|False|5|8|10| -Inferno City|56-1|Give Up TREATMENT Vol.11|False|6|8|10| -Paradigm Shift|56-2|Give Up TREATMENT Vol.11|False|4|7|10| -Snapdragon|56-3|Give Up TREATMENT Vol.11|False|5|7|10| -Prestige and Vestige|56-4|Give Up TREATMENT Vol.11|True|6|8|11| -Tiny Fate|56-5|Give Up TREATMENT Vol.11|False|7|9|11| -Tsuki ni Murakumo Hana ni Kaze|55-0|Touhou Mugakudan -2-|False|3|5|7| -Patchouli's - Best Hit GSK|55-1|Touhou Mugakudan -2-|False|3|5|8| -Monosugoi Space Shuttle de Koishi ga Monosugoi uta|55-2|Touhou Mugakudan -2-|False|3|5|7|11 -Kakoinaki Yo wa Ichigo no Tsukikage|55-3|Touhou Mugakudan -2-|False|3|6|8| -Psychedelic Kizakura Doumei|55-4|Touhou Mugakudan -2-|False|4|7|10| -Mischievous Sensation|55-5|Touhou Mugakudan -2-|False|5|7|9| -White Canvas|54-0|MEGAREX THE FUTURE|False|3|6|8| -Gloomy Flash|54-1|MEGAREX THE FUTURE|False|5|8|10| -Find this Month's Featured Playlist|54-2|MEGAREX THE FUTURE|False|?|?|¿| -Sunday Night|54-3|MEGAREX THE FUTURE|False|3|6|9| -Goodbye Goodnight|54-4|MEGAREX THE FUTURE|False|4|6|9| -ENDLESS CIDER|54-5|MEGAREX THE FUTURE|False|4|6|8| -On And On!!|53-0|Happy Otaku Pack Vol.15|True|4|7|9|11 -Trip!|53-1|Happy Otaku Pack Vol.15|True|3|5|7| -Hoshi no otoshimono|53-2|Happy Otaku Pack Vol.15|False|5|7|9| -Plucky Race|53-3|Happy Otaku Pack Vol.15|True|5|8|10|11 -Fantasia Sonata Destiny|53-4|Happy Otaku Pack Vol.15|True|3|7|10| -Run through|53-5|Happy Otaku Pack Vol.15|False|5|8|10| -marooned night|52-0|MUSE RADIO FM103|False|2|4|6| -daydream girl|52-1|MUSE RADIO FM103|False|3|6|8| -Not Ornament|52-2|MUSE RADIO FM103|True|3|5|8| -Baby Pink|52-3|MUSE RADIO FM103|False|3|5|8| -I'm Here|52-4|MUSE RADIO FM103|False|4|6|8| -Masquerade Diary|51-0|Virtual Idol Production|True|2|5|8| -Reminiscence|51-1|Virtual Idol Production|True|5|7|9| -DarakuDatenshi|51-2|Virtual Idol Production|True|3|6|9| -D.I.Y.|51-3|Virtual Idol Production|False|4|6|9| -Boys in Virtual Land|51-4|Virtual Idol Production|False|4|7|9| -kui|51-5|Virtual Idol Production|True|5|7|9|11 -Nyan Cat|50-0|Nyanya Universe!|False|4|7|9| -PeroPero in the Universe|50-1|Nyanya Universe!|True|?|?|¿| -In-kya Yo-kya Onmyoji|50-2|Nyanya Universe!|False|6|8|10| -KABOOOOOM!!!!|50-3|Nyanya Universe!|True|4|6|8| -Doppelganger|50-4|Nyanya Universe!|True|5|7|9|12 -Pray a LOVE|49-0|DokiDoki! Valentine!|False|2|5|8| -Love-Avoidance Addiction|49-1|DokiDoki! Valentine!|False|3|5|7| -Daisuki Dayo feat.Wotoha|49-2|DokiDoki! Valentine!|False|5|7|10| -glory day|48-0|DJMAX Reflect|False|2|5|7| -Bright Dream|48-1|DJMAX Reflect|False|2|4|7| -Groovin Up|48-2|DJMAX Reflect|False|4|6|8| -I Want You|48-3|DJMAX Reflect|False|3|6|8| -OBLIVION|48-4|DJMAX Reflect|False|3|6|9| -Elastic STAR|48-5|DJMAX Reflect|False|4|6|8| -U.A.D|48-6|DJMAX Reflect|False|4|6|8|10 -Jealousy|48-7|DJMAX Reflect|False|3|5|7| -Memory of Beach|48-8|DJMAX Reflect|False|3|6|8| -Don't Die|48-9|DJMAX Reflect|False|6|8|10| -Y CE Ver.|48-10|DJMAX Reflect|False|4|6|9| -Fancy Night|48-11|DJMAX Reflect|False|4|6|8| -Can We Talk|48-12|DJMAX Reflect|False|4|6|8| -Give Me 5|48-13|DJMAX Reflect|False|2|6|8| -Nightmare|48-14|DJMAX Reflect|False|7|9|11| -Haze of Autumn|47-0|Arcaea|True|3|6|9| -GIMME DA BLOOD|47-1|Arcaea|False|3|6|9| -Libertas|47-2|Arcaea|False|4|7|10| -Cyaegha|47-3|Arcaea|False|5|7|9|11 -Bang!!|46-0|Happy Otaku Pack Vol.14|False|4|6|8| -Paradise 2|46-1|Happy Otaku Pack Vol.14|False|4|6|8| -Symbol|46-2|Happy Otaku Pack Vol.14|False|5|7|9| -Nekojarashi|46-3|Happy Otaku Pack Vol.14|False|5|8|10|11 -A Philosophical Wanderer|46-4|Happy Otaku Pack Vol.14|False|4|6|10| -Isouten|46-5|Happy Otaku Pack Vol.14|True|6|8|10|11 -ONOMATO Pairing!!!|45-0|WACCA Horizon|False|4|6|9| -with U|45-1|WACCA Horizon|False|6|8|10|11 -Chariot|45-2|WACCA Horizon|False|3|6|9| -GASHATT|45-3|WACCA Horizon|False|5|7|10| -LIN NE KRO NE feat. lasah|45-4|WACCA Horizon|False|6|8|10| -ANGEL HALO|45-5|WACCA Horizon|False|5|8|11| -Party in the HOLLOWood|44-0|Happy Otaku Pack Vol.13|False|3|6|8| -Ying Ying da Zuozhan|44-1|Happy Otaku Pack Vol.13|True|5|7|9| -Howlin' Pumpkin|44-2|Happy Otaku Pack Vol.13|True|4|6|8| -Bad Apple!! feat. Nomico|42-0|Touhou Mugakudan -1-|False|1|3|6|8 -Iro wa Nioedo, Chirinuru wo|42-1|Touhou Mugakudan -1-|False|2|4|7| -Cirno's Perfect Math Class|42-2|Touhou Mugakudan -1-|False|4|7|9| -Hiiro Gekka Kyousai no Zetsu|42-3|Touhou Mugakudan -1-|False|4|6|8| -Flowery Moonlit Night|42-4|Touhou Mugakudan -1-|False|3|6|8| -Unconscious Requiem|42-5|Touhou Mugakudan -1-|False|3|6|8| -Super Battleworn Insomniac|41-0|7th Beat Games|True|4|7|9|? -Bomb-Sniffing Pomeranian|41-1|7th Beat Games|True|4|6|8| -Rollerdisco Rumble|41-2|7th Beat Games|True|4|6|9| -Rose Garden|41-3|7th Beat Games|False|5|8|9| -EMOMOMO|41-4|7th Beat Games|True|4|7|10| -Heracles|41-5|7th Beat Games|False|6|8|10|? -Rush-More|40-0|Happy Otaku Pack Vol.12|False|4|7|9| -Kill My Fortune|40-1|Happy Otaku Pack Vol.12|False|5|7|10| -Yosari Tsukibotaru Suminoborite|40-2|Happy Otaku Pack Vol.12|False|5|7|9| -JUMP! HardCandy|40-3|Happy Otaku Pack Vol.12|False|3|6|8| -Hibari|40-4|Happy Otaku Pack Vol.12|False|3|5|8| -OCCHOCO-REST-LESS|40-5|Happy Otaku Pack Vol.12|True|4|7|9| -See-Saw Day|39-0|MUSE RADIO FM102|True|1|3|6| -happy hour|39-1|MUSE RADIO FM102|True|2|4|7| -Seikimatsu no Natsu|39-2|MUSE RADIO FM102|True|4|6|8| -twinkle night|39-3|MUSE RADIO FM102|False|3|6|8| -ARUYA HARERUYA|39-4|MUSE RADIO FM102|False|2|5|7| -Blush|39-5|MUSE RADIO FM102|False|2|4|7| -Naked Summer|39-6|MUSE RADIO FM102|True|4|6|8| -BLESS ME|39-7|MUSE RADIO FM102|True|2|5|7| -FM 17314 SUGAR RADIO|39-8|MUSE RADIO FM102|True|?|?|?| -NO ONE YES MAN|38-0|Phigros|False|5|7|9| -Snowfall, Merry Christmas|38-1|Phigros|False|5|8|10| -Igallta|38-2|Phigros|False|6|8|10|11 -Colored Glass|37-0|Cute Is Everything Vol.7|False|1|4|7| -Neonlights|37-1|Cute Is Everything Vol.7|False|4|7|9| -Hope for the flowers|37-2|Cute Is Everything Vol.7|False|4|7|9| -Seaside Cycling on May 30|37-3|Cute Is Everything Vol.7|False|3|6|8| -SKY HIGH|37-4|Cute Is Everything Vol.7|False|2|4|6| -Mousou Chu!!|37-5|Cute Is Everything Vol.7|False|4|7|8| -NightTheater|36-0|Give Up TREATMENT Vol.10|True|6|8|11| -Cutter|36-1|Give Up TREATMENT Vol.10|False|4|7|10| -bamboo|36-2|Give Up TREATMENT Vol.10|False|6|8|10|11 -enchanted love|36-3|Give Up TREATMENT Vol.10|False|2|6|9| -c.s.q.n.|36-4|Give Up TREATMENT Vol.10|False|5|8|11| -Booouncing!!|36-5|Give Up TREATMENT Vol.10|False|5|7|10| -PeroPeroGames goes Bankrupt|35-0|Happy Otaku Pack SP|True|6|8|10| -MARENOL|35-1|Happy Otaku Pack SP|False|4|7|10| -I am really good at Japanese style|35-2|Happy Otaku Pack SP|True|6|8|10| -Rush B|35-3|Happy Otaku Pack SP|True|4|7|9| -DataErr0r|35-4|Happy Otaku Pack SP|False|5|7|9|? -Burn|35-5|Happy Otaku Pack SP|True|4|7|9| -ALiVE|34-0|HARDCORE TANO*C|False|5|7|10| -BATTLE NO.1|34-1|HARDCORE TANO*C|False|5|8|10|11 -Cthugha|34-2|HARDCORE TANO*C|False|6|8|10|11 -TWINKLE*MAGIC|34-3|HARDCORE TANO*C|False|4|7|10|11 -Comet Coaster|34-4|HARDCORE TANO*C|False|6|8|10|11 -XODUS|34-5|HARDCORE TANO*C|False|7|9|11|12 -Fireflies|33-0|cyTus|True|1|4|7| -Light up my love!!|33-1|cyTus|True|3|5|7| -Happiness Breeze|33-2|cyTus|True|4|6|8|9 -Chrome VOX|33-3|cyTus|True|6|8|10|11 -CHAOS|33-4|cyTus|True|3|6|9| -Saika|33-5|cyTus|True|3|5|8| -Standby for Action|33-6|cyTus|True|4|6|8| -Hydrangea|33-7|cyTus|True|5|7|9| -Amenemhat|33-8|cyTus|True|6|8|10| -Santouka|33-9|cyTus|True|2|5|8| -HEXENNACHTROCK-katashihaya-|33-10|cyTus|True|4|8|10| -Blah!!|33-11|cyTus|True|5|8|11| -CHAOS Glitch|33-12|cyTus|True|0|?|0| -Preparara|32-0|Let's Do Bad Things Together|False|1|4|6| -Whatcha;Whatcha Doin'|32-1|Let's Do Bad Things Together|False|3|6|9| -Madara|32-2|Let's Do Bad Things Together|False|4|6|9| -pICARESq|32-3|Let's Do Bad Things Together|False|4|6|8| -Desastre|32-4|Let's Do Bad Things Together|False|4|6|8| -Shoot for the Moon|32-5|Let's Do Bad Things Together|False|2|5|8| -The 90's Decision|31-0|Happy Otaku Pack Vol.11|True|5|7|9| -Medusa|31-1|Happy Otaku Pack Vol.11|False|4|6|8|10 -Final Step!|31-2|Happy Otaku Pack Vol.11|False|5|7|10| -MAGENTA POTION|31-3|Happy Otaku Pack Vol.11|False|4|7|9| -Cross Ray|31-4|Happy Otaku Pack Vol.11|False|3|6|9| -Square Lake|31-5|Happy Otaku Pack Vol.11|False|6|8|9|11 -Girly Cupid|30-0|Cute Is Everything Vol.6|False|3|6|8| -sheep in the light|30-1|Cute Is Everything Vol.6|False|2|5|8| -Breaker city|30-2|Cute Is Everything Vol.6|False|4|6|9| -heterodoxy|30-3|Cute Is Everything Vol.6|False|4|6|8| -Computer Music Girl|30-4|Cute Is Everything Vol.6|False|3|5|7| -Focus Point|30-5|Cute Is Everything Vol.6|True|2|5|7| -Groove Prayer|29-0|Let' s GROOVE!|True|3|5|7| -FUJIN Rumble|29-1|Let' s GROOVE!|True|5|7|10|11 -Marry me, Nightmare|29-2|Let' s GROOVE!|False|6|8|11| -HG Makaizou Polyvinyl Shounen|29-3|Let' s GROOVE!|True|4|7|9|10 -Seizya no Ibuki|29-4|Let' s GROOVE!|True|6|8|10| -ouroboros -twin stroke of the end-|29-5|Let' s GROOVE!|True|4|6|9|12 -Heisha Onsha|28-0|Happy Otaku Pack Vol.10|False|4|6|8| -Ginevra|28-1|Happy Otaku Pack Vol.10|True|5|7|10|10 -Paracelestia|28-2|Happy Otaku Pack Vol.10|False|5|8|10| -un secret|28-3|Happy Otaku Pack Vol.10|False|2|4|6| -Good Life|28-4|Happy Otaku Pack Vol.10|False|4|6|8| -nini-nini-|28-5|Happy Otaku Pack Vol.10|False|4|7|9| -Can I friend you on Bassbook? lol|27-0|Nanahira Festival|False|3|6|8| -Gaming*Everything|27-1|Nanahira Festival|False|5|8|11| -Renji de haochi|27-2|Nanahira Festival|False|5|7|9| -You Make My Life 1UP|27-3|Nanahira Festival|False|4|6|8| -Newbies, Geeks, Internets|27-4|Nanahira Festival|False|6|8|10| -Onegai!Kon kon Oinarisama|27-5|Nanahira Festival|False|3|6|9| -Legend of Eastern Rabbit -SKY DEFENDER-|26-0|Give Up TREATMENT Vol.9|False|4|6|9| -ENERGY SYNERGY MATRIX|26-1|Give Up TREATMENT Vol.9|False|6|8|10| -Punai Punai Genso|26-2|Give Up TREATMENT Vol.9|False|2|7|11| -Better Graphic Animation|26-3|Give Up TREATMENT Vol.9|False|5|8|11| -Variant Cross|26-4|Give Up TREATMENT Vol.9|False|4|7|10| -Ultra Happy Miracle Bazoooooka!!|26-5|Give Up TREATMENT Vol.9|False|7|9|11| -tape/stop/night|25-0|MUSE RADIO FM101|True|3|5|7| -Pixel Galaxy|25-1|MUSE RADIO FM101|False|2|5|8| -Notice|25-2|MUSE RADIO FM101|False|4|7|10| -Strawberry Godzilla|25-3|MUSE RADIO FM101|True|2|5|7| -OKIMOCHI EXPRESSION|25-4|MUSE RADIO FM101|False|4|6|10| -Kimi to pool disco|25-5|MUSE RADIO FM101|False|4|6|8| -The Last Page|24-0|Happy Otaku Pack Vol.9|False|3|5|7| -IKAROS|24-1|Happy Otaku Pack Vol.9|False|4|7|10| -Tsukuyomi|24-2|Happy Otaku Pack Vol.9|False|3|6|9| -Future Stream|24-3|Happy Otaku Pack Vol.9|False|4|6|8| -FULi AUTO SHOOTER|24-4|Happy Otaku Pack Vol.9|True|4|7|9| -GOODFORTUNE|24-5|Happy Otaku Pack Vol.9|False|5|7|9| -The Dessert After Rain|23-0|Cute Is Everything Vol.5|True|2|4|6| -Confession Support Formula|23-1|Cute Is Everything Vol.5|False|3|5|7| -Omatsuri|23-2|Cute Is Everything Vol.5|False|1|3|6| -FUTUREPOP|23-3|Cute Is Everything Vol.5|True|2|5|7| -The Breeze|23-4|Cute Is Everything Vol.5|False|1|4|6| -I LOVE LETTUCE FRIED RICE!!|23-5|Cute Is Everything Vol.5|False|3|7|9| -The NightScape|22-0|Give Up TREATMENT Vol.8|False|4|7|9| -FREEDOM DiVE|22-1|Give Up TREATMENT Vol.8|False|6|8|10|12 -Phi|22-2|Give Up TREATMENT Vol.8|False|5|8|10| -Lueur de la nuit|22-3|Give Up TREATMENT Vol.8|False|6|8|11| -Creamy Sugary OVERDRIVE!!!|22-4|Give Up TREATMENT Vol.8|True|4|7|10| -Disorder|22-5|Give Up TREATMENT Vol.8|False|5|7|11| -Glimmer|21-0|Budget Is Burning: Nano Core|False|2|5|8| -EXIST|21-1|Budget Is Burning: Nano Core|False|3|5|8| -Irreplaceable|21-2|Budget Is Burning: Nano Core|False|4|6|8| -Moonlight Banquet|20-0|Happy Otaku Pack Vol.8|True|2|5|8| -Flashdance|20-1|Happy Otaku Pack Vol.8|False|3|6|9| -INFiNiTE ENERZY -Overdoze-|20-2|Happy Otaku Pack Vol.8|False|4|7|9|10 -One Way Street|20-3|Happy Otaku Pack Vol.8|False|3|6|10| -This Club is Not 4 U|20-4|Happy Otaku Pack Vol.8|False|4|7|9| -ULTRA MEGA HAPPY PARTY!!!|20-5|Happy Otaku Pack Vol.8|False|5|7|10| -INFINITY|19-0|Give Up TREATMENT Vol.7|True|5|8|10| -Punai Punai Senso|19-1|Give Up TREATMENT Vol.7|False|2|7|11| -Maxi|19-2|Give Up TREATMENT Vol.7|False|5|8|10| -YInMn Blue|19-3|Give Up TREATMENT Vol.7|False|6|8|10| -Plumage|19-4|Give Up TREATMENT Vol.7|False|4|7|10| -Dr.Techro|19-5|Give Up TREATMENT Vol.7|False|7|9|11| -SWEETSWEETSWEET|18-0|Cute Is Everything Vol.4|True|2|5|7| -Deep Blue and the Breaths of the Night|18-1|Cute Is Everything Vol.4|True|2|4|6| -Joy Connection|18-2|Cute Is Everything Vol.4|False|3|6|8| -Self Willed Girl Ver.B|18-3|Cute Is Everything Vol.4|True|4|6|8| -Just Disobedient|18-4|Cute Is Everything Vol.4|False|3|6|8| -Holy Sh*t Grass Snake|18-5|Cute Is Everything Vol.4|False|2|6|9| -Cotton Candy Wonderland|17-0|Happy Otaku Pack Vol.7|False|2|5|8| -Punai Punai Taiso|17-1|Happy Otaku Pack Vol.7|False|2|7|10| -Fly High|17-2|Happy Otaku Pack Vol.7|False|3|5|7| -prejudice|17-3|Happy Otaku Pack Vol.7|True|4|6|9| -The 89's Momentum|17-4|Happy Otaku Pack Vol.7|True|5|7|9| -energy night|17-5|Happy Otaku Pack Vol.7|True|5|7|10| -Future Dive|16-0|Give Up TREATMENT Vol.6|True|4|6|9| -Re End of a Dream|16-1|Give Up TREATMENT Vol.6|False|5|8|11| -Etude -Storm-|16-2|Give Up TREATMENT Vol.6|True|6|8|10| -Unlimited Katharsis|16-3|Give Up TREATMENT Vol.6|False|4|6|10| -Magic Knight Girl|16-4|Give Up TREATMENT Vol.6|False|4|7|9| -Eeliaas|16-5|Give Up TREATMENT Vol.6|False|6|9|11| -Magic Spell|15-0|Cute Is Everything Vol.3|True|2|5|7| -Colorful Star, Colored Drawing, Travel Poem|15-1|Cute Is Everything Vol.3|False|3|4|6| -Satell Knight|15-2|Cute Is Everything Vol.3|False|3|6|8| -Black River Feat.Mes|15-3|Cute Is Everything Vol.3|True|1|4|6| -I am sorry|15-4|Cute Is Everything Vol.3|False|2|5|8| -Ueta Tori Tachi|15-5|Cute Is Everything Vol.3|False|3|6|8| -Elysion's Old Mans|14-0|Happy Otaku Pack Vol.6|False|3|5|8| -AXION|14-1|Happy Otaku Pack Vol.6|False|4|5|8| -Amnesia|14-2|Happy Otaku Pack Vol.6|True|3|6|9| -Onsen Dai Sakusen|14-3|Happy Otaku Pack Vol.6|True|4|6|8| -Gleam stone|14-4|Happy Otaku Pack Vol.6|False|4|7|9| -GOODWORLD|14-5|Happy Otaku Pack Vol.6|False|4|7|10| -Instant Soluble Neon|13-0|Cute Is Everything Vol.2|True|2|4|7| -Retrospective Poem on the Planet|13-1|Cute Is Everything Vol.2|False|3|5|7| -I'm Gonna Buy! Buy! Buy!|13-2|Cute Is Everything Vol.2|True|4|6|8| -Dating Manifesto|13-3|Cute Is Everything Vol.2|True|2|4|6| -First Snow|13-4|Cute Is Everything Vol.2|True|2|3|6| -Xin Shang Huahai|13-5|Cute Is Everything Vol.2|False|3|6|8| -Gaikan Chrysalis|12-0|Give Up TREATMENT Vol.5|False|4|6|8| -Sterelogue|12-1|Give Up TREATMENT Vol.5|True|5|7|10| -Cheshire's Dance|12-2|Give Up TREATMENT Vol.5|True|4|7|10| -Skrik|12-3|Give Up TREATMENT Vol.5|True|5|7|11| -Soda Pop Canva5!|12-4|Give Up TREATMENT Vol.5|False|5|8|10| -RUBY LINTe|12-5|Give Up TREATMENT Vol.5|False|5|8|11| -Brave My Heart|11-0|Happy Otaku Pack Vol.5|True|3|5|7| -Sakura Fubuki|11-1|Happy Otaku Pack Vol.5|False|4|7|10| -8bit Adventurer|11-2|Happy Otaku Pack Vol.5|False|6|8|10| -Suffering of screw|11-3|Happy Otaku Pack Vol.5|False|3|5|8| -tiny lady|11-4|Happy Otaku Pack Vol.5|True|4|6|9| -Power Attack|11-5|Happy Otaku Pack Vol.5|False|5|7|10| -Destr0yer|10-0|Give Up TREATMENT Vol.4|False|4|7|9| -Noel|10-1|Give Up TREATMENT Vol.4|False|5|8|10| -Kyoukiranbu|10-2|Give Up TREATMENT Vol.4|False|7|9|11| -Two Phace|10-3|Give Up TREATMENT Vol.4|True|4|7|10| -Fly Again|10-4|Give Up TREATMENT Vol.4|False|5|7|10| -ouroVoros|10-5|Give Up TREATMENT Vol.4|False|7|9|11| -Leave It Alone|9-0|Happy Otaku Pack Vol.4|True|2|5|8| -Tsubasa no Oreta Tenshitachi no Requiem|9-1|Happy Otaku Pack Vol.4|False|4|7|9| -Chronomia|9-2|Happy Otaku Pack Vol.4|False|5|7|10| -Dandelion's Daydream|9-3|Happy Otaku Pack Vol.4|True|5|7|8| -Lorikeet Flat design|9-4|Happy Otaku Pack Vol.4|True|5|7|10| -GOODRAGE|9-5|Happy Otaku Pack Vol.4|False|6|9|11| -Altale|8-0|Give Up TREATMENT Vol.3|False|3|5|7|10 -Brain Power|8-1|Give Up TREATMENT Vol.3|False|4|7|10| -Berry Go!!|8-2|Give Up TREATMENT Vol.3|False|3|6|9| -Sweet* Witch* Girl*|8-3|Give Up TREATMENT Vol.3|False|6|8|10|? -trippers feeling!|8-4|Give Up TREATMENT Vol.3|True|5|7|9|11 -Lilith ambivalence lovers|8-5|Give Up TREATMENT Vol.3|False|5|8|10| -Brave My Soul|7-0|Give Up TREATMENT Vol.2|False|4|6|8| -Halcyon|7-1|Give Up TREATMENT Vol.2|False|4|7|10| -Crimson Nightingale|7-2|Give Up TREATMENT Vol.2|True|4|7|10| -Invader|7-3|Give Up TREATMENT Vol.2|True|3|7|11| -Lyrith|7-4|Give Up TREATMENT Vol.2|False|5|7|10| -GOODBOUNCE|7-5|Give Up TREATMENT Vol.2|False|4|6|9| -Out of Sense|6-0|Budget Is Burning Vol.1|False|3|5|8| -My Life Is For You|6-1|Budget Is Burning Vol.1|False|2|4|7| -Etude -Sunset-|6-2|Budget Is Burning Vol.1|True|5|7|9| -Goodbye Boss|6-3|Budget Is Burning Vol.1|False|4|6|8| -Stargazer|6-4|Budget Is Burning Vol.1|True|2|5|8|9 -Lys Tourbillon|6-5|Budget Is Burning Vol.1|True|4|6|8| -Thirty Million Persona|5-0|Happy Otaku Pack Vol.3|False|2|4|6| -conflict|5-1|Happy Otaku Pack Vol.3|False|2|6|9|10 -Enka Dance Music|5-2|Happy Otaku Pack Vol.3|False|3|5|7| -XING|5-3|Happy Otaku Pack Vol.3|True|4|6|8|9 -Amakakeru Soukyuu no Serenade|5-4|Happy Otaku Pack Vol.3|False|3|6|9| -Gift box|5-5|Happy Otaku Pack Vol.3|False|5|7|10| -MUSEDASH!!!!|4-0|Happy Otaku Pack Vol.2|False|2|6|9|0 -Imprinting|4-1|Happy Otaku Pack Vol.2|False|3|6|9|0 -Skyward|4-2|Happy Otaku Pack Vol.2|True|4|7|10|0 -La nuit de vif|4-3|Happy Otaku Pack Vol.2|True|2|5|8|0 -Bit-alize|4-4|Happy Otaku Pack Vol.2|False|3|6|8|0 -GOODTEK|4-5|Happy Otaku Pack Vol.2|False|4|6|9|? -Maharajah|3-0|Happy Otaku Pack Vol.1|False|1|3|6| -keep on running|3-1|Happy Otaku Pack Vol.1|False|5|7|9| -Kafig|3-2|Happy Otaku Pack Vol.1|True|4|6|8| --+|3-3|Happy Otaku Pack Vol.1|True|4|6|8| -Tenri Kaku Jou|3-4|Happy Otaku Pack Vol.1|True|3|6|9| -Adjudicatorz-DanZai-|3-5|Happy Otaku Pack Vol.1|False|3|7|10| -Oriens|2-0|Give Up TREATMENT Vol.1|True|3|7|9| -PUPA|2-1|Give Up TREATMENT Vol.1|False|6|8|11| -Luna Express 2032|2-2|Give Up TREATMENT Vol.1|False|4|6|8| -Ukiyoe Yokochou|2-3|Give Up TREATMENT Vol.1|False|6|7|9| -Alice in Misanthrope|2-4|Give Up TREATMENT Vol.1|False|5|7|10| -GOODMEN|2-5|Give Up TREATMENT Vol.1|False|5|7|10| -Sunshine and Rainbow after August Rain|1-0|Cute Is Everything Vol.1|False|2|5|8| -Magical Number|1-1|Cute Is Everything Vol.1|False|2|5|8| -Dreaming Girl|1-2|Cute Is Everything Vol.1|False|2|5|6| -Daruma-san Fell Over|1-3|Cute Is Everything Vol.1|False|3|4|6| -Different|1-4|Cute Is Everything Vol.1|False|1|3|6| -The Future of the Phantom|1-5|Cute Is Everything Vol.1|False|1|3|5| -Doki Doki Jump!|63-0|MUSE RADIO FM104|True|3|5|7| -Centennial Streamers High|63-1|MUSE RADIO FM104|False|4|7|9| -Love Patrol|63-2|MUSE RADIO FM104|True|3|5|7| -Mahorova|63-3|MUSE RADIO FM104|True|3|5|8| -Yoru no machi|63-4|MUSE RADIO FM104|True|1|4|7| -INTERNET YAMERO|63-5|MUSE RADIO FM104|True|6|8|10| -Abracadabra|43-24|MD Plus Project|False|6|8|10| -Squalldecimator feat. EZ-Ven|43-25|MD Plus Project|True|5|7|9| -Amateras Rhythm|43-26|MD Plus Project|True|6|8|11| -Record one's Dream|43-27|MD Plus Project|False|4|7|10| -Lunatic|43-28|MD Plus Project|True|5|8|10| -Jiumeng|43-29|MD Plus Project|True|3|6|8| -The Day We Become Family|43-30|MD Plus Project|True|3|5|8| -Sutori ma FIRE!?!?|64-0|COSMIC RADIO PEROLIST|True|3|5|8| -Tanuki Step|64-1|COSMIC RADIO PEROLIST|True|5|7|10|11 -Space Stationery|64-2|COSMIC RADIO PEROLIST|True|5|7|10| -Songs Are Judged 90% by Chorus feat. Mameko|64-3|COSMIC RADIO PEROLIST|True|6|8|10| -Kawai Splendid Space Thief|64-4|COSMIC RADIO PEROLIST|False|6|8|10|11 -Night City Runway|64-5|COSMIC RADIO PEROLIST|True|4|6|8| -Chaos Shotgun feat. ChumuNote|64-6|COSMIC RADIO PEROLIST|True|6|8|10| -mew mew magical summer|64-7|COSMIC RADIO PEROLIST|False|5|8|10|11 -BrainDance|65-0|NeonAbyss|True|3|6|9| -My Focus!|65-1|NeonAbyss|True|5|7|10| -ABABABA BURST|65-2|NeonAbyss|True|5|7|9| -ULTRA HIGHER|65-3|NeonAbyss|True|4|7|10| -Silver Bullet|43-31|MD Plus Project|True|5|7|10| -Random|43-32|MD Plus Project|True|4|7|9| -OTOGE-BOSS-KYOKU-CHAN|43-33|MD Plus Project|False|6|8|10|11 -Crow Rabbit|43-34|MD Plus Project|True|7|9|11| -SyZyGy|43-35|MD Plus Project|True|6|8|10|11 -Mermaid Radio|43-36|MD Plus Project|True|3|5|7| -Helixir|43-37|MD Plus Project|False|6|8|10| -Highway Cruisin'|43-38|MD Plus Project|False|3|5|8| -JACK PT BOSS|43-39|MD Plus Project|False|6|8|10| -Time Capsule|43-40|MD Plus Project|False|7|9|11| -39 Music!|66-0|Miku in Museland|False|3|5|8| -Hand in Hand|66-1|Miku in Museland|False|1|3|6| -Cynical Night Plan|66-2|Miku in Museland|False|4|6|8| -God-ish|66-3|Miku in Museland|False|4|7|10| -Darling Dance|66-4|Miku in Museland|False|4|7|9| -Hatsune Creation Myth|66-5|Miku in Museland|False|6|8|10|11 -The Vampire|66-6|Miku in Museland|False|4|6|9| -Future Eve|66-7|Miku in Museland|False|4|8|11| -Unknown Mother Goose|66-8|Miku in Museland|False|4|8|10| -Shun-ran|66-9|Miku in Museland|False|4|7|9| -NICE TYPE feat. monii|43-41|MD Plus Project|True|3|6|8| -Rainy Angel|67-0|Happy Otaku Pack Vol.18|True|4|6|9|11 -Gullinkambi|67-1|Happy Otaku Pack Vol.18|True|4|7|10| -RakiRaki Rebuilders!!!|67-2|Happy Otaku Pack Vol.18|True|5|7|10| -Laniakea|67-3|Happy Otaku Pack Vol.18|False|5|8|10| -OTTAMA GAZER|67-4|Happy Otaku Pack Vol.18|True|5|8|10| -Sleep Tight feat.Macoto|67-5|Happy Otaku Pack Vol.18|True|3|5|8| -New York Back Raise|68-0|Gambler's Tricks|True|6|8|10| -slic.hertz|68-1|Gambler's Tricks|True|5|7|9| -Fuzzy-Navel|68-2|Gambler's Tricks|True|6|8|10|11 -Swing Edge|68-3|Gambler's Tricks|True|4|8|10| -Twisted Escape|68-4|Gambler's Tricks|True|5|8|10|11 -Swing Sweet Twee Dance|68-5|Gambler's Tricks|False|4|7|10| -Sanyousei SAY YA!!!|43-42|MD Plus Project|False|4|6|8| -YUKEMURI TAMAONSEN II|43-43|MD Plus Project|False|3|6|9| -Samayoi no mei Amatsu|69-0|Touhou Mugakudan -3-|False|4|6|9| -INTERNET SURVIVOR|69-1|Touhou Mugakudan -3-|False|5|8|10| -Shuki*RaiRai|69-2|Touhou Mugakudan -3-|False|5|7|9| -HELLOHELL|69-3|Touhou Mugakudan -3-|False|4|7|10| -Calamity Fortune|69-4|Touhou Mugakudan -3-|True|6|8|10|11 -Tsurupettan|69-5|Touhou Mugakudan -3-|True|2|5|8| -Twilight Poems|43-44|MD Plus Project|True|3|6|8| -All My Friends feat. RANASOL|43-45|MD Plus Project|True|4|7|9| -Heartache|43-46|MD Plus Project|True|5|7|10| -Blue Lemonade|43-47|MD Plus Project|True|3|6|8| -Haunted Dance|43-48|MD Plus Project|False|6|9|11| -Hey Vincent.|43-49|MD Plus Project|True|6|8|10| -Meteor feat. TEA|43-50|MD Plus Project|True|3|6|9| -Narcissism Angel|43-51|MD Plus Project|True|1|3|6| -AlterLuna|43-52|MD Plus Project|True|6|8|11|12 -Niki Tousen|43-53|MD Plus Project|True|6|8|10|12 -Rettou Joutou|70-0|Rin Len's Mirrorland|False|4|7|9| -Telecaster B-Boy|70-1|Rin Len's Mirrorland|False|5|7|10| -Iya Iya Iya|70-2|Rin Len's Mirrorland|False|2|4|7| -Nee Nee Nee|70-3|Rin Len's Mirrorland|False|4|6|8| -Chaotic Love Revolution|70-4|Rin Len's Mirrorland|False|4|6|8| -Dance of the Corpses|70-5|Rin Len's Mirrorland|False|2|5|8| -Bitter Choco Decoration|70-6|Rin Len's Mirrorland|False|3|6|9| -Dance Robot Dance|70-7|Rin Len's Mirrorland|False|4|7|10| -Sweet Devil|70-8|Rin Len's Mirrorland|False|5|7|9| -Someday'z Coming|70-9|Rin Len's Mirrorland|False|5|7|9| -Yume Ou Mono Yo Secret|0-53|Default Music|True|6|8|10| -Yume Ou Mono Yo|0-54|Default Music|True|1|4|0| -Sweet Dream VIVINOS|71-0|Valentine Stage|False|1|4|7| -Ruler Of My Heart VIVINOS|71-1|Valentine Stage|False|2|4|6| -Reality Show|71-2|Valentine Stage|False|5|7|10| -SIG feat.Tobokegao|71-3|Valentine Stage|True|3|6|8| -Rose Love|71-4|Valentine Stage|True|2|4|7| -Euphoria|71-5|Valentine Stage|True|1|3|6| -P E R O P E R O Brother Dance|72-0|Legends of Muse Warriors|True|0|?|0| -PA PPA PANIC|72-1|Legends of Muse Warriors|False|4|8|10| -How To Make Music Game Song!|72-2|Legends of Muse Warriors|True|6|8|10|11 -Re Re|72-3|Legends of Muse Warriors|True|7|9|11|12 -Marmalade Twins|72-4|Legends of Muse Warriors|True|5|8|10| -DOMINATOR|72-5|Legends of Muse Warriors|True|7|9|11| -Teshikani TESHiKANi|72-6|Legends of Muse Warriors|True|5|7|9| -Urban Magic|73-0|Happy Otaku Pack Vol.19|True|3|5|7| -Maid's Prank|73-1|Happy Otaku Pack Vol.19|True|5|7|10| -Dance Dance Good Night Dance|73-2|Happy Otaku Pack Vol.19|True|2|4|7| -Ops Limone|73-3|Happy Otaku Pack Vol.19|True|5|8|11| -NOVA|73-4|Happy Otaku Pack Vol.19|True|6|8|10| -Heaven's Gradius|73-5|Happy Otaku Pack Vol.19|True|6|8|10| -Ray Tuning|74-0|CHUNITHM COURSE MUSE|True|6|8|10| -World Vanquisher|74-1|CHUNITHM COURSE MUSE|True|6|8|10|11 -Tsukuyomi Ni Naru Replaced|74-2|CHUNITHM COURSE MUSE|True|5|7|9| -The wheel to the right|74-3|CHUNITHM COURSE MUSE|True|5|7|9|11 -Climax|74-4|CHUNITHM COURSE MUSE|True|4|8|11|11 -Spider's Thread|74-5|CHUNITHM COURSE MUSE|True|5|8|10|12 -HIT ME UP|43-54|MD Plus Project|True|4|6|8| -Test Me feat. Uyeon|43-55|MD Plus Project|True|3|5|9| -Assault TAXI|43-56|MD Plus Project|True|4|7|10| -No|43-57|MD Plus Project|False|4|6|9| -Pop it|43-58|MD Plus Project|True|1|3|6| -HEARTBEAT! KyunKyun!|43-59|MD Plus Project|True|4|6|9| -SUPERHERO|75-0|Novice Rider Pack|False|2|4|7| -Highway_Summer|75-1|Novice Rider Pack|True|2|4|6| -Mx. Black Box|75-2|Novice Rider Pack|True|5|7|9| -Sweet Encounter|75-3|Novice Rider Pack|True|2|4|7| -Echo over you... Secret|0-55|Default Music|False|6|8|10| -Echo over you...|0-56|Default Music|False|1|4|0| -Tsukuyomi Ni Naru|74-6|CHUNITHM COURSE MUSE|True|5|8|10| -disco light|76-0|MUSE RADIO FM105|True|5|7|9| -room light feat.chancylemon|76-1|MUSE RADIO FM105|True|3|5|7| -Invisible|76-2|MUSE RADIO FM105|True|3|5|8| -Christmas Season-LLABB|76-3|MUSE RADIO FM105|True|1|4|7| -Hyouryu|77-0|Let's Rhythm Jam!|False|6|8|10| -The Whole Rest|77-1|Let's Rhythm Jam!|False|5|8|10|11 -Hydra|77-2|Let's Rhythm Jam!|False|4|7|11| -Pastel Lines|77-3|Let's Rhythm Jam!|False|3|6|9| -LINK x LIN#S|77-4|Let's Rhythm Jam!|False|3|6|9| -Arcade ViruZ|77-5|Let's Rhythm Jam!|False|6|8|11| -Eve Avenir|78-0|Endless Pirouette|True|6|8|10| -Silverstring|78-1|Endless Pirouette|True|5|7|10| -Melusia|78-2|Endless Pirouette|False|5|7|10|11 -Devil's Castle|78-3|Endless Pirouette|True|4|7|10| -Abatement|78-4|Endless Pirouette|True|6|8|10|11 -Azalea|78-5|Endless Pirouette|False|4|8|10| -Brightly World|78-6|Endless Pirouette|True|6|8|10| -We'll meet in every world ***|78-7|Endless Pirouette|True|7|9|11| -Collapsar|78-8|Endless Pirouette|True|7|9|10|11 -Parousia|78-9|Endless Pirouette|False|6|8|10| -Gunners in the Rain|79-0|Ensemble Arcanum|False|5|8|10| -Halzion|79-1|Ensemble Arcanum|False|2|5|8| -SHOWTIME!!|79-2|Ensemble Arcanum|False|6|8|10| -Achromic Riddle|79-3|Ensemble Arcanum|False|6|8|10|11 -karanosu|79-4|Ensemble Arcanum|False|3|6|8| diff --git a/worlds/musedash/Options.py b/worlds/musedash/Options.py index b8c969c39b..9f729c2d03 100644 --- a/worlds/musedash/Options.py +++ b/worlds/musedash/Options.py @@ -1,13 +1,14 @@ -from Options import Toggle, Range, Choice, DeathLink, ItemSet, OptionSet, PerGameCommonOptions, OptionGroup, Removed +from Options import Toggle, Range, Choice, DeathLink, OptionSet, PerGameCommonOptions, OptionGroup, Removed from dataclasses import dataclass from .MuseDashCollection import MuseDashCollections +from .MuseDashData import SONG_DATA class DLCMusicPacks(OptionSet): """ Choose which DLC Packs will be included in the pool of chooseable songs. - + Note: The [Just As Planned] DLC contains all [Muse Plus] songs. """ display_name = "DLC Packs" @@ -17,7 +18,7 @@ class DLCMusicPacks(OptionSet): class StreamerModeEnabled(Toggle): """ In Muse Dash, an option named 'Streamer Mode' removes songs which may trigger copyright issues when streaming. - + If this is enabled, only songs available under Streamer Mode will be available for randomization. """ display_name = "Streamer Mode Only Songs" @@ -69,7 +70,7 @@ class DifficultyMode(Choice): class DifficultyModeOverrideMin(Range): """ Ensures that 1 difficulty has at least 1 this value or higher per song. - + Note: Difficulty Mode must be set to Manual. """ display_name = "Manual Difficulty Min" @@ -82,7 +83,7 @@ class DifficultyModeOverrideMin(Range): class DifficultyModeOverrideMax(Range): """ Ensures that 1 difficulty has at least 1 this value or lower per song. - + Note: Difficulty Mode must be set to Manual. """ display_name = "Manual Difficulty Max" @@ -114,7 +115,7 @@ class GradeNeeded(Choice): class MusicSheetCountPercentage(Range): """ Controls how many music sheets are added to the pool based on the number of songs, including starting songs. - + Higher numbers leads to more consistent game lengths, but will cause individual music sheets to be less important. """ range_start = 10 @@ -137,7 +138,7 @@ class ChosenTraps(OptionSet): - Traps last the length of a song, or until you die. - VFX Traps consist of visual effects that play over the song. (i.e. Grayscale.) - SFX Traps consist of changing your sfx setting to one possibly more annoying sfx. - + Note: SFX traps are only available if [Just as Planned] DLC songs are enabled. """ display_name = "Chosen Traps" @@ -152,24 +153,26 @@ class TrapCountPercentage(Range): display_name = "Trap Percentage" -class IncludeSongs(ItemSet): +class SongSet(OptionSet): + valid_keys = SONG_DATA.keys() + + +class IncludeSongs(SongSet): """ These songs will be guaranteed to show up within the seed. - You must have the DLC enabled to play these songs. - Difficulty options will not affect these songs. - If there are too many included songs, this will act as a whitelist ignoring song difficulty. """ - verify_item_name = True display_name = "Include Songs" -class ExcludeSongs(ItemSet): +class ExcludeSongs(SongSet): """ These songs will be guaranteed to not show up within the seed. - + Note: Does not affect songs within the "Include Songs" list. """ - verify_item_name = True display_name = "Exclude Songs" @@ -211,7 +214,7 @@ class MuseDashOptions(PerGameCommonOptions): death_link: DeathLink include_songs: IncludeSongs exclude_songs: ExcludeSongs - + # Removed allow_just_as_planned_dlc_songs: Removed available_trap_types: Removed diff --git a/worlds/musedash/__init__.py b/worlds/musedash/__init__.py index be2eec2f87..d793308a7c 100644 --- a/worlds/musedash/__init__.py +++ b/worlds/musedash/__init__.py @@ -63,6 +63,11 @@ class MuseDashWorld(World): item_name_to_id = {name: code for name, code in md_collection.item_names_to_id.items()} location_name_to_id = {name: code for name, code in md_collection.location_names_to_id.items()} + item_name_groups = { + "Songs": {name for name in md_collection.song_items.keys()}, + "Filler Items": {name for name in md_collection.filler_items.keys()}, + "Traps": {name for name in md_collection.trap_items.keys()} + } # Working Data victory_song_name: str = "" @@ -179,10 +184,6 @@ class MuseDashWorld(World): if trap: return MuseDashFixedItem(name, ItemClassification.trap, trap, self.player) - album = self.md_collection.album_items.get(name) - if album: - return MuseDashSongItem(name, self.player, album) - song = self.md_collection.song_items[name] return MuseDashSongItem(name, self.player, song) diff --git a/worlds/musedash/test/TestDifficultyRanges.py b/worlds/musedash/test/TestDifficultyRanges.py index a9c36985af..27798243a5 100644 --- a/worlds/musedash/test/TestDifficultyRanges.py +++ b/worlds/musedash/test/TestDifficultyRanges.py @@ -1,7 +1,17 @@ from . import MuseDashTestBase +from typing import List class DifficultyRanges(MuseDashTestBase): + DIFF_OVERRIDES: List[str] = [ + "MuseDash ka nanika hi", + "Rush-Hour", + "Find this Month's Featured Playlist", + "PeroPero in the Universe", + "umpopoff", + "P E R O P E R O Brother Dance", + ] + def test_all_difficulty_ranges(self) -> None: muse_dash_world = self.get_world() dlc_set = {x for x in muse_dash_world.md_collection.DLC} @@ -63,7 +73,7 @@ class DifficultyRanges(MuseDashTestBase): def test_songs_have_difficulty(self) -> None: muse_dash_world = self.get_world() - for song_name in muse_dash_world.md_collection.DIFF_OVERRIDES: + for song_name in self.DIFF_OVERRIDES: song = muse_dash_world.md_collection.song_items[song_name] # Some songs are weird and have less than the usual 3 difficulties. diff --git a/worlds/noita/items.py b/worlds/noita/items.py index 394bcdb575..20d9ff1930 100644 --- a/worlds/noita/items.py +++ b/worlds/noita/items.py @@ -52,8 +52,8 @@ def create_kantele(victory_condition: VictoryCondition) -> List[str]: def create_random_items(world: NoitaWorld, weights: Dict[str, int], count: int) -> List[str]: filler_pool = weights.copy() if not world.options.bad_effects: - del filler_pool["Trap"] - del filler_pool["Greed Die"] + filler_pool["Trap"] = 0 + filler_pool["Greed Die"] = 0 return world.random.choices(population=list(filler_pool.keys()), weights=list(filler_pool.values()), diff --git a/worlds/noita/options.py b/worlds/noita/options.py index 0fdd62365a..8a973a0d72 100644 --- a/worlds/noita/options.py +++ b/worlds/noita/options.py @@ -20,6 +20,8 @@ class PathOption(Choice): class HiddenChests(Range): """ Number of hidden chest checks added to the applicable biomes. + Note: The number of hidden chests that spawn per run in each biome varies. + You are expected do multiple runs to get all of your checks. """ display_name = "Hidden Chests per Biome" range_start = 0 @@ -30,6 +32,8 @@ class HiddenChests(Range): class PedestalChecks(Range): """ Number of checks that will spawn on pedestals in the applicable biomes. + Note: The number of pedestals that spawn per run in each biome varies. + You are expected do multiple runs to get all of your checks. """ display_name = "Pedestal Checks per Biome" range_start = 0 diff --git a/worlds/oot/Patches.py b/worlds/oot/Patches.py index 561d7c3f7b..cd940e052a 100644 --- a/worlds/oot/Patches.py +++ b/worlds/oot/Patches.py @@ -2200,7 +2200,7 @@ def patch_rom(world, rom): elif world.shuffle_bosses != 'off': vanilla_reward = world.get_location(boss_name).vanilla_item vanilla_reward_location = world.multiworld.find_item(vanilla_reward, world.player) # hinted_dungeon_reward_locations[vanilla_reward.name] - area = HintArea.at(vanilla_reward_location).text(world.clearer_hints, preposition=True) + area = HintArea.at(vanilla_reward_location).text(world.hint_rng, world.clearer_hints, preposition=True) compass_message = "\x13\x75\x08You found the \x05\x41Compass\x05\x40\x01for %s\x05\x40!\x01The %s can be found\x01%s!\x09" % (dungeon_name, vanilla_reward, area) else: boss_location = next(filter(lambda loc: loc.type == 'Boss', world.get_entrance(f'{dungeon} Boss Door -> {boss_name} Boss Room').connected_region.locations)) diff --git a/worlds/oot/__init__.py b/worlds/oot/__init__.py index 975902ae6e..3de55f6824 100644 --- a/worlds/oot/__init__.py +++ b/worlds/oot/__init__.py @@ -582,8 +582,7 @@ class OOTWorld(World): new_exit = OOTEntrance(self.player, self.multiworld, '%s -> %s' % (new_region.name, exit), new_region) new_exit.vanilla_connected_region = exit new_exit.rule_string = rule - if self.options.logic_rules != 'no_logic': - self.parser.parse_spot_rule(new_exit) + self.parser.parse_spot_rule(new_exit) if new_exit.never: logger.debug('Dropping unreachable exit: %s', new_exit.name) else: diff --git a/worlds/pokemon_emerald/CHANGELOG.md b/worlds/pokemon_emerald/CHANGELOG.md index 0dd874b250..8d33d70900 100644 --- a/worlds/pokemon_emerald/CHANGELOG.md +++ b/worlds/pokemon_emerald/CHANGELOG.md @@ -1,3 +1,16 @@ +# 2.4.0 + +### Features + +- New option `free_fly_blacklist` limits which cities can show up as a free fly location. +- Spoiler log and hint text for maps where a species can be found now use human-friendly labels. +- Added many item and location groups based on item type, location type, and location geography. + +### Fixes + +- Now excludes the location "Navel Rock Top - Hidden Item Sacred Ash" if your goal is Champion and you didn't randomize +event tickets. + # 2.3.0 ### Features diff --git a/worlds/pokemon_emerald/__init__.py b/worlds/pokemon_emerald/__init__.py index 7b62b9ef73..50d6279179 100644 --- a/worlds/pokemon_emerald/__init__.py +++ b/worlds/pokemon_emerald/__init__.py @@ -22,7 +22,7 @@ from .locations import (PokemonEmeraldLocation, create_location_label_to_id_map, set_free_fly, set_legendary_cave_entrances) from .opponents import randomize_opponent_parties from .options import (Goal, DarkCavesRequireFlash, HmRequirements, ItemPoolType, PokemonEmeraldOptions, - RandomizeWildPokemon, RandomizeBadges, RandomizeHms, NormanRequirement) + RandomizeWildPokemon, RandomizeBadges, RandomizeHms, NormanRequirement, OPTION_GROUPS) from .pokemon import (get_random_move, get_species_id_by_label, randomize_abilities, randomize_learnsets, randomize_legendary_encounters, randomize_misc_pokemon, randomize_starters, randomize_tm_hm_compatibility,randomize_types, randomize_wild_encounters) @@ -63,6 +63,7 @@ class PokemonEmeraldWebWorld(WebWorld): ) tutorials = [setup_en, setup_es, setup_sv] + option_groups = OPTION_GROUPS class PokemonEmeraldSettings(settings.Group): diff --git a/worlds/pokemon_emerald/client.py b/worlds/pokemon_emerald/client.py index 5add7b3fca..411fdd1a33 100644 --- a/worlds/pokemon_emerald/client.py +++ b/worlds/pokemon_emerald/client.py @@ -287,7 +287,7 @@ class PokemonEmeraldClient(BizHawkClient): pokedex_caught_bytes = read_result[0] game_clear = False - local_checked_locations = set() + local_checked_locations: set[int] = set() local_set_events = {flag_name: False for flag_name in TRACKER_EVENT_FLAGS} local_found_key_items = {location_name: False for location_name in KEY_LOCATION_FLAGS} defeated_legendaries = {legendary_name: False for legendary_name in LEGENDARY_NAMES.values()} @@ -350,10 +350,7 @@ class PokemonEmeraldClient(BizHawkClient): self.local_checked_locations = local_checked_locations if local_checked_locations is not None: - await ctx.send_msgs([{ - "cmd": "LocationChecks", - "locations": list(local_checked_locations), - }]) + await ctx.check_locations(local_checked_locations) # Send game clear if not ctx.finished_game and game_clear: diff --git a/worlds/pokemon_emerald/locations.py b/worlds/pokemon_emerald/locations.py index 473c189166..49ce147041 100644 --- a/worlds/pokemon_emerald/locations.py +++ b/worlds/pokemon_emerald/locations.py @@ -33,6 +33,26 @@ VISITED_EVENT_NAME_TO_ID = { "EVENT_VISITED_SOUTHERN_ISLAND": 17, } +BLACKLIST_OPTION_TO_VISITED_EVENT = { + "Littleroot Town": "EVENT_VISITED_LITTLEROOT_TOWN", + "Oldale Town": "EVENT_VISITED_OLDALE_TOWN", + "Petalburg City": "EVENT_VISITED_PETALBURG_CITY", + "Rustboro City": "EVENT_VISITED_RUSTBORO_CITY", + "Dewford Town": "EVENT_VISITED_DEWFORD_TOWN", + "Slateport City": "EVENT_VISITED_SLATEPORT_CITY", + "Mauville City": "EVENT_VISITED_MAUVILLE_CITY", + "Verdanturf Town": "EVENT_VISITED_VERDANTURF_TOWN", + "Fallarbor Town": "EVENT_VISITED_FALLARBOR_TOWN", + "Lavaridge Town": "EVENT_VISITED_LAVARIDGE_TOWN", + "Fortree City": "EVENT_VISITED_FORTREE_CITY", + "Lilycove City": "EVENT_VISITED_LILYCOVE_CITY", + "Mossdeep City": "EVENT_VISITED_MOSSDEEP_CITY", + "Sootopolis City": "EVENT_VISITED_SOOTOPOLIS_CITY", + "Ever Grande City": "EVENT_VISITED_EVER_GRANDE_CITY", +} + +VISITED_EVENTS = frozenset(BLACKLIST_OPTION_TO_VISITED_EVENT.values()) + class PokemonEmeraldLocation(Location): game: str = "Pokemon Emerald" @@ -129,18 +149,10 @@ def set_free_fly(world: "PokemonEmeraldWorld") -> None: # If not enabled, set it to Littleroot Town by default fly_location_name = "EVENT_VISITED_LITTLEROOT_TOWN" if world.options.free_fly_location: - fly_location_name = world.random.choice([ - "EVENT_VISITED_SLATEPORT_CITY", - "EVENT_VISITED_MAUVILLE_CITY", - "EVENT_VISITED_VERDANTURF_TOWN", - "EVENT_VISITED_FALLARBOR_TOWN", - "EVENT_VISITED_LAVARIDGE_TOWN", - "EVENT_VISITED_FORTREE_CITY", - "EVENT_VISITED_LILYCOVE_CITY", - "EVENT_VISITED_MOSSDEEP_CITY", - "EVENT_VISITED_SOOTOPOLIS_CITY", - "EVENT_VISITED_EVER_GRANDE_CITY", - ]) + blacklisted_locations = set(BLACKLIST_OPTION_TO_VISITED_EVENT[city] for city in world.options.free_fly_blacklist.value) + free_fly_locations = sorted(VISITED_EVENTS - blacklisted_locations) + if free_fly_locations: + fly_location_name = world.random.choice(free_fly_locations) world.free_fly_location_id = VISITED_EVENT_NAME_TO_ID[fly_location_name] diff --git a/worlds/pokemon_emerald/options.py b/worlds/pokemon_emerald/options.py index 8fcc74d1c3..29929bd672 100644 --- a/worlds/pokemon_emerald/options.py +++ b/worlds/pokemon_emerald/options.py @@ -4,7 +4,7 @@ Option definitions for Pokemon Emerald from dataclasses import dataclass from Options import (Choice, DeathLink, DefaultOnToggle, OptionSet, NamedRange, Range, Toggle, FreeText, - PerGameCommonOptions) + PerGameCommonOptions, OptionGroup, StartInventory) from .data import data @@ -726,6 +726,39 @@ class FreeFlyLocation(Toggle): display_name = "Free Fly Location" +class FreeFlyBlacklist(OptionSet): + """ + Disables specific locations as valid free fly locations. + + Has no effect if Free Fly Location is disabled. + """ + display_name = "Free Fly Blacklist" + valid_keys = [ + "Littleroot Town", + "Oldale Town", + "Petalburg City", + "Rustboro City", + "Dewford Town", + "Slateport City", + "Mauville City", + "Verdanturf Town", + "Fallarbor Town", + "Lavaridge Town", + "Fortree City", + "Lilycove City", + "Mossdeep City", + "Sootopolis City", + "Ever Grande City", + ] + default = [ + "Littleroot Town", + "Oldale Town", + "Petalburg City", + "Rustboro City", + "Dewford Town", + ] + + class HmRequirements(Choice): """ Sets the requirements to use HMs outside of battle. @@ -785,6 +818,10 @@ class RandomizeFanfares(Toggle): display_name = "Randomize Fanfares" +class PokemonEmeraldDeathLink(DeathLink): + __doc__ = DeathLink.__doc__ + "\n\n In Pokemon Emerald, whiting out sends a death and receiving a death causes you to white out." + + class WonderTrading(DefaultOnToggle): """ Allows participation in wonder trading with other players in your current multiworld. Speak with the center receptionist on the second floor of any pokecenter. @@ -810,6 +847,14 @@ class EasterEgg(FreeText): default = "EMERALD SECRET" +class PokemonEmeraldStartInventory(StartInventory): + """ + Start with these items. + + They will be in your PC, which you can access from your home or a pokemon center. + """ + + @dataclass class PokemonEmeraldOptions(PerGameCommonOptions): goal: Goal @@ -876,6 +921,7 @@ class PokemonEmeraldOptions(PerGameCommonOptions): extra_bumpy_slope: ExtraBumpySlope modify_118: ModifyRoute118 free_fly_location: FreeFlyLocation + free_fly_blacklist: FreeFlyBlacklist hm_requirements: HmRequirements turbo_a: TurboA @@ -885,7 +931,18 @@ class PokemonEmeraldOptions(PerGameCommonOptions): music: RandomizeMusic fanfares: RandomizeFanfares - death_link: DeathLink + death_link: PokemonEmeraldDeathLink enable_wonder_trading: WonderTrading easter_egg: EasterEgg + + start_inventory: PokemonEmeraldStartInventory + + +OPTION_GROUPS = [ + OptionGroup( + "Item & Location Options", [ + PokemonEmeraldStartInventory, + ], True, + ), +] diff --git a/worlds/pokemon_rb/regions.py b/worlds/pokemon_rb/regions.py index 575f4a61ca..d4b8a8f506 100644 --- a/worlds/pokemon_rb/regions.py +++ b/worlds/pokemon_rb/regions.py @@ -1718,7 +1718,7 @@ def create_regions(world): connect(multiworld, player, "Vermilion City", "Vermilion City-Dock", lambda state: state.has("S.S. Ticket", player)) connect(multiworld, player, "Vermilion City", "Route 11") connect(multiworld, player, "Route 12-N", "Route 12-S", lambda state: logic.can_surf(state, world, player)) - connect(multiworld, player, "Route 12-W", "Route 11-E", lambda state: state.has("Poke Flute", player)) + connect(multiworld, player, "Route 12-W", "Route 11-E") connect(multiworld, player, "Route 12-W", "Route 12-N", lambda state: state.has("Poke Flute", player)) connect(multiworld, player, "Route 12-W", "Route 12-S", lambda state: state.has("Poke Flute", player)) connect(multiworld, player, "Route 12-S", "Route 12-Grass", lambda state: logic.can_cut(state, world, player), one_way=True) diff --git a/worlds/sa2b/docs/setup_en.md b/worlds/sa2b/docs/setup_en.md index f32001a678..c34e45ce9b 100644 --- a/worlds/sa2b/docs/setup_en.md +++ b/worlds/sa2b/docs/setup_en.md @@ -5,7 +5,7 @@ - Sonic Adventure 2: Battle from: [Sonic Adventure 2: Battle Steam Store Page](https://store.steampowered.com/app/213610/Sonic_Adventure_2/) - The Battle DLC is required if you choose to add Chao Karate locations to the randomizer - SA Mod Manager from: [SA Mod Manager GitHub Releases Page](https://github.com/X-Hax/SA-Mod-Manager/releases) -- .NET Desktop Runtime 7.0 from: [.NET Desktop Runtime 7.0 Download Page](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-7.0.9-windows-x64-installer) +- .NET Desktop Runtime 8.0 from: [.NET Desktop Runtime 8.0 Download Page](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.12-windows-x64-installer) - Archipelago Mod for Sonic Adventure 2: Battle from: [Sonic Adventure 2: Battle Archipelago Randomizer Mod Releases Page](https://github.com/PoryGone/SA2B_Archipelago/releases/) @@ -36,27 +36,23 @@ 1. Install Sonic Adventure 2: Battle from Steam. -2. In the properties for Sonic Adventure 2 on Steam, force the use of Proton Experimental as the compatibility tool. +2. Launch the game at least once without mods. -3. Launch the game at least once without mods. +3. Create both a `/mods` directory and a `/SAManager` directory in the folder into which you installed Sonic Adventure 2: Battle. -4. Create both a `/mods` directory and a `/SAManager` directory in the folder into which you installed Sonic Adventure 2: Battle. +4. Unpack the Archipelago Mod into this folder, so that `/mods/SA2B_Archipelago` is a valid path. -5. Install SA Mod Manager as per [its instructions](https://github.com/X-Hax/SA-Mod-Manager/tree/master?tab=readme-ov-file). Specifically, extract SAModManager.exe file to the folder that Sonic Adventure 2: Battle is installed to. To launch it, add ``SAModManager.exe`` as a non-Steam game. In the properties on Steam for SA Mod Manager, set it to use Proton as the compatibility tool. +5. In the SA2B_Archipelago folder, copy the `APCpp.dll` file and paste it in the Sonic Adventure 2 install folder (where `sonic2app.exe` is). -6. Run SAModManager.exe from Steam once. It should produce an error popup for a missing dependency, close the error. +6. Install SA Mod Manager as per [its instructions](https://github.com/X-Hax/SA-Mod-Manager/tree/master?tab=readme-ov-file). Specifically, extract SAModManager.exe file to the folder that Sonic Adventure 2: Battle is installed to. To launch it, add ``SAModManager.exe`` as a non-Steam game. In the properties on Steam for SA Mod Manager, set it to use Proton as the compatibility tool. -7. Install protontricks, on the Steam Deck this can be done via the Discover store, on other distros instructions vary, [see its github page](https://github.com/Matoking/protontricks). +7. Run SAModManager.exe from Steam once. It should produce an error popup saying you need .NET Desktop Runtime and ask you if you'd like to download it. Say yes and it will download through your browser. -8. Download the [.NET 7 Desktop Runtime for x64 Windows](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-7.0.17-windows-x64-installer). If this link does not work, the download can be found on [this page](https://dotnet.microsoft.com/en-us/download/dotnet/7.0). +8. Install protontricks, on the Steam Deck this can be done via the Discover store, on other distros instructions vary, [see its github page](https://github.com/Matoking/protontricks). -9. Right click the .NET 7 Desktop Runtime exe, and assuming protontricks was installed correctly, the option to "Open with Protontricks Launcher" should be available. Click that, and in the popup window that opens, select SAModManager.exe. Follow the prompts after this to install the .NET 7 Desktop Runtime for SAModManager. Once it is done, you should be able to successfully launch SAModManager to steam. +9. Right click the .NET Desktop Runtime exe that was downloaded in step 6, and assuming protontricks was installed correctly, the option to "Open with Protontricks Launcher" should be available. Click that, and in the popup window that opens, select SAModManager.exe. Follow the prompts after this to install the .NET Desktop Runtime for SAModManager. Once it is done, you should be able to successfully launch SAModManager to steam. -6. Unpack the Archipelago Mod into this folder, so that `/mods/SA2B_Archipelago` is a valid path. - -7. In the SA2B_Archipelago folder, copy the `APCpp.dll` file and paste it in the Sonic Adventure 2 install folder (where `sonic2app.exe` is). - -8. Launch `SAModManager.exe` from Steam and make sure the SA2B_Archipelago mod is listed and enabled. +10. Launch `SAModManager.exe` from Steam and make sure the SA2B_Archipelago mod is listed and enabled. Note: Ensure that you launch Sonic Adventure 2 from Steam directly on Linux, rather than launching using the `Save & Play` button in SA Mod Manager. @@ -77,7 +73,7 @@ Note: Ensure that you launch Sonic Adventure 2 from Steam directly on Linux, rat ## Additional Options Some additional settings related to the Archipelago messages in game can be adjusted in the SAModManager if you select `Configure Mod` on the SA2B_Archipelago mod. This settings will be under a `General Settings` tab. - + - Message Display Count: This is the maximum number of Archipelago messages that can be displayed on screen at any given time. - Message Display Duration: This dictates how long Archipelago messages are displayed on screen (in seconds). - Message Font Size: The is the size of the font used to display the messages from Archipelago. @@ -94,7 +90,7 @@ If you wish to use the `SADX Music` option of the Randomizer, you must own a cop - "The following mods didn't load correctly: SA2B_Archipelago: DLL error - The specified module could not be found." - Make sure the `APCpp.dll` is in the same folder as the `sonic2app.exe`. (See Installation Procedures step 6) - + - "sonic2app.exe - Entry Point Not Found" - Make sure the `APCpp.dll` is up to date. Follow Installation Procedures step 6 to update the dll. @@ -116,7 +112,7 @@ If you wish to use the `SADX Music` option of the Randomizer, you must own a cop 1. Run the Launcher.exe which should be in the same folder as the your Sonic Adventure 2: Battle install. 2. Select the `Player` tab and reselect the controller for the player 1 input method. 3. Click the `Save settings and launch SONIC ADVENTURE 2` button. (Any mod manager settings will apply even if the game is launched this way rather than through the mod manager) - + - Game crashes after display logos. - This may be caused by a high monitor refresh rate. - Change the monitor refresh rate to 60 Hz [Change display refresh rate on Windows] (https://support.microsoft.com/en-us/windows/change-your-display-refresh-rate-in-windows-c8ea729e-0678-015c-c415-f806f04aae5a) @@ -125,13 +121,13 @@ If you wish to use the `SADX Music` option of the Randomizer, you must own a cop 2. Select the `Compatibility` tab. 3. Check the `Run this program in compatility mode for:` box and select Windows 7 in the drop down. 4. Click the `Apply` button. - + - No resolution options in the Launcher.exe. - In the `Graphics device` dropdown, select the device and display you plan to run the game on. The `Resolution` dropdown should populate once a graphics device is selected. - + - No music is playing in the game. - If you enabled an `SADX Music` option, then most likely the music data was not copied properly into the mod folder (See Additional Options for instructions). - + - Mission 1 is missing a texture in the stage select UI. - Most likely another mod is conflicting and overwriting the texture pack. It is recommeded to have the SA2B Archipelago mod load last in the mod manager. diff --git a/worlds/shivers/__init__.py b/worlds/shivers/__init__.py index 5c6203fd57..85f2cf1861 100644 --- a/worlds/shivers/__init__.py +++ b/worlds/shivers/__init__.py @@ -245,7 +245,7 @@ class ShiversWorld(World): storage_items += [self.create_item("Empty") for _ in range(3)] - state = self.multiworld.get_all_state(True) + state = self.multiworld.get_all_state(False) self.random.shuffle(storage_locs) self.random.shuffle(storage_items) diff --git a/worlds/shivers/docs/en_Shivers.md b/worlds/shivers/docs/en_Shivers.md index 9490b577bd..f36cbcce36 100644 --- a/worlds/shivers/docs/en_Shivers.md +++ b/worlds/shivers/docs/en_Shivers.md @@ -9,6 +9,7 @@ configuration file. All Ixupi pot pieces are randomized. Keys have been added to the game to lock off different rooms in the museum, these are randomized. Crawling has been added and is required to use any crawl space. +Randomization can also control if Ixupi pots are in pieces, mixed, or complete, and in which worlds they will show up in. ## What is considered a location check in Shivers? @@ -27,4 +28,5 @@ Victory is achieved when the player has captured the required number Ixupi set i ## Encountered a bug? -Please contact GodlFire or Cynbel_Terreus on Discord for bugs related to Shivers world generation or the Shivers Randomizer. +Please contact GodlFire or Cynbel_Terreus on Discord for bugs related to Shivers world generation or the Shivers Randomizer. +You may also open issues for the Shivers Randomizer Client [here](https://github.com/Shivers-Randomizer/Shivers-Randomizer/issues). diff --git a/worlds/shivers/docs/setup_en.md b/worlds/shivers/docs/setup_en.md index a495c87b22..5d73a81b29 100644 --- a/worlds/shivers/docs/setup_en.md +++ b/worlds/shivers/docs/setup_en.md @@ -5,12 +5,12 @@ - [Shivers (GOG version)](https://www.gog.com/en/game/shivers) or original disc - [ScummVM](https://www.scummvm.org/downloads/) version 2.7.0 or later -- [Shivers Randomizer](https://github.com/GodlFire/Shivers-Randomizer-CSharp/releases/latest) Latest release version +- [Shivers Randomizer Client](https://github.com/Shivers-Randomizer/Shivers-Randomizer/releases/latest) Latest release version ## Optional Software - [PopTracker](https://github.com/black-sliver/PopTracker/releases/) - - [Jax's Shivers PopTracker pack](https://github.com/blazik-barth/Shivers-Tracker/releases/) + - [Shivers PopTracker pack](https://github.com/Shivers-Randomizer/Shivers-AP-Tracker/releases/latest) ## Setup ScummVM for Shivers @@ -59,7 +59,9 @@ validator page: [YAML Validation page](/mysterycheck) ## What is a check -- Every puzzle -- Every puzzle hint/solution -- Every document that is considered a Flashback +- All puzzles +- All puzzle hints or solutions +- All documents that are considered Flashbacks +- All Ixupi captures (Lightning only if early) - Optionally information plaques +- Optionally elevators diff --git a/worlds/sm/Rom.py b/worlds/sm/Rom.py index ac516ae48b..c5b6645ed8 100644 --- a/worlds/sm/Rom.py +++ b/worlds/sm/Rom.py @@ -4,18 +4,59 @@ import os import json import Utils from Utils import read_snes_rom -from worlds.Files import APDeltaPatch +from worlds.Files import APPatchExtension, APProcedurePatch, APTokenMixin, APTokenTypes from .variaRandomizer.utils.utils import openFile SMJUHASH = '21f3e98df4780ee1c667b84e57d88675' SM_ROM_MAX_PLAYERID = 65535 SM_ROM_PLAYERDATA_COUNT = 202 -class SMDeltaPatch(APDeltaPatch): +class SMPatchExtensions(APPatchExtension): + game = "Super Metroid" + + @staticmethod + def write_crc(caller: APProcedurePatch, rom: bytes) -> bytes: + def checksum_mirror_sum(start, length, mask = 0x800000): + while not(length & mask) and mask: + mask >>= 1 + + part1 = sum(start[:mask]) & 0xFFFF + part2 = 0 + + next_length = length - mask + if next_length: + part2 = checksum_mirror_sum(start[mask:], next_length, mask >> 1) + + while (next_length < mask): + next_length += next_length + part2 += part2 + + return (part1 + part2) & 0xFFFF + + def write_bytes(buffer, startaddress: int, values): + buffer[startaddress:startaddress + len(values)] = values + + buffer = bytearray(rom) + crc = checksum_mirror_sum(buffer, len(buffer)) + inv = crc ^ 0xFFFF + write_bytes(buffer, 0x7FDC, [inv & 0xFF, (inv >> 8) & 0xFF, crc & 0xFF, (crc >> 8) & 0xFF]) + return bytes(buffer) + +class SMProcedurePatch(APProcedurePatch, APTokenMixin): hash = SMJUHASH game = "Super Metroid" patch_file_ending = ".apsm" + procedure = [ + ("apply_tokens", ["token_data.bin"]), + ("write_crc", []) + ] + + def write_tokens(self, patches): + for addr, data in patches.items(): + self.write_token(APTokenTypes.WRITE, addr, bytes(data)) + self.write_file("token_data.bin", self.get_token_binary()) + @classmethod def get_source_data(cls) -> bytes: return get_base_rom_bytes() diff --git a/worlds/sm/__init__.py b/worlds/sm/__init__.py index 160b7e4ec7..5d53270d61 100644 --- a/worlds/sm/__init__.py +++ b/worlds/sm/__init__.py @@ -17,7 +17,7 @@ logger = logging.getLogger("Super Metroid") from .Options import SMOptions from .Client import SMSNIClient -from .Rom import get_base_rom_path, SM_ROM_MAX_PLAYERID, SM_ROM_PLAYERDATA_COUNT, SMDeltaPatch, get_sm_symbols +from .Rom import SM_ROM_MAX_PLAYERID, SM_ROM_PLAYERDATA_COUNT, SMProcedurePatch, get_sm_symbols import Utils from .variaRandomizer.logic.smboolmanager import SMBoolManager @@ -40,7 +40,7 @@ class SMSettings(settings.Group): """File name of the v1.0 J rom""" description = "Super Metroid (JU) ROM" copy_to = "Super Metroid (JU).sfc" - md5s = [SMDeltaPatch.hash] + md5s = [SMProcedurePatch.hash] rom_file: RomFile = RomFile(RomFile.copy_to) @@ -120,12 +120,6 @@ class SMWorld(World): self.locations = {} super().__init__(world, player) - @classmethod - def stage_assert_generate(cls, multiworld: MultiWorld): - rom_file = get_base_rom_path() - if not os.path.exists(rom_file): - raise FileNotFoundError(rom_file) - def generate_early(self): Logic.factory('vanilla') @@ -802,23 +796,19 @@ class SMWorld(World): romPatcher.end() def generate_output(self, output_directory: str): - self.variaRando.args.rom = get_base_rom_path() - outfilebase = self.multiworld.get_out_file_name_base(self.player) - outputFilename = os.path.join(output_directory, f"{outfilebase}.sfc") - try: - self.variaRando.PatchRom(outputFilename, self.APPrePatchRom, self.APPostPatchRom) - self.write_crc(outputFilename) + patcher = self.variaRando.PatchRom(self.APPrePatchRom, self.APPostPatchRom) self.rom_name = self.romName + + patch = SMProcedurePatch(player=self.player, player_name=self.multiworld.player_name[self.player]) + patch.write_tokens(patcher.romFile.getPatchDict()) + rom_path = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}" + f"{patch.patch_file_ending}") + patch.write(rom_path) + except: raise - else: - patch = SMDeltaPatch(os.path.splitext(outputFilename)[0] + SMDeltaPatch.patch_file_ending, player=self.player, - player_name=self.multiworld.player_name[self.player], patched_path=outputFilename) - patch.write() finally: - if os.path.exists(outputFilename): - os.unlink(outputFilename) self.rom_name_available_event.set() # make sure threading continues and errors are collected def checksum_mirror_sum(self, start, length, mask = 0x800000): diff --git a/worlds/sm/variaRandomizer/randomizer.py b/worlds/sm/variaRandomizer/randomizer.py index 8a7a2ea0e2..22712aa442 100644 --- a/worlds/sm/variaRandomizer/randomizer.py +++ b/worlds/sm/variaRandomizer/randomizer.py @@ -680,7 +680,7 @@ class VariaRandomizer: #dumpErrorMsg(args.output, self.randoExec.errorMsg) raise Exception("Can't generate " + self.fileName + " with the given parameters: {}".format(self.randoExec.errorMsg)) - def PatchRom(self, outputFilename, customPrePatchApply = None, customPostPatchApply = None): + def PatchRom(self, customPrePatchApply = None, customPostPatchApply = None) -> RomPatcher: args = self.args optErrMsgs = self.optErrMsgs @@ -758,9 +758,9 @@ class VariaRandomizer: # args.output is not None: generate local json named args.output if args.rom is not None: # patch local rom - romFileName = args.rom - shutil.copyfile(romFileName, outputFilename) - romPatcher = RomPatcher(settings=patcherSettings, romFileName=outputFilename, magic=args.raceMagic, player=self.player) + # romFileName = args.rom + # shutil.copyfile(romFileName, outputFilename) + romPatcher = RomPatcher(settings=patcherSettings, magic=args.raceMagic, player=self.player) else: romPatcher = RomPatcher(settings=patcherSettings, magic=args.raceMagic) @@ -779,24 +779,12 @@ class VariaRandomizer: #msg = randoExec.errorMsg msg = '' - if args.rom is None: # web mode - data = romPatcher.romFile.data - self.fileName = '{}.sfc'.format(self.fileName) - data["fileName"] = self.fileName - # error msg in json to be displayed by the web site - data["errorMsg"] = msg - # replaced parameters to update stats in database - if len(self.forcedArgs) > 0: - data["forcedArgs"] = self.forcedArgs - with open(outputFilename, 'w') as jsonFile: - json.dump(data, jsonFile) - else: # CLI mode - if msg != "": - print(msg) + return romPatcher + except Exception as e: import traceback traceback.print_exc(file=sys.stdout) - raise Exception("Error patching {}: ({}: {})".format(outputFilename, type(e).__name__, e)) + raise Exception("Error patching: ({}: {})".format(type(e).__name__, e)) #dumpErrorMsg(args.output, msg) # if stuck == True: diff --git a/worlds/sm/variaRandomizer/rom/ips.py b/worlds/sm/variaRandomizer/rom/ips.py index dd3f30a3ac..add187a86a 100644 --- a/worlds/sm/variaRandomizer/rom/ips.py +++ b/worlds/sm/variaRandomizer/rom/ips.py @@ -21,10 +21,23 @@ class IPS_Patch(object): def toDict(self): ret = {} for record in self.records: - if 'rle_count' in record: - ret[record['address']] = [int.from_bytes(record['data'],'little')]*record['rle_count'] + if record['address'] in ret.keys(): + if 'rle_count' in record: + if len(ret[record['address']]) > record['rle_count']: + ret[record['address']][:record['rle_count']] = [int.from_bytes(record['data'],'little')]*record['rle_count'] + else: + ret[record['address']] = [int.from_bytes(record['data'],'little')]*record['rle_count'] + else: + size = len(record['data']) + if len(ret[record['address']]) > size: + ret[record['address']][:size] = [int(b) for b in record['data']] + else: + ret[record['address']] = [int(b) for b in record['data']] else: - ret[record['address']] = [int(b) for b in record['data']] + if 'rle_count' in record: + ret[record['address']] = [int.from_bytes(record['data'],'little')]*record['rle_count'] + else: + ret[record['address']] = [int(b) for b in record['data']] return ret @staticmethod diff --git a/worlds/sm/variaRandomizer/rom/rom.py b/worlds/sm/variaRandomizer/rom/rom.py index 37c15698a2..f0f37b76a3 100644 --- a/worlds/sm/variaRandomizer/rom/rom.py +++ b/worlds/sm/variaRandomizer/rom/rom.py @@ -86,7 +86,67 @@ class ROM(object): self.seek(self.maxAddress + BANK_SIZE - off - 1) self.writeByte(0xff) assert (self.maxAddress % BANK_SIZE) == 0 - + +class FakeROM(ROM): + # to have the same code for real ROM and the webservice + def __init__(self, data={}): + super(FakeROM, self).__init__() + self.data = data + self.ipsPatches = [] + + def write(self, bytes): + for byte in bytes: + self.data[self.address] = byte + self.inc() + + def read(self, byteCount): + bytes = [] + for i in range(byteCount): + bytes.append(self.data[self.address]) + self.inc() + + return bytes + + def ipsPatch(self, ipsPatches): + self.ipsPatches += ipsPatches + + # generate ips from self data + def ips(self): + groupedData = {} + startAddress = -1 + prevAddress = -1 + curData = [] + for address in sorted(self.data): + if address == prevAddress + 1: + curData.append(self.data[address]) + prevAddress = address + else: + if len(curData) > 0: + groupedData[startAddress] = curData + startAddress = address + prevAddress = address + curData = [self.data[startAddress]] + if startAddress != -1: + groupedData[startAddress] = curData + + return IPS_Patch(groupedData) + + # generate final IPS for web patching with first the IPS patches, then written data + def close(self): + self.mergedIPS = IPS_Patch() + for ips in self.ipsPatches: + self.mergedIPS.append(ips) + self.mergedIPS.append(self.ips()) + #patchData = mergedIPS.encode() + #self.data = {} + #self.data["ips"] = base64.b64encode(patchData).decode() + #if mergedIPS.truncate_length is not None: + # self.data["truncate_length"] = mergedIPS.truncate_length + #self.data["max_size"] = mergedIPS.max_size + + def getPatchDict(self): + return self.mergedIPS.toDict() + class RealROM(ROM): def __init__(self, name): super(RealROM, self).__init__() diff --git a/worlds/sm/variaRandomizer/rom/rompatcher.py b/worlds/sm/variaRandomizer/rom/rompatcher.py index 2dcf554a00..a350764a9c 100644 --- a/worlds/sm/variaRandomizer/rom/rompatcher.py +++ b/worlds/sm/variaRandomizer/rom/rompatcher.py @@ -7,7 +7,7 @@ from ..utils.doorsmanager import DoorsManager, IndicatorFlag from ..utils.objectives import Objectives from ..graph.graph_utils import GraphUtils, getAccessPoint, locIdsByAreaAddresses, graphAreas from ..logic.logic import Logic -from ..rom.rom import RealROM, snes_to_pc, pc_to_snes +from ..rom.rom import FakeROM, snes_to_pc, pc_to_snes from ..rom.addresses import Addresses from ..rom.rom_patches import RomPatches from ..patches.patchaccess import PatchAccess @@ -52,10 +52,10 @@ class RomPatcher: def __init__(self, settings=None, romFileName=None, magic=None, player=0): self.log = log.get('RomPatcher') self.settings = settings - self.romFileName = romFileName + #self.romFileName = romFileName self.patchAccess = PatchAccess() self.race = None - self.romFile = RealROM(romFileName) + self.romFile = FakeROM() #if magic is not None: # from rom.race_mode import RaceModePatcher # self.race = RaceModePatcher(self, magic) @@ -312,7 +312,7 @@ class RomPatcher: self.applyStartAP(self.settings["startLocation"], plms, doors) self.applyPLMs(plms) except Exception as e: - raise Exception("Error patching {}. ({})".format(self.romFileName, e)) + raise Exception("Error patching. ({})".format(e)) def applyIPSPatch(self, patchName, patchDict=None, ipsDir=None): if patchDict is None: @@ -493,6 +493,7 @@ class RomPatcher: def commitIPS(self): self.romFile.ipsPatch(self.ipsPatches) + self.ipsPatches = [] def writeSeed(self, seed): random.seed(seed) diff --git a/worlds/sm64ex/__init__.py b/worlds/sm64ex/__init__.py index afa67f233c..d54e0fc64d 100644 --- a/worlds/sm64ex/__init__.py +++ b/worlds/sm64ex/__init__.py @@ -48,6 +48,17 @@ class SM64World(World): filler_count: int star_costs: typing.Dict[str, int] + # Spoiler specific variable(s) + star_costs_spoiler_key_maxlen = len(max([ + 'First Floor Big Star Door', + 'Basement Big Star Door', + 'Second Floor Big Star Door', + 'MIPS 1', + 'MIPS 2', + 'Endless Stairs', + ], key=len)) + + def generate_early(self): max_stars = 120 if (not self.options.enable_coin_stars): @@ -238,3 +249,19 @@ class SM64World(World): for location in region.locations: er_hint_data[location.address] = entrance_name hint_data[self.player] = er_hint_data + + def write_spoiler(self, spoiler_handle: typing.TextIO) -> None: + # Write calculated star costs to spoiler. + star_cost_spoiler_header = '\n\n' + self.player_name + ' Star Costs for Super Mario 64:\n\n' + spoiler_handle.write(star_cost_spoiler_header) + # - Reformat star costs dictionary in spoiler to be a bit more readable. + star_costs_spoiler = {} + star_costs_copy = self.star_costs.copy() + star_costs_spoiler['First Floor Big Star Door'] = star_costs_copy['FirstBowserDoorCost'] + star_costs_spoiler['Basement Big Star Door'] = star_costs_copy['BasementDoorCost'] + star_costs_spoiler['Second Floor Big Star Door'] = star_costs_copy['SecondFloorDoorCost'] + star_costs_spoiler['MIPS 1'] = star_costs_copy['MIPS1Cost'] + star_costs_spoiler['MIPS 2'] = star_costs_copy['MIPS2Cost'] + star_costs_spoiler['Endless Stairs'] = star_costs_copy['StarsToFinish'] + for star, cost in star_costs_spoiler.items(): + spoiler_handle.write(f"{star:{self.star_costs_spoiler_key_maxlen}s} = {cost}\n") diff --git a/worlds/smz3/__init__.py b/worlds/smz3/__init__.py index 5998db8e65..dca105b162 100644 --- a/worlds/smz3/__init__.py +++ b/worlds/smz3/__init__.py @@ -87,6 +87,21 @@ class SMZ3World(World): self.rom_name_available_event = threading.Event() self.locations: Dict[str, Location] = {} self.unreachable = [] + self.junkItemsNames = [item.name for item in [ + ItemType.Arrow, + ItemType.OneHundredRupees, + ItemType.TenArrows, + ItemType.ThreeBombs, + ItemType.OneRupee, + ItemType.FiveRupees, + ItemType.TwentyRupees, + ItemType.FiftyRupees, + ItemType.ThreeHundredRupees, + ItemType.ETank, + ItemType.Missile, + ItemType.Super, + ItemType.PowerBomb + ]] super().__init__(world, player) @classmethod @@ -202,6 +217,10 @@ class SMZ3World(World): SMZ3World.location_names = frozenset(self.smz3World.locationLookup.keys()) self.multiworld.state.smz3state[self.player] = TotalSMZ3Item.Progression([]) + + if not self.smz3World.Config.Keysanity: + # Dungeons items here are not in the itempool and will be prefilled locally so they must stay local + self.options.non_local_items.value -= frozenset(item_name for item_name in self.item_names if TotalSMZ3Item.Item.IsNameDungeonItem(item_name)) def create_items(self): self.dungeon = TotalSMZ3Item.Item.CreateDungeonPool(self.smz3World) @@ -218,8 +237,6 @@ class SMZ3World(World): progressionItems = self.progression + self.dungeon + self.keyCardsItems + self.SmMapsItems else: progressionItems = self.progression - # Dungeons items here are not in the itempool and will be prefilled locally so they must stay local - self.options.non_local_items.value -= frozenset(item_name for item_name in self.item_names if TotalSMZ3Item.Item.IsNameDungeonItem(item_name)) for item in self.keyCardsItems: self.multiworld.push_precollected(SMZ3Item(item.Type.name, ItemClassification.filler, item.Type, self.item_name_to_id[item.Type.name], self.player, item)) diff --git a/worlds/soe/options.py b/worlds/soe/options.py index 5ecd0f9e66..9e0798e1a6 100644 --- a/worlds/soe/options.py +++ b/worlds/soe/options.py @@ -309,7 +309,7 @@ class SoEOptions(PerGameCommonOptions): @property def flags(self) -> str: - flags = '' + flags = 'AGBo' # configures auto-tracker to AP's fill for field in fields(self): option = getattr(self, field.name) if isinstance(option, (EvermizerFlag, EvermizerFlags)): diff --git a/worlds/soe/requirements.txt b/worlds/soe/requirements.txt index 4bcacb33c3..6a569e83a1 100644 --- a/worlds/soe/requirements.txt +++ b/worlds/soe/requirements.txt @@ -1,36 +1,37 @@ -pyevermizer==0.48.0 \ - --hash=sha256:069ce348e480e04fd6208cfd0f789c600b18d7c34b5272375b95823be191ed57 \ - --hash=sha256:58164dddaba2f340b0a8b4f39605e9dac46d8b0ffb16120e2e57bef2bfc1d683 \ - --hash=sha256:115dd09d38a10f11d4629b340dfd75e2ba4089a1ff9e9748a11619829e02c876 \ - --hash=sha256:b5e79cfe721e75cd7dec306b5eecd6385ce059e31ef7523ba7f677e22161ec6f \ - --hash=sha256:382882fa9d641b9969a6c3ed89449a814bdabcb6b17b558872d95008a6cc908b \ - --hash=sha256:92f67700e9132064a90858d391dd0b8fb111aff6dfd472befed57772d89ae567 \ - --hash=sha256:fe4c453b7dbd5aa834b81f9a7aedb949a605455650b938b8b304d8e5a7edcbf7 \ - --hash=sha256:c6bdbc45daf73818f763ed59ad079f16494593395d806f772dd62605c722b3e9 \ - --hash=sha256:bb09f45448fdfd28566ae6fcc38c35a6632f4c31a9de2483848f6ce17b2359b5 \ - --hash=sha256:00a8b9014744bd1528d0d39c33ede7c0d1713ad797a331cebb33d377a5bc1064 \ - --hash=sha256:64ee69edc0a7d3b3caded78f2e46975f9beaff1ff8feaf29b87da44c45f38d7d \ - --hash=sha256:9211bdb1313e9f4869ed5bdc61f3831d39679bd08bb4087f1c1e5475d9e3018b \ - --hash=sha256:4a57821e422a1d75fe3307931a78db7a65e76955f8e401c4b347db6570390d09 \ - --hash=sha256:04670cee0a0b913f24d2b9a1e771781560e2485bda31e6cd372a08421cf85cfa \ - --hash=sha256:971fe77d0a20a1db984020ad253b613d0983f5e23ff22cba60ee5ac00d8128de \ - --hash=sha256:127265fdb49f718f54706bf15604af1cec23590afd00d423089dea4331dcfc61 \ - --hash=sha256:d47576360337c1a23f424cd49944a8d68fc4f3338e00719c9f89972c84604bef \ - --hash=sha256:879659603e51130a0de8d9885d815a2fa1df8bd6cebe6d520d1c6002302adfdb \ - --hash=sha256:6a91bfc53dd130db6424adf8ac97a1133e97b4157ed00f889d8cbd26a2a4b340 \ - --hash=sha256:f3bf35fc5eef4cda49d2de77339fc201dd3206660a3dc15db005625b15bb806c \ - --hash=sha256:e7c8d5bf59a3c16db20411bc5d8e9c9087a30b6b4edf1b5ed9f4c013291427e4 \ - --hash=sha256:054a4d84ffe75448d41e88e1e0642ef719eb6111be5fe608e71e27a558c59069 \ - --hash=sha256:e6f141ca367469c69ba7fbf65836c479ec6672c598cfcb6b39e8098c60d346bc \ - --hash=sha256:6e65eb88f0c1ff4acde1c13b24ce649b0fe3d1d3916d02d96836c781a5022571 \ - --hash=sha256:e61e8f476b6da809cf38912755ed8bb009665f589e913eb8df877e9fa763024b \ - --hash=sha256:7e7c5484c0a2e3da6064de3f73d8d988d6703db58ab0be4730cbbf1a82319237 \ - --hash=sha256:9033b954e5f4878fd94af6d2056c78e3316115521fb1c24a4416d5cbf2ad66ad \ - --hash=sha256:824c623fff8ae4da176306c458ad63ad16a06a495a16db700665eca3c115924f \ - --hash=sha256:8e31031409a8386c6a63b79d480393481badb3ba29f32ff7a0db2b4abed20ac8 \ - --hash=sha256:7dbb7bb13e1e94f69f7ccdbcf4d35776424555fce5af1ca29d0256f91fdf087a \ - --hash=sha256:3a24e331b259407b6912d6e0738aa8a675831db3b7493fcf54dc17cb0cb80d37 \ - --hash=sha256:fdda06662a994271e96633cba100dd92b2fcd524acef8b2f664d1aaa14503cbd \ - --hash=sha256:0f0fc81bef3dbb78ba6a7622dd4296f23c59825968a0bb0448beb16eb3397cc2 \ - --hash=sha256:e07cbef776a7468669211546887357cc88e9afcf1578b23a4a4f2480517b15d9 \ - --hash=sha256:e442212695bdf60e455673b7b9dd83a5d4b830d714376477093d2c9054d92832 +pyevermizer==0.50.1 \ + --hash=sha256:4d1f43d5f8016e7bfcb5cd80b447a4f278b60b1b250a6153e66150230bf280e8 \ + --hash=sha256:06af4f66ae1f21932a936bf741a0547bbb8ff92eea8fb8efece6bc1760a8a999 \ + --hash=sha256:1ddbc36860704385a767d24364eac6504acc74f185c98b50cf52219c6e0148c6 \ + --hash=sha256:61f0adc4f615867e51bfcd7d7c90f19779a61391a995c721e7393005e8413950 \ + --hash=sha256:d84761ee03ebdaf011befe01638db1fff128b1c37405088868f0025e064977f3 \ + --hash=sha256:0433507dd8ad96375f3b64534faefdf9d325b69a19e108db1414fc75d6e72160 \ + --hash=sha256:e8857f719da9eaaa54f564886ff1b36cb89b8ccf08aa6ccca2d5d3c41da0b067 \ + --hash=sha256:40e76a30968b1fce3d727b47b2693d4151a9ad29b053a33bf06cde8fa63c3d15 \ + --hash=sha256:09ced5349a183656c1f8dcb85e41bdd496d1c5f2bb8f712d12a055d6efa7b917 \ + --hash=sha256:162806e7b0156e25612e60d25af68772cf553b3352a5cf31866d838295ccb591 \ + --hash=sha256:79750965bc63ffa351c167672b51c32f2a8d3242e07e769f925d1f306564a18d \ + --hash=sha256:b1875eb79c8800352f30180db296036d8b512082d6609e2368aa7032c1cf7e27 \ + --hash=sha256:7989e6f06c1ea38687a6b14416b179f459282ea81edbb86086d426fe0d63bf7a \ + --hash=sha256:8a4c5c62997e7378457624a88c12b27b52d345b365c3cfae7fee77ee46eb7cd0 \ + --hash=sha256:a22557f56ada1ace61b781e731e06466c22b6cc605c1aa9dec10e3697b10f5e6 \ + --hash=sha256:d1057e70be839e9c3a91f0f173bc795fc0014cf560767d699cc26eba5f5cfc6f \ + --hash=sha256:8540bd8e8ec49422b494beece1f6bf4cca61aa452a4c0f85c3a8b77283b24753 \ + --hash=sha256:569b98352fc6e1fae85a8c2ee3f2e61276762bc158ac5b7e07a476ee0f9e2617 \ + --hash=sha256:1b21eed21eb9338a6e7024b015d0107eaecf78c61f8ece8e6553d77f7f0ba726 \ + --hash=sha256:51ff863e92c7b608d464da10c775b5df5ad3651a05c2d316c1d60a46572fdef9 \ + --hash=sha256:0f920d745df15e3171412cbda05fc21c9354323d0e8dfc066ed6051fa7df9879 \ + --hash=sha256:d78970415fb03c1dd22aef8da7526e5b33eaf4c9848f5cbad843ad159254f526 \ + --hash=sha256:50536924bbf702d310b92d307d7c5060f6a4307bf99b61f79571ba2675ebb1ff \ + --hash=sha256:1123f8f87ce6415183126842eca1fff98362ff545204adfd4c7b6cf1c396b738 \ + --hash=sha256:1b248af5aa7321e46ae05675b15a5993e28311dfabc68cee2e398ce571f28eb2 \ + --hash=sha256:a76e9d17ec3af9317b3a9d5e9f9f04aea80a5902c33f6fe82d02381f2fd2cb69 \ + --hash=sha256:081ed52f8e1693ca48262cb5a9687ee62c4f9a50c667a487192c72be4c1b7fac \ + --hash=sha256:2978aa13826337d59799f41dda41fa4cecd9f59fae8843613230cf298b06fa6e \ + --hash=sha256:d377c2fd68c3d529d89ba40a762b6424c3b04c0d58593c02f06adbdf236f72ad \ + --hash=sha256:800d6c30eab6ca3ee39a6c297d08cb74cfa5a4bce498aa3f05a612596f8c513b \ + --hash=sha256:0cf40413f4b7ae5d561e47706f446b91440a1b74abe33b8fabc995d92c3325ca \ + --hash=sha256:97791b8695aa215ef407824d1e6c0582a2a2f89f3a0f254f5d791a5a84a0ad00 \ + --hash=sha256:2174db5e4550f94cb63e17584973c9f9afdc23e5230cb556de8bf87bd72145ff \ + --hash=sha256:f3a4cd6a9b292e7385722d8200e834a936886136ddaef2069035f7ec5eb50d34 \ + --hash=sha256:7646efdf7e091c75dac9aebb6c9faf215de4f6b8567c049944790e43cbe63d51 \ + --hash=sha256:cd56cca26ed9675790154dd70402ad28a381fc3c9031bd02eb9b1dad8c317398 \ diff --git a/worlds/soe/test/test_oob.py b/worlds/soe/test/test_oob.py index 3c1a2829de..0878fd56e3 100644 --- a/worlds/soe/test/test_oob.py +++ b/worlds/soe/test/test_oob.py @@ -12,13 +12,13 @@ class OoBTest(SoETestBase): # some locations that just need a weapon + OoB oob_reachable = [ "Aquagoth", "Sons of Sth.", "Mad Monk", "Magmar", # OoB can use volcano shop to skip rock skip - "Levitate", "Fireball", "Drain", "Speed", + "Levitate", "Fireball", "Speed", "E. Crustacia #107", "Energy Core #285", "Vanilla Gauge #57", ] # some locations that should still be unreachable oob_unreachable = [ "Tiny", "Rimsala", - "Barrier", "Call Up", "Reflect", "Force Field", "Stop", # Stop guy doesn't spawn for the other entrances + "Barrier", "Drain", "Call Up", "Reflect", "Force Field", "Stop", # Stop guy only spawns from one entrance "Pyramid bottom #118", "Tiny's hideout #160", "Tiny's hideout #161", "Greenhouse #275", ] # OoB + Diamond Eyes @@ -31,11 +31,42 @@ class OoBTest(SoETestBase): "Tiny's hideout #161", ] - self.assertLocationReachability(reachable=oob_reachable, unreachable=oob_unreachable, satisfied=False) - self.collect_by_name("Gladiator Sword") - self.assertLocationReachability(reachable=oob_reachable, unreachable=oob_unreachable, satisfied=in_logic) - self.collect_by_name("Diamond Eye") - self.assertLocationReachability(reachable=de_reachable, unreachable=de_unreachable, satisfied=in_logic) + with self.subTest("No items", oob_logic=in_logic): + self.assertLocationReachability(reachable=oob_reachable, unreachable=oob_unreachable, satisfied=False) + with self.subTest("Cutting Weapon", oob_logic=in_logic): + self.collect_by_name("Gladiator Sword") + self.assertLocationReachability(reachable=oob_reachable, unreachable=oob_unreachable, satisfied=in_logic) + with self.subTest("Cutting Weapon + DEs", oob_logic=in_logic): + self.collect_by_name("Diamond Eye") + self.assertLocationReachability(reachable=de_reachable, unreachable=de_unreachable, satisfied=in_logic) + + def test_real_axe(self) -> None: + in_logic = self.options["out_of_bounds"] == "logic" + + # needs real Bronze Axe+, regardless of OoB + real_axe_required = [ + "Drain", + "Drain Cave #180", + "Drain Cave #181", + ] + also_des_required = [ + "Double Drain", + ] + + with self.subTest("No Axe", oob_logic=in_logic): + self.collect_by_name("Gladiator Sword") + self.assertLocationReachability(reachable=real_axe_required, satisfied=False) + with self.subTest("Bronze Axe", oob_logic=in_logic): + self.collect_by_name("Bronze Axe") + self.assertLocationReachability(reachable=real_axe_required, satisfied=True) + with self.subTest("Knight Basher", oob_logic=in_logic): + self.remove_by_name("Bronze Axe") + self.collect_by_name("Knight Basher") + self.assertLocationReachability(reachable=real_axe_required, satisfied=True) + self.assertLocationReachability(reachable=also_des_required, satisfied=False) + with self.subTest("Knight Basher + DEs", oob_logic=in_logic): + self.collect_by_name("Diamond Eye") + self.assertLocationReachability(reachable=also_des_required, satisfied=True) def test_oob_goal(self) -> None: # still need Energy Core with OoB if sequence breaks are not in logic diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 6ba0e35e0a..e2d49e64ae 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -1,33 +1,27 @@ import logging from random import Random -from typing import Dict, Any, Iterable, Optional, Union, List, TextIO +from typing import Dict, Any, Iterable, Optional, List, TextIO, cast from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState from Options import PerGameCommonOptions from worlds.AutoWorld import World, WebWorld -from . import rules from .bundles.bundle_room import BundleRoom from .bundles.bundles import get_all_bundles -from .content import content_packs, StardewContent, unpack_content, create_content +from .content import StardewContent, create_content from .early_items import setup_early_items from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs from .locations import location_table, create_locations, LocationData, locations_by_tag -from .logic.bundle_logic import BundleLogic from .logic.logic import StardewLogic -from .logic.time_logic import MAX_MONTHS from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, EnabledFillerBuffs, NumberOfMovementBuffs, \ - BuildingProgression, ExcludeGingerIsland, TrapItems, EntranceRandomization, FarmType, Walnutsanity + BuildingProgression, ExcludeGingerIsland, TrapItems, EntranceRandomization, FarmType from .options.forced_options import force_change_options_if_incompatible from .options.option_groups import sv_option_groups from .options.presets import sv_options_presets from .regions import create_regions from .rules import set_rules -from .stardew_rule import True_, StardewRule, HasProgressionPercent, true_ +from .stardew_rule import True_, StardewRule, HasProgressionPercent from .strings.ap_names.event_names import Event -from .strings.entrance_names import Entrance as EntranceName from .strings.goal_names import Goal as GoalName -from .strings.metal_names import Ore -from .strings.region_names import Region as RegionName, LogicRegion logger = logging.getLogger(__name__) @@ -94,7 +88,6 @@ class StardewValleyWorld(World): randomized_entrances: Dict[str, str] total_progression_items: int - excluded_from_total_progression_items: List[str] = [Event.received_walnuts] def __init__(self, multiworld: MultiWorld, player: int): super().__init__(multiworld, player) @@ -131,7 +124,7 @@ class StardewValleyWorld(World): self.options) def add_location(name: str, code: Optional[int], region: str): - region = world_regions[region] + region: Region = world_regions[region] location = StardewLocation(self.player, name, code, region) region.locations.append(location) @@ -159,7 +152,7 @@ class StardewValleyWorld(World): self.multiworld.itempool += created_items setup_early_items(self.multiworld, self.options, self.content, self.player, self.random) - self.setup_player_events() + self.setup_logic_events() self.setup_victory() # This is really a best-effort to get the total progression items count. It is mostly used to spread grinds across spheres are push back locations that @@ -182,7 +175,7 @@ class StardewValleyWorld(World): if self.options.season_randomization == SeasonRandomization.option_disabled: for season in season_pool: - self.multiworld.push_precollected(self.create_starting_item(season)) + self.multiworld.push_precollected(self.create_item(season)) return if [item for item in self.multiworld.precollected_items[self.player] @@ -192,26 +185,12 @@ class StardewValleyWorld(World): if self.options.season_randomization == SeasonRandomization.option_randomized_not_winter: season_pool = [season for season in season_pool if season.name != "Winter"] - starting_season = self.create_starting_item(self.random.choice(season_pool)) + starting_season = self.create_item(self.random.choice(season_pool)) self.multiworld.push_precollected(starting_season) def precollect_farm_type_items(self): if self.options.farm_type == FarmType.option_meadowlands and self.options.building_progression & BuildingProgression.option_progressive: - self.multiworld.push_precollected(self.create_starting_item("Progressive Coop")) - - def setup_player_events(self): - self.setup_action_events() - self.setup_logic_events() - - def setup_action_events(self): - spring_farming = LocationData(None, LogicRegion.spring_farming, Event.spring_farming) - self.create_event_location(spring_farming, true_, Event.spring_farming) - summer_farming = LocationData(None, LogicRegion.summer_farming, Event.summer_farming) - self.create_event_location(summer_farming, true_, Event.summer_farming) - fall_farming = LocationData(None, LogicRegion.fall_farming, Event.fall_farming) - self.create_event_location(fall_farming, true_, Event.fall_farming) - winter_farming = LocationData(None, LogicRegion.winter_farming, Event.winter_farming) - self.create_event_location(winter_farming, true_, Event.winter_farming) + self.multiworld.push_precollected(self.create_item("Progressive Coop")) def setup_logic_events(self): def register_event(name: str, region: str, rule: StardewRule): @@ -291,7 +270,7 @@ class StardewValleyWorld(World): def get_all_location_names(self) -> List[str]: return list(location.name for location in self.multiworld.get_locations(self.player)) - def create_item(self, item: Union[str, ItemData], override_classification: ItemClassification = None) -> StardewItem: + def create_item(self, item: str | ItemData, override_classification: ItemClassification = None) -> StardewItem: if isinstance(item, str): item = item_table[item] @@ -300,12 +279,6 @@ class StardewValleyWorld(World): return StardewItem(item.name, override_classification, item.code, self.player) - def create_starting_item(self, item: Union[str, ItemData]) -> StardewItem: - if isinstance(item, str): - item = item_table[item] - - return StardewItem(item.name, item.classification, item.code, self.player) - def create_event_location(self, location_data: LocationData, rule: StardewRule = None, item: Optional[str] = None): if rule is None: rule = True_() @@ -341,9 +314,9 @@ class StardewValleyWorld(World): include_traps = True exclude_island = False for player in link_group["players"]: - player_options = self.multiworld.worlds[player].options if self.multiworld.game[player] != self.game: continue + player_options = cast(StardewValleyOptions, self.multiworld.worlds[player].options) if player_options.trap_items == TrapItems.option_no_traps: include_traps = False if player_options.exclude_ginger_island == ExcludeGingerIsland.option_true: @@ -413,9 +386,19 @@ class StardewValleyWorld(World): if not change: return False + player_state = state.prog_items[self.player] + + received_progression_count = player_state[Event.received_progression_item] + received_progression_count += 1 + if self.total_progression_items: + # Total progression items is not set until all items are created, but collect will be called during the item creation when an item is precollected. + # We can't update the percentage if we don't know the total progression items, can't divide by 0. + player_state[Event.received_progression_percent] = received_progression_count * 100 // self.total_progression_items + player_state[Event.received_progression_item] = received_progression_count + walnut_amount = self.get_walnut_amount(item.name) if walnut_amount: - state.prog_items[self.player][Event.received_walnuts] += walnut_amount + player_state[Event.received_walnuts] += walnut_amount return True @@ -424,9 +407,18 @@ class StardewValleyWorld(World): if not change: return False + player_state = state.prog_items[self.player] + + received_progression_count = player_state[Event.received_progression_item] + received_progression_count -= 1 + if self.total_progression_items: + # We can't update the percentage if we don't know the total progression items, can't divide by 0. + player_state[Event.received_progression_percent] = received_progression_count * 100 // self.total_progression_items + player_state[Event.received_progression_item] = received_progression_count + walnut_amount = self.get_walnut_amount(item.name) if walnut_amount: - state.prog_items[self.player][Event.received_walnuts] -= walnut_amount + player_state[Event.received_walnuts] -= walnut_amount return True diff --git a/worlds/stardew_valley/bundles/bundle_room.py b/worlds/stardew_valley/bundles/bundle_room.py index 8068ff17ac..225fb4feab 100644 --- a/worlds/stardew_valley/bundles/bundle_room.py +++ b/worlds/stardew_valley/bundles/bundle_room.py @@ -4,7 +4,7 @@ from typing import List from .bundle import Bundle, BundleTemplate from ..content import StardewContent -from ..options import BundlePrice, StardewValleyOptions +from ..options import StardewValleyOptions @dataclass diff --git a/worlds/stardew_valley/content/mods/sve.py b/worlds/stardew_valley/content/mods/sve.py index a68d4ae9c0..12b3e3558a 100644 --- a/worlds/stardew_valley/content/mods/sve.py +++ b/worlds/stardew_valley/content/mods/sve.py @@ -10,15 +10,14 @@ from ...data.shop import ShopSource from ...mods.mod_data import ModNames from ...strings.craftable_names import ModEdible from ...strings.crop_names import Fruit, SVEVegetable, SVEFruit -from ...strings.fish_names import WaterItem, SVEFish, SVEWaterItem +from ...strings.fish_names import WaterItem, SVEWaterItem from ...strings.flower_names import Flower from ...strings.food_names import SVEMeal, SVEBeverage from ...strings.forageable_names import Mushroom, Forageable, SVEForage from ...strings.gift_names import SVEGift -from ...strings.metal_names import Ore -from ...strings.monster_drop_names import ModLoot, Loot +from ...strings.monster_drop_names import ModLoot from ...strings.performance_names import Performance -from ...strings.region_names import Region, SVERegion, LogicRegion +from ...strings.region_names import Region, SVERegion from ...strings.season_names import Season from ...strings.seed_names import SVESeed from ...strings.skill_names import Skill @@ -81,7 +80,8 @@ register_mod_content_pack(SVEContentPack( ModEdible.lightning_elixir: (ShopSource(money_price=12000, shop_region=SVERegion.galmoran_outpost),), ModEdible.barbarian_elixir: (ShopSource(money_price=22000, shop_region=SVERegion.galmoran_outpost),), ModEdible.gravity_elixir: (ShopSource(money_price=4000, shop_region=SVERegion.galmoran_outpost),), - SVEMeal.grampleton_orange_chicken: (ShopSource(money_price=650, shop_region=Region.saloon, other_requirements=(RelationshipRequirement(ModNPC.sophia, 6),)),), + SVEMeal.grampleton_orange_chicken: ( + ShopSource(money_price=650, shop_region=Region.saloon, other_requirements=(RelationshipRequirement(ModNPC.sophia, 6),)),), ModEdible.hero_elixir: (ShopSource(money_price=8000, shop_region=SVERegion.isaac_shop),), ModEdible.aegis_elixir: (ShopSource(money_price=28000, shop_region=SVERegion.galmoran_outpost),), SVEBeverage.sports_drink: (ShopSource(money_price=750, shop_region=Region.hospital),), @@ -92,7 +92,8 @@ register_mod_content_pack(SVEContentPack( ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.summer, Season.fall)), ForagingSource(regions=(SVERegion.sprite_spring_cave,), ) ), Mushroom.purple: ( - ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.fall,)), ForagingSource(regions=(SVERegion.sprite_spring_cave, SVERegion.junimo_woods), ) + ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.fall,)), + ForagingSource(regions=(SVERegion.sprite_spring_cave, SVERegion.junimo_woods), ) ), Mushroom.morel: ( ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.fall,)), ForagingSource(regions=(SVERegion.sprite_spring_cave,), ) @@ -117,7 +118,8 @@ register_mod_content_pack(SVEContentPack( ModLoot.green_mushroom: (ForagingSource(regions=(SVERegion.highlands_pond,), seasons=Season.not_winter),), ModLoot.ornate_treasure_chest: (ForagingSource(regions=(SVERegion.highlands_outside,), - other_requirements=(CombatRequirement(Performance.galaxy), ToolRequirement(Tool.axe, ToolMaterial.iron))),), + other_requirements=( + CombatRequirement(Performance.galaxy), ToolRequirement(Tool.axe, ToolMaterial.iron))),), ModLoot.swirl_stone: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.galaxy),)),), ModLoot.void_soul: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.good),)),), SVEForage.winter_star_rose: (ForagingSource(regions=(SVERegion.summit,), seasons=(Season.winter,)),), @@ -137,7 +139,8 @@ register_mod_content_pack(SVEContentPack( SVEForage.thistle: (ForagingSource(regions=(SVERegion.summit,)),), ModLoot.void_pebble: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.great),)),), ModLoot.void_shard: (ForagingSource(regions=(SVERegion.crimson_badlands,), - other_requirements=(CombatRequirement(Performance.galaxy), SkillRequirement(Skill.combat, 10), YearRequirement(3),)),), + other_requirements=( + CombatRequirement(Performance.galaxy), SkillRequirement(Skill.combat, 10), YearRequirement(3),)),), SVEWaterItem.dulse_seaweed: (ForagingSource(regions=(Region.beach,), other_requirements=(FishingRequirement(Region.beach),)),), # Fable Reef diff --git a/worlds/stardew_valley/content/vanilla/base.py b/worlds/stardew_valley/content/vanilla/base.py index 2c910df5d0..9e5f53eb86 100644 --- a/worlds/stardew_valley/content/vanilla/base.py +++ b/worlds/stardew_valley/content/vanilla/base.py @@ -140,7 +140,7 @@ base_game = BaseGameContentPack( Vegetable.broccoli: (HarvestCropSource(seed=Seed.broccoli, seasons=(Season.fall,)),), Vegetable.carrot: (HarvestCropSource(seed=Seed.carrot, seasons=(Season.spring,)),), - Fruit.powdermelon: (HarvestCropSource(seed=Seed.powdermelon, seasons=(Season.summer,)),), + Fruit.powdermelon: (HarvestCropSource(seed=Seed.powdermelon, seasons=(Season.winter,)),), Vegetable.summer_squash: (HarvestCropSource(seed=Seed.summer_squash, seasons=(Season.summer,)),), Fruit.strawberry: (HarvestCropSource(seed=Seed.strawberry, seasons=(Season.spring,)),), diff --git a/worlds/stardew_valley/content/vanilla/qi_board.py b/worlds/stardew_valley/content/vanilla/qi_board.py index d859d3b16f..e5f67c4319 100644 --- a/worlds/stardew_valley/content/vanilla/qi_board.py +++ b/worlds/stardew_valley/content/vanilla/qi_board.py @@ -6,7 +6,6 @@ from ...data.game_item import GenericSource, ItemTag from ...data.harvest import HarvestCropSource from ...strings.crop_names import Fruit from ...strings.region_names import Region -from ...strings.season_names import Season from ...strings.seed_names import Seed diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 8b2e189c79..75f0f75a23 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -10,7 +10,7 @@ from ..strings.craftable_names import Fishing, Craftable, Bomb, Consumable, Ligh from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro -from ..strings.fish_names import Fish, WaterItem, Trash, all_fish +from ..strings.fish_names import Fish, WaterItem, Trash from ..strings.flower_names import Flower from ..strings.food_names import Beverage, Meal from ..strings.forageable_names import Forageable, Mushroom @@ -832,7 +832,7 @@ calico_items = [calico_egg.as_amount(200), calico_egg.as_amount(200), calico_egg magic_rock_candy, mega_bomb.as_amount(10), mystery_box.as_amount(10), mixed_seeds.as_amount(50), strawberry_seeds.as_amount(20), spicy_eel.as_amount(5), crab_cakes.as_amount(5), eggplant_parmesan.as_amount(5), - pumpkin_soup.as_amount(5), lucky_lunch.as_amount(5),] + pumpkin_soup.as_amount(5), lucky_lunch.as_amount(5)] calico_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.calico, calico_items, 2, 2) raccoon_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.raccoon, raccoon_foraging_items, 4, 4) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 713db47320..de371b7c3a 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -11,10 +11,10 @@ from ..strings.craftable_names import Bomb, Fence, Sprinkler, WildSeeds, Floor, from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro -from ..strings.fish_names import Fish, WaterItem, ModTrash +from ..strings.fish_names import Fish, WaterItem, ModTrash, Trash from ..strings.flower_names import Flower from ..strings.food_names import Meal -from ..strings.forageable_names import Forageable, SVEForage, DistantLandsForageable, Mushroom +from ..strings.forageable_names import Forageable, DistantLandsForageable, Mushroom from ..strings.gift_names import Gift from ..strings.ingredient_names import Ingredient from ..strings.machine_names import Machine @@ -318,7 +318,8 @@ travel_charm = shop_recipe(ModCraftable.travel_core, Region.adventurer_guild, 25 preservation_chamber = skill_recipe(ModMachine.preservation_chamber, ModSkill.archaeology, 1, {MetalBar.copper: 1, Material.wood: 15, ArtisanGood.oak_resin: 30}, ModNames.archaeology) -restoration_table = skill_recipe(ModMachine.restoration_table, ModSkill.archaeology, 1, {Material.wood: 15, MetalBar.copper: 1, MetalBar.iron: 1}, ModNames.archaeology) +restoration_table = skill_recipe(ModMachine.restoration_table, ModSkill.archaeology, 1, {Material.wood: 15, MetalBar.copper: 1, MetalBar.iron: 1}, + ModNames.archaeology) preservation_chamber_h = skill_recipe(ModMachine.hardwood_preservation_chamber, ModSkill.archaeology, 6, {MetalBar.copper: 1, Material.hardwood: 15, ArtisanGood.oak_resin: 30}, ModNames.archaeology) grinder = skill_recipe(ModMachine.grinder, ModSkill.archaeology, 2, {Artifact.rusty_cog: 10, MetalBar.iron: 5, ArtisanGood.battery_pack: 1}, @@ -330,12 +331,14 @@ glass_path = skill_recipe(ModFloor.glass_path, ModSkill.archaeology, 3, {Artifac glass_fence = skill_recipe(ModCraftable.glass_fence, ModSkill.archaeology, 7, {Artifact.glass_shards: 5}, ModNames.archaeology) bone_path = skill_recipe(ModFloor.bone_path, ModSkill.archaeology, 4, {Fossil.bone_fragment: 1}, ModNames.archaeology) rust_path = skill_recipe(ModFloor.rusty_path, ModSkill.archaeology, 2, {ModTrash.rusty_scrap: 2}, ModNames.archaeology) -rusty_brazier = skill_recipe(ModCraftable.rusty_brazier, ModSkill.archaeology, 3, {ModTrash.rusty_scrap: 10, Material.coal: 1, Material.fiber: 1}, ModNames.archaeology) +rusty_brazier = skill_recipe(ModCraftable.rusty_brazier, ModSkill.archaeology, 3, {ModTrash.rusty_scrap: 10, Material.coal: 1, Material.fiber: 1}, + ModNames.archaeology) bone_fence = skill_recipe(ModCraftable.bone_fence, ModSkill.archaeology, 8, {Fossil.bone_fragment: 2}, ModNames.archaeology) water_shifter = skill_recipe(ModCraftable.water_shifter, ModSkill.archaeology, 4, {Material.wood: 40, MetalBar.copper: 4}, ModNames.archaeology) wooden_display = skill_recipe(ModCraftable.wooden_display, ModSkill.archaeology, 1, {Material.wood: 25}, ModNames.archaeology) hardwood_display = skill_recipe(ModCraftable.hardwood_display, ModSkill.archaeology, 7, {Material.hardwood: 10}, ModNames.archaeology) -lucky_ring = skill_recipe(Ring.lucky_ring, ModSkill.archaeology, 8, {Artifact.elvish_jewelry: 1, AnimalProduct.rabbit_foot: 5, Mineral.tigerseye: 1}, ModNames.archaeology) +lucky_ring = skill_recipe(Ring.lucky_ring, ModSkill.archaeology, 8, {Artifact.elvish_jewelry: 1, AnimalProduct.rabbit_foot: 5, Mineral.tigerseye: 1}, + ModNames.archaeology) volcano_totem = skill_recipe(ModConsumable.volcano_totem, ModSkill.archaeology, 9, {Material.cinder_shard: 5, Artifact.rare_disc: 1, Artifact.dwarf_gadget: 1}, ModNames.archaeology) haste_elixir = shop_recipe(ModEdible.haste_elixir, SVERegion.alesia_shop, 35000, {Loot.void_essence: 35, ModLoot.void_soul: 5, Ingredient.sugar: 1, @@ -378,4 +381,12 @@ recycling_bin = skill_recipe(ModMachine.recycling_bin, ModSkill.binning, 7, {Met advanced_recycling_machine = skill_recipe(ModMachine.advanced_recycling_machine, ModSkill.binning, 9, {MetalBar.iridium: 5, ArtisanGood.battery_pack: 2, MetalBar.quartz: 10}, ModNames.binning_skill) +coppper_slot_machine = skill_recipe(ModMachine.copper_slot_machine, ModSkill.luck, 2, {MetalBar.copper: 15, Material.stone: 1, Material.wood: 1, + Material.fiber: 1, Material.sap: 1, Loot.slime: 1, + Forageable.salmonberry: 1, Material.clay: 1, Trash.joja_cola: 1}, ModNames.luck_skill) + +gold_slot_machine = skill_recipe(ModMachine.gold_slot_machine, ModSkill.luck, 4, {MetalBar.gold: 15, ModMachine.copper_slot_machine: 1}, ModNames.luck_skill) +iridium_slot_machine = skill_recipe(ModMachine.iridium_slot_machine, ModSkill.luck, 4, {MetalBar.iridium: 15, ModMachine.gold_slot_machine: 1}, ModNames.luck_skill) +radioactive_slot_machine = skill_recipe(ModMachine.radioactive_slot_machine, ModSkill.luck, 4, {MetalBar.radioactive: 15, ModMachine.iridium_slot_machine: 1}, ModNames.luck_skill) + all_crafting_recipes_by_name = {recipe.item: recipe for recipe in all_crafting_recipes} diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 680ddfcbac..66a9157b34 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2935,6 +2935,10 @@ id,region,name,tags,mod_name 7433,Farm,Craft Composter,CRAFTSANITY,Binning Skill 7434,Farm,Craft Recycling Bin,CRAFTSANITY,Binning Skill 7435,Farm,Craft Advanced Recycling Machine,CRAFTSANITY,Binning Skill +7440,Farm,Craft Copper Slot Machine,"CRAFTSANITY",Luck Skill +7441,Farm,Craft Gold Slot Machine,"CRAFTSANITY",Luck Skill +7442,Farm,Craft Iridium Slot Machine,"CRAFTSANITY",Luck Skill +7443,Farm,Craft Radioactive Slot Machine,"CRAFTSANITY,GINGER_ISLAND",Luck Skill 7451,Adventurer's Guild,Magic Elixir Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded @@ -3241,7 +3245,7 @@ id,region,name,tags,mod_name 8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology 8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology 8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology -8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology +8202,Shipping,Shipsanity: Water Shifter,"SHIPSANITY,DEPRECATED",Archaeology 8203,Shipping,Shipsanity: Brown Amanita,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul 8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul 8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 3123bb9243..667227cb9e 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -1,15 +1,16 @@ from typing import Dict, List, Optional -from ..mods.mod_data import ModNames + from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource, ShopFriendshipSource +from ..mods.mod_data import ModNames from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.craftable_names import ModEdible, Edible from ..strings.crop_names import Fruit, Vegetable, SVEFruit, DistantLandsCrop from ..strings.fish_names import Fish, SVEFish, WaterItem, DistantLandsFish, SVEWaterItem from ..strings.flower_names import Flower -from ..strings.forageable_names import Forageable, SVEForage, DistantLandsForageable, Mushroom -from ..strings.ingredient_names import Ingredient from ..strings.food_names import Meal, SVEMeal, Beverage, DistantLandsMeal, BoardingHouseMeal, ArchaeologyMeal, TrashyMeal +from ..strings.forageable_names import Forageable, SVEForage, Mushroom +from ..strings.ingredient_names import Ingredient from ..strings.material_names import Material from ..strings.metal_names import Fossil, Artifact from ..strings.monster_drop_names import Loot @@ -45,7 +46,8 @@ def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str return create_recipe(name, ingredients, source, mod_name) -def friendship_and_shop_recipe(name: str, friend: str, hearts: int, region: str, price: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CookingRecipe: +def friendship_and_shop_recipe(name: str, friend: str, hearts: int, region: str, price: int, ingredients: Dict[str, int], + mod_name: Optional[str] = None) -> CookingRecipe: source = ShopFriendshipSource(friend, hearts, region, price) return create_recipe(name, ingredients, source, mod_name) @@ -85,7 +87,8 @@ algae_soup = friendship_recipe(Meal.algae_soup, NPC.clint, 3, {WaterItem.green_a artichoke_dip = queen_of_sauce_recipe(Meal.artichoke_dip, 1, Season.fall, 28, {Vegetable.artichoke: 1, AnimalProduct.cow_milk: 1}) autumn_bounty = friendship_recipe(Meal.autumn_bounty, NPC.demetrius, 7, {Vegetable.yam: 1, Vegetable.pumpkin: 1}) baked_fish = queen_of_sauce_recipe(Meal.baked_fish, 1, Season.summer, 7, {Fish.sunfish: 1, Fish.bream: 1, Ingredient.wheat_flour: 1}) -banana_pudding = shop_trade_recipe(Meal.banana_pudding, Region.island_trader, Fossil.bone_fragment, 30, {Fruit.banana: 1, AnimalProduct.cow_milk: 1, Ingredient.sugar: 1}) +banana_pudding = shop_trade_recipe(Meal.banana_pudding, Region.island_trader, Fossil.bone_fragment, 30, + {Fruit.banana: 1, AnimalProduct.cow_milk: 1, Ingredient.sugar: 1}) bean_hotpot = friendship_recipe(Meal.bean_hotpot, NPC.clint, 7, {Vegetable.green_bean: 2}) blackberry_cobbler_ingredients = {Forageable.blackberry: 2, Ingredient.sugar: 1, Ingredient.wheat_flour: 1} blackberry_cobbler_qos = queen_of_sauce_recipe(Meal.blackberry_cobbler, 2, Season.fall, 14, blackberry_cobbler_ingredients) @@ -181,21 +184,23 @@ vegetable_medley = friendship_recipe(Meal.vegetable_medley, NPC.caroline, 7, {Ve magic_elixir = shop_recipe(ModEdible.magic_elixir, Region.adventurer_guild, 3000, {Edible.life_elixir: 1, Mushroom.purple: 1}, ModNames.magic) baked_berry_oatmeal = shop_recipe(SVEMeal.baked_berry_oatmeal, SVERegion.bear_shop, 0, {Forageable.salmonberry: 15, Forageable.blackberry: 15, - Ingredient.sugar: 1, Ingredient.wheat_flour: 2}, ModNames.sve) + Ingredient.sugar: 1, Ingredient.wheat_flour: 2}, ModNames.sve) big_bark_burger = friendship_and_shop_recipe(SVEMeal.big_bark_burger, NPC.gus, 5, Region.saloon, 5500, {SVEFish.puppyfish: 1, Meal.bread: 1, Ingredient.oil: 1}, ModNames.sve) flower_cookie = shop_recipe(SVEMeal.flower_cookie, SVERegion.bear_shop, 0, {SVEForage.ferngill_primrose: 1, SVEForage.goldenrod: 1, - SVEForage.winter_star_rose: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, - AnimalProduct.large_egg: 1}, ModNames.sve) + SVEForage.winter_star_rose: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, + AnimalProduct.large_egg: 1}, ModNames.sve) frog_legs = shop_recipe(SVEMeal.frog_legs, Region.adventurer_guild, 2000, {SVEFish.frog: 1, Ingredient.oil: 1, Ingredient.wheat_flour: 1}, ModNames.sve) glazed_butterfish = friendship_and_shop_recipe(SVEMeal.glazed_butterfish, NPC.gus, 10, Region.saloon, 4000, {SVEFish.butterfish: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}, ModNames.sve) mixed_berry_pie = shop_recipe(SVEMeal.mixed_berry_pie, Region.saloon, 3500, {Fruit.strawberry: 6, SVEFruit.salal_berry: 6, Forageable.blackberry: 6, SVEForage.bearberry: 6, Ingredient.sugar: 1, Ingredient.wheat_flour: 1}, ModNames.sve) -mushroom_berry_rice = friendship_and_shop_recipe(SVEMeal.mushroom_berry_rice, ModNPC.marlon, 6, Region.adventurer_guild, 1500, {SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10, - Ingredient.rice: 1, Ingredient.sugar: 2}, ModNames.sve) -seaweed_salad = shop_recipe(SVEMeal.seaweed_salad, Region.fish_shop, 1250, {SVEWaterItem.dulse_seaweed: 2, WaterItem.seaweed: 2, Ingredient.oil: 1}, ModNames.sve) +mushroom_berry_rice = friendship_and_shop_recipe(SVEMeal.mushroom_berry_rice, ModNPC.marlon, 6, Region.adventurer_guild, 1500, + {SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10, Ingredient.rice: 1, Ingredient.sugar: 2}, + ModNames.sve) +seaweed_salad = shop_recipe(SVEMeal.seaweed_salad, Region.fish_shop, 1250, {SVEWaterItem.dulse_seaweed: 2, WaterItem.seaweed: 2, Ingredient.oil: 1}, + ModNames.sve) void_delight = friendship_and_shop_recipe(SVEMeal.void_delight, NPC.krobus, 10, Region.sewer, 5000, {SVEFish.void_eel: 1, Loot.void_essence: 50, Loot.solar_essence: 20}, ModNames.sve) void_salmon_sushi = friendship_and_shop_recipe(SVEMeal.void_salmon_sushi, NPC.krobus, 10, Region.sewer, 5000, @@ -205,17 +210,22 @@ mushroom_kebab = friendship_recipe(DistantLandsMeal.mushroom_kebab, ModNPC.gobli Mushroom.red: 1, Material.wood: 1}, ModNames.distant_lands) void_mint_tea = friendship_recipe(DistantLandsMeal.void_mint_tea, ModNPC.goblin, 4, {DistantLandsCrop.void_mint: 1}, ModNames.distant_lands) crayfish_soup = friendship_recipe(DistantLandsMeal.crayfish_soup, ModNPC.goblin, 6, {Forageable.cave_carrot: 1, Fish.crayfish: 1, - DistantLandsFish.purple_algae: 1, WaterItem.white_algae: 1}, ModNames.distant_lands) + DistantLandsFish.purple_algae: 1, WaterItem.white_algae: 1}, + ModNames.distant_lands) pemmican = friendship_recipe(DistantLandsMeal.pemmican, ModNPC.goblin, 8, {Loot.bug_meat: 1, Fish.any: 1, Forageable.salmonberry: 3, Material.stone: 2}, ModNames.distant_lands) special_pumpkin_soup = friendship_recipe(BoardingHouseMeal.special_pumpkin_soup, ModNPC.joel, 6, {Vegetable.pumpkin: 2, AnimalProduct.large_goat_milk: 1, Vegetable.garlic: 1}, ModNames.boarding_house) -diggers_delight = skill_recipe(ArchaeologyMeal.diggers_delight, ModSkill.archaeology, 3, {Forageable.cave_carrot: 2, Ingredient.sugar: 1, AnimalProduct.milk: 1}, ModNames.archaeology) -rocky_root = skill_recipe(ArchaeologyMeal.rocky_root, ModSkill.archaeology, 7, {Forageable.cave_carrot: 3, Seed.coffee: 1, Material.stone: 1}, ModNames.archaeology) -ancient_jello = skill_recipe(ArchaeologyMeal.ancient_jello, ModSkill.archaeology, 9, {WaterItem.cave_jelly: 6, Ingredient.sugar: 5, AnimalProduct.egg: 1, AnimalProduct.milk: 1, Artifact.chipped_amphora: 1}, ModNames.archaeology) +diggers_delight = skill_recipe(ArchaeologyMeal.diggers_delight, ModSkill.archaeology, 3, + {Forageable.cave_carrot: 2, Ingredient.sugar: 1, AnimalProduct.milk: 1}, ModNames.archaeology) +rocky_root = skill_recipe(ArchaeologyMeal.rocky_root, ModSkill.archaeology, 7, {Forageable.cave_carrot: 3, Seed.coffee: 1, Material.stone: 1}, + ModNames.archaeology) +ancient_jello = skill_recipe(ArchaeologyMeal.ancient_jello, ModSkill.archaeology, 9, + {WaterItem.cave_jelly: 6, Ingredient.sugar: 5, AnimalProduct.egg: 1, AnimalProduct.milk: 1, Artifact.chipped_amphora: 1}, + ModNames.archaeology) grilled_cheese = skill_recipe(TrashyMeal.grilled_cheese, ModSkill.binning, 1, {Meal.bread: 1, ArtisanGood.cheese: 1}, ModNames.binning_skill) fish_casserole = skill_recipe(TrashyMeal.fish_casserole, ModSkill.binning, 8, {Fish.any: 1, AnimalProduct.milk: 1, Vegetable.carrot: 1}, ModNames.binning_skill) -all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} \ No newline at end of file +all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py index ead4d62f16..bc8c09ee92 100644 --- a/worlds/stardew_valley/data/recipe_source.py +++ b/worlds/stardew_valley/data/recipe_source.py @@ -106,7 +106,7 @@ class MasterySource(RecipeSource): self.skill = skill def __repr__(self): - return f"MasterySource at level {self.level} {self.skill}" + return f"MasterySource {self.skill}" class ShopSource(RecipeSource): diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index b3a8db6f03..02c8a5441c 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -110,6 +110,8 @@ class LocationTags(enum.Enum): MAGIC_LEVEL = enum.auto() ARCHAEOLOGY_LEVEL = enum.auto() + DEPRECATED = enum.auto() + @dataclass(frozen=True) class LocationData: @@ -519,6 +521,10 @@ def create_locations(location_collector: StardewLocationCollector, location_collector(location_data.name, location_data.code, location_data.region) +def filter_deprecated_locations(locations: Iterable[LocationData]) -> Iterable[LocationData]: + return [location for location in locations if LocationTags.DEPRECATED not in location.tags] + + def filter_farm_type(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]: # On Meadowlands, "Feeding Animals" replaces "Raising Animals" if options.farm_type == FarmType.option_meadowlands: @@ -549,7 +555,8 @@ def filter_modded_locations(options: StardewValleyOptions, locations: Iterable[L def filter_disabled_locations(options: StardewValleyOptions, content: StardewContent, locations: Iterable[LocationData]) -> Iterable[LocationData]: - locations_farm_filter = filter_farm_type(options, locations) + locations_deprecated_filter = filter_deprecated_locations(locations) + locations_farm_filter = filter_farm_type(options, locations_deprecated_filter) locations_island_filter = filter_ginger_island(options, locations_farm_filter) locations_qi_filter = filter_qi_order_locations(options, locations_island_filter) locations_masteries_filter = filter_masteries_locations(content, locations_qi_filter) diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index add99a2c2e..2038d995a7 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -1,7 +1,7 @@ +import typing from typing import Union from .base_logic import BaseLogicMixin, BaseLogic -from .cooking_logic import CookingLogicMixin from .mine_logic import MineLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin @@ -13,6 +13,11 @@ from ..strings.region_names import Region from ..strings.skill_names import Skill, ModSkill from ..strings.tool_names import ToolMaterial, Tool +if typing.TYPE_CHECKING: + from ..mods.logic.mod_logic import ModLogicMixin +else: + ModLogicMixin = object + class AbilityLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): @@ -20,7 +25,8 @@ class AbilityLogicMixin(BaseLogicMixin): self.ability = AbilityLogic(*args, **kwargs) -class AbilityLogic(BaseLogic[Union[AbilityLogicMixin, RegionLogicMixin, ReceivedLogicMixin, ToolLogicMixin, SkillLogicMixin, MineLogicMixin, MagicLogicMixin]]): +class AbilityLogic(BaseLogic[Union[AbilityLogicMixin, RegionLogicMixin, ReceivedLogicMixin, ToolLogicMixin, SkillLogicMixin, MineLogicMixin, MagicLogicMixin, +ModLogicMixin]]): def can_mine_perfectly(self) -> StardewRule: return self.logic.mine.can_progress_in_the_mines_from_floor(160) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index dc5deda427..5b117de68c 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -6,7 +6,6 @@ from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .tool_logic import ToolLogicMixin -from ..options import ToolProgression from ..stardew_rule import StardewRule, True_ from ..strings.generic_names import Generic from ..strings.geode_names import Geode diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index 88523bb85d..cb8a55e6b4 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -10,17 +10,16 @@ from .season_logic import SeasonLogicMixin from .tool_logic import ToolLogicMixin from .. import options from ..stardew_rule import StardewRule, True_, false_ -from ..strings.ap_names.event_names import Event from ..strings.fertilizer_names import Fertilizer -from ..strings.region_names import Region +from ..strings.region_names import Region, LogicRegion from ..strings.season_names import Season from ..strings.tool_names import Tool -farming_event_by_season = { - Season.spring: Event.spring_farming, - Season.summer: Event.summer_farming, - Season.fall: Event.fall_farming, - Season.winter: Event.winter_farming, +farming_region_by_season = { + Season.spring: LogicRegion.spring_farming, + Season.summer: LogicRegion.summer_farming, + Season.fall: LogicRegion.fall_farming, + Season.winter: LogicRegion.winter_farming, } @@ -54,7 +53,7 @@ class FarmingLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogi if isinstance(seasons, str): seasons = (seasons,) - return self.logic.or_(*(self.logic.received(farming_event_by_season[season]) for season in seasons)) + return self.logic.or_(*(self.logic.region.can_reach(farming_region_by_season[season]) for season in seasons)) def has_island_farm(self) -> StardewRule: if self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_false: diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index bc2f6cb126..6d0cd11baf 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -1,3 +1,4 @@ +import typing from functools import cached_property from typing import Union, Tuple @@ -24,6 +25,11 @@ from ..strings.skill_names import Skill, all_mod_skills, all_vanilla_skills from ..strings.tool_names import ToolMaterial, Tool from ..strings.wallet_item_names import Wallet +if typing.TYPE_CHECKING: + from ..mods.logic.mod_logic import ModLogicMixin +else: + ModLogicMixin = object + fishing_regions = (Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west) vanilla_skill_items = ("Farming Level", "Mining Level", "Foraging Level", "Fishing Level", "Combat Level") @@ -35,7 +41,7 @@ class SkillLogicMixin(BaseLogicMixin): class SkillLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, ToolLogicMixin, SkillLogicMixin, -CombatLogicMixin, MagicLogicMixin, HarvestingLogicMixin]]): +CombatLogicMixin, MagicLogicMixin, HarvestingLogicMixin, ModLogicMixin]]): # Should be cached def can_earn_level(self, skill: str, level: int) -> StardewRule: diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index ef5eab0134..12e824d212 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -2,7 +2,6 @@ from typing import Dict, Union from ..mod_data import ModNames from ... import options -from ...data.craftable_data import all_crafting_recipes_by_name from ...logic.base_logic import BaseLogicMixin, BaseLogic from ...logic.combat_logic import CombatLogicMixin from ...logic.cooking_logic import CookingLogicMixin @@ -20,11 +19,9 @@ from ...logic.season_logic import SeasonLogicMixin from ...logic.skill_logic import SkillLogicMixin from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin -from ...options import Cropsanity -from ...stardew_rule import StardewRule, True_ +from ...stardew_rule import StardewRule from ...strings.artisan_good_names import ModArtisanGood -from ...strings.craftable_names import ModCraftable, ModMachine -from ...strings.fish_names import ModTrash +from ...strings.craftable_names import ModCraftable from ...strings.ingredient_names import Ingredient from ...strings.material_names import Material from ...strings.metal_names import all_fossils, all_artifacts, Ore, ModFossil diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 1aa71404ae..2ff7452394 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -3,8 +3,8 @@ from typing import Dict, Union from ..mod_data import ModNames from ...logic.base_logic import BaseLogic, BaseLogicMixin from ...logic.has_logic import HasLogicMixin -from ...logic.quest_logic import QuestLogicMixin from ...logic.monster_logic import MonsterLogicMixin +from ...logic.quest_logic import QuestLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin @@ -16,7 +16,6 @@ from ...strings.artisan_good_names import ArtisanGood from ...strings.crop_names import Fruit, SVEFruit, SVEVegetable, Vegetable from ...strings.fertilizer_names import Fertilizer from ...strings.food_names import Meal, Beverage -from ...strings.forageable_names import SVEForage from ...strings.material_names import Material from ...strings.metal_names import Ore, MetalBar from ...strings.monster_drop_names import Loot, ModLoot @@ -35,7 +34,7 @@ class ModQuestLogicMixin(BaseLogicMixin): class ModQuestLogic(BaseLogic[Union[HasLogicMixin, QuestLogicMixin, ReceivedLogicMixin, RegionLogicMixin, - TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MonsterLogicMixin]]): +TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MonsterLogicMixin]]): def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests = dict() quests.update(self._get_juna_quest_rules()) diff --git a/worlds/stardew_valley/options/options.py b/worlds/stardew_valley/options/options.py index db94971883..aaeeedd1b3 100644 --- a/worlds/stardew_valley/options/options.py +++ b/worlds/stardew_valley/options/options.py @@ -66,7 +66,8 @@ class Goal(Choice): class FarmType(Choice): - """What farm to play on?""" + """What farm to play on? + Custom farms are not supported""" internal_name = "farm_type" display_name = "Farm Type" default = "random" @@ -203,7 +204,7 @@ class SeasonRandomization(Choice): class Cropsanity(Choice): - """Formerly named "Seed Shuffle" + """ Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops Enabled: Seeds are unlocked as archipelago items, for each seed there is a location check for growing and harvesting that crop @@ -233,9 +234,9 @@ class BackpackProgression(Choice): class ToolProgression(Choice): """Shuffle the tool upgrades? Vanilla: Clint will upgrade your tools with metal bars. - Progressive: You will randomly find Progressive Tool upgrades. - Cheap: Tool Upgrades will cost 2/5th as much - Very Cheap: Tool Upgrades will cost 1/5th as much""" + Progressive: Your tools upgrades are randomized. + Cheap: Tool Upgrades have a 60% discount + Very Cheap: Tool Upgrades have an 80% discount""" internal_name = "tool_progression" display_name = "Tool Progression" default = 1 @@ -279,8 +280,8 @@ class BuildingProgression(Choice): Vanilla: You can buy each building normally. Progressive: You will receive the buildings and will be able to build the first one of each type for free, once it is received. If you want more of the same building, it will cost the vanilla price. - Cheap: Buildings will cost half as much - Very Cheap: Buildings will cost 1/5th as much + Cheap: Buildings will have a 50% discount + Very Cheap: Buildings will an 80% discount """ internal_name = "building_progression" display_name = "Building Progression" @@ -327,7 +328,7 @@ class ArcadeMachineLocations(Choice): class SpecialOrderLocations(Choice): """Shuffle Special Orders? - Disabled: The special orders are not included in the Archipelago shuffling. + Vanilla: The special orders are not included in the Archipelago shuffling. You may need to complete some of them anyway for their vanilla rewards Board Only: The Special Orders on the board in town are location checks Board and Qi: The Special Orders from Mr Qi's walnut room are checks, in addition to the board in town Short: All Special Order requirements are reduced by 40% @@ -377,12 +378,12 @@ class QuestLocations(NamedRange): class Fishsanity(Choice): - """Locations for catching a fish the first time? + """Locations for catching each fish the first time? None: There are no locations for catching fish Legendaries: Each of the 5 legendary fish are checks, plus the extended family if qi board is turned on Special: A curated selection of strong fish are checks Randomized: A random selection of fish are checks - All: Every single fish in the game is a location that contains an item. Pairs well with the Master Angler Goal + All: Every single fish in the game is a location that contains an item. Exclude Legendaries: Every fish except legendaries Exclude Hard Fish: Every fish under difficulty 80 Only Easy Fish: Every fish under difficulty 50 @@ -517,7 +518,7 @@ class Chefsanity(NamedRange): class Craftsanity(Choice): """Checks for crafting items? If enabled, all recipes purchased in shops will be checks as well. - Recipes obtained from other sources will depend on related archipelago settings + Recipes obtained from other sources will depend on their respective archipelago settings """ internal_name = "craftsanity" display_name = "Craftsanity" @@ -530,9 +531,9 @@ class Friendsanity(Choice): """Shuffle Friendships? None: Friendship hearts are earned normally Bachelors: Hearts with bachelors are shuffled - Starting NPCs: Hearts for NPCs available immediately are checks - All: Hearts for all npcs are checks, including Leo, Kent, Sandy, etc - All With Marriage: Hearts for all npcs are checks, including romance hearts up to 14 when applicable + Starting NPCs: Hearts for NPCs available immediately are shuffled + All: Hearts for all npcs are shuffled, including Leo, Kent, Sandy, etc + All With Marriage: All hearts for all npcs are shuffled, including romance hearts up to 14 when applicable """ internal_name = "friendsanity" display_name = "Friendsanity" @@ -577,7 +578,7 @@ class Walnutsanity(OptionSet): """Shuffle walnuts? Puzzles: Walnuts obtained from solving a special puzzle or winning a minigame Bushes: Walnuts that are in a bush and can be collected by clicking it - Dig spots: Walnuts that are underground and must be digged up. Includes Journal scrap walnuts + Dig Spots: Walnuts that are underground and must be digged up. Includes Journal scrap walnuts Repeatables: Random chance walnuts from normal actions (fishing, farming, combat, etc) """ internal_name = "walnutsanity" @@ -612,7 +613,7 @@ class NumberOfMovementBuffs(Range): class EnabledFillerBuffs(OptionSet): """Enable various permanent player buffs to roll as filler items - Luck: Increase daily luck + Luck: Increased daily luck Damage: Increased Damage % Defense: Increased Defense Immunity: Increased Immunity @@ -637,7 +638,7 @@ class EnabledFillerBuffs(OptionSet): class ExcludeGingerIsland(Toggle): """Exclude Ginger Island? This option will forcefully exclude everything related to Ginger Island from the slot. - If you pick a goal that requires Ginger Island, you cannot exclude it and it will get included anyway""" + If you pick a goal that requires Ginger Island, this option will get forced to 'false'""" internal_name = "exclude_ginger_island" display_name = "Exclude Ginger Island" default = 0 @@ -757,6 +758,14 @@ class Gifting(Toggle): default = 1 +all_mods = {ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, + ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology, + ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, + ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, + ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, + ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.distant_lands, + ModNames.alecto, ModNames.lacey, ModNames.boarding_house} + # These mods have been disabled because either they are not updated for the current supported version of Stardew Valley, # or we didn't find the time to validate that they work or fix compatibility issues if they do. # Once a mod is validated to be functional, it can simply be removed from this list @@ -766,8 +775,7 @@ disabled_mods = {ModNames.deepwoods, ModNames.magic, ModNames.wellwick, ModNames.shiko, ModNames.delores, ModNames.riley, ModNames.boarding_house} -if 'unittest' in sys.modules.keys() or 'pytest' in sys.modules.keys(): - disabled_mods = {} +enabled_mods = all_mods.difference(disabled_mods) class Mods(OptionSet): @@ -775,13 +783,11 @@ class Mods(OptionSet): visibility = Visibility.all & ~Visibility.simple_ui internal_name = "mods" display_name = "Mods" - valid_keys = {ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, - ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology, - ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, - ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, - ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, - ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.distant_lands, - ModNames.alecto, ModNames.lacey, ModNames.boarding_house}.difference(disabled_mods) + valid_keys = enabled_mods + # In tests, we keep even the disabled mods active, because we expect some of them to eventually get updated for SV 1.6 + # In that case, we want to maintain content and logic for them, and therefore keep testing them + if 'unittest' in sys.modules.keys() or 'pytest' in sys.modules.keys(): + valid_keys = all_mods class BundlePlando(OptionSet): diff --git a/worlds/stardew_valley/options/presets.py b/worlds/stardew_valley/options/presets.py index c2c210e5ca..3dbb5ab3f5 100644 --- a/worlds/stardew_valley/options/presets.py +++ b/worlds/stardew_valley/options/presets.py @@ -122,7 +122,7 @@ medium_settings = { options.Friendsanity.internal_name: options.Friendsanity.option_starting_npcs, options.FriendsanityHeartSize.internal_name: 4, options.Booksanity.internal_name: options.Booksanity.option_power_skill, - options.Walnutsanity.internal_name: [WalnutsanityOptionName.puzzles], + options.Walnutsanity.internal_name: options.Walnutsanity.preset_none, options.NumberOfMovementBuffs.internal_name: 6, options.EnabledFillerBuffs.internal_name: options.EnabledFillerBuffs.preset_all, options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index d59439a487..7a680d5faa 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -7,7 +7,7 @@ from .mods.mod_regions import ModDataList, vanilla_connections_to_remove_by_mod from .options import EntranceRandomization, ExcludeGingerIsland, StardewValleyOptions from .region_classes import RegionData, ConnectionData, RandomizationFlag, ModificationFlag from .strings.entrance_names import Entrance, LogicEntrance -from .strings.region_names import Region, LogicRegion +from .strings.region_names import Region as RegionName, LogicRegion class RegionFactory(Protocol): @@ -16,192 +16,192 @@ class RegionFactory(Protocol): vanilla_regions = [ - RegionData(Region.menu, [Entrance.to_stardew_valley]), - RegionData(Region.stardew_valley, [Entrance.to_farmhouse]), - RegionData(Region.farm_house, + RegionData(RegionName.menu, [Entrance.to_stardew_valley]), + RegionData(RegionName.stardew_valley, [Entrance.to_farmhouse]), + RegionData(RegionName.farm_house, [Entrance.farmhouse_to_farm, Entrance.downstairs_to_cellar, LogicEntrance.farmhouse_cooking, LogicEntrance.watch_queen_of_sauce]), - RegionData(Region.cellar), - RegionData(Region.farm, + RegionData(RegionName.cellar), + RegionData(RegionName.farm, [Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse, Entrance.enter_coop, Entrance.enter_barn, Entrance.enter_shed, Entrance.enter_slime_hutch, LogicEntrance.grow_spring_crops, LogicEntrance.grow_summer_crops, LogicEntrance.grow_fall_crops, LogicEntrance.grow_winter_crops, LogicEntrance.shipping]), - RegionData(Region.backwoods, [Entrance.backwoods_to_mountain]), - RegionData(Region.bus_stop, + RegionData(RegionName.backwoods, [Entrance.backwoods_to_mountain]), + RegionData(RegionName.bus_stop, [Entrance.bus_stop_to_town, Entrance.take_bus_to_desert, Entrance.bus_stop_to_tunnel_entrance]), - RegionData(Region.forest, + RegionData(RegionName.forest, [Entrance.forest_to_town, Entrance.enter_secret_woods, Entrance.forest_to_wizard_tower, Entrance.forest_to_marnie_ranch, Entrance.forest_to_leah_cottage, Entrance.forest_to_sewer, Entrance.forest_to_mastery_cave, LogicEntrance.buy_from_traveling_merchant, LogicEntrance.complete_raccoon_requests, LogicEntrance.fish_in_waterfall, LogicEntrance.attend_flower_dance, LogicEntrance.attend_trout_derby, LogicEntrance.attend_festival_of_ice]), RegionData(LogicRegion.forest_waterfall), - RegionData(Region.farm_cave), - RegionData(Region.greenhouse, + RegionData(RegionName.farm_cave), + RegionData(RegionName.greenhouse, [LogicEntrance.grow_spring_crops_in_greenhouse, LogicEntrance.grow_summer_crops_in_greenhouse, LogicEntrance.grow_fall_crops_in_greenhouse, LogicEntrance.grow_winter_crops_in_greenhouse, LogicEntrance.grow_indoor_crops_in_greenhouse]), - RegionData(Region.mountain, + RegionData(RegionName.mountain, [Entrance.mountain_to_railroad, Entrance.mountain_to_tent, Entrance.mountain_to_carpenter_shop, Entrance.mountain_to_the_mines, Entrance.enter_quarry, Entrance.mountain_to_adventurer_guild, Entrance.mountain_to_town, Entrance.mountain_to_maru_room, Entrance.mountain_to_leo_treehouse]), - RegionData(Region.leo_treehouse, is_ginger_island=True), - RegionData(Region.maru_room), - RegionData(Region.tunnel_entrance, [Entrance.tunnel_entrance_to_bus_tunnel]), - RegionData(Region.bus_tunnel), - RegionData(Region.town, + RegionData(RegionName.leo_treehouse, is_ginger_island=True), + RegionData(RegionName.maru_room), + RegionData(RegionName.tunnel_entrance, [Entrance.tunnel_entrance_to_bus_tunnel]), + RegionData(RegionName.bus_tunnel), + RegionData(RegionName.town, [Entrance.town_to_community_center, Entrance.town_to_beach, Entrance.town_to_hospital, Entrance.town_to_pierre_general_store, Entrance.town_to_saloon, Entrance.town_to_alex_house, Entrance.town_to_trailer, Entrance.town_to_mayor_manor, Entrance.town_to_sam_house, Entrance.town_to_haley_house, Entrance.town_to_sewer, Entrance.town_to_clint_blacksmith, Entrance.town_to_museum, Entrance.town_to_jojamart, Entrance.purchase_movie_ticket, LogicEntrance.buy_experience_books, LogicEntrance.attend_egg_festival, LogicEntrance.attend_fair, LogicEntrance.attend_spirit_eve, LogicEntrance.attend_winter_star]), - RegionData(Region.beach, + RegionData(RegionName.beach, [Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, LogicEntrance.fishing, LogicEntrance.attend_luau, LogicEntrance.attend_moonlight_jellies, LogicEntrance.attend_night_market, LogicEntrance.attend_squidfest]), - RegionData(Region.railroad, [Entrance.enter_bathhouse_entrance, Entrance.enter_witch_warp_cave]), - RegionData(Region.ranch), - RegionData(Region.leah_house), - RegionData(Region.mastery_cave), - RegionData(Region.sewer, [Entrance.enter_mutant_bug_lair]), - RegionData(Region.mutant_bug_lair), - RegionData(Region.wizard_tower, [Entrance.enter_wizard_basement, Entrance.use_desert_obelisk, Entrance.use_island_obelisk]), - RegionData(Region.wizard_basement), - RegionData(Region.tent), - RegionData(Region.carpenter, [Entrance.enter_sebastian_room]), - RegionData(Region.sebastian_room), - RegionData(Region.adventurer_guild, [Entrance.adventurer_guild_to_bedroom]), - RegionData(Region.adventurer_guild_bedroom), - RegionData(Region.community_center, + RegionData(RegionName.railroad, [Entrance.enter_bathhouse_entrance, Entrance.enter_witch_warp_cave]), + RegionData(RegionName.ranch), + RegionData(RegionName.leah_house), + RegionData(RegionName.mastery_cave), + RegionData(RegionName.sewer, [Entrance.enter_mutant_bug_lair]), + RegionData(RegionName.mutant_bug_lair), + RegionData(RegionName.wizard_tower, [Entrance.enter_wizard_basement, Entrance.use_desert_obelisk, Entrance.use_island_obelisk]), + RegionData(RegionName.wizard_basement), + RegionData(RegionName.tent), + RegionData(RegionName.carpenter, [Entrance.enter_sebastian_room]), + RegionData(RegionName.sebastian_room), + RegionData(RegionName.adventurer_guild, [Entrance.adventurer_guild_to_bedroom]), + RegionData(RegionName.adventurer_guild_bedroom), + RegionData(RegionName.community_center, [Entrance.access_crafts_room, Entrance.access_pantry, Entrance.access_fish_tank, Entrance.access_boiler_room, Entrance.access_bulletin_board, Entrance.access_vault]), - RegionData(Region.crafts_room), - RegionData(Region.pantry), - RegionData(Region.fish_tank), - RegionData(Region.boiler_room), - RegionData(Region.bulletin_board), - RegionData(Region.vault), - RegionData(Region.hospital, [Entrance.enter_harvey_room]), - RegionData(Region.harvey_room), - RegionData(Region.pierre_store, [Entrance.enter_sunroom]), - RegionData(Region.sunroom), - RegionData(Region.saloon, [Entrance.play_journey_of_the_prairie_king, Entrance.play_junimo_kart]), - RegionData(Region.jotpk_world_1, [Entrance.reach_jotpk_world_2]), - RegionData(Region.jotpk_world_2, [Entrance.reach_jotpk_world_3]), - RegionData(Region.jotpk_world_3), - RegionData(Region.junimo_kart_1, [Entrance.reach_junimo_kart_2]), - RegionData(Region.junimo_kart_2, [Entrance.reach_junimo_kart_3]), - RegionData(Region.junimo_kart_3, [Entrance.reach_junimo_kart_4]), - RegionData(Region.junimo_kart_4), - RegionData(Region.alex_house), - RegionData(Region.trailer), - RegionData(Region.mayor_house), - RegionData(Region.sam_house), - RegionData(Region.haley_house), - RegionData(Region.blacksmith, [LogicEntrance.blacksmith_copper]), - RegionData(Region.museum), - RegionData(Region.jojamart, [Entrance.enter_abandoned_jojamart]), - RegionData(Region.abandoned_jojamart, [Entrance.enter_movie_theater]), - RegionData(Region.movie_ticket_stand), - RegionData(Region.movie_theater), - RegionData(Region.fish_shop, [Entrance.fish_shop_to_boat_tunnel]), - RegionData(Region.boat_tunnel, [Entrance.boat_to_ginger_island], is_ginger_island=True), - RegionData(Region.elliott_house), - RegionData(Region.tide_pools), - RegionData(Region.bathhouse_entrance, [Entrance.enter_locker_room]), - RegionData(Region.locker_room, [Entrance.enter_public_bath]), - RegionData(Region.public_bath), - RegionData(Region.witch_warp_cave, [Entrance.enter_witch_swamp]), - RegionData(Region.witch_swamp, [Entrance.enter_witch_hut]), - RegionData(Region.witch_hut, [Entrance.witch_warp_to_wizard_basement]), - RegionData(Region.quarry, [Entrance.enter_quarry_mine_entrance]), - RegionData(Region.quarry_mine_entrance, [Entrance.enter_quarry_mine]), - RegionData(Region.quarry_mine), - RegionData(Region.secret_woods), - RegionData(Region.desert, [Entrance.enter_skull_cavern_entrance, Entrance.enter_oasis, LogicEntrance.attend_desert_festival]), - RegionData(Region.oasis, [Entrance.enter_casino]), - RegionData(Region.casino), - RegionData(Region.skull_cavern_entrance, [Entrance.enter_skull_cavern]), - RegionData(Region.skull_cavern, [Entrance.mine_to_skull_cavern_floor_25]), - RegionData(Region.skull_cavern_25, [Entrance.mine_to_skull_cavern_floor_50]), - RegionData(Region.skull_cavern_50, [Entrance.mine_to_skull_cavern_floor_75]), - RegionData(Region.skull_cavern_75, [Entrance.mine_to_skull_cavern_floor_100]), - RegionData(Region.skull_cavern_100, [Entrance.mine_to_skull_cavern_floor_125]), - RegionData(Region.skull_cavern_125, [Entrance.mine_to_skull_cavern_floor_150]), - RegionData(Region.skull_cavern_150, [Entrance.mine_to_skull_cavern_floor_175]), - RegionData(Region.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200]), - RegionData(Region.skull_cavern_200, [Entrance.enter_dangerous_skull_cavern]), - RegionData(Region.dangerous_skull_cavern, is_ginger_island=True), - RegionData(Region.island_south, + RegionData(RegionName.crafts_room), + RegionData(RegionName.pantry), + RegionData(RegionName.fish_tank), + RegionData(RegionName.boiler_room), + RegionData(RegionName.bulletin_board), + RegionData(RegionName.vault), + RegionData(RegionName.hospital, [Entrance.enter_harvey_room]), + RegionData(RegionName.harvey_room), + RegionData(RegionName.pierre_store, [Entrance.enter_sunroom]), + RegionData(RegionName.sunroom), + RegionData(RegionName.saloon, [Entrance.play_journey_of_the_prairie_king, Entrance.play_junimo_kart]), + RegionData(RegionName.jotpk_world_1, [Entrance.reach_jotpk_world_2]), + RegionData(RegionName.jotpk_world_2, [Entrance.reach_jotpk_world_3]), + RegionData(RegionName.jotpk_world_3), + RegionData(RegionName.junimo_kart_1, [Entrance.reach_junimo_kart_2]), + RegionData(RegionName.junimo_kart_2, [Entrance.reach_junimo_kart_3]), + RegionData(RegionName.junimo_kart_3, [Entrance.reach_junimo_kart_4]), + RegionData(RegionName.junimo_kart_4), + RegionData(RegionName.alex_house), + RegionData(RegionName.trailer), + RegionData(RegionName.mayor_house), + RegionData(RegionName.sam_house), + RegionData(RegionName.haley_house), + RegionData(RegionName.blacksmith, [LogicEntrance.blacksmith_copper]), + RegionData(RegionName.museum), + RegionData(RegionName.jojamart, [Entrance.enter_abandoned_jojamart]), + RegionData(RegionName.abandoned_jojamart, [Entrance.enter_movie_theater]), + RegionData(RegionName.movie_ticket_stand), + RegionData(RegionName.movie_theater), + RegionData(RegionName.fish_shop, [Entrance.fish_shop_to_boat_tunnel]), + RegionData(RegionName.boat_tunnel, [Entrance.boat_to_ginger_island], is_ginger_island=True), + RegionData(RegionName.elliott_house), + RegionData(RegionName.tide_pools), + RegionData(RegionName.bathhouse_entrance, [Entrance.enter_locker_room]), + RegionData(RegionName.locker_room, [Entrance.enter_public_bath]), + RegionData(RegionName.public_bath), + RegionData(RegionName.witch_warp_cave, [Entrance.enter_witch_swamp]), + RegionData(RegionName.witch_swamp, [Entrance.enter_witch_hut]), + RegionData(RegionName.witch_hut, [Entrance.witch_warp_to_wizard_basement]), + RegionData(RegionName.quarry, [Entrance.enter_quarry_mine_entrance]), + RegionData(RegionName.quarry_mine_entrance, [Entrance.enter_quarry_mine]), + RegionData(RegionName.quarry_mine), + RegionData(RegionName.secret_woods), + RegionData(RegionName.desert, [Entrance.enter_skull_cavern_entrance, Entrance.enter_oasis, LogicEntrance.attend_desert_festival]), + RegionData(RegionName.oasis, [Entrance.enter_casino]), + RegionData(RegionName.casino), + RegionData(RegionName.skull_cavern_entrance, [Entrance.enter_skull_cavern]), + RegionData(RegionName.skull_cavern, [Entrance.mine_to_skull_cavern_floor_25]), + RegionData(RegionName.skull_cavern_25, [Entrance.mine_to_skull_cavern_floor_50]), + RegionData(RegionName.skull_cavern_50, [Entrance.mine_to_skull_cavern_floor_75]), + RegionData(RegionName.skull_cavern_75, [Entrance.mine_to_skull_cavern_floor_100]), + RegionData(RegionName.skull_cavern_100, [Entrance.mine_to_skull_cavern_floor_125]), + RegionData(RegionName.skull_cavern_125, [Entrance.mine_to_skull_cavern_floor_150]), + RegionData(RegionName.skull_cavern_150, [Entrance.mine_to_skull_cavern_floor_175]), + RegionData(RegionName.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200]), + RegionData(RegionName.skull_cavern_200, [Entrance.enter_dangerous_skull_cavern]), + RegionData(RegionName.dangerous_skull_cavern, is_ginger_island=True), + RegionData(RegionName.island_south, [Entrance.island_south_to_west, Entrance.island_south_to_north, Entrance.island_south_to_east, Entrance.island_south_to_southeast, Entrance.use_island_resort, Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_docks_to_dig_site, Entrance.parrot_express_docks_to_jungle], is_ginger_island=True), - RegionData(Region.island_resort, is_ginger_island=True), - RegionData(Region.island_west, + RegionData(RegionName.island_resort, is_ginger_island=True), + RegionData(RegionName.island_west, [Entrance.island_west_to_islandfarmhouse, Entrance.island_west_to_gourmand_cave, Entrance.island_west_to_crystals_cave, Entrance.island_west_to_shipwreck, Entrance.island_west_to_qi_walnut_room, Entrance.use_farm_obelisk, Entrance.parrot_express_jungle_to_docks, Entrance.parrot_express_jungle_to_dig_site, Entrance.parrot_express_jungle_to_volcano, LogicEntrance.grow_spring_crops_on_island, LogicEntrance.grow_summer_crops_on_island, LogicEntrance.grow_fall_crops_on_island, LogicEntrance.grow_winter_crops_on_island, LogicEntrance.grow_indoor_crops_on_island], is_ginger_island=True), - RegionData(Region.island_east, [Entrance.island_east_to_leo_hut, Entrance.island_east_to_island_shrine], is_ginger_island=True), - RegionData(Region.island_shrine, is_ginger_island=True), - RegionData(Region.island_south_east, [Entrance.island_southeast_to_pirate_cove], is_ginger_island=True), - RegionData(Region.island_north, + RegionData(RegionName.island_east, [Entrance.island_east_to_leo_hut, Entrance.island_east_to_island_shrine], is_ginger_island=True), + RegionData(RegionName.island_shrine, is_ginger_island=True), + RegionData(RegionName.island_south_east, [Entrance.island_southeast_to_pirate_cove], is_ginger_island=True), + RegionData(RegionName.island_north, [Entrance.talk_to_island_trader, Entrance.island_north_to_field_office, Entrance.island_north_to_dig_site, Entrance.island_north_to_volcano, Entrance.parrot_express_volcano_to_dig_site, Entrance.parrot_express_volcano_to_jungle, Entrance.parrot_express_volcano_to_docks], is_ginger_island=True), - RegionData(Region.volcano, [Entrance.climb_to_volcano_5, Entrance.volcano_to_secret_beach], is_ginger_island=True), - RegionData(Region.volcano_secret_beach, is_ginger_island=True), - RegionData(Region.volcano_floor_5, [Entrance.talk_to_volcano_dwarf, Entrance.climb_to_volcano_10], is_ginger_island=True), - RegionData(Region.volcano_dwarf_shop, is_ginger_island=True), - RegionData(Region.volcano_floor_10, is_ginger_island=True), - RegionData(Region.island_trader, is_ginger_island=True), - RegionData(Region.island_farmhouse, [LogicEntrance.island_cooking], is_ginger_island=True), - RegionData(Region.gourmand_frog_cave, is_ginger_island=True), - RegionData(Region.colored_crystals_cave, is_ginger_island=True), - RegionData(Region.shipwreck, is_ginger_island=True), - RegionData(Region.qi_walnut_room, is_ginger_island=True), - RegionData(Region.leo_hut, is_ginger_island=True), - RegionData(Region.pirate_cove, is_ginger_island=True), - RegionData(Region.field_office, is_ginger_island=True), - RegionData(Region.dig_site, + RegionData(RegionName.volcano, [Entrance.climb_to_volcano_5, Entrance.volcano_to_secret_beach], is_ginger_island=True), + RegionData(RegionName.volcano_secret_beach, is_ginger_island=True), + RegionData(RegionName.volcano_floor_5, [Entrance.talk_to_volcano_dwarf, Entrance.climb_to_volcano_10], is_ginger_island=True), + RegionData(RegionName.volcano_dwarf_shop, is_ginger_island=True), + RegionData(RegionName.volcano_floor_10, is_ginger_island=True), + RegionData(RegionName.island_trader, is_ginger_island=True), + RegionData(RegionName.island_farmhouse, [LogicEntrance.island_cooking], is_ginger_island=True), + RegionData(RegionName.gourmand_frog_cave, is_ginger_island=True), + RegionData(RegionName.colored_crystals_cave, is_ginger_island=True), + RegionData(RegionName.shipwreck, is_ginger_island=True), + RegionData(RegionName.qi_walnut_room, is_ginger_island=True), + RegionData(RegionName.leo_hut, is_ginger_island=True), + RegionData(RegionName.pirate_cove, is_ginger_island=True), + RegionData(RegionName.field_office, is_ginger_island=True), + RegionData(RegionName.dig_site, [Entrance.dig_site_to_professor_snail_cave, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_dig_site_to_docks, Entrance.parrot_express_dig_site_to_jungle], is_ginger_island=True), - RegionData(Region.professor_snail_cave, is_ginger_island=True), - RegionData(Region.coop), - RegionData(Region.barn), - RegionData(Region.shed), - RegionData(Region.slime_hutch), + RegionData(RegionName.professor_snail_cave, is_ginger_island=True), + RegionData(RegionName.coop), + RegionData(RegionName.barn), + RegionData(RegionName.shed), + RegionData(RegionName.slime_hutch), - RegionData(Region.mines, [LogicEntrance.talk_to_mines_dwarf, - Entrance.dig_to_mines_floor_5]), - RegionData(Region.mines_floor_5, [Entrance.dig_to_mines_floor_10]), - RegionData(Region.mines_floor_10, [Entrance.dig_to_mines_floor_15]), - RegionData(Region.mines_floor_15, [Entrance.dig_to_mines_floor_20]), - RegionData(Region.mines_floor_20, [Entrance.dig_to_mines_floor_25]), - RegionData(Region.mines_floor_25, [Entrance.dig_to_mines_floor_30]), - RegionData(Region.mines_floor_30, [Entrance.dig_to_mines_floor_35]), - RegionData(Region.mines_floor_35, [Entrance.dig_to_mines_floor_40]), - RegionData(Region.mines_floor_40, [Entrance.dig_to_mines_floor_45]), - RegionData(Region.mines_floor_45, [Entrance.dig_to_mines_floor_50]), - RegionData(Region.mines_floor_50, [Entrance.dig_to_mines_floor_55]), - RegionData(Region.mines_floor_55, [Entrance.dig_to_mines_floor_60]), - RegionData(Region.mines_floor_60, [Entrance.dig_to_mines_floor_65]), - RegionData(Region.mines_floor_65, [Entrance.dig_to_mines_floor_70]), - RegionData(Region.mines_floor_70, [Entrance.dig_to_mines_floor_75]), - RegionData(Region.mines_floor_75, [Entrance.dig_to_mines_floor_80]), - RegionData(Region.mines_floor_80, [Entrance.dig_to_mines_floor_85]), - RegionData(Region.mines_floor_85, [Entrance.dig_to_mines_floor_90]), - RegionData(Region.mines_floor_90, [Entrance.dig_to_mines_floor_95]), - RegionData(Region.mines_floor_95, [Entrance.dig_to_mines_floor_100]), - RegionData(Region.mines_floor_100, [Entrance.dig_to_mines_floor_105]), - RegionData(Region.mines_floor_105, [Entrance.dig_to_mines_floor_110]), - RegionData(Region.mines_floor_110, [Entrance.dig_to_mines_floor_115]), - RegionData(Region.mines_floor_115, [Entrance.dig_to_mines_floor_120]), - RegionData(Region.mines_floor_120, [Entrance.dig_to_dangerous_mines_20, Entrance.dig_to_dangerous_mines_60, Entrance.dig_to_dangerous_mines_100]), - RegionData(Region.dangerous_mines_20, is_ginger_island=True), - RegionData(Region.dangerous_mines_60, is_ginger_island=True), - RegionData(Region.dangerous_mines_100, is_ginger_island=True), + RegionData(RegionName.mines, [LogicEntrance.talk_to_mines_dwarf, + Entrance.dig_to_mines_floor_5]), + RegionData(RegionName.mines_floor_5, [Entrance.dig_to_mines_floor_10]), + RegionData(RegionName.mines_floor_10, [Entrance.dig_to_mines_floor_15]), + RegionData(RegionName.mines_floor_15, [Entrance.dig_to_mines_floor_20]), + RegionData(RegionName.mines_floor_20, [Entrance.dig_to_mines_floor_25]), + RegionData(RegionName.mines_floor_25, [Entrance.dig_to_mines_floor_30]), + RegionData(RegionName.mines_floor_30, [Entrance.dig_to_mines_floor_35]), + RegionData(RegionName.mines_floor_35, [Entrance.dig_to_mines_floor_40]), + RegionData(RegionName.mines_floor_40, [Entrance.dig_to_mines_floor_45]), + RegionData(RegionName.mines_floor_45, [Entrance.dig_to_mines_floor_50]), + RegionData(RegionName.mines_floor_50, [Entrance.dig_to_mines_floor_55]), + RegionData(RegionName.mines_floor_55, [Entrance.dig_to_mines_floor_60]), + RegionData(RegionName.mines_floor_60, [Entrance.dig_to_mines_floor_65]), + RegionData(RegionName.mines_floor_65, [Entrance.dig_to_mines_floor_70]), + RegionData(RegionName.mines_floor_70, [Entrance.dig_to_mines_floor_75]), + RegionData(RegionName.mines_floor_75, [Entrance.dig_to_mines_floor_80]), + RegionData(RegionName.mines_floor_80, [Entrance.dig_to_mines_floor_85]), + RegionData(RegionName.mines_floor_85, [Entrance.dig_to_mines_floor_90]), + RegionData(RegionName.mines_floor_90, [Entrance.dig_to_mines_floor_95]), + RegionData(RegionName.mines_floor_95, [Entrance.dig_to_mines_floor_100]), + RegionData(RegionName.mines_floor_100, [Entrance.dig_to_mines_floor_105]), + RegionData(RegionName.mines_floor_105, [Entrance.dig_to_mines_floor_110]), + RegionData(RegionName.mines_floor_110, [Entrance.dig_to_mines_floor_115]), + RegionData(RegionName.mines_floor_115, [Entrance.dig_to_mines_floor_120]), + RegionData(RegionName.mines_floor_120, [Entrance.dig_to_dangerous_mines_20, Entrance.dig_to_dangerous_mines_60, Entrance.dig_to_dangerous_mines_100]), + RegionData(RegionName.dangerous_mines_20, is_ginger_island=True), + RegionData(RegionName.dangerous_mines_60, is_ginger_island=True), + RegionData(RegionName.dangerous_mines_100, is_ginger_island=True), RegionData(LogicRegion.mines_dwarf_shop), RegionData(LogicRegion.blacksmith_copper, [LogicEntrance.blacksmith_iron]), @@ -256,206 +256,207 @@ vanilla_regions = [ # Exists and where they lead vanilla_connections = [ - ConnectionData(Entrance.to_stardew_valley, Region.stardew_valley), - ConnectionData(Entrance.to_farmhouse, Region.farm_house), - ConnectionData(Entrance.farmhouse_to_farm, Region.farm), - ConnectionData(Entrance.downstairs_to_cellar, Region.cellar), - ConnectionData(Entrance.farm_to_backwoods, Region.backwoods), - ConnectionData(Entrance.farm_to_bus_stop, Region.bus_stop), - ConnectionData(Entrance.farm_to_forest, Region.forest), - ConnectionData(Entrance.farm_to_farmcave, Region.farm_cave, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(Entrance.enter_greenhouse, Region.greenhouse), - ConnectionData(Entrance.enter_coop, Region.coop), - ConnectionData(Entrance.enter_barn, Region.barn), - ConnectionData(Entrance.enter_shed, Region.shed), - ConnectionData(Entrance.enter_slime_hutch, Region.slime_hutch), - ConnectionData(Entrance.use_desert_obelisk, Region.desert), - ConnectionData(Entrance.use_island_obelisk, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.use_farm_obelisk, Region.farm), - ConnectionData(Entrance.backwoods_to_mountain, Region.mountain), - ConnectionData(Entrance.bus_stop_to_town, Region.town), - ConnectionData(Entrance.bus_stop_to_tunnel_entrance, Region.tunnel_entrance), - ConnectionData(Entrance.tunnel_entrance_to_bus_tunnel, Region.bus_tunnel, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(Entrance.take_bus_to_desert, Region.desert), - ConnectionData(Entrance.forest_to_town, Region.town), - ConnectionData(Entrance.forest_to_wizard_tower, Region.wizard_tower, + ConnectionData(Entrance.to_stardew_valley, RegionName.stardew_valley), + ConnectionData(Entrance.to_farmhouse, RegionName.farm_house), + ConnectionData(Entrance.farmhouse_to_farm, RegionName.farm), + ConnectionData(Entrance.downstairs_to_cellar, RegionName.cellar), + ConnectionData(Entrance.farm_to_backwoods, RegionName.backwoods), + ConnectionData(Entrance.farm_to_bus_stop, RegionName.bus_stop), + ConnectionData(Entrance.farm_to_forest, RegionName.forest), + ConnectionData(Entrance.farm_to_farmcave, RegionName.farm_cave, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(Entrance.enter_greenhouse, RegionName.greenhouse), + ConnectionData(Entrance.enter_coop, RegionName.coop), + ConnectionData(Entrance.enter_barn, RegionName.barn), + ConnectionData(Entrance.enter_shed, RegionName.shed), + ConnectionData(Entrance.enter_slime_hutch, RegionName.slime_hutch), + ConnectionData(Entrance.use_desert_obelisk, RegionName.desert), + ConnectionData(Entrance.use_island_obelisk, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.use_farm_obelisk, RegionName.farm), + ConnectionData(Entrance.backwoods_to_mountain, RegionName.mountain), + ConnectionData(Entrance.bus_stop_to_town, RegionName.town), + ConnectionData(Entrance.bus_stop_to_tunnel_entrance, RegionName.tunnel_entrance), + ConnectionData(Entrance.tunnel_entrance_to_bus_tunnel, RegionName.bus_tunnel, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(Entrance.take_bus_to_desert, RegionName.desert), + ConnectionData(Entrance.forest_to_town, RegionName.town), + ConnectionData(Entrance.forest_to_wizard_tower, RegionName.wizard_tower, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_wizard_basement, Region.wizard_basement, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.forest_to_marnie_ranch, Region.ranch, + ConnectionData(Entrance.enter_wizard_basement, RegionName.wizard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.forest_to_marnie_ranch, RegionName.ranch, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.forest_to_leah_cottage, Region.leah_house, + ConnectionData(Entrance.forest_to_leah_cottage, RegionName.leah_house, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_secret_woods, Region.secret_woods), - ConnectionData(Entrance.forest_to_sewer, Region.sewer, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.forest_to_mastery_cave, Region.mastery_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.MASTERIES), - ConnectionData(Entrance.town_to_sewer, Region.sewer, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.enter_mutant_bug_lair, Region.mutant_bug_lair, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.mountain_to_railroad, Region.railroad), - ConnectionData(Entrance.mountain_to_tent, Region.tent, + ConnectionData(Entrance.enter_secret_woods, RegionName.secret_woods), + ConnectionData(Entrance.forest_to_sewer, RegionName.sewer, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.forest_to_mastery_cave, RegionName.mastery_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.MASTERIES), + ConnectionData(Entrance.town_to_sewer, RegionName.sewer, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.enter_mutant_bug_lair, RegionName.mutant_bug_lair, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.mountain_to_railroad, RegionName.railroad), + ConnectionData(Entrance.mountain_to_tent, RegionName.tent, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.mountain_to_leo_treehouse, Region.leo_treehouse, + ConnectionData(Entrance.mountain_to_leo_treehouse, RegionName.leo_treehouse, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.mountain_to_carpenter_shop, Region.carpenter, + ConnectionData(Entrance.mountain_to_carpenter_shop, RegionName.carpenter, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.mountain_to_maru_room, Region.maru_room, + ConnectionData(Entrance.mountain_to_maru_room, RegionName.maru_room, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_sebastian_room, Region.sebastian_room, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.mountain_to_adventurer_guild, Region.adventurer_guild, + ConnectionData(Entrance.enter_sebastian_room, RegionName.sebastian_room, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.mountain_to_adventurer_guild, RegionName.adventurer_guild, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.adventurer_guild_to_bedroom, Region.adventurer_guild_bedroom), - ConnectionData(Entrance.enter_quarry, Region.quarry), - ConnectionData(Entrance.enter_quarry_mine_entrance, Region.quarry_mine_entrance, + ConnectionData(Entrance.adventurer_guild_to_bedroom, RegionName.adventurer_guild_bedroom), + ConnectionData(Entrance.enter_quarry, RegionName.quarry), + ConnectionData(Entrance.enter_quarry_mine_entrance, RegionName.quarry_mine_entrance, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.enter_quarry_mine, Region.quarry_mine), - ConnectionData(Entrance.mountain_to_town, Region.town), - ConnectionData(Entrance.town_to_community_center, Region.community_center, + ConnectionData(Entrance.enter_quarry_mine, RegionName.quarry_mine), + ConnectionData(Entrance.mountain_to_town, RegionName.town), + ConnectionData(Entrance.town_to_community_center, RegionName.community_center, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.access_crafts_room, Region.crafts_room), - ConnectionData(Entrance.access_pantry, Region.pantry), - ConnectionData(Entrance.access_fish_tank, Region.fish_tank), - ConnectionData(Entrance.access_boiler_room, Region.boiler_room), - ConnectionData(Entrance.access_bulletin_board, Region.bulletin_board), - ConnectionData(Entrance.access_vault, Region.vault), - ConnectionData(Entrance.town_to_hospital, Region.hospital, + ConnectionData(Entrance.access_crafts_room, RegionName.crafts_room), + ConnectionData(Entrance.access_pantry, RegionName.pantry), + ConnectionData(Entrance.access_fish_tank, RegionName.fish_tank), + ConnectionData(Entrance.access_boiler_room, RegionName.boiler_room), + ConnectionData(Entrance.access_bulletin_board, RegionName.bulletin_board), + ConnectionData(Entrance.access_vault, RegionName.vault), + ConnectionData(Entrance.town_to_hospital, RegionName.hospital, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_harvey_room, Region.harvey_room, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.town_to_pierre_general_store, Region.pierre_store, + ConnectionData(Entrance.enter_harvey_room, RegionName.harvey_room, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.town_to_pierre_general_store, RegionName.pierre_store, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_sunroom, Region.sunroom, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.town_to_clint_blacksmith, Region.blacksmith, + ConnectionData(Entrance.enter_sunroom, RegionName.sunroom, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.town_to_clint_blacksmith, RegionName.blacksmith, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.town_to_saloon, Region.saloon, + ConnectionData(Entrance.town_to_saloon, RegionName.saloon, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.play_journey_of_the_prairie_king, Region.jotpk_world_1), - ConnectionData(Entrance.reach_jotpk_world_2, Region.jotpk_world_2), - ConnectionData(Entrance.reach_jotpk_world_3, Region.jotpk_world_3), - ConnectionData(Entrance.play_junimo_kart, Region.junimo_kart_1), - ConnectionData(Entrance.reach_junimo_kart_2, Region.junimo_kart_2), - ConnectionData(Entrance.reach_junimo_kart_3, Region.junimo_kart_3), - ConnectionData(Entrance.reach_junimo_kart_4, Region.junimo_kart_4), - ConnectionData(Entrance.town_to_sam_house, Region.sam_house, + ConnectionData(Entrance.play_journey_of_the_prairie_king, RegionName.jotpk_world_1), + ConnectionData(Entrance.reach_jotpk_world_2, RegionName.jotpk_world_2), + ConnectionData(Entrance.reach_jotpk_world_3, RegionName.jotpk_world_3), + ConnectionData(Entrance.play_junimo_kart, RegionName.junimo_kart_1), + ConnectionData(Entrance.reach_junimo_kart_2, RegionName.junimo_kart_2), + ConnectionData(Entrance.reach_junimo_kart_3, RegionName.junimo_kart_3), + ConnectionData(Entrance.reach_junimo_kart_4, RegionName.junimo_kart_4), + ConnectionData(Entrance.town_to_sam_house, RegionName.sam_house, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.town_to_haley_house, Region.haley_house, + ConnectionData(Entrance.town_to_haley_house, RegionName.haley_house, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.town_to_mayor_manor, Region.mayor_house, + ConnectionData(Entrance.town_to_mayor_manor, RegionName.mayor_house, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.town_to_alex_house, Region.alex_house, + ConnectionData(Entrance.town_to_alex_house, RegionName.alex_house, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.town_to_trailer, Region.trailer, + ConnectionData(Entrance.town_to_trailer, RegionName.trailer, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.town_to_museum, Region.museum, + ConnectionData(Entrance.town_to_museum, RegionName.museum, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.town_to_jojamart, Region.jojamart, + ConnectionData(Entrance.town_to_jojamart, RegionName.jojamart, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.purchase_movie_ticket, Region.movie_ticket_stand), - ConnectionData(Entrance.enter_abandoned_jojamart, Region.abandoned_jojamart), - ConnectionData(Entrance.enter_movie_theater, Region.movie_theater), - ConnectionData(Entrance.town_to_beach, Region.beach), - ConnectionData(Entrance.enter_elliott_house, Region.elliott_house, + ConnectionData(Entrance.purchase_movie_ticket, RegionName.movie_ticket_stand), + ConnectionData(Entrance.enter_abandoned_jojamart, RegionName.abandoned_jojamart), + ConnectionData(Entrance.enter_movie_theater, RegionName.movie_theater), + ConnectionData(Entrance.town_to_beach, RegionName.beach), + ConnectionData(Entrance.enter_elliott_house, RegionName.elliott_house, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.beach_to_willy_fish_shop, Region.fish_shop, + ConnectionData(Entrance.beach_to_willy_fish_shop, RegionName.fish_shop, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.fish_shop_to_boat_tunnel, Region.boat_tunnel, + ConnectionData(Entrance.fish_shop_to_boat_tunnel, RegionName.boat_tunnel, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.boat_to_ginger_island, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.enter_tide_pools, Region.tide_pools), - ConnectionData(Entrance.mountain_to_the_mines, Region.mines, + ConnectionData(Entrance.boat_to_ginger_island, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.enter_tide_pools, RegionName.tide_pools), + ConnectionData(Entrance.mountain_to_the_mines, RegionName.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.dig_to_mines_floor_5, Region.mines_floor_5), - ConnectionData(Entrance.dig_to_mines_floor_10, Region.mines_floor_10), - ConnectionData(Entrance.dig_to_mines_floor_15, Region.mines_floor_15), - ConnectionData(Entrance.dig_to_mines_floor_20, Region.mines_floor_20), - ConnectionData(Entrance.dig_to_mines_floor_25, Region.mines_floor_25), - ConnectionData(Entrance.dig_to_mines_floor_30, Region.mines_floor_30), - ConnectionData(Entrance.dig_to_mines_floor_35, Region.mines_floor_35), - ConnectionData(Entrance.dig_to_mines_floor_40, Region.mines_floor_40), - ConnectionData(Entrance.dig_to_mines_floor_45, Region.mines_floor_45), - ConnectionData(Entrance.dig_to_mines_floor_50, Region.mines_floor_50), - ConnectionData(Entrance.dig_to_mines_floor_55, Region.mines_floor_55), - ConnectionData(Entrance.dig_to_mines_floor_60, Region.mines_floor_60), - ConnectionData(Entrance.dig_to_mines_floor_65, Region.mines_floor_65), - ConnectionData(Entrance.dig_to_mines_floor_70, Region.mines_floor_70), - ConnectionData(Entrance.dig_to_mines_floor_75, Region.mines_floor_75), - ConnectionData(Entrance.dig_to_mines_floor_80, Region.mines_floor_80), - ConnectionData(Entrance.dig_to_mines_floor_85, Region.mines_floor_85), - ConnectionData(Entrance.dig_to_mines_floor_90, Region.mines_floor_90), - ConnectionData(Entrance.dig_to_mines_floor_95, Region.mines_floor_95), - ConnectionData(Entrance.dig_to_mines_floor_100, Region.mines_floor_100), - ConnectionData(Entrance.dig_to_mines_floor_105, Region.mines_floor_105), - ConnectionData(Entrance.dig_to_mines_floor_110, Region.mines_floor_110), - ConnectionData(Entrance.dig_to_mines_floor_115, Region.mines_floor_115), - ConnectionData(Entrance.dig_to_mines_floor_120, Region.mines_floor_120), - ConnectionData(Entrance.dig_to_dangerous_mines_20, Region.dangerous_mines_20, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.dig_to_dangerous_mines_60, Region.dangerous_mines_60, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.dig_to_dangerous_mines_100, Region.dangerous_mines_100, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.enter_skull_cavern_entrance, Region.skull_cavern_entrance, + ConnectionData(Entrance.dig_to_mines_floor_5, RegionName.mines_floor_5), + ConnectionData(Entrance.dig_to_mines_floor_10, RegionName.mines_floor_10), + ConnectionData(Entrance.dig_to_mines_floor_15, RegionName.mines_floor_15), + ConnectionData(Entrance.dig_to_mines_floor_20, RegionName.mines_floor_20), + ConnectionData(Entrance.dig_to_mines_floor_25, RegionName.mines_floor_25), + ConnectionData(Entrance.dig_to_mines_floor_30, RegionName.mines_floor_30), + ConnectionData(Entrance.dig_to_mines_floor_35, RegionName.mines_floor_35), + ConnectionData(Entrance.dig_to_mines_floor_40, RegionName.mines_floor_40), + ConnectionData(Entrance.dig_to_mines_floor_45, RegionName.mines_floor_45), + ConnectionData(Entrance.dig_to_mines_floor_50, RegionName.mines_floor_50), + ConnectionData(Entrance.dig_to_mines_floor_55, RegionName.mines_floor_55), + ConnectionData(Entrance.dig_to_mines_floor_60, RegionName.mines_floor_60), + ConnectionData(Entrance.dig_to_mines_floor_65, RegionName.mines_floor_65), + ConnectionData(Entrance.dig_to_mines_floor_70, RegionName.mines_floor_70), + ConnectionData(Entrance.dig_to_mines_floor_75, RegionName.mines_floor_75), + ConnectionData(Entrance.dig_to_mines_floor_80, RegionName.mines_floor_80), + ConnectionData(Entrance.dig_to_mines_floor_85, RegionName.mines_floor_85), + ConnectionData(Entrance.dig_to_mines_floor_90, RegionName.mines_floor_90), + ConnectionData(Entrance.dig_to_mines_floor_95, RegionName.mines_floor_95), + ConnectionData(Entrance.dig_to_mines_floor_100, RegionName.mines_floor_100), + ConnectionData(Entrance.dig_to_mines_floor_105, RegionName.mines_floor_105), + ConnectionData(Entrance.dig_to_mines_floor_110, RegionName.mines_floor_110), + ConnectionData(Entrance.dig_to_mines_floor_115, RegionName.mines_floor_115), + ConnectionData(Entrance.dig_to_mines_floor_120, RegionName.mines_floor_120), + ConnectionData(Entrance.dig_to_dangerous_mines_20, RegionName.dangerous_mines_20, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.dig_to_dangerous_mines_60, RegionName.dangerous_mines_60, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.dig_to_dangerous_mines_100, RegionName.dangerous_mines_100, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.enter_skull_cavern_entrance, RegionName.skull_cavern_entrance, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_oasis, Region.oasis, + ConnectionData(Entrance.enter_oasis, RegionName.oasis, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_casino, Region.casino, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.enter_skull_cavern, Region.skull_cavern), - ConnectionData(Entrance.mine_to_skull_cavern_floor_25, Region.skull_cavern_25), - ConnectionData(Entrance.mine_to_skull_cavern_floor_50, Region.skull_cavern_50), - ConnectionData(Entrance.mine_to_skull_cavern_floor_75, Region.skull_cavern_75), - ConnectionData(Entrance.mine_to_skull_cavern_floor_100, Region.skull_cavern_100), - ConnectionData(Entrance.mine_to_skull_cavern_floor_125, Region.skull_cavern_125), - ConnectionData(Entrance.mine_to_skull_cavern_floor_150, Region.skull_cavern_150), - ConnectionData(Entrance.mine_to_skull_cavern_floor_175, Region.skull_cavern_175), - ConnectionData(Entrance.mine_to_skull_cavern_floor_200, Region.skull_cavern_200), - ConnectionData(Entrance.enter_dangerous_skull_cavern, Region.dangerous_skull_cavern, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.enter_witch_warp_cave, Region.witch_warp_cave, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.enter_witch_swamp, Region.witch_swamp, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.enter_witch_hut, Region.witch_hut, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.witch_warp_to_wizard_basement, Region.wizard_basement, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.enter_bathhouse_entrance, Region.bathhouse_entrance, + ConnectionData(Entrance.enter_casino, RegionName.casino, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.enter_skull_cavern, RegionName.skull_cavern), + ConnectionData(Entrance.mine_to_skull_cavern_floor_25, RegionName.skull_cavern_25), + ConnectionData(Entrance.mine_to_skull_cavern_floor_50, RegionName.skull_cavern_50), + ConnectionData(Entrance.mine_to_skull_cavern_floor_75, RegionName.skull_cavern_75), + ConnectionData(Entrance.mine_to_skull_cavern_floor_100, RegionName.skull_cavern_100), + ConnectionData(Entrance.mine_to_skull_cavern_floor_125, RegionName.skull_cavern_125), + ConnectionData(Entrance.mine_to_skull_cavern_floor_150, RegionName.skull_cavern_150), + ConnectionData(Entrance.mine_to_skull_cavern_floor_175, RegionName.skull_cavern_175), + ConnectionData(Entrance.mine_to_skull_cavern_floor_200, RegionName.skull_cavern_200), + ConnectionData(Entrance.enter_dangerous_skull_cavern, RegionName.dangerous_skull_cavern, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.enter_witch_warp_cave, RegionName.witch_warp_cave, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.enter_witch_swamp, RegionName.witch_swamp, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.enter_witch_hut, RegionName.witch_hut, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.witch_warp_to_wizard_basement, RegionName.wizard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.enter_bathhouse_entrance, RegionName.bathhouse_entrance, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(Entrance.enter_locker_room, Region.locker_room, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.enter_public_bath, Region.public_bath, flag=RandomizationFlag.BUILDINGS), - ConnectionData(Entrance.island_south_to_west, Region.island_west, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_south_to_north, Region.island_north, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_south_to_east, Region.island_east, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_south_to_southeast, Region.island_south_east, + ConnectionData(Entrance.enter_locker_room, RegionName.locker_room, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.enter_public_bath, RegionName.public_bath, flag=RandomizationFlag.BUILDINGS), + ConnectionData(Entrance.island_south_to_west, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.island_south_to_north, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.island_south_to_east, RegionName.island_east, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.island_south_to_southeast, RegionName.island_south_east, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.use_island_resort, Region.island_resort, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_west_to_islandfarmhouse, Region.island_farmhouse, + ConnectionData(Entrance.use_island_resort, RegionName.island_resort, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.island_west_to_islandfarmhouse, RegionName.island_farmhouse, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_west_to_gourmand_cave, Region.gourmand_frog_cave, + ConnectionData(Entrance.island_west_to_gourmand_cave, RegionName.gourmand_frog_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_west_to_crystals_cave, Region.colored_crystals_cave, + ConnectionData(Entrance.island_west_to_crystals_cave, RegionName.colored_crystals_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_west_to_shipwreck, Region.shipwreck, + ConnectionData(Entrance.island_west_to_shipwreck, RegionName.shipwreck, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_west_to_qi_walnut_room, Region.qi_walnut_room, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_east_to_leo_hut, Region.leo_hut, + ConnectionData(Entrance.island_west_to_qi_walnut_room, RegionName.qi_walnut_room, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.island_east_to_leo_hut, RegionName.leo_hut, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_east_to_island_shrine, Region.island_shrine, + ConnectionData(Entrance.island_east_to_island_shrine, RegionName.island_shrine, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_southeast_to_pirate_cove, Region.pirate_cove, + ConnectionData(Entrance.island_southeast_to_pirate_cove, RegionName.pirate_cove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_north_to_field_office, Region.field_office, + ConnectionData(Entrance.island_north_to_field_office, RegionName.field_office, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_north_to_dig_site, Region.dig_site, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.dig_site_to_professor_snail_cave, Region.professor_snail_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_north_to_volcano, Region.volcano, + ConnectionData(Entrance.island_north_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.dig_site_to_professor_snail_cave, RegionName.professor_snail_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.volcano_to_secret_beach, Region.volcano_secret_beach, + ConnectionData(Entrance.island_north_to_volcano, RegionName.volcano, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.talk_to_island_trader, Region.island_trader, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.climb_to_volcano_5, Region.volcano_floor_5, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.talk_to_volcano_dwarf, Region.volcano_dwarf_shop, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.climb_to_volcano_10, Region.volcano_floor_10, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_jungle_to_docks, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_dig_site_to_docks, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_volcano_to_docks, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_volcano_to_jungle, Region.island_west, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_docks_to_jungle, Region.island_west, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_dig_site_to_jungle, Region.island_west, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_docks_to_dig_site, Region.dig_site, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_volcano_to_dig_site, Region.dig_site, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_jungle_to_dig_site, Region.dig_site, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_dig_site_to_volcano, Region.island_north, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_docks_to_volcano, Region.island_north, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.parrot_express_jungle_to_volcano, Region.island_north, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.volcano_to_secret_beach, RegionName.volcano_secret_beach, + flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.talk_to_island_trader, RegionName.island_trader, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.climb_to_volcano_5, RegionName.volcano_floor_5, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.talk_to_volcano_dwarf, RegionName.volcano_dwarf_shop, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.climb_to_volcano_10, RegionName.volcano_floor_10, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_jungle_to_docks, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_dig_site_to_docks, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_volcano_to_docks, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_volcano_to_jungle, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_docks_to_jungle, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_dig_site_to_jungle, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_docks_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_volcano_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_jungle_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_dig_site_to_volcano, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_docks_to_volcano, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_jungle_to_volcano, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(LogicEntrance.talk_to_mines_dwarf, LogicRegion.mines_dwarf_shop), @@ -708,7 +709,7 @@ def swap_connections_until_valid(regions_by_name, connections_by_name: Dict[str, def region_should_be_reachable(region_name: str, connections_in_slot: Iterable[ConnectionData]) -> bool: - if region_name == Region.menu: + if region_name == RegionName.menu: return True for connection in connections_in_slot: if region_name == connection.destination: @@ -718,11 +719,11 @@ def region_should_be_reachable(region_name: str, connections_in_slot: Iterable[C def find_reachable_regions(regions_by_name, connections_by_name, randomized_connections: Dict[ConnectionData, ConnectionData]): - reachable_regions = {Region.menu} + reachable_regions = {RegionName.menu} unreachable_regions = {region for region in regions_by_name.keys()} # unreachable_regions = {region for region in regions_by_name.keys() if region_should_be_reachable(region, connections_by_name.values())} - unreachable_regions.remove(Region.menu) - exits_to_explore = list(regions_by_name[Region.menu].exits) + unreachable_regions.remove(RegionName.menu) + exits_to_explore = list(regions_by_name[RegionName.menu].exits) while exits_to_explore: exit_name = exits_to_explore.pop() # if exit_name not in connections_by_name: diff --git a/worlds/stardew_valley/scripts/update_data.py b/worlds/stardew_valley/scripts/update_data.py index ae8f7f8d55..5c2e6a57a4 100644 --- a/worlds/stardew_valley/scripts/update_data.py +++ b/worlds/stardew_valley/scripts/update_data.py @@ -12,7 +12,7 @@ from typing import List from worlds.stardew_valley import LocationData from worlds.stardew_valley.items import load_item_csv, Group, ItemData -from worlds.stardew_valley.locations import load_location_csv, LocationTags +from worlds.stardew_valley.locations import load_location_csv RESOURCE_PACK_CODE_OFFSET = 5000 script_folder = Path(__file__) @@ -56,9 +56,9 @@ if __name__ == "__main__": and item.code_without_offset is not None) + 1) resource_pack_counter = itertools.count(max(item.code_without_offset - for item in loaded_items - if Group.RESOURCE_PACK in item.groups - and item.code_without_offset is not None) + 1) + for item in loaded_items + if Group.RESOURCE_PACK in item.groups + and item.code_without_offset is not None) + 1) items_to_write = [] for item in loaded_items: if item.code_without_offset is None: diff --git a/worlds/stardew_valley/stardew_rule/base.py b/worlds/stardew_valley/stardew_rule/base.py index af4c3c3533..ff1fbba376 100644 --- a/worlds/stardew_valley/stardew_rule/base.py +++ b/worlds/stardew_valley/stardew_rule/base.py @@ -6,7 +6,7 @@ from dataclasses import dataclass, field from functools import cached_property from itertools import chain from threading import Lock -from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional +from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional, cast from BaseClasses import CollectionState from .literal import true_, false_, LiteralStardewRule @@ -318,6 +318,7 @@ class Or(AggregatingStardewRule): return Or(_combinable_rules=other.add_into(self.combinable_rules, self.combine), _simplification_state=self.simplification_state) if type(other) is Or: + other = cast(Or, other) return Or(_combinable_rules=self.merge(self.combinable_rules, other.combinable_rules), _simplification_state=self.simplification_state.merge(other.simplification_state)) @@ -344,6 +345,7 @@ class And(AggregatingStardewRule): return And(_combinable_rules=other.add_into(self.combinable_rules, self.combine), _simplification_state=self.simplification_state) if type(other) is And: + other = cast(And, other) return And(_combinable_rules=self.merge(self.combinable_rules, other.combinable_rules), _simplification_state=self.simplification_state.merge(other.simplification_state)) diff --git a/worlds/stardew_valley/stardew_rule/state.py b/worlds/stardew_valley/stardew_rule/state.py index 6fc349a627..d60f08ac4c 100644 --- a/worlds/stardew_valley/stardew_rule/state.py +++ b/worlds/stardew_valley/stardew_rule/state.py @@ -4,6 +4,7 @@ from typing import Iterable, Union, List, Tuple, Hashable, TYPE_CHECKING from BaseClasses import CollectionState from .base import BaseStardewRule, CombinableStardewRule from .protocol import StardewRule +from ..strings.ap_names.event_names import Event if TYPE_CHECKING: from .. import StardewValleyWorld @@ -87,45 +88,13 @@ class Reach(BaseStardewRule): return f"Reach {self.resolution_hint} {self.spot}" -@dataclass(frozen=True) -class HasProgressionPercent(CombinableStardewRule): - player: int - percent: int +class HasProgressionPercent(Received): + def __init__(self, player: int, percent: int): + super().__init__(Event.received_progression_percent, player, percent, event=True) def __post_init__(self): - assert self.percent > 0, "HasProgressionPercent rule must be above 0%" - assert self.percent <= 100, "HasProgressionPercent rule can't require more than 100% of items" - - @property - def combination_key(self) -> Hashable: - return HasProgressionPercent.__name__ - - @property - def value(self): - return self.percent - - def __call__(self, state: CollectionState) -> bool: - stardew_world: "StardewValleyWorld" = state.multiworld.worlds[self.player] - total_count = stardew_world.total_progression_items - needed_count = (total_count * self.percent) // 100 - player_state = state.prog_items[self.player] - - if needed_count <= len(player_state) - len(stardew_world.excluded_from_total_progression_items): - return True - - total_count = 0 - for item, item_count in player_state.items(): - if item in stardew_world.excluded_from_total_progression_items: - continue - - total_count += item_count - if total_count >= needed_count: - return True - - return False - - def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - return self, self(state) + assert self.count > 0, "HasProgressionPercent rule must be above 0%" + assert self.count <= 100, "HasProgressionPercent rule can't require more than 100% of items" def __repr__(self): - return f"Received {self.percent}% progression items" + return f"Received {self.count}% progression items" diff --git a/worlds/stardew_valley/strings/ap_names/event_names.py b/worlds/stardew_valley/strings/ap_names/event_names.py index 449bb67209..68f000bdc3 100644 --- a/worlds/stardew_valley/strings/ap_names/event_names.py +++ b/worlds/stardew_valley/strings/ap_names/event_names.py @@ -8,9 +8,7 @@ def event(name: str): class Event: victory = event("Victory") - spring_farming = event("Spring Farming") - summer_farming = event("Summer Farming") - fall_farming = event("Fall Farming") - winter_farming = event("Winter Farming") received_walnuts = event("Received Walnuts") + received_progression_item = event("Received Progression Item") + received_progression_percent = event("Received Progression Percent") diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index 83445c702c..891330c3ae 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -201,6 +201,10 @@ class ModMachine: composter = "Composter" recycling_bin = "Recycling Bin" advanced_recycling_machine = "Advanced Recycling Machine" + copper_slot_machine = "Copper Slot Machine" + gold_slot_machine = "Gold Slot Machine" + iridium_slot_machine = "Iridium Slot Machine" + radioactive_slot_machine = "Radioactive Slot Machine" class ModFloor: diff --git a/worlds/stardew_valley/test/TestBooksanity.py b/worlds/stardew_valley/test/TestBooksanity.py index 942f35d961..3c737e502c 100644 --- a/worlds/stardew_valley/test/TestBooksanity.py +++ b/worlds/stardew_valley/test/TestBooksanity.py @@ -65,7 +65,7 @@ class TestBooksanityNone(SVTestBase): if item_to_ship not in power_books and item_to_ship not in skill_books: continue with self.subTest(location.name): - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) class TestBooksanityPowers(SVTestBase): @@ -111,7 +111,7 @@ class TestBooksanityPowers(SVTestBase): if item_to_ship not in power_books and item_to_ship not in skill_books: continue with self.subTest(location.name): - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) class TestBooksanityPowersAndSkills(SVTestBase): @@ -157,7 +157,7 @@ class TestBooksanityPowersAndSkills(SVTestBase): if item_to_ship not in power_books and item_to_ship not in skill_books: continue with self.subTest(location.name): - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) class TestBooksanityAll(SVTestBase): @@ -203,4 +203,4 @@ class TestBooksanityAll(SVTestBase): if item_to_ship not in power_books and item_to_ship not in skill_books: continue with self.subTest(location.name): - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) diff --git a/worlds/stardew_valley/test/TestMultiplePlayers.py b/worlds/stardew_valley/test/TestMultiplePlayers.py index 2f2092fdf7..d8db616f66 100644 --- a/worlds/stardew_valley/test/TestMultiplePlayers.py +++ b/worlds/stardew_valley/test/TestMultiplePlayers.py @@ -53,8 +53,6 @@ class TestDifferentSettings(SVTestCase): def test_money_rule_caching(self): options_festivals_limited_money = {FestivalLocations.internal_name: FestivalLocations.option_easy, StartingMoney.internal_name: 5000} - options_festivals_limited_money = {FestivalLocations.internal_name: FestivalLocations.option_easy, - StartingMoney.internal_name: 5000} multiplayer_options = [options_festivals_limited_money, options_festivals_limited_money] multiworld = setup_multiworld(multiplayer_options) diff --git a/worlds/stardew_valley/test/TestNumberLocations.py b/worlds/stardew_valley/test/TestNumberLocations.py index ef552c10e8..a1c6a96741 100644 --- a/worlds/stardew_valley/test/TestNumberLocations.py +++ b/worlds/stardew_valley/test/TestNumberLocations.py @@ -1,5 +1,6 @@ from . import SVTestBase, allsanity_no_mods_6_x_x, \ - allsanity_mods_6_x_x, minimal_locations_maximal_items, minimal_locations_maximal_items_with_island, get_minsanity_options, default_6_x_x + allsanity_mods_6_x_x, minimal_locations_maximal_items, minimal_locations_maximal_items_with_island, get_minsanity_options, default_6_x_x, \ + allsanity_mods_6_x_x_exclude_disabled from .. import location_table from ..items import Group, item_table @@ -70,7 +71,7 @@ class TestAllSanitySettingsHasAllExpectedLocations(SVTestBase): options = allsanity_no_mods_6_x_x() def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 2238 + expected_locations = 2256 real_locations = self.get_real_locations() number_locations = len(real_locations) print(f"Stardew Valley - Allsanity Locations without mods: {number_locations}") @@ -83,10 +84,10 @@ class TestAllSanitySettingsHasAllExpectedLocations(SVTestBase): class TestAllSanityWithModsSettingsHasAllExpectedLocations(SVTestBase): - options = allsanity_mods_6_x_x() + options = allsanity_mods_6_x_x_exclude_disabled() def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 3096 + expected_locations = 2908 real_locations = self.get_real_locations() number_locations = len(real_locations) print(f"Stardew Valley - Allsanity Locations with all mods: {number_locations}") diff --git a/worlds/stardew_valley/test/TestWalnutsanity.py b/worlds/stardew_valley/test/TestWalnutsanity.py index c1e8c2c8f0..862553dee1 100644 --- a/worlds/stardew_valley/test/TestWalnutsanity.py +++ b/worlds/stardew_valley/test/TestWalnutsanity.py @@ -25,7 +25,7 @@ class TestWalnutsanityNone(SVTestBase): self.collect("Island Obelisk") self.collect("Island West Turtle") self.collect("Progressive House") - items = self.collect("5 Golden Walnuts", 10) + self.collect("5 Golden Walnuts", 10) self.assertFalse(self.multiworld.state.can_reach_location("Parrot Express", self.player)) self.collect("Island North Turtle") @@ -81,10 +81,10 @@ class TestWalnutsanityPuzzles(SVTestBase): self.collect("Combat Level", 10) self.collect("Mining Level", 10) for location in locations: - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) self.collect("Open Professor Snail Cave") for location in locations: - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) class TestWalnutsanityBushes(SVTestBase): @@ -126,10 +126,10 @@ class TestWalnutsanityPuzzlesAndBushes(SVTestBase): # You need to receive 25, and collect 15 self.collect("Island Obelisk") self.collect("Island West Turtle") - items = self.collect("5 Golden Walnuts", 5) + self.collect("5 Golden Walnuts", 5) self.assertFalse(self.multiworld.state.can_reach_location("Parrot Express", self.player)) - items = self.collect("Island North Turtle") + self.collect("Island North Turtle") self.assertTrue(self.multiworld.state.can_reach_location("Parrot Express", self.player)) @@ -203,7 +203,7 @@ class TestWalnutsanityAll(SVTestBase): self.assertTrue(self.multiworld.state.can_reach_location("Parrot Express", self.player)) self.remove(items) self.assertFalse(self.multiworld.state.can_reach_location("Parrot Express", self.player)) - items = self.collect("5 Golden Walnuts", 4) - items = self.collect("3 Golden Walnuts", 6) - items = self.collect("Golden Walnut", 2) + self.collect("5 Golden Walnuts", 4) + self.collect("3 Golden Walnuts", 6) + self.collect("Golden Walnut", 2) self.assertTrue(self.multiworld.state.can_reach_location("Parrot Express", self.player)) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index de0ed97882..880a3fda5c 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -13,6 +13,7 @@ from .assertion import RuleAssertMixin from .options.utils import fill_namespace_with_default, parse_class_option_keys, fill_dataclass_with_default from .. import StardewValleyWorld, options, StardewItem from ..options import StardewValleyOption +from ..options.options import enabled_mods logger = logging.getLogger(__name__) @@ -98,6 +99,12 @@ def allsanity_mods_6_x_x(): return allsanity +def allsanity_mods_6_x_x_exclude_disabled(): + allsanity = allsanity_no_mods_6_x_x() + allsanity.update({options.Mods.internal_name: frozenset(enabled_mods)}) + return allsanity + + def get_minsanity_options(): return { options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled, diff --git a/worlds/stardew_valley/test/assertion/rule_assert.py b/worlds/stardew_valley/test/assertion/rule_assert.py index 1031a18e11..02362f2d15 100644 --- a/worlds/stardew_valley/test/assertion/rule_assert.py +++ b/worlds/stardew_valley/test/assertion/rule_assert.py @@ -1,7 +1,7 @@ from typing import List from unittest import TestCase -from BaseClasses import CollectionState, Location +from BaseClasses import CollectionState, Location, Region from ...stardew_rule import StardewRule, false_, MISSING_ITEM, Reach from ...stardew_rule.rule_explain import explain @@ -40,19 +40,42 @@ class RuleAssertMixin(TestCase): raise AssertionError(f"Error while checking rule {rule}: {e}" f"\nExplanation: {expl}") - def assert_reach_location_true(self, location: Location, state: CollectionState): - expl = explain(Reach(location.name, "Location", 1), state) + def assert_can_reach_location(self, location: Location | str, state: CollectionState) -> None: + location_name = location.name if isinstance(location, Location) else location + expl = explain(Reach(location_name, "Location", 1), state) try: - can_reach = location.can_reach(state) + can_reach = state.can_reach_location(location_name, 1) self.assertTrue(can_reach, expl) except KeyError as e: - raise AssertionError(f"Error while checking location {location.name}: {e}" + raise AssertionError(f"Error while checking location {location_name}: {e}" f"\nExplanation: {expl}") - def assert_reach_location_false(self, location: Location, state: CollectionState): - expl = explain(Reach(location.name, "Location", 1), state, expected=False) + def assert_cannot_reach_location(self, location: Location | str, state: CollectionState) -> None: + location_name = location.name if isinstance(location, Location) else location + expl = explain(Reach(location_name, "Location", 1), state, expected=False) try: - self.assertFalse(location.can_reach(state), expl) + can_reach = state.can_reach_location(location_name, 1) + self.assertFalse(can_reach, expl) except KeyError as e: - raise AssertionError(f"Error while checking location {location.name}: {e}" + raise AssertionError(f"Error while checking location {location_name}: {e}" + f"\nExplanation: {expl}") + + def assert_can_reach_region(self, region: Region | str, state: CollectionState) -> None: + region_name = region.name if isinstance(region, Region) else region + expl = explain(Reach(region_name, "Region", 1), state) + try: + can_reach = state.can_reach_region(region_name, 1) + self.assertTrue(can_reach, expl) + except KeyError as e: + raise AssertionError(f"Error while checking region {region_name}: {e}" + f"\nExplanation: {expl}") + + def assert_cannot_reach_region(self, region: Region | str, state: CollectionState) -> None: + region_name = region.name if isinstance(region, Region) else region + expl = explain(Reach(region_name, "Region", 1), state, expected=False) + try: + can_reach = state.can_reach_region(region_name, 1) + self.assertFalse(can_reach, expl) + except KeyError as e: + raise AssertionError(f"Error while checking region {region_name}: {e}" f"\nExplanation: {expl}") diff --git a/worlds/stardew_valley/test/assertion/world_assert.py b/worlds/stardew_valley/test/assertion/world_assert.py index 9717283454..97f5376058 100644 --- a/worlds/stardew_valley/test/assertion/world_assert.py +++ b/worlds/stardew_valley/test/assertion/world_assert.py @@ -53,7 +53,7 @@ class WorldAssertMixin(RuleAssertMixin, TestCase): def assert_can_reach_everything(self, multiworld: MultiWorld): for location in multiworld.get_locations(): - self.assert_reach_location_true(location, multiworld.state) + self.assert_can_reach_location(location, multiworld.state) def assert_basic_checks(self, multiworld: MultiWorld): self.assert_same_number_items_locations(multiworld) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 89f82870e4..1dd2ab4902 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -1,13 +1,13 @@ import random from BaseClasses import get_seed -from .. import SVTestBase, SVTestCase, allsanity_no_mods_6_x_x, allsanity_mods_6_x_x, solo_multiworld, \ - fill_dataclass_with_default +from .. import SVTestBase, SVTestCase, allsanity_mods_6_x_x, fill_dataclass_with_default from ..assertion import ModAssertMixin, WorldAssertMixin from ... import items, Group, ItemClassification, create_content from ... import options -from ...items import items_by_group +from ...mods.mod_data import ModNames from ...options import SkillProgression, Walnutsanity +from ...options.options import all_mods from ...regions import RandomizationFlag, randomize_connections, create_final_connections_and_regions @@ -20,17 +20,58 @@ class TestGenerateModsOptions(WorldAssertMixin, ModAssertMixin, SVTestCase): self.assert_basic_checks(multi_world) self.assert_stray_mod_items(mod, multi_world) - def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basic_checks(self): - for option in options.EntranceRandomization.options: - for mod in options.Mods.valid_keys: - world_options = { - options.EntranceRandomization: options.EntranceRandomization.options[option], - options.Mods: mod, - options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_false - } - with self.solo_world_sub_test(f"entrance_randomization: {option}, Mod: {mod}", world_options) as (multi_world, _): - self.assert_basic_checks(multi_world) - self.assert_stray_mod_items(mod, multi_world) + # The following tests validate that ER still generates winnable and logically-sane games with given mods. + # Mods that do not interact with entrances are skipped + # Not all ER settings are tested, because 'buildings' is, essentially, a superset of all others + def test_deepwoods_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.deepwoods, options.EntranceRandomization.option_buildings) + + def test_juna_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.juna, options.EntranceRandomization.option_buildings) + + def test_jasper_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.jasper, options.EntranceRandomization.option_buildings) + + def test_alec_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.alec, options.EntranceRandomization.option_buildings) + + def test_yoba_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.yoba, options.EntranceRandomization.option_buildings) + + def test_eugene_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.eugene, options.EntranceRandomization.option_buildings) + + def test_ayeisha_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.ayeisha, options.EntranceRandomization.option_buildings) + + def test_riley_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.riley, options.EntranceRandomization.option_buildings) + + def test_sve_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.sve, options.EntranceRandomization.option_buildings) + + def test_alecto_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.alecto, options.EntranceRandomization.option_buildings) + + def test_lacey_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.lacey, options.EntranceRandomization.option_buildings) + + def test_boarding_house_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(ModNames.boarding_house, options.EntranceRandomization.option_buildings) + + def test_all_mods_entrance_randomization_buildings(self): + self.perform_basic_checks_on_mod_with_er(all_mods, options.EntranceRandomization.option_buildings) + + def perform_basic_checks_on_mod_with_er(self, mods: str | set[str], er_option: int) -> None: + if isinstance(mods, str): + mods = {mods} + world_options = { + options.EntranceRandomization: er_option, + options.Mods: frozenset(mods), + options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_false + } + with self.solo_world_sub_test(f"entrance_randomization: {er_option}, Mods: {mods}", world_options) as (multi_world, _): + self.assert_basic_checks(multi_world) def test_allsanity_all_mods_when_generate_then_basic_checks(self): with self.solo_world_sub_test(world_options=allsanity_mods_6_x_x()) as (multi_world, _): @@ -147,19 +188,3 @@ class TestModEntranceRando(SVTestCase): self.assertEqual(len(set(randomized_connections.values())), len(randomized_connections.values()), f"Connections are duplicated in randomization.") - - -class TestModTraps(SVTestCase): - def test_given_traps_when_generate_then_all_traps_in_pool(self): - for value in options.TrapItems.options: - if value == "no_traps": - continue - - world_options = allsanity_no_mods_6_x_x() - world_options.update({options.TrapItems.internal_name: options.TrapItems.options[value], options.Mods.internal_name: "Magic"}) - with solo_multiworld(world_options) as (multi_world, _): - trap_items = [item_data.name for item_data in items_by_group[Group.TRAP] if Group.DEPRECATED not in item_data.groups] - multiworld_items = [item.name for item in multi_world.get_items()] - for item in trap_items: - with self.subTest(f"Option: {value}, Item: {item}"): - self.assertIn(item, multiworld_items) diff --git a/worlds/stardew_valley/test/mods/TestModsFill.py b/worlds/stardew_valley/test/mods/TestModsFill.py new file mode 100644 index 0000000000..a140f5abae --- /dev/null +++ b/worlds/stardew_valley/test/mods/TestModsFill.py @@ -0,0 +1,28 @@ +from .. import SVTestBase +from ... import options + + +class TestNoGingerIslandCraftingRecipesAreRequired(SVTestBase): + options = { + options.Goal.internal_name: options.Goal.option_craft_master, + options.Craftsanity.internal_name: options.Craftsanity.option_all, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.Mods.internal_name: frozenset(options.Mods.valid_keys) + } + + @property + def run_default_tests(self) -> bool: + return True + + +class TestNoGingerIslandCookingRecipesAreRequired(SVTestBase): + options = { + options.Goal.internal_name: options.Goal.option_gourmet_chef, + options.Cooksanity.internal_name: options.Cooksanity.option_all, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.Mods.internal_name: frozenset(options.Mods.valid_keys) + } + + @property + def run_default_tests(self) -> bool: + return True diff --git a/worlds/stardew_valley/test/rules/TestBooks.py b/worlds/stardew_valley/test/rules/TestBooks.py index 6605e7e645..af0055d228 100644 --- a/worlds/stardew_valley/test/rules/TestBooks.py +++ b/worlds/stardew_valley/test/rules/TestBooks.py @@ -12,15 +12,13 @@ class TestBooksLogic(SVTestBase): location = self.multiworld.get_location("Read Mapping Cave Systems", self.player) - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) self.collect("Progressive Mine Elevator") self.collect("Progressive Mine Elevator") self.collect("Progressive Mine Elevator") self.collect("Progressive Mine Elevator") - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) self.collect("Progressive Weapon") - self.assert_reach_location_true(location, self.multiworld.state) - - + self.assert_can_reach_location(location, self.multiworld.state) diff --git a/worlds/stardew_valley/test/rules/TestFishing.py b/worlds/stardew_valley/test/rules/TestFishing.py index 04a1528dd8..74a33f3668 100644 --- a/worlds/stardew_valley/test/rules/TestFishing.py +++ b/worlds/stardew_valley/test/rules/TestFishing.py @@ -1,5 +1,4 @@ -from ...options import SeasonRandomization, Friendsanity, FriendsanityHeartSize, Fishsanity, ExcludeGingerIsland, SkillProgression, ToolProgression, \ - ElevatorProgression, SpecialOrderLocations +from ...options import SeasonRandomization, Fishsanity, ExcludeGingerIsland, SkillProgression, ToolProgression, ElevatorProgression, SpecialOrderLocations from ...strings.fish_names import Fish from ...test import SVTestBase @@ -44,18 +43,18 @@ class TestNeedRegionToCatchFish(SVTestBase): self.collect_all_the_money() item_names = fish_and_items[fish] location = self.multiworld.get_location(f"Fishsanity: {fish}", self.player) - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) items = [] for item_name in item_names: items.append(self.collect(item_name)) with self.subTest(f"{fish} can be reached with {item_names}"): - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) for item_required in items: self.multiworld.state = self.original_state.copy() with self.subTest(f"{fish} requires {item_required.name}"): for item_to_collect in items: if item_to_collect.name != item_required.name: self.collect(item_to_collect) - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) self.multiworld.state = self.original_state.copy() diff --git a/worlds/stardew_valley/test/rules/TestShipping.py b/worlds/stardew_valley/test/rules/TestShipping.py index b26d1e94ee..125b7f31d0 100644 --- a/worlds/stardew_valley/test/rules/TestShipping.py +++ b/worlds/stardew_valley/test/rules/TestShipping.py @@ -69,14 +69,17 @@ class TestShipsanityEverything(SVTestBase): def test_all_shipsanity_locations_require_shipping_bin(self): bin_name = "Shipping Bin" self.collect_all_except(bin_name) - shipsanity_locations = [location for location in self.get_real_locations() if - LocationTags.SHIPSANITY in location_table[location.name].tags] + shipsanity_locations = [location + for location in self.get_real_locations() + if LocationTags.SHIPSANITY in location_table[location.name].tags] bin_item = self.create_item(bin_name) + for location in shipsanity_locations: with self.subTest(location.name): - self.remove(bin_item) self.assertFalse(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state)) - self.multiworld.state.collect(bin_item) + + self.collect(bin_item) shipsanity_rule = self.world.logic.region.can_reach_location(location.name) self.assert_rule_true(shipsanity_rule, self.multiworld.state) + self.remove(bin_item) diff --git a/worlds/stardew_valley/test/rules/TestSkills.py b/worlds/stardew_valley/test/rules/TestSkills.py index 77adade886..ee605bfaa1 100644 --- a/worlds/stardew_valley/test/rules/TestSkills.py +++ b/worlds/stardew_valley/test/rules/TestSkills.py @@ -39,10 +39,10 @@ class TestSkillProgressionProgressive(SVTestBase): with self.subTest(location_name): if level > 1: - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) self.collect(f"{skill} Level") - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) self.reset_collection_state() @@ -88,7 +88,7 @@ class TestSkillProgressionProgressiveWithMasteryWithoutMods(SVTestBase): for skill in all_vanilla_skills: with self.subTest(skill): location = self.multiworld.get_location(f"{skill} Mastery", self.player) - self.assert_reach_location_true(location, self.multiworld.state) + self.assert_can_reach_location(location, self.multiworld.state) self.reset_collection_state() @@ -99,7 +99,7 @@ class TestSkillProgressionProgressiveWithMasteryWithoutMods(SVTestBase): self.remove_one_by_name(f"{skill} Level") location = self.multiworld.get_location(f"{skill} Mastery", self.player) - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) self.reset_collection_state() @@ -108,6 +108,6 @@ class TestSkillProgressionProgressiveWithMasteryWithoutMods(SVTestBase): self.remove_one_by_name(f"Progressive Pickaxe") location = self.multiworld.get_location("Mining Mastery", self.player) - self.assert_reach_location_false(location, self.multiworld.state) + self.assert_cannot_reach_location(location, self.multiworld.state) self.reset_collection_state() diff --git a/worlds/stardew_valley/test/rules/TestTools.py b/worlds/stardew_valley/test/rules/TestTools.py index 5b8975f4e7..31dd581916 100644 --- a/worlds/stardew_valley/test/rules/TestTools.py +++ b/worlds/stardew_valley/test/rules/TestTools.py @@ -1,7 +1,7 @@ from collections import Counter from .. import SVTestBase -from ... import Event, options +from ... import options from ...options import ToolProgression, SeasonRandomization from ...strings.entrance_names import Entrance from ...strings.region_names import Region @@ -74,12 +74,10 @@ class TestProgressiveToolsLogic(SVTestBase): self.assert_rule_true(rule, self.multiworld.state) self.remove(fall) - self.remove(self.create_item(Event.fall_farming)) self.assert_rule_false(rule, self.multiworld.state) self.remove(tuesday) green_house = self.create_item("Greenhouse") - self.collect(self.create_item(Event.fall_farming)) self.multiworld.state.collect(green_house) self.assert_rule_false(rule, self.multiworld.state) @@ -88,7 +86,6 @@ class TestProgressiveToolsLogic(SVTestBase): self.assertTrue(self.multiworld.get_location("Old Master Cannoli", 1).access_rule(self.multiworld.state)) self.remove(green_house) - self.remove(self.create_item(Event.fall_farming)) self.assert_rule_false(rule, self.multiworld.state) self.remove(friday) diff --git a/worlds/subnautica/__init__.py b/worlds/subnautica/__init__.py index c3cf40a7c0..850c23c7dd 100644 --- a/worlds/subnautica/__init__.py +++ b/worlds/subnautica/__init__.py @@ -1,6 +1,5 @@ from __future__ import annotations -import logging import itertools from typing import List, Dict, Any, cast @@ -10,13 +9,11 @@ from . import items from . import locations from . import creatures from . import options -from .items import item_table, group_items, items_by_type, ItemType +from .items import item_table, group_items from .rules import set_rules -logger = logging.getLogger("Subnautica") - -class SubnaticaWeb(WebWorld): +class SubnauticaWeb(WebWorld): tutorials = [Tutorial( "Multiworld Setup Guide", "A guide to setting up the Subnautica randomizer connected to an Archipelago Multiworld", @@ -38,7 +35,7 @@ class SubnauticaWorld(World): You must find a cure for yourself, build an escape rocket, and leave the planet. """ game = "Subnautica" - web = SubnaticaWeb() + web = SubnauticaWeb() item_name_to_id = {data.name: item_id for item_id, data in items.item_table.items()} location_name_to_id = all_locations diff --git a/worlds/tloz/docs/multiworld_en.md b/worlds/tloz/docs/multiworld_en.md index 366531e2e4..e09d188ba4 100644 --- a/worlds/tloz/docs/multiworld_en.md +++ b/worlds/tloz/docs/multiworld_en.md @@ -40,7 +40,7 @@ guide: [Basic Multiworld Setup Guide](/tutorial/Archipelago/setup/en) ### Where do I get a config file? The Player Options page on the website allows you to configure your personal options and export a config file from -them. Player options page: [The Legend of Zelda Player Sptions Page](/games/The%20Legend%20of%20Zelda/player-options) +them. Player options page: [The Legend of Zelda Player Options Page](/games/The%20Legend%20of%20Zelda/player-options) ### Verifying your config file diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 8525a3fc43..e86f731381 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -1,19 +1,20 @@ -from typing import Dict, List, Any, Tuple, TypedDict, ClassVar, Union +from typing import Dict, List, Any, Tuple, TypedDict, ClassVar, Union, Set, TextIO from logging import warning from BaseClasses import Region, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState from .items import (item_name_to_id, item_table, item_name_groups, fool_tiers, filler_items, slot_data_item_names, combat_items) -from .locations import location_table, location_name_groups, location_name_to_id, hexagon_locations +from .locations import location_table, location_name_groups, standard_location_name_to_id, hexagon_locations, sphere_one from .rules import set_location_rules, set_region_rules, randomize_ability_unlocks, gold_hexagon from .er_rules import set_er_location_rules from .regions import tunic_regions from .er_scripts import create_er_regions +from .grass import grass_location_table, grass_location_name_to_id, grass_location_name_groups, excluded_grass_locations from .er_data import portal_mapping, RegionInfo, tunic_er_regions from .options import (TunicOptions, EntranceRando, tunic_option_groups, tunic_option_presets, TunicPlandoConnections, LaurelsLocation, LogicRules, LaurelsZips, IceGrappling, LadderStorage) from .combat_logic import area_data, CombatState from worlds.AutoWorld import WebWorld, World -from Options import PlandoConnection +from Options import PlandoConnection, OptionError from decimal import Decimal, ROUND_HALF_UP from settings import Group, Bool @@ -22,7 +23,11 @@ class TunicSettings(Group): class DisableLocalSpoiler(Bool): """Disallows the TUNIC client from creating a local spoiler log.""" + class LimitGrassRando(Bool): + """Limits the impact of Grass Randomizer on the multiworld by disallowing local_fill percentages below 95.""" + disable_local_spoiler: Union[DisableLocalSpoiler, bool] = False + limit_grass_rando: Union[LimitGrassRando, bool] = True class TunicWeb(WebWorld): @@ -73,10 +78,14 @@ class TunicWorld(World): settings: ClassVar[TunicSettings] item_name_groups = item_name_groups location_name_groups = location_name_groups + for group_name, members in grass_location_name_groups.items(): + location_name_groups.setdefault(group_name, set()).update(members) item_name_to_id = item_name_to_id - location_name_to_id = location_name_to_id + location_name_to_id = standard_location_name_to_id.copy() + location_name_to_id.update(grass_location_name_to_id) + player_location_table: Dict[str, int] ability_unlocks: Dict[str, int] slot_data_items: List[TunicItem] tunic_portal_pairs: Dict[str, str] @@ -85,11 +94,20 @@ class TunicWorld(World): shop_num: int = 1 # need to make it so that you can walk out of shops, but also that they aren't all connected er_regions: Dict[str, RegionInfo] # absolutely needed so outlet regions work + # for the local_fill option + fill_items: List[TunicItem] + fill_locations: List[Location] + amount_to_local_fill: int + # so we only loop the multiworld locations once # if these are locations instead of their info, it gives a memory leak error item_link_locations: Dict[int, Dict[str, List[Tuple[int, str]]]] = {} player_item_link_locations: Dict[str, List[Location]] + using_ut: bool # so we can check if we're using UT only once + passthrough: Dict[str, Any] + ut_can_gen_without_yaml = True # class var that tells it to ignore the player yaml + def generate_early(self) -> None: if self.options.logic_rules >= LogicRules.option_no_major_glitches: self.options.laurels_zips.value = LaurelsZips.option_true @@ -113,23 +131,45 @@ class TunicWorld(World): # Universal tracker stuff, shouldn't do anything in standard gen if hasattr(self.multiworld, "re_gen_passthrough"): if "TUNIC" in self.multiworld.re_gen_passthrough: - passthrough = self.multiworld.re_gen_passthrough["TUNIC"] - self.options.start_with_sword.value = passthrough["start_with_sword"] - self.options.keys_behind_bosses.value = passthrough["keys_behind_bosses"] - self.options.sword_progression.value = passthrough["sword_progression"] - self.options.ability_shuffling.value = passthrough["ability_shuffling"] - self.options.laurels_zips.value = passthrough["laurels_zips"] - self.options.ice_grappling.value = passthrough["ice_grappling"] - self.options.ladder_storage.value = passthrough["ladder_storage"] - self.options.ladder_storage_without_items = passthrough["ladder_storage_without_items"] - self.options.lanternless.value = passthrough["lanternless"] - self.options.maskless.value = passthrough["maskless"] - self.options.hexagon_quest.value = passthrough["hexagon_quest"] - self.options.entrance_rando.value = passthrough["entrance_rando"] - self.options.shuffle_ladders.value = passthrough["shuffle_ladders"] + self.using_ut = True + self.passthrough = self.multiworld.re_gen_passthrough["TUNIC"] + self.options.start_with_sword.value = self.passthrough["start_with_sword"] + self.options.keys_behind_bosses.value = self.passthrough["keys_behind_bosses"] + self.options.sword_progression.value = self.passthrough["sword_progression"] + self.options.ability_shuffling.value = self.passthrough["ability_shuffling"] + self.options.laurels_zips.value = self.passthrough["laurels_zips"] + self.options.ice_grappling.value = self.passthrough["ice_grappling"] + self.options.ladder_storage.value = self.passthrough["ladder_storage"] + self.options.ladder_storage_without_items = self.passthrough["ladder_storage_without_items"] + self.options.lanternless.value = self.passthrough["lanternless"] + self.options.maskless.value = self.passthrough["maskless"] + self.options.hexagon_quest.value = self.passthrough["hexagon_quest"] + self.options.entrance_rando.value = self.passthrough["entrance_rando"] + self.options.shuffle_ladders.value = self.passthrough["shuffle_ladders"] + self.options.grass_randomizer.value = self.passthrough.get("grass_randomizer", 0) self.options.fixed_shop.value = self.options.fixed_shop.option_false self.options.laurels_location.value = self.options.laurels_location.option_anywhere - self.options.combat_logic.value = passthrough["combat_logic"] + self.options.combat_logic.value = self.passthrough["combat_logic"] + else: + self.using_ut = False + else: + self.using_ut = False + + self.player_location_table = standard_location_name_to_id.copy() + + if self.options.local_fill == -1: + if self.options.grass_randomizer: + self.options.local_fill.value = 95 + else: + self.options.local_fill.value = 0 + + if self.options.grass_randomizer: + if self.settings.limit_grass_rando and self.options.local_fill < 95 and self.multiworld.players > 1: + raise OptionError(f"TUNIC: Player {self.player_name} has their Local Fill option set too low. " + f"They must either bring it above 95% or the host needs to disable limit_grass_rando " + f"in their host.yaml settings") + + self.player_location_table.update(grass_location_name_to_id) @classmethod def stage_generate_early(cls, multiworld: MultiWorld) -> None: @@ -202,10 +242,18 @@ class TunicWorld(World): def create_item(self, name: str, classification: ItemClassification = None) -> TunicItem: item_data = item_table[name] - # if item_data.combat_ic is None, it'll take item_data.classification instead - itemclass: ItemClassification = ((item_data.combat_ic if self.options.combat_logic else None) + # evaluate alternate classifications based on options + # it'll choose whichever classification isn't None first in this if else tree + itemclass: ItemClassification = (classification + or (item_data.combat_ic if self.options.combat_logic else None) + or (ItemClassification.progression | ItemClassification.useful + if name == "Glass Cannon" and self.options.grass_randomizer + and not self.options.start_with_sword else None) + or (ItemClassification.progression | ItemClassification.useful + if name == "Shield" and self.options.ladder_storage + and not self.options.ladder_storage_without_items else None) or item_data.classification) - return TunicItem(name, classification or itemclass, self.item_name_to_id[name], self.player) + return TunicItem(name, itemclass, self.item_name_to_id[name], self.player) def create_items(self) -> None: tunic_items: List[TunicItem] = [] @@ -236,6 +284,12 @@ class TunicWorld(World): self.get_location("Secret Gathering Place - 10 Fairy Reward").place_locked_item(laurels) items_to_create["Hero's Laurels"] = 0 + if self.options.grass_randomizer: + items_to_create["Grass"] = len(grass_location_table) + for grass_location in excluded_grass_locations: + self.get_location(grass_location).place_locked_item(self.create_item("Grass")) + items_to_create["Grass"] -= len(excluded_grass_locations) + if self.options.keys_behind_bosses: for rgb_hexagon, location in hexagon_locations.items(): hex_item = self.create_item(gold_hexagon if self.options.hexagon_quest else rgb_hexagon) @@ -284,10 +338,11 @@ class TunicWorld(World): remove_filler(items_to_create[gold_hexagon]) - # Sort for deterministic order - for hero_relic in sorted(item_name_groups["Hero Relics"]): - tunic_items.append(self.create_item(hero_relic, ItemClassification.useful)) - items_to_create[hero_relic] = 0 + if not self.options.combat_logic: + # Sort for deterministic order + for hero_relic in sorted(item_name_groups["Hero Relics"]): + tunic_items.append(self.create_item(hero_relic, ItemClassification.useful)) + items_to_create[hero_relic] = 0 if not self.options.ability_shuffling: # Sort for deterministic order @@ -302,11 +357,6 @@ class TunicWorld(World): tunic_items.append(self.create_item(page, ItemClassification.progression | ItemClassification.useful)) items_to_create[page] = 0 - # logically relevant if you have ladder storage enabled - if self.options.ladder_storage and not self.options.ladder_storage_without_items: - tunic_items.append(self.create_item("Shield", ItemClassification.progression)) - items_to_create["Shield"] = 0 - if self.options.maskless: tunic_items.append(self.create_item("Scavenger Mask", ItemClassification.useful)) items_to_create["Scavenger Mask"] = 0 @@ -323,23 +373,85 @@ class TunicWorld(World): if tunic_item.name in slot_data_item_names: self.slot_data_items.append(tunic_item) + # pull out the filler so that we can place it manually during pre_fill + self.fill_items = [] + if self.options.local_fill > 0 and self.multiworld.players > 1: + # skip items marked local or non-local, let fill deal with them in its own way + # discard grass from non_local if it's meant to be limited + if self.settings.limit_grass_rando: + self.options.non_local_items.value.discard("Grass") + all_filler: List[TunicItem] = [] + non_filler: List[TunicItem] = [] + for tunic_item in tunic_items: + if (tunic_item.excludable + and tunic_item.name not in self.options.local_items + and tunic_item.name not in self.options.non_local_items): + all_filler.append(tunic_item) + else: + non_filler.append(tunic_item) + self.amount_to_local_fill = int(self.options.local_fill.value * len(all_filler) / 100) + self.fill_items += all_filler[:self.amount_to_local_fill] + del all_filler[:self.amount_to_local_fill] + tunic_items = all_filler + non_filler + self.multiworld.itempool += tunic_items + def pre_fill(self) -> None: + if self.options.local_fill > 0 and self.multiworld.players > 1: + # we need to reserve a couple locations so that we don't fill up every sphere 1 location + reserved_locations: Set[str] = set(self.random.sample(sphere_one, 2)) + viable_locations = [loc for loc in self.multiworld.get_unfilled_locations(self.player) + if loc.name not in reserved_locations + and loc.name not in self.options.priority_locations.value] + + if len(viable_locations) < self.amount_to_local_fill: + raise OptionError(f"TUNIC: Not enough locations for local_fill option for {self.player_name}. " + f"This is likely due to excess plando or priority locations.") + self.random.shuffle(viable_locations) + self.fill_locations = viable_locations[:self.amount_to_local_fill] + + @classmethod + def stage_pre_fill(cls, multiworld: MultiWorld) -> None: + tunic_fill_worlds: List[TunicWorld] = [world for world in multiworld.get_game_worlds("TUNIC") + if world.options.local_fill.value > 0] + if tunic_fill_worlds and multiworld.players > 1: + grass_fill: List[TunicItem] = [] + non_grass_fill: List[TunicItem] = [] + grass_fill_locations: List[Location] = [] + non_grass_fill_locations: List[Location] = [] + for world in tunic_fill_worlds: + if world.options.grass_randomizer: + grass_fill.extend(world.fill_items) + grass_fill_locations.extend(world.fill_locations) + else: + non_grass_fill.extend(world.fill_items) + non_grass_fill_locations.extend(world.fill_locations) + + multiworld.random.shuffle(grass_fill) + multiworld.random.shuffle(non_grass_fill) + multiworld.random.shuffle(grass_fill_locations) + multiworld.random.shuffle(non_grass_fill_locations) + + for filler_item in grass_fill: + multiworld.push_item(grass_fill_locations.pop(), filler_item, collect=False) + + for filler_item in non_grass_fill: + multiworld.push_item(non_grass_fill_locations.pop(), filler_item, collect=False) + def create_regions(self) -> None: self.tunic_portal_pairs = {} self.er_portal_hints = {} self.ability_unlocks = randomize_ability_unlocks(self.random, self.options) # stuff for universal tracker support, can be ignored for standard gen - if hasattr(self.multiworld, "re_gen_passthrough"): - if "TUNIC" in self.multiworld.re_gen_passthrough: - passthrough = self.multiworld.re_gen_passthrough["TUNIC"] - self.ability_unlocks["Pages 24-25 (Prayer)"] = passthrough["Hexagon Quest Prayer"] - self.ability_unlocks["Pages 42-43 (Holy Cross)"] = passthrough["Hexagon Quest Holy Cross"] - self.ability_unlocks["Pages 52-53 (Icebolt)"] = passthrough["Hexagon Quest Icebolt"] + if self.using_ut: + self.ability_unlocks["Pages 24-25 (Prayer)"] = self.passthrough["Hexagon Quest Prayer"] + self.ability_unlocks["Pages 42-43 (Holy Cross)"] = self.passthrough["Hexagon Quest Holy Cross"] + self.ability_unlocks["Pages 52-53 (Icebolt)"] = self.passthrough["Hexagon Quest Icebolt"] # Ladders and Combat Logic uses ER rules with vanilla connections for easier maintenance - if self.options.entrance_rando or self.options.shuffle_ladders or self.options.combat_logic: + if (self.options.entrance_rando or self.options.shuffle_ladders or self.options.combat_logic + or self.options.grass_randomizer): portal_pairs = create_er_regions(self) if self.options.entrance_rando: # these get interpreted by the game to tell it which entrances to connect @@ -355,7 +467,7 @@ class TunicWorld(World): region = self.get_region(region_name) region.add_exits(exits) - for location_name, location_id in self.location_name_to_id.items(): + for location_name, location_id in self.player_location_table.items(): region = self.get_region(location_table[location_name].region) location = TunicLocation(self.player, location_name, location_id, region) region.locations.append(location) @@ -368,7 +480,8 @@ class TunicWorld(World): def set_rules(self) -> None: # same reason as in create_regions, could probably be put into create_regions - if self.options.entrance_rando or self.options.shuffle_ladders or self.options.combat_logic: + if (self.options.entrance_rando or self.options.shuffle_ladders or self.options.combat_logic + or self.options.grass_randomizer): set_er_location_rules(self) else: set_region_rules(self) @@ -390,6 +503,13 @@ class TunicWorld(World): state.tunic_need_to_reset_combat_from_remove[self.player] = True return change + def write_spoiler_header(self, spoiler_handle: TextIO): + if self.options.hexagon_quest and self.options.ability_shuffling: + spoiler_handle.write("\nAbility Unlocks (Hexagon Quest):\n") + for ability in self.ability_unlocks: + # Remove parentheses for better readability + spoiler_handle.write(f'{ability[ability.find("(")+1:ability.find(")")]}: {self.ability_unlocks[ability]} Gold Questagons\n') + def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]) -> None: if self.options.entrance_rando: hint_data.update({self.player: {}}) @@ -456,6 +576,7 @@ class TunicWorld(World): "maskless": self.options.maskless.value, "entrance_rando": int(bool(self.options.entrance_rando.value)), "shuffle_ladders": self.options.shuffle_ladders.value, + "grass_randomizer": self.options.grass_randomizer.value, "combat_logic": self.options.combat_logic.value, "Hexagon Quest Prayer": self.ability_unlocks["Pages 24-25 (Prayer)"], "Hexagon Quest Holy Cross": self.ability_unlocks["Pages 42-43 (Holy Cross)"], diff --git a/worlds/tunic/combat_logic.py b/worlds/tunic/combat_logic.py index 9ff363942c..2e9f19dbc2 100644 --- a/worlds/tunic/combat_logic.py +++ b/worlds/tunic/combat_logic.py @@ -8,6 +8,7 @@ from worlds.AutoWorld import LogicMixin # the vanilla stats you are expected to have to get through an area, based on where they are in vanilla class AreaStats(NamedTuple): + """Attack, Defense, Potion, HP, SP, MP, Flasks, Equipment, is_boss""" att_level: int def_level: int potion_level: int # all 3 are before your first bonfire after getting the upgrade page, third costs 1k @@ -41,7 +42,7 @@ area_data: Dict[str, AreaStats] = { "Rooted Ziggurat": AreaStats(5, 5, 3, 5, 3, 3, 6, ["Sword", "Shield", "Magic"]), "Boss Scavenger": AreaStats(5, 5, 3, 5, 3, 3, 6, ["Sword", "Shield", "Magic"], is_boss=True), "Swamp": AreaStats(1, 1, 1, 1, 1, 1, 6, ["Sword", "Shield", "Magic"]), - "Cathedral": AreaStats(1, 1, 1, 1, 1, 1, 6, ["Sword", "Shield", "Magic"]), + # Cathedral has the same requirements as Swamp # marked as boss because the garden knights can't get hurt by stick "Gauntlet": AreaStats(1, 1, 1, 1, 1, 1, 6, ["Sword", "Shield", "Magic"], is_boss=True), "The Heir": AreaStats(5, 5, 3, 5, 3, 3, 6, ["Sword", "Shield", "Magic", "Laurels"], is_boss=True), @@ -49,8 +50,10 @@ area_data: Dict[str, AreaStats] = { # these are used for caching which areas can currently be reached in state +# Gauntlet does not have exclusively higher stat requirements, so it will be checked separately boss_areas: List[str] = [name for name, data in area_data.items() if data.is_boss and name != "Gauntlet"] -non_boss_areas: List[str] = [name for name, data in area_data.items() if not data.is_boss] +# Swamp does not have exclusively higher stat requirements, so it will be checked separately +non_boss_areas: List[str] = [name for name, data in area_data.items() if not data.is_boss and name != "Swamp"] class CombatState(IntEnum): @@ -89,6 +92,7 @@ def has_combat_reqs(area_name: str, state: CollectionState, player: int) -> bool elif area_name in non_boss_areas: area_list = non_boss_areas else: + # this is to check Swamp and Gauntlet on their own area_list = [area_name] if met_combat_reqs: @@ -114,88 +118,89 @@ def check_combat_reqs(area_name: str, state: CollectionState, player: int, alt_d extra_att_needed = 0 extra_def_needed = 0 extra_mp_needed = 0 - has_magic = state.has_any({"Magic Wand", "Gun"}, player) - stick_bool = False - sword_bool = False + has_magic = state.has_any(("Magic Wand", "Gun"), player) + sword_bool = has_sword(state, player) + stick_bool = sword_bool or has_melee(state, player) + equipment = data.equipment.copy() for item in data.equipment: if item == "Stick": - if not has_melee(state, player): + if not stick_bool: if has_magic: + equipment.remove("Stick") + if "Magic" not in equipment: + equipment.append("Magic") # magic can make up for the lack of stick extra_mp_needed += 2 - extra_att_needed -= 16 + extra_att_needed -= 32 else: return False - else: - stick_bool = True elif item == "Sword": - if not has_sword(state, player): + if not sword_bool: # need sword for bosses if data.is_boss: return False - if has_magic: - # +4 mp pretty much makes up for the lack of sword, at least in Quarry - extra_mp_needed += 4 - # stick is a backup plan, and doesn't scale well, so let's require a little less - extra_att_needed -= 2 - elif has_melee(state, player): + if stick_bool: + equipment.remove("Sword") + equipment.append("Stick") # may revise this later based on feedback extra_att_needed += 3 extra_def_needed += 2 + # this is for when it changes over to the magic-only state if it needs to later + extra_mp_needed += 4 else: return False - else: - sword_bool = True + # just increase the stat requirement, we'll check for shield when calculating defense elif item == "Shield": - if not state.has("Shield", player): - extra_def_needed += 2 + equipment.remove("Shield") + extra_def_needed += 2 + elif item == "Laurels": if not state.has("Hero's Laurels", player): - # these are entirely based on vibes - extra_att_needed += 2 - extra_def_needed += 3 + # require Laurels for the Heir + return False + elif item == "Magic": if not has_magic: + equipment.remove("Magic") extra_att_needed += 2 extra_def_needed += 2 - extra_mp_needed -= 16 + extra_mp_needed -= 32 + modified_stats = AreaStats(data.att_level + extra_att_needed, data.def_level + extra_def_needed, data.potion_level, - data.hp_level, data.sp_level, data.mp_level + extra_mp_needed, data.potion_count) - if not has_required_stats(modified_stats, state, player): + data.hp_level, data.sp_level, data.mp_level + extra_mp_needed, data.potion_count, + equipment, data.is_boss) + if has_required_stats(modified_stats, state, player): + return True + else: # we may need to check if you would have the required stats if you were missing a weapon - # it's kinda janky, but these only get hit in less than once per 100 generations, so whatever - if sword_bool and "Sword" in data.equipment and "Magic" in data.equipment: - # we need to check if you would have the required stats if you didn't have melee - equip_list = [item for item in data.equipment if item != "Sword"] - more_modified_stats = AreaStats(data.att_level - 16, data.def_level, data.potion_level, - data.hp_level, data.sp_level, data.mp_level + 4, data.potion_count, - equip_list) + if sword_bool and "Sword" in equipment and has_magic: + # we need to check if you would have the required stats if you didn't have the sword + equip_list = [item for item in equipment if item != "Sword"] + if "Magic" not in equip_list: + equip_list.append("Magic") + more_modified_stats = AreaStats(modified_stats.att_level - 32, modified_stats.def_level, + modified_stats.potion_level, modified_stats.hp_level, + modified_stats.sp_level, modified_stats.mp_level + 4, + modified_stats.potion_count, equip_list, data.is_boss) if check_combat_reqs("none", state, player, more_modified_stats): return True - # and we need to check if you would have the required stats if you didn't have magic - equip_list = [item for item in data.equipment if item != "Magic"] - more_modified_stats = AreaStats(data.att_level + 2, data.def_level + 2, data.potion_level, - data.hp_level, data.sp_level, data.mp_level - 16, data.potion_count, - equip_list) - if check_combat_reqs("none", state, player, more_modified_stats): - return True - return False - - elif stick_bool and "Stick" in data.equipment and "Magic" in data.equipment: + elif stick_bool and "Stick" in equipment and has_magic: # we need to check if you would have the required stats if you didn't have the stick - equip_list = [item for item in data.equipment if item != "Stick"] - more_modified_stats = AreaStats(data.att_level - 16, data.def_level, data.potion_level, - data.hp_level, data.sp_level, data.mp_level + 4, data.potion_count, - equip_list) + equip_list = [item for item in equipment if item != "Stick"] + if "Magic" not in equip_list: + equip_list.append("Magic") + more_modified_stats = AreaStats(modified_stats.att_level - 32, modified_stats.def_level, + modified_stats.potion_level, modified_stats.hp_level, + modified_stats.sp_level, modified_stats.mp_level + 2, + modified_stats.potion_count, equip_list, data.is_boss) if check_combat_reqs("none", state, player, more_modified_stats): return True - return False else: return False - return True + return False # check if you have the required stats, and the money to afford them @@ -203,72 +208,63 @@ def check_combat_reqs(area_name: str, state: CollectionState, player: int, alt_d # but that's fine -- it's already pretty generous to begin with def has_required_stats(data: AreaStats, state: CollectionState, player: int) -> bool: money_required = 0 - player_att = 0 + att_required = data.att_level + player_att, att_offerings = get_att_level(state, player) - # check if we actually need the stat before checking state - if data.att_level > 1: - player_att, att_offerings = get_att_level(state, player) - if player_att < data.att_level: - return False + # if you have 2 more attack than needed, we can forego needing mp + if data.mp_level > 1 and "Magic" in data.equipment: + if player_att < data.att_level + 2: + player_mp, mp_offerings = get_mp_level(state, player) + if player_mp < data.mp_level: + return False + else: + extra_mp = player_mp - data.mp_level + paid_mp = max(0, mp_offerings - extra_mp) + # mp costs 300 for the first, +50 for each additional + money_per_mp = 300 + for _ in range(paid_mp): + money_required += money_per_mp + money_per_mp += 50 else: - extra_att = player_att - data.att_level - paid_att = max(0, att_offerings - extra_att) - # attack upgrades cost 100 for the first, +50 for each additional - money_per_att = 100 - for _ in range(paid_att): - money_required += money_per_att - money_per_att += 50 + att_required += 2 + + if player_att < att_required: + return False + else: + extra_att = player_att - att_required + paid_att = max(0, att_offerings - extra_att) + # attack upgrades cost 100 for the first, +50 for each additional + money_per_att = 100 + for _ in range(paid_att): + money_required += money_per_att + money_per_att += 50 # adding defense and sp together since they accomplish similar things: making you take less damage if data.def_level + data.sp_level > 2: player_def, def_offerings = get_def_level(state, player) player_sp, sp_offerings = get_sp_level(state, player) - if player_def + player_sp < data.def_level + data.sp_level: + req_stats = data.def_level + data.sp_level + if player_def + player_sp < req_stats: return False else: free_def = player_def - def_offerings free_sp = player_sp - sp_offerings - paid_stats = data.def_level + data.sp_level - free_def - free_sp - sp_to_buy = 0 - - if paid_stats <= 0: - # if you don't have to pay for any stats, you don't need money for these upgrades - def_to_buy = 0 - elif paid_stats <= def_offerings: - # get the amount needed to buy these def offerings - def_to_buy = paid_stats + if free_sp + free_def >= req_stats: + # you don't need to buy upgrades + pass else: - def_to_buy = def_offerings - sp_to_buy = max(0, paid_stats - def_offerings) - - # if you have to buy more than 3 def, it's cheaper to buy 1 extra sp - if def_to_buy > 3 and sp_offerings > 0: - def_to_buy -= 1 - sp_to_buy += 1 - # def costs 100 for the first, +50 for each additional - money_per_def = 100 - for _ in range(def_to_buy): - money_required += money_per_def - money_per_def += 50 - # sp costs 200 for the first, +200 for each additional - money_per_sp = 200 - for _ in range(sp_to_buy): - money_required += money_per_sp - money_per_sp += 200 - - # if you have 2 more attack than needed, we can forego needing mp - if data.mp_level > 1 and player_att < data.att_level + 2: - player_mp, mp_offerings = get_mp_level(state, player) - if player_mp < data.mp_level: - return False - else: - extra_mp = player_mp - data.mp_level - paid_mp = max(0, mp_offerings - extra_mp) - # mp costs 300 for the first, +50 for each additional - money_per_mp = 300 - for _ in range(paid_mp): - money_required += money_per_mp - money_per_mp += 50 + # we need to pick the cheapest option that gets us above the stats we need + # first number is def, second number is sp + upgrade_options: set[tuple[int, int]] = set() + stats_to_buy = req_stats - free_def - free_sp + for paid_def in range(0, min(def_offerings + 1, stats_to_buy + 1)): + sp_required = stats_to_buy - paid_def + if sp_offerings >= sp_required: + if sp_required < 0: + break + upgrade_options.add((paid_def, stats_to_buy - paid_def)) + costs = [calc_def_sp_cost(defense, sp) for defense, sp in upgrade_options] + money_required += min(costs) req_effective_hp = calc_effective_hp(data.hp_level, data.potion_level, data.potion_count) player_potion, potion_offerings = get_potion_level(state, player) @@ -279,53 +275,30 @@ def has_required_stats(data: AreaStats, state: CollectionState, player: int) -> return False else: # need a way to determine which of potion offerings or hp offerings you can reduce - # your level if you didn't pay for offerings free_potion = player_potion - potion_offerings free_hp = player_hp - hp_offerings - paid_hp_count = 0 - paid_potion_count = 0 if calc_effective_hp(free_hp, free_potion, player_potion_count) >= req_effective_hp: # you don't need to buy upgrades pass - # if you have no potions, or no potion upgrades, you only need to check your hp upgrades - elif player_potion_count == 0 or potion_offerings == 0: - # check if you have enough hp at each paid hp offering - for i in range(hp_offerings): - paid_hp_count = i + 1 - if calc_effective_hp(paid_hp_count, 0, player_potion_count) > req_effective_hp: - break else: - for i in range(potion_offerings): - paid_potion_count = i + 1 - if calc_effective_hp(free_hp, free_potion + paid_potion_count, player_potion_count) > req_effective_hp: - break - for j in range(hp_offerings): - paid_hp_count = j + 1 - if (calc_effective_hp(free_hp + paid_hp_count, free_potion + paid_potion_count, player_potion_count) - > req_effective_hp): + # we need to pick the cheapest option that gets us above the amount of effective HP we need + # first number is hp, second number is potion + upgrade_options: set[tuple[int, int]] = set() + # filter out exclusively worse options + lowest_hp_added = hp_offerings + 1 + for paid_potion in range(0, potion_offerings + 1): + # check quantities of hp offerings for each potion offering + for paid_hp in range(0, lowest_hp_added): + if (calc_effective_hp(free_hp + paid_hp, free_potion + paid_potion, player_potion_count) + >= req_effective_hp): + upgrade_options.add((paid_hp, paid_potion)) + lowest_hp_added = paid_hp break - # hp costs 200 for the first, +50 for each additional - money_per_hp = 200 - for _ in range(paid_hp_count): - money_required += money_per_hp - money_per_hp += 50 - # potion costs 100 for the first, 300 for the second, 1,000 for the third, and +200 for each additional - # currently we assume you will not buy past the second potion upgrade, but we might change our minds later - money_per_potion = 100 - for _ in range(paid_potion_count): - money_required += money_per_potion - if money_per_potion == 100: - money_per_potion = 300 - elif money_per_potion == 300: - money_per_potion = 1000 - else: - money_per_potion += 200 + costs = [calc_hp_potion_cost(hp, potion) for hp, potion in upgrade_options] + money_required += min(costs) - if money_required > get_money_count(state, player): - return False - - return True + return get_money_count(state, player) >= money_required # returns a tuple of your max attack level, the number of attack offerings @@ -336,7 +309,8 @@ def get_att_level(state: CollectionState, player: int) -> Tuple[int, int]: if sword_level >= 3: att_upgrades += min(2, sword_level - 2) # attack falls off, can just cap it at 8 for simplicity - return min(8, 1 + att_offerings + att_upgrades), att_offerings + return (min(8, 1 + att_offerings + att_upgrades) + + (1 if state.has("Hero's Laurels", player) else 0), att_offerings) # returns a tuple of your max defense level, the number of defense offerings @@ -344,7 +318,9 @@ def get_def_level(state: CollectionState, player: int) -> Tuple[int, int]: def_offerings = state.count("DEF Offering", player) # defense falls off, can just cap it at 8 for simplicity return (min(8, 1 + def_offerings - + state.count_from_list({"Hero Relic - DEF", "Secret Legend", "Phonomath"}, player)), + + state.count_from_list({"Hero Relic - DEF", "Secret Legend", "Phonomath"}, player)) + + (2 if state.has("Shield", player) else 0) + + (2 if state.has("Hero's Laurels", player) else 0), def_offerings) @@ -408,6 +384,46 @@ def get_money_count(state: CollectionState, player: int) -> int: return money +def calc_hp_potion_cost(hp_upgrades: int, potion_upgrades: int) -> int: + money = 0 + + # hp costs 200 for the first, +50 for each additional + money_per_hp = 200 + for _ in range(hp_upgrades): + money += money_per_hp + money_per_hp += 50 + + # potion costs 100 for the first, 300 for the second, 1,000 for the third, and +200 for each additional + # currently we assume you will not buy past the second potion upgrade, but we might change our minds later + money_per_potion = 100 + for _ in range(potion_upgrades): + money += money_per_potion + if money_per_potion == 100: + money_per_potion = 300 + elif money_per_potion == 300: + money_per_potion = 1000 + else: + money_per_potion += 200 + + return money + + +def calc_def_sp_cost(def_upgrades: int, sp_upgrades: int) -> int: + money = 0 + + money_per_def = 100 + for _ in range(def_upgrades): + money += money_per_def + money_per_def += 50 + + money_per_sp = 200 + for _ in range(sp_upgrades): + money += money_per_sp + money_per_sp += 200 + + return money + + class TunicState(LogicMixin): tunic_need_to_reset_combat_from_collect: Dict[int, bool] tunic_need_to_reset_combat_from_remove: Dict[int, bool] @@ -420,3 +436,5 @@ class TunicState(LogicMixin): self.tunic_need_to_reset_combat_from_remove = defaultdict(lambda: False) # the per-player, per-area state of combat checking -- unchecked, failed, or succeeded self.tunic_area_combat_state = defaultdict(lambda: defaultdict(lambda: CombatState.unchecked)) + # a copy_mixin was intentionally excluded because the empty state from init_mixin + # will always be appropriate for recalculating the logic cache diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 1dc06d586d..f1a428cce1 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -629,14 +629,16 @@ tunic_er_regions: Dict[str, RegionInfo] = { "Beneath the Well Back": RegionInfo("Sewer"), # the back two portals, and all 4 upper chests "West Garden before Terry": RegionInfo("Archipelagos Redux"), # the lower entry point, near hero grave "West Garden after Terry": RegionInfo("Archipelagos Redux"), # after Terry, up until next chompignons + "West Garden West Combat": RegionInfo("Archipelagos Redux"), # for grass rando basically "West Garden at Dagger House": RegionInfo("Archipelagos Redux"), # just outside magic dagger house - "West Garden South Checkpoint": RegionInfo("Archipelagos Redux"), + "West Garden South Checkpoint": RegionInfo("Archipelagos Redux"), # the checkpoint and the blue lines area "Magic Dagger House": RegionInfo("archipelagos_house", dead_end=DeadEnd.all_cats), - "West Garden Portal": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted, outlet_region="West Garden by Portal"), + "West Garden Portal": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted, + outlet_region="West Garden by Portal"), "West Garden by Portal": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted), "West Garden Portal Item": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted), "West Garden Laurels Exit Region": RegionInfo("Archipelagos Redux"), - "West Garden before Boss": RegionInfo("Archipelagos Redux"), # main west garden + "West Garden before Boss": RegionInfo("Archipelagos Redux"), # up the ladder before garden knight "West Garden after Boss": RegionInfo("Archipelagos Redux"), "West Garden Hero's Grave Region": RegionInfo("Archipelagos Redux", outlet_region="West Garden before Terry"), "Ruined Atoll": RegionInfo("Atoll Redux"), @@ -1165,8 +1167,10 @@ traversal_requirements: Dict[str, Dict[str, List[List[str]]]] = { "West Garden after Terry": { "West Garden before Terry": [], - "West Garden South Checkpoint": + "West Garden West Combat": [], + "West Garden South Checkpoint": + [["Hyperdash"]], "West Garden Laurels Exit Region": [["LS1"]], }, @@ -1176,6 +1180,8 @@ traversal_requirements: Dict[str, Dict[str, List[List[str]]]] = { "West Garden at Dagger House": [], "West Garden after Terry": + [["Hyperdash"]], + "West Garden West Combat": [], }, "West Garden before Boss": { diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 6e9ae551db..1d3ede21a4 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1,12 +1,13 @@ from typing import Dict, FrozenSet, Tuple, TYPE_CHECKING from worlds.generic.Rules import set_rule, add_rule, forbid_item +from BaseClasses import Region, CollectionState from .options import IceGrappling, LadderStorage, CombatLogic from .rules import (has_ability, has_sword, has_melee, has_ice_grapple_logic, has_lantern, has_mask, can_ladder_storage, laurels_zip, bomb_walls) from .er_data import Portal, get_portal_outlet_region from .ladder_storage_data import ow_ladder_groups, region_ladders, easy_ls, medium_ls, hard_ls from .combat_logic import has_combat_reqs -from BaseClasses import Region, CollectionState +from .grass import set_grass_location_rules if TYPE_CHECKING: from . import TunicWorld @@ -555,7 +556,6 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ regions["Dark Tomb Upper"].connect( connecting_region=regions["Dark Tomb Entry Point"]) - # ice grapple through the wall, get the little secret sound to trigger regions["Dark Tomb Upper"].connect( connecting_region=regions["Dark Tomb Main"], rule=lambda state: has_ladder("Ladder in Dark Tomb", state, world) @@ -577,11 +577,24 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ wg_after_to_before_terry = regions["West Garden after Terry"].connect( connecting_region=regions["West Garden before Terry"]) - regions["West Garden after Terry"].connect( - connecting_region=regions["West Garden South Checkpoint"]) - wg_checkpoint_to_after_terry = regions["West Garden South Checkpoint"].connect( + wg_after_terry_to_west_combat = regions["West Garden after Terry"].connect( + connecting_region=regions["West Garden West Combat"]) + regions["West Garden West Combat"].connect( connecting_region=regions["West Garden after Terry"]) + wg_checkpoint_to_west_combat = regions["West Garden South Checkpoint"].connect( + connecting_region=regions["West Garden West Combat"]) + regions["West Garden West Combat"].connect( + connecting_region=regions["West Garden South Checkpoint"]) + + # if not laurels, it goes through the west combat region instead + regions["West Garden after Terry"].connect( + connecting_region=regions["West Garden South Checkpoint"], + rule=lambda state: state.has(laurels, player)) + regions["West Garden South Checkpoint"].connect( + connecting_region=regions["West Garden after Terry"], + rule=lambda state: state.has(laurels, player)) + wg_checkpoint_to_dagger = regions["West Garden South Checkpoint"].connect( connecting_region=regions["West Garden at Dagger House"]) regions["West Garden at Dagger House"].connect( @@ -977,7 +990,9 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ rule=lambda state: has_ice_grapple_logic(True, IceGrappling.option_hard, state, world)) monastery_front_to_back = regions["Monastery Front"].connect( - connecting_region=regions["Monastery Back"]) + connecting_region=regions["Monastery Back"], + rule=lambda state: has_sword(state, player) or state.has(fire_wand, player) + or laurels_zip(state, world)) # laurels through the gate, no setup needed regions["Monastery Back"].connect( connecting_region=regions["Monastery Front"], @@ -1373,9 +1388,9 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ # need to fight through the rudelings and turret, or just laurels from near the windmill set_rule(ow_to_well_entry, lambda state: state.has(laurels, player) - or has_combat_reqs("East Forest", state, player)) + or has_combat_reqs("Before Well", state, player)) set_rule(ow_tunnel_beach, - lambda state: has_combat_reqs("East Forest", state, player)) + lambda state: has_combat_reqs("Before Well", state, player)) add_rule(atoll_statue, lambda state: has_combat_reqs("Ruined Atoll", state, player)) @@ -1402,11 +1417,15 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ set_rule(wg_after_to_before_terry, lambda state: state.has_any({laurels, ice_dagger}, player) or has_combat_reqs("West Garden", state, player)) - # laurels through, probably to the checkpoint, or just fight - set_rule(wg_checkpoint_to_after_terry, - lambda state: state.has(laurels, player) or has_combat_reqs("West Garden", state, player)) - set_rule(wg_checkpoint_to_before_boss, + + set_rule(wg_after_terry_to_west_combat, lambda state: has_combat_reqs("West Garden", state, player)) + set_rule(wg_checkpoint_to_west_combat, + lambda state: has_combat_reqs("West Garden", state, player)) + + # maybe a little too generous? probably fine though + set_rule(wg_checkpoint_to_before_boss, + lambda state: state.has(laurels, player) or has_combat_reqs("West Garden", state, player)) add_rule(btv_front_to_main, lambda state: has_combat_reqs("Beneath the Vault", state, player)) @@ -1450,12 +1469,12 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ set_rule(cath_entry_to_elev, lambda state: options.entrance_rando or has_ice_grapple_logic(False, IceGrappling.option_medium, state, world) - or (has_ability(prayer, state, world) and has_combat_reqs("Cathedral", state, player))) + or (has_ability(prayer, state, world) and has_combat_reqs("Swamp", state, player))) set_rule(cath_entry_to_main, - lambda state: has_combat_reqs("Cathedral", state, player)) + lambda state: has_combat_reqs("Swamp", state, player)) set_rule(cath_elev_to_main, - lambda state: has_combat_reqs("Cathedral", state, player)) + lambda state: has_combat_reqs("Swamp", state, player)) # for spots where you can go into and come out of an entrance to reset enemy aggro if world.options.entrance_rando: @@ -1528,6 +1547,9 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ def set_er_location_rules(world: "TunicWorld") -> None: player = world.player + if world.options.grass_randomizer: + set_grass_location_rules(world) + forbid_item(world.get_location("Secret Gathering Place - 20 Fairy Reward"), fairies, player) # Ability Shuffle Exclusive Rules @@ -1675,7 +1697,7 @@ def set_er_location_rules(world: "TunicWorld") -> None: # Beneath the Vault set_rule(world.get_location("Beneath the Fortress - Bridge"), - lambda state: has_melee(state, player) or state.has_any({laurels, fire_wand}, player)) + lambda state: has_melee(state, player) or state.has_any((laurels, fire_wand, ice_dagger, gun), player)) # Quarry set_rule(world.get_location("Quarry - [Central] Above Ladder Dash Chest"), @@ -1812,13 +1834,13 @@ def set_er_location_rules(world: "TunicWorld") -> None: if world.options.combat_logic == CombatLogic.option_on: combat_logic_to_loc("Overworld - [Northeast] Flowers Holy Cross", "Garden Knight") combat_logic_to_loc("Overworld - [Northwest] Chest Near Quarry Gate", "Before Well", dagger=True) - combat_logic_to_loc("Overworld - [Northeast] Chest Above Patrol Cave", "Garden Knight", dagger=True) + combat_logic_to_loc("Overworld - [Northeast] Chest Above Patrol Cave", "West Garden", dagger=True) combat_logic_to_loc("Overworld - [Southwest] West Beach Guarded By Turret", "Overworld", dagger=True) combat_logic_to_loc("Overworld - [Southwest] West Beach Guarded By Turret 2", "Overworld") - combat_logic_to_loc("Overworld - [Southwest] Bombable Wall Near Fountain", "East Forest", dagger=True) - combat_logic_to_loc("Overworld - [Southwest] Fountain Holy Cross", "East Forest", dagger=True) - combat_logic_to_loc("Overworld - [Southwest] South Chest Near Guard", "East Forest", dagger=True) - combat_logic_to_loc("Overworld - [Southwest] Tunnel Guarded By Turret", "East Forest", dagger=True) + combat_logic_to_loc("Overworld - [Southwest] Bombable Wall Near Fountain", "Before Well", dagger=True) + combat_logic_to_loc("Overworld - [Southwest] Fountain Holy Cross", "Before Well", dagger=True) + combat_logic_to_loc("Overworld - [Southwest] South Chest Near Guard", "Before Well", dagger=True) + combat_logic_to_loc("Overworld - [Southwest] Tunnel Guarded By Turret", "Before Well", dagger=True) combat_logic_to_loc("Overworld - [Northwest] Chest Near Turret", "Before Well") add_rule(world.get_location("Hourglass Cave - Hourglass Chest"), @@ -1852,6 +1874,8 @@ def set_er_location_rules(world: "TunicWorld") -> None: combat_logic_to_loc("West Garden - [Central Lowlands] Chest Beneath Faeries", "West Garden") combat_logic_to_loc("West Garden - [Central Lowlands] Chest Beneath Save Point", "West Garden") combat_logic_to_loc("West Garden - [West Highlands] Upper Left Walkway", "West Garden") + combat_logic_to_loc("West Garden - [Central Highlands] Holy Cross (Blue Lines)", "West Garden") + combat_logic_to_loc("West Garden - [Central Highlands] Behind Guard Captain", "West Garden") # with combat logic on, I presume the player will want to be able to see to avoid the spiders set_rule(world.get_location("Beneath the Fortress - Bridge"), @@ -1905,4 +1929,4 @@ def set_er_location_rules(world: "TunicWorld") -> None: # zip through the rubble to sneakily grab this chest, or just fight to it add_rule(world.get_location("Cathedral - [1F] Near Spikes"), - lambda state: laurels_zip(state, world) or has_combat_reqs("Cathedral", state, player)) + lambda state: laurels_zip(state, world) or has_combat_reqs("Swamp", state, player)) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index aa5833b4db..4cd0f49ddf 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -1,6 +1,6 @@ from typing import Dict, List, Set, Tuple, TYPE_CHECKING from BaseClasses import Region, ItemClassification, Item, Location -from .locations import location_table +from .locations import all_locations from .er_data import Portal, portal_mapping, traversal_requirements, DeadEnd, RegionInfo from .er_rules import set_er_region_rules from Options import PlandoConnection @@ -53,8 +53,8 @@ def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]: set_er_region_rules(world, regions, portal_pairs) - for location_name, location_id in world.location_name_to_id.items(): - region = regions[location_table[location_name].er_region] + for location_name, location_id in world.player_location_table.items(): + region = regions[all_locations[location_name].er_region] location = TunicERLocation(world.player, location_name, location_id, region) region.locations.append(location) @@ -177,7 +177,7 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal logic_tricks: Tuple[bool, int, int] = (laurels_zips, ice_grappling, ladder_storage) # marking that you don't immediately have laurels - if laurels_location == "10_fairies" and not hasattr(world.multiworld, "re_gen_passthrough"): + if laurels_location == "10_fairies" and not world.using_ut: has_laurels = False shop_count = 6 @@ -191,9 +191,8 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal break # If using Universal Tracker, restore portal_map. Could be cleaner, but it does not matter for UT even a little bit - if hasattr(world.multiworld, "re_gen_passthrough"): - if "TUNIC" in world.multiworld.re_gen_passthrough: - portal_map = portal_mapping.copy() + if world.using_ut: + portal_map = portal_mapping.copy() # create separate lists for dead ends and non-dead ends for portal in portal_map: @@ -232,25 +231,24 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal plando_connections = world.seed_groups[world.options.entrance_rando.value]["plando"] # universal tracker support stuff, don't need to care about region dependency - if hasattr(world.multiworld, "re_gen_passthrough"): - if "TUNIC" in world.multiworld.re_gen_passthrough: - plando_connections.clear() - # universal tracker stuff, won't do anything in normal gen - for portal1, portal2 in world.multiworld.re_gen_passthrough["TUNIC"]["Entrance Rando"].items(): - portal_name1 = "" - portal_name2 = "" + if world.using_ut: + plando_connections.clear() + # universal tracker stuff, won't do anything in normal gen + for portal1, portal2 in world.passthrough["Entrance Rando"].items(): + portal_name1 = "" + portal_name2 = "" - for portal in portal_mapping: - if portal.scene_destination() == portal1: - portal_name1 = portal.name - # connected_regions.update(add_dependent_regions(portal.region, logic_rules)) - if portal.scene_destination() == portal2: - portal_name2 = portal.name - # connected_regions.update(add_dependent_regions(portal.region, logic_rules)) - # shops have special handling - if not portal_name2 and portal2 == "Shop, Previous Region_": - portal_name2 = "Shop Portal" - plando_connections.append(PlandoConnection(portal_name1, portal_name2, "both")) + for portal in portal_mapping: + if portal.scene_destination() == portal1: + portal_name1 = portal.name + # connected_regions.update(add_dependent_regions(portal.region, logic_rules)) + if portal.scene_destination() == portal2: + portal_name2 = portal.name + # connected_regions.update(add_dependent_regions(portal.region, logic_rules)) + # shops have special handling + if not portal_name2 and portal2 == "Shop, Previous Region_": + portal_name2 = "Shop Portal" + plando_connections.append(PlandoConnection(portal_name1, portal_name2, "both")) non_dead_end_regions = set() for region_name, region_info in world.er_regions.items(): @@ -362,7 +360,7 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal # if we have plando connections, our connected regions may change somewhat connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_tricks) - if fixed_shop and not hasattr(world.multiworld, "re_gen_passthrough"): + if fixed_shop and not world.using_ut: portal1 = None for portal in two_plus: if portal.scene_destination() == "Overworld Redux, Windmill_": @@ -392,7 +390,7 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal fail_count = 0 while len(connected_regions) < len(non_dead_end_regions): # if this is universal tracker, just break immediately and move on - if hasattr(world.multiworld, "re_gen_passthrough"): + if world.using_ut: break # if the connected regions length stays unchanged for too long, it's stuck in a loop # should, hopefully, only ever occur if someone plandos connections poorly @@ -445,9 +443,8 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal random_object.shuffle(two_plus) # for universal tracker, we want to skip shop gen - if hasattr(world.multiworld, "re_gen_passthrough"): - if "TUNIC" in world.multiworld.re_gen_passthrough: - shop_count = 0 + if world.using_ut: + shop_count = 0 for i in range(shop_count): portal1 = two_plus.pop() @@ -462,7 +459,7 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal # connect dead ends to random non-dead ends # none of the key events are in dead ends, so we don't need to do gate_before_switch while len(dead_ends) > 0: - if hasattr(world.multiworld, "re_gen_passthrough"): + if world.using_ut: break portal1 = two_plus.pop() portal2 = dead_ends.pop() @@ -470,7 +467,7 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal # then randomly connect the remaining portals to each other # every region is accessible, so gate_before_switch is not necessary while len(two_plus) > 1: - if hasattr(world.multiworld, "re_gen_passthrough"): + if world.using_ut: break portal1 = two_plus.pop() portal2 = two_plus.pop() diff --git a/worlds/tunic/grass.py b/worlds/tunic/grass.py new file mode 100644 index 0000000000..eb688199dc --- /dev/null +++ b/worlds/tunic/grass.py @@ -0,0 +1,7946 @@ +from typing import Dict, NamedTuple, Optional, TYPE_CHECKING, Set + +from BaseClasses import CollectionState +from worlds.generic.Rules import set_rule, add_rule +from .rules import has_sword, has_melee +if TYPE_CHECKING: + from . import TunicWorld + + +class TunicLocationData(NamedTuple): + region: str + er_region: str # entrance rando region + location_group: Optional[str] = None + + +location_base_id = 509342400 + +grass_location_table: Dict[str, TunicLocationData] = { + "Overworld - Overworld Grass (576) (7.0, 4.0, -223.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (572) (6.0, 4.0, -223.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (574) (7.0, 4.0, -224.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (568) (5.0, 4.0, -223.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (562) (4.0, 4.0, -223.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (570) (6.0, 4.0, -224.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (569) (5.0, 4.0, -225.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (566) (5.0, 4.0, -224.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (563) (4.0, 4.0, -224.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (564) (4.0, 4.0, -225.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (573) (6.0, 4.0, -225.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (577) (7.0, 4.0, -225.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (578) (3.0, 4.0, -223.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (575) (2.0, 4.0, -223.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (579) (3.0, 4.0, -224.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (571) (2.0, 4.0, -224.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (583) (-2.4, 4.0, -224.4)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (580) (-3.4, 4.0, -224.4)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (581) (-2.4, 4.0, -225.4)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (582) (-3.4, 4.0, -225.4)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (586) (-3.4, 4.0, -219.6)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (584) (-3.4, 4.0, -218.6)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (585) (-2.4, 4.0, -219.6)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (587) (-2.4, 4.0, -218.6)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (615) (13.0, 8.0, -217.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (616) (14.0, 8.0, -217.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (614) (13.0, 8.0, -216.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (613) (14.0, 8.0, -216.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (142) (13.0, 8.0, -224.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (141) (13.0, 8.0, -226.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (140) (13.0, 8.0, -228.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (591) (-8.0, 12.0, -212.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (590) (-8.0, 12.0, -212.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (589) (-9.0, 12.0, -212.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (588) (-9.0, 12.0, -213.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (592) (-8.0, 12.0, -213.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (606) (8.0, 12.0, -208.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (607) (8.0, 12.0, -209.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (608) (9.0, 12.0, -208.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (605) (9.0, 12.0, -209.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (600) (12.0, 12.0, -199.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (598) (12.0, 12.0, -200.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (599) (13.0, 12.0, -199.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (597) (13.0, 12.0, -200.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (602) (12.0, 12.0, -198.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (603) (13.0, 12.0, -197.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (601) (13.0, 12.0, -198.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (604) (12.0, 12.0, -197.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (593) (8.0, 12.0, -190.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (596) (9.0, 12.0, -190.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (594) (9.0, 12.0, -189.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (595) (8.0, 12.0, -189.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (612) (-8.0, 12.0, -188.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (609) (-8.0, 12.0, -189.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (610) (-9.0, 12.0, -188.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (611) (-9.0, 12.0, -189.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (895) (-6.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (894) (-6.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (891) (-6.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (892) (-7.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (889) (-7.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (893) (-7.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (899) (-7.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (905) (-8.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (890) (-6.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (906) (-9.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (907) (-10.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (908) (-10.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (898) (-15.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (897) (-15.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (909) (-14.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (887) (-15.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (900) (-16.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (888) (-16.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (896) (-16.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (901) (-17.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (886) (-16.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (904) (-17.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (902) (-18.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (903) (-18.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (334) (-20.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (322) (-20.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (320) (-20.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (321) (-21.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (332) (-21.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (323) (-21.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (337) (-22.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (336) (-22.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (339) (-23.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (338) (-23.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (335) (-20.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (333) (-21.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (349) (-21.0, 12.0, -141.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (344) (-22.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (346) (-23.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (345) (-22.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (347) (-23.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (340) (-20.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (343) (-21.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (342) (-21.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (356) (-21.0, 12.0, -144.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (353) (-19.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (351) (-20.0, 12.0, -141.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (358) (-20.0, 12.0, -144.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (341) (-20.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (348) (-21.0, 12.0, -140.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (354) (-18.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (352) (-19.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (350) (-20.0, 12.0, -140.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (359) (-20.0, 12.0, -145.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (357) (-21.0, 12.0, -145.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (355) (-18.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (131) (13.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (130) (13.0, 12.0, -141.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (129) (15.0, 12.0, -141.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (372) (14.5, 12.0, -139.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (128) (13.0, 12.0, -139.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (375) (14.5, 12.0, -138.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (373) (15.5, 12.0, -139.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (379) (16.5, 12.0, -138.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (376) (16.5, 12.0, -139.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (374) (15.5, 12.0, -138.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (369) (15.5, 12.0, -137.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (368) (14.5, 12.0, -137.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (366) (13.5, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (365) (13.5, 12.0, -137.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (371) (14.5, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (364) (12.5, 12.0, -137.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (367) (12.5, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (361) (13.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (127) (15.0, 12.0, -135.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (370) (15.5, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (362) (13.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (363) (12.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (360) (12.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (388) (16.5, 12.0, -137.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (389) (17.5, 12.0, -137.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (378) (17.5, 12.0, -138.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (377) (17.5, 12.0, -139.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (391) (16.5, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (392) (18.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (390) (17.5, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (385) (17.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (384) (16.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (386) (17.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (387) (16.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (382) (17.5, 12.0, -140.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (383) (16.5, 12.0, -140.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (381) (17.5, 12.0, -141.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (395) (18.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (394) (19.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (285) (19.5, 12.0, -132.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (279) (19.5, 12.0, -133.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (124) (18.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (393) (19.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (397) (20.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (282) (20.5, 12.0, -133.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (284) (20.5, 12.0, -132.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (289) (21.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (287) (21.5, 12.0, -133.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (281) (22.5, 12.0, -132.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (278) (22.5, 12.0, -133.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (286) (21.5, 12.0, -132.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (267) (21.5, 12.0, -131.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (126) (20.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (125) (18.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (283) (22.5, 12.0, -134.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (277) (23.5, 12.0, -132.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (276) (23.5, 12.0, -133.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (271) (22.5, 12.0, -131.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (269) (24.5, 12.0, -132.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (268) (24.5, 12.0, -133.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (266) (24.5, 12.0, -131.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (270) (24.5, 12.0, -130.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (275) (23.5, 12.0, -131.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (274) (23.5, 12.0, -130.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (272) (22.5, 12.0, -130.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (273) (21.5, 12.0, -130.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (396) (20.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (288) (21.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (280) (22.5, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (380) (16.5, 12.0, -141.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (262) (44.0, 12.0, -145.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (264) (45.0, 12.0, -144.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (263) (45.0, 12.0, -145.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (255) (39.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (256) (39.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (251) (39.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (254) (38.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (252) (38.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (257) (38.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (261) (40.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (258) (40.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (250) (39.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (260) (41.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (259) (41.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (253) (38.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (106) (47.0, 12.0, -147.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (31) (48.0, 12.0, -153.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (249) (50.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (245) (50.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (247) (50.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (242) (50.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (246) (51.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (244) (51.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (248) (51.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (17) (53.0, 12.0, -153.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (16) (53.0, 12.0, -151.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (243) (51.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (30) (51.0, 12.0, -149.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (32) (55.0, 12.0, -153.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (28) (55.0, 12.0, -149.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (13) (53.0, 12.0, -149.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (11) (53.0, 12.0, -147.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (27) (55.0, 12.0, -147.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (29) (51.0, 12.0, -147.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (33) (55.0, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (876) (68.0, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (878) (69.0, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (877) (69.0, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (879) (70.0, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (880) (70.0, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (873) (67.0, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (875) (68.0, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (874) (67.0, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (184) (69.5, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (183) (71.5, 12.0, -155.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (182) (71.5, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (871) (74.0, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (185) (73.5, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (870) (73.0, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (869) (73.0, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (872) (74.0, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (195) (65.5, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (950) (75.0, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (951) (75.0, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (953) (76.0, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (952) (76.0, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (194) (73.5, 12.0, -150.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (954) (76.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (189) (75.5, 12.0, -148.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (193) (73.5, 12.0, -148.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (955) (76.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (867) (78.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (866) (77.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (861) (79.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (862) (79.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (868) (78.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (865) (77.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (964) (78.5, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (965) (78.5, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (967) (79.5, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (966) (79.5, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (960) (80.5, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (962) (81.5, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (956) (80.5, 12.0, -158.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (961) (80.5, 12.0, -157.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (963) (81.5, 12.0, -156.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (957) (80.5, 12.0, -159.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (959) (81.5, 12.0, -158.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (958) (81.5, 12.0, -159.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (930) (84.5, 12.0, -158.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (933) (85.5, 12.0, -158.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (913) (86.5, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (40) (87.0, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (39) (87.0, 12.0, -159.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (41) (89.0, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (914) (87.5, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (48) (89.0, 12.0, -155.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (915) (87.5, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (912) (86.5, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (42) (91.0, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (47) (91.0, 12.0, -155.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (940) (89.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (938) (88.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (939) (88.5, 12.0, -153.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (941) (89.5, 12.0, -152.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (943) (88.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (944) (89.5, 12.0, -151.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (945) (89.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (942) (88.5, 12.0, -150.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (948) (89.5, 12.0, -149.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (949) (89.5, 12.0, -148.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (947) (88.5, 12.0, -149.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (946) (88.5, 12.0, -148.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (934) (94.5, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (85) (93.0, 12.0, -155.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (43) (93.0, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (935) (94.5, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (936) (95.5, 12.0, -155.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (84) (95.0, 12.0, -157.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (937) (95.5, 12.0, -154.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (932) (85.5, 12.0, -159.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (928) (85.5, 12.0, -161.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (929) (85.5, 12.0, -160.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (916) (84.5, 12.0, -160.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (931) (84.5, 12.0, -159.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (38) (87.0, 12.0, -161.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (310) (86.5, 12.0, -162.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (917) (84.5, 12.0, -161.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (313) (87.5, 12.0, -162.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (311) (86.5, 12.0, -163.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (312) (87.5, 12.0, -163.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (980) (86.5, 12.0, -170.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (981) (86.5, 12.0, -171.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (982) (87.5, 12.0, -171.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (983) (87.5, 12.0, -170.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (968) (86.5, 12.0, -174.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (969) (86.5, 12.0, -175.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (979) (85.5, 12.0, -174.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (971) (87.5, 12.0, -174.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (970) (87.5, 12.0, -175.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (975) (87.5, 12.0, -176.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (978) (85.5, 12.0, -175.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (976) (84.5, 12.0, -174.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (977) (84.5, 12.0, -175.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (972) (86.5, 12.0, -176.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (973) (86.5, 12.0, -177.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (974) (87.5, 12.0, -177.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (619) (-3.0, 20.0, -126.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (621) (-4.0, 20.0, -126.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (626) (-5.0, 20.0, -126.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (623) (-5.0, 20.0, -127.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (624) (-6.0, 20.0, -126.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (622) (-3.0, 20.0, -127.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (620) (-4.0, 20.0, -127.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (452) (-3.0, 20.0, -128.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (451) (-3.0, 20.0, -129.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (625) (-6.0, 20.0, -127.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (627) (-14.0, 20.0, -126.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (630) (-14.0, 20.0, -127.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (629) (-15.0, 20.0, -126.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (628) (-15.0, 20.0, -127.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (423) (-9.0, 20.0, -116.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (449) (-8.0, 20.0, -118.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (415) (-8.0, 20.0, -116.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (446) (-8.0, 20.0, -117.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (448) (-7.0, 20.0, -117.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (447) (-7.0, 20.0, -118.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (425) (-10.0, 20.0, -116.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (417) (-7.0, 20.0, -116.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (411) (-7.0, 20.0, -115.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (413) (-8.0, 20.0, -115.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (424) (-9.0, 20.0, -115.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (422) (-10.0, 20.0, -115.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (840) (14.0, 20.0, -117.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (844) (16.0, 20.0, -118.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (841) (16.0, 20.0, -117.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (838) (15.0, 20.0, -117.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (839) (15.0, 20.0, -116.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (837) (14.0, 20.0, -116.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (843) (17.0, 20.0, -117.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (833) (14.0, 20.0, -114.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (836) (14.0, 20.0, -115.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (834) (15.0, 20.0, -115.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (835) (15.0, 20.0, -114.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (831) (19.5, 20.0, -128.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (830) (19.5, 20.0, -129.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (829) (18.5, 20.0, -128.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (832) (18.5, 20.0, -129.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (821) (20.5, 20.0, -128.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (828) (20.5, 20.0, -127.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (822) (21.5, 20.0, -129.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (826) (21.5, 20.0, -127.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (823) (21.5, 20.0, -128.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (824) (20.5, 20.0, -129.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (825) (20.5, 20.0, -126.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (827) (21.5, 20.0, -126.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (536) (8.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (508) (9.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (534) (7.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (506) (10.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (509) (10.0, 28.0, -93.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (507) (9.0, 28.0, -93.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (535) (8.0, 28.0, -93.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (537) (7.0, 28.0, -93.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (500) (12.0, 28.0, -95.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (503) (12.0, 28.0, -96.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (504) (12.0, 28.0, -97.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (498) (13.0, 28.0, -95.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (505) (13.0, 28.0, -96.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (502) (13.0, 28.0, -97.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (499) (12.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (501) (13.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (517) (7.0, 28.0, -99.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (515) (8.0, 28.0, -99.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (514) (7.0, 28.0, -100.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (516) (8.0, 28.0, -100.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (484) (12.0, 28.0, -102.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (483) (12.0, 28.0, -103.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (491) (11.0, 28.0, -104.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (485) (13.0, 28.0, -102.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (489) (12.0, 28.0, -104.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (482) (13.0, 28.0, -103.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (486) (12.0, 28.0, -105.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (488) (13.0, 28.0, -105.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (487) (13.0, 28.0, -104.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (492) (11.0, 28.0, -105.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (493) (10.0, 28.0, -104.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (490) (10.0, 28.0, -105.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (513) (9.0, 28.0, -106.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (511) (10.0, 28.0, -106.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (512) (10.0, 28.0, -107.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (510) (9.0, 28.0, -107.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (495) (8.0, 28.0, -104.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (496) (8.0, 28.0, -105.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (497) (7.0, 28.0, -104.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (494) (7.0, 28.0, -105.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (520) (-4.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (521) (-5.0, 28.0, -93.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (525) (-5.0, 28.0, -95.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (518) (-5.0, 28.0, -94.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (519) (-4.0, 28.0, -93.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (523) (-6.0, 28.0, -95.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (631) (-7.0, 28.0, -95.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (522) (-5.0, 28.0, -96.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (524) (-6.0, 28.0, -96.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (632) (-7.0, 28.0, -96.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (533) (-7.0, 28.0, -97.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (633) (-8.0, 28.5, -95.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (634) (-8.0, 28.0, -96.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (531) (-8.0, 28.0, -97.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (532) (-8.0, 28.0, -98.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (530) (-7.0, 28.0, -98.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (769) (-8.5, 28.0, -105.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (772) (-8.5, 28.0, -104.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (770) (-9.5, 28.0, -104.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (771) (-9.5, 28.0, -105.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (758) (-7.5, 28.0, -107.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (760) (-6.5, 28.0, -107.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (754) (-5.5, 28.0, -107.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (757) (-6.5, 28.0, -108.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (755) (-5.5, 28.0, -108.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (764) (-6.5, 28.0, -109.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (753) (-4.5, 28.0, -108.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (756) (-4.5, 28.0, -107.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (765) (-2.5, 28.0, -107.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (168) (-3.0, 28.0, -109.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (767) (-3.5, 28.0, -107.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (766) (-3.5, 28.0, -106.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (768) (-2.5, 28.0, -106.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (169) (-5.0, 28.0, -111.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (166) (-3.0, 28.0, -111.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (167) (-5.0, 28.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (116) (-3.0, 28.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (761) (-6.5, 28.0, -110.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (762) (-7.5, 28.0, -109.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (759) (-7.5, 28.0, -108.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (763) (-7.5, 28.0, -110.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (151) (-21.0, 28.0, -109.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (170) (-21.0, 28.0, -111.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (171) (-19.0, 28.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (149) (-23.0, 28.0, -107.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (24) (-25.0, 28.0, -109.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (138) (-25.0, 28.0, -111.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (148) (-25.0, 28.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (172) (-23.0, 28.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (25) (-25.0, 28.0, -107.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (150) (-21.0, 28.0, -107.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (26) (-19.0, 28.0, -107.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (23) (-19.0, 28.0, -105.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (9) (-19.0, 28.0, -103.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (471) (-16.0, 36.0, -87.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (472) (-16.0, 36.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (470) (-17.0, 36.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (473) (-17.0, 36.0, -87.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (468) (-17.0, 36.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (466) (-16.0, 36.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (474) (-15.0, 36.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (467) (-17.0, 36.0, -89.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (469) (-16.0, 36.0, -89.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (477) (-15.0, 36.0, -89.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (475) (-14.0, 36.0, -89.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (476) (-14.0, 36.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (459) (-4.0, 36.0, -75.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (460) (-4.0, 36.0, -74.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (458) (-3.0, 36.0, -74.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (461) (-3.0, 36.0, -75.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (457) (-4.0, 36.0, -73.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (455) (-3.0, 36.0, -73.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (456) (-3.0, 36.0, -72.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (454) (-4.0, 36.0, -72.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (463) (-9.0, 36.0, -70.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (465) (-8.0, 36.0, -70.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (462) (-8.0, 36.0, -69.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (464) (-9.0, 36.0, -69.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (567) (-7.0, 36.0, -68.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (617) (-7.0, 36.0, -67.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (618) (-6.0, 36.0, -68.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (565) (-6.0, 36.0, -67.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (792) (-14.5, 36.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (789) (-14.5, 36.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (790) (-15.5, 36.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (791) (-15.5, 36.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (180) (-13.0, 36.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (776) (-12.5, 36.0, -59.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (779) (-11.5, 36.0, -60.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (778) (-11.5, 36.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (777) (-10.5, 36.0, -60.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (780) (-10.5, 36.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (774) (-13.5, 36.0, -59.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (178) (-11.0, 36.0, -59.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (773) (-12.5, 36.0, -58.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (775) (-13.5, 36.0, -58.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (785) (-14.5, 36.0, -58.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (788) (-14.5, 36.0, -59.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (786) (-15.5, 36.0, -59.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (179) (-13.0, 36.0, -57.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (177) (-11.0, 36.0, -57.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (174) (-13.0, 36.0, -55.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (784) (-14.5, 36.0, -57.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (781) (-14.5, 36.0, -56.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (176) (-15.0, 36.0, -55.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (783) (-15.5, 36.0, -56.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (782) (-15.5, 36.0, -57.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (787) (-15.5, 36.0, -58.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (173) (-11.0, 36.0, -55.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (181) (-17.0, 36.0, -58.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (800) (-16.5, 36.0, -53.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (175) (-15.0, 36.0, -53.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (797) (-16.5, 36.0, -52.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (136) (-15.0, 36.0, -51.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (796) (-16.5, 36.0, -51.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (793) (-16.5, 36.0, -50.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (794) (-17.5, 36.0, -51.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (799) (-17.5, 36.0, -52.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (798) (-17.5, 36.0, -53.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (135) (-15.0, 36.0, -49.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (134) (-17.0, 36.0, -49.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (795) (-17.5, 36.0, -50.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (132) (-15.0, 36.0, -47.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (133) (-17.0, 36.0, -47.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (437) (11.0, 36.0, -72.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (434) (11.0, 36.0, -71.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (435) (10.0, 36.0, -72.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (433) (10.0, 36.0, -70.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (436) (10.0, 36.0, -71.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (432) (11.0, 36.0, -70.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (441) (9.0, 36.0, -72.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (438) (9.0, 36.0, -71.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (440) (8.0, 36.0, -71.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (439) (8.0, 36.0, -72.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (445) (8.0, 36.0, -74.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (442) (8.0, 36.0, -73.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (430) (10.0, 36.0, -69.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (431) (11.0, 36.0, -69.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (444) (7.0, 36.0, -73.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (443) (7.0, 36.0, -74.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (652) (28.0, 36.0, -110.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (647) (27.0, 36.0, -112.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (648) (26.0, 36.0, -112.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (654) (28.0, 36.0, -111.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (646) (28.0, 36.0, -112.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (645) (28.0, 36.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (649) (27.0, 36.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (653) (29.0, 36.0, -111.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (643) (29.0, 36.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (644) (29.0, 36.0, -112.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (651) (29.0, 36.0, -110.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (650) (26.0, 36.0, -113.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (845) (-4.5, 44.0, -68.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (847) (-3.5, 44.0, -68.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (846) (-4.5, 44.0, -69.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (848) (-3.5, 44.0, -69.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (850) (9.5, 44.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (856) (7.5, 44.0, -66.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (853) (8.5, 44.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (854) (8.5, 44.0, -66.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (859) (7.5, 44.0, -67.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (860) (7.5, 44.0, -68.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (857) (8.5, 44.0, -67.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (858) (8.5, 44.0, -68.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (849) (9.5, 44.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (851) (10.5, 44.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (852) (10.5, 44.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (855) (7.5, 44.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (410) (-6.0, 44.0, -64.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (416) (-6.0, 44.0, -65.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (421) (-4.0, 44.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (407) (-6.0, 44.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (420) (-5.0, 44.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (403) (-6.0, 44.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (409) (-7.0, 44.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (418) (-5.0, 44.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (412) (-7.0, 44.0, -64.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (405) (-7.0, 44.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (400) (-7.0, 44.0, -61.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (414) (-7.0, 44.0, -65.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (402) (-8.0, 44.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (399) (-8.0, 44.0, -61.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (406) (-8.0, 44.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (401) (-6.0, 44.0, -61.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (404) (-9.0, 44.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (408) (-9.0, 44.0, -63.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (426) (-8.0, 44.0, -60.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (398) (-9.0, 44.0, -61.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (429) (-8.0, 44.0, -59.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (428) (-9.0, 44.0, -59.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (427) (-9.0, 44.0, -60.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (667) (-6.0, 44.0, -50.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (669) (-5.0, 44.0, -50.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (668) (-5.0, 44.0, -51.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (670) (-6.0, 44.0, -51.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (665) (-6.0, 44.0, -48.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (666) (-5.0, 44.0, -48.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (664) (-6.0, 44.0, -47.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (663) (-5.0, 44.0, -47.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (672) (8.0, 44.0, -48.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (674) (7.0, 44.0, -48.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (671) (7.0, 44.0, -47.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (677) (6.0, 44.0, -48.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (676) (6.0, 44.0, -49.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (675) (5.0, 44.0, -48.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (678) (5.0, 44.0, -49.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (673) (8.0, 44.0, -47.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (5) (12.0, 44.0, -6.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (4) (13.0, 44.0, -6.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (3) (12.0, 44.0, -5.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1) (13.0, 44.0, -5.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (6) (11.0, 44.0, -5.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (13.0, 44.0, -4.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (2) (12.0, 44.0, -4.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (7) (11.0, 44.0, -4.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (30) (10.0, 44.0, -4.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1137) (8.0, 46.0, -2.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1135) (9.0, 46.0, -2.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1138) (9.0, 46.0, -3.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1136) (8.0, 46.0, -1.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1134) (9.0, 46.0, -1.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1139) (-4.0, 46.0, -1.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1141) (-4.0, 46.0, -2.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1142) (-5.0, 46.0, -2.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1140) (-5.0, 46.0, -1.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (26) (-6.5, 44.0, -5.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (27) (-6.5, 44.0, -4.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (24) (-7.5, 44.0, -5.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (25) (-7.5, 44.0, -4.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (28) (-8.5, 44.0, -6.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (22) (-8.5, 44.0, -5.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (21) (-8.5, 44.0, -4.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (29) (-9.5, 44.0, -6.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (18) (-8.5, 44.0, -10.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (11) (-8.5, 44.0, -12.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (13) (-8.5, 44.0, -11.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (19) (-9.5, 44.0, -10.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (12) (-9.5, 44.0, -11.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (15) (-7.5, 44.0, -12.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (9) (-9.5, 44.0, -12.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (8) (-9.5, 44.0, -13.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (10) (-8.5, 44.0, -13.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (16) (-6.5, 44.0, -12.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (17) (-6.5, 44.0, -13.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (14) (-7.5, 44.0, -13.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (698) (-32.0, 38.0, -49.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (699) (-31.0, 38.0, -49.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (697) (-32.0, 38.0, -50.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (700) (-31.0, 38.0, -50.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (696) (-32.5, 38.0, -46.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (693) (-33.5, 38.5, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (695) (-33.5, 38.0, -46.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (694) (-33.5, 38.5, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (691) (-34.5, 38.0, -46.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (692) (-34.5, 38.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (560) (-32.0, 40.0, -33.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (554) (-31.0, 40.0, -34.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (553) (-31.0, 40.0, -33.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (555) (-30.0, 40.0, -34.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (557) (-31.0, 40.0, -35.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (550) (-31.0, 40.0, -32.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (552) (-30.0, 40.0, -33.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (551) (-30.0, 40.0, -32.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (559) (-32.0, 40.0, -32.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (558) (-33.0, 40.0, -32.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (561) (-33.0, 40.0, -33.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (139) (-31.0, 40.0, -28.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (145) (-33.0, 40.0, -30.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (143) (-33.0, 40.0, -28.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (556) (-30.0, 40.0, -35.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (137) (-39.0, 40.0, -28.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (93) (-41.0, 40.0, -28.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (94) (-39.0, 40.0, -33.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (479) (-38.5, 40.0, -34.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (480) (-38.5, 40.0, -35.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (478) (-39.5, 40.0, -34.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (190) (-37.0, 40.0, -33.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (481) (-39.5, 40.0, -35.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (-41.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (6) (-39.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (1) (-41.0, 40.0, -39.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (4) (-39.0, 40.0, -39.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (2) (-41.0, 40.0, -41.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (7) (-39.0, 40.0, -41.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (128) (-39.5, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (130) (-39.5, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (5) (-41.0, 40.0, -43.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (545) (-37.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (538) (-37.5, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (131) (-38.5, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (126) (-38.5, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (544) (-36.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (542) (-37.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (543) (-36.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (541) (-37.5, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (540) (-36.5, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (539) (-36.5, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (546) (-35.5, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (548) (-34.5, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (549) (-35.5, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (547) (-34.5, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (191) (-38.0, 40.0, -45.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (689) (-40.0, 40.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (687) (-41.0, 40.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (690) (-40.0, 40.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (688) (-41.0, 40.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (117) (-42.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (114) (-42.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (98) (-43.0, 40.0, -39.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (116) (-43.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (115) (-43.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (121) (-44.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (113) (-44.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (118) (-44.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (192) (-43.0, 40.0, -43.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (110) (-44.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (95) (-43.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (96) (-45.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (112) (-45.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (111) (-45.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (124) (-46.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (97) (-47.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (122) (-47.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (123) (-46.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (125) (-47.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (134) (-46.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (120) (-45.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (119) (-45.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (108) (-48.5, 40.0, -37.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (109) (-49.5, 40.0, -37.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (136) (-47.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (135) (-47.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (137) (-46.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (196) (-47.3, 40.0, -43.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (133) (-49.0, 40.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (686) (-50.0, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (685) (-51.0, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (684) (-52.0, 40.0, -42.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (683) (-52.0, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (682) (-51.0, 40.0, -43.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (680) (-52.0, 40.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (127) (-50.0, 40.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (129) (-51.0, 40.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (450) (-51.0, 40.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (681) (-52.0, 40.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (453) (-50.0, 40.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (679) (-49.0, 40.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (115) (-53.5, 40.0, -43.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (8) (-51.0, 40.0, -39.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (99) (-51.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (106) (-49.5, 40.0, -36.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (3) (-53.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (107) (-48.5, 40.0, -36.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (138) (-71.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (141) (-71.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (140) (-72.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (139) (-72.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (102) (-72.0, 40.0, -41.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (105) (-72.0, 40.0, -43.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (104) (-74.0, 40.0, -41.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (101) (-74.0, 40.0, -39.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (153) (-76.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (145) (-75.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (152) (-75.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (151) (-75.5, 40.0, -41.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (143) (-76.5, 40.0, -39.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (150) (-76.5, 40.0, -40.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (103) (-74.0, 40.0, -43.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (144) (-76.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (142) (-75.5, 40.0, -38.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (100) (-76.0, 40.0, -37.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (147) (-77.5, 40.0, -37.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (148) (-77.5, 40.0, -36.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (149) (-78.5, 40.0, -37.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (146) (-78.5, 40.0, -36.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (156) (-82.5, 40.0, -36.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (155) (-82.5, 40.0, -37.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (154) (-83.5, 40.0, -36.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (157) (-83.5, 40.0, -37.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (907) (-48.5, 43.0, 20.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (908) (-48.5, 43.0, 21.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (905) (-49.5, 43.0, 21.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (906) (-49.5, 43.0, 20.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (911) (-53.8, 43.0, 20.3)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (909) (-53.8, 43.0, 21.3)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (910) (-54.8, 43.0, 21.3)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (819) (-52.0, 28.0, -52.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (817) (-51.0, 28.0, -52.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (818) (-52.0, 28.0, -53.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (820) (-51.0, 28.0, -53.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (813) (-46.5, 28.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (816) (-46.5, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (814) (-47.5, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (815) (-47.5, 28.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (807) (-44.0, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (803) (-45.0, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (806) (-44.0, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (801) (-44.0, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (805) (-43.0, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (808) (-43.0, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (811) (-42.0, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (809) (-41.0, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (810) (-42.0, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (812) (-41.0, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (804) (-44.0, 28.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (802) (-45.0, 28.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (529) (-35.0, 28.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (527) (-34.0, 28.0, -61.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (528) (-34.0, 28.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (526) (-35.0, 28.0, -61.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (641) (-32.0, 28.0, -65.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (642) (-32.0, 28.0, -66.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (640) (-31.0, 28.0, -65.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (636) (-30.0, 28.0, -65.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (639) (-31.0, 28.0, -66.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (637) (-29.0, 28.0, -66.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (635) (-29.0, 28.0, -65.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (638) (-30.0, 28.0, -66.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (744) (-32.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (741) (-32.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (158) (-32.0, 28.0, -84.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (742) (-31.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (743) (-31.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (748) (-29.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (745) (-30.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (746) (-30.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (163) (-30.0, 28.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (162) (-30.0, 28.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (747) (-29.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (750) (-30.5, 28.0, -90.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (749) (-30.5, 28.0, -89.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (751) (-29.5, 28.0, -89.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (752) (-29.5, 28.0, -90.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (165) (-57.5, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (162) (-57.5, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (164) (-58.5, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (163) (-58.5, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (176) (-59.5, 28.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (173) (-59.5, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (170) (-59.5, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (159) (-59.5, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (172) (-60.5, 28.0, -63.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (174) (-60.5, 28.0, -65.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (171) (-60.5, 28.0, -64.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (175) (-59.5, 28.0, -66.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (177) (-60.5, 28.0, -66.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (112) (-56.0, 28.0, -64.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (110) (-58.0, 28.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (111) (-56.0, 28.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (160) (-59.5, 28.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (169) (-59.5, 28.0, -60.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (108) (-58.0, 28.0, -60.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (158) (-60.5, 28.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (161) (-60.5, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (109) (-56.0, 28.0, -60.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (107) (-58.0, 28.0, -58.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (166) (-59.5, 28.0, -59.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (168) (-60.5, 28.0, -59.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (167) (-60.5, 28.0, -60.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (180) (-61.5, 28.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (178) (-62.5, 28.0, -61.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (179) (-61.5, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (181) (-62.5, 28.0, -62.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (713) (-62.5, 28.0, -74.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (714) (-62.5, 28.0, -75.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (715) (-63.5, 28.0, -74.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (716) (-63.5, 28.0, -75.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (711) (-66.0, 28.0, -76.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (710) (-66.0, 28.0, -77.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (712) (-67.0, 28.0, -76.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (709) (-67.0, 28.0, -77.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (160) (-61.5, 28.0, -81.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (157) (-59.5, 28.0, -81.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (156) (-59.5, 28.0, -79.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (154) (-57.5, 28.0, -79.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (159) (-61.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (155) (-59.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (152) (-57.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (153) (-57.5, 28.0, -81.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (727) (-63.0, 28.0, -83.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (725) (-64.0, 28.0, -83.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (728) (-64.0, 28.0, -84.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (726) (-63.0, 28.0, -84.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (722) (-63.0, 28.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (723) (-63.0, 28.0, -85.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (721) (-64.0, 28.0, -85.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (717) (-62.0, 28.0, -85.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (720) (-62.0, 28.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (719) (-61.0, 28.0, -85.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (724) (-64.0, 28.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (718) (-61.0, 28.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (234) (-69.5, 28.0, -96.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (236) (-68.5, 28.0, -96.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (237) (-69.5, 28.0, -97.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (230) (-69.5, 28.0, -98.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (240) (-67.5, 28.0, -98.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (232) (-68.5, 28.0, -98.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (235) (-68.5, 28.0, -97.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (233) (-69.5, 28.0, -99.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (231) (-68.5, 28.0, -99.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (239) (-67.5, 28.0, -99.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (241) (-66.5, 28.0, -99.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (238) (-66.5, 28.0, -98.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (739) (-71.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (737) (-72.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (734) (-73.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (735) (-73.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (733) (-74.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (736) (-74.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (740) (-72.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (738) (-71.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (731) (-74.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (729) (-75.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (732) (-75.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (730) (-74.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (227) (-83.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (229) (-84.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (228) (-83.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (226) (-84.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (222) (-85.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (119) (-86.0, 28.0, -82.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (122) (-86.0, 28.0, -84.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (224) (-86.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (211) (-87.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (208) (-87.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (210) (-88.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (209) (-88.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (223) (-86.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (161) (-88.0, 28.0, -86.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (225) (-85.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (217) (-89.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (186) (-88.0, 28.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (165) (-88.0, 28.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (164) (-86.0, 28.0, -88.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (203) (-89.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (218) (-89.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (214) (-89.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (216) (-90.5, 28.0, -85.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (215) (-90.5, 28.0, -84.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (202) (-90.5, 28.0, -83.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (219) (-90.5, 28.0, -86.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (207) (-89.5, 28.0, -82.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (198) (-89.5, 28.0, -81.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (123) (-88.0, 28.0, -82.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (213) (-89.5, 28.0, -80.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (199) (-90.5, 28.0, -82.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (121) (-88.0, 28.0, -80.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (200) (-89.5, 28.0, -79.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (212) (-90.5, 28.0, -79.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (201) (-90.5, 28.0, -80.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (206) (-90.5, 28.0, -81.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (220) (-91.5, 28.0, -81.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (205) (-91.5, 28.0, -82.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (221) (-92.5, 28.0, -82.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (204) (-92.5, 28.0, -81.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (120) (-86.0, 28.0, -80.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (118) (-88.0, 28.0, -78.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (703) (-78.0, 28.0, -75.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (704) (-78.0, 28.0, -76.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (705) (-77.0, 28.0, -74.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (702) (-77.0, 28.0, -75.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (701) (-77.0, 28.0, -76.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (706) (-76.0, 28.0, -74.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (708) (-77.0, 28.0, -73.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (707) (-76.0, 28.0, -73.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (117) (-57.0, 28.0, -47.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (114) (-55.0, 28.0, -45.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Bush (113) (-57.0, 28.0, -45.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (183) (-58.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (184) (-58.5, 28.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (185) (-59.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (197) (-60.5, 28.0, -46.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (196) (-61.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (195) (-61.5, 28.0, -46.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (194) (-60.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (190) (-62.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (193) (-62.5, 28.0, -46.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (191) (-63.5, 28.0, -46.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (182) (-59.5, 28.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (192) (-63.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (189) (-64.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (186) (-64.5, 28.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (187) (-65.5, 28.0, -45.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (188) (-65.5, 28.0, -44.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (-132.0, 28.0, -52.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (3) (-132.0, 28.0, -53.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1) (-133.0, 28.0, -52.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (2) (-131.0, 28.0, -52.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (5) (-120.5, 28.0, -52.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (4) (-119.5, 28.0, -52.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (7) (-119.5, 28.0, -51.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (8) (-117.5, 28.0, -55.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (6) (-116.5, 28.0, -55.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (9) (-116.5, 28.0, -54.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1083) (-86.5, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1082) (-85.5, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1084) (-85.5, 12.0, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1085) (-86.5, 12.0, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1087) (-87.5, 12.0, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1089) (-88.5, 12.0, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1086) (-87.5, 12.0, -129.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1088) (-88.5, 12.0, -129.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1080) (-89.0, 12.0, -143.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1081) (-90.0, 12.0, -143.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1078) (-89.0, 12.0, -144.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1075) (-88.0, 12.0, -144.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1079) (-90.0, 12.0, -144.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1074) (-87.0, 12.0, -144.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1077) (-88.0, 12.0, -145.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1076) (-87.0, 12.0, -145.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1070) (-78.0, 12.0, -142.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1072) (-77.0, 12.0, -143.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1071) (-77.0, 12.0, -142.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1073) (-78.0, 12.0, -143.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (294) (-64.0, 12.0, -144.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (292) (-64.0, 12.0, -145.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (290) (-64.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (74) (-65.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (293) (-63.0, 12.0, -144.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (132) (-63.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (291) (-63.0, 12.0, -145.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (77) (-64.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (76) (-63.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (73) (-65.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (75) (-66.0, 12.0, -143.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (70) (-66.0, 12.0, -142.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1093) (-55.0, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1092) (-54.0, 12.0, -136.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1090) (-55.0, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1091) (-54.0, 12.0, -135.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1056) (-68.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1054) (-69.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1050) (-67.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1057) (-68.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1052) (-66.0, 12.0, -134.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1053) (-66.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1051) (-67.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1060) (-68.0, 12.5, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1055) (-69.0, 12.0, -133.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1058) (-69.0, 12.5, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1062) (-70.0, 12.5, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1061) (-68.0, 12.5, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1059) (-69.0, 12.5, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1063) (-70.0, 12.5, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1065) (-71.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1064) (-71.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1047) (-72.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1068) (-72.0, 13.0, -129.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1067) (-72.0, 12.5, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1048) (-72.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1066) (-73.0, 12.5, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1069) (-73.0, 12.5, -129.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1046) (-73.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1044) (-74.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1043) (-74.0, 12.0, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1049) (-73.0, 12.0, -132.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1045) (-75.0, 12.0, -131.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (1042) (-75.0, 12.0, -130.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (842) (17.0, 20.0, -118.5)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Grass (419) (-4.0, 44.0, -62.0)": TunicLocationData("Overworld", "Overworld"), + "Overworld - Overworld Swamp Lower Entry Grass (1103) (80.5, 2.7, -175.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - Overworld Swamp Lower Entry Grass (1102) (80.5, 2.7, -174.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - Overworld Swamp Lower Entry Grass (1100) (79.5, 2.1, -174.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - Overworld Swamp Lower Entry Grass (1101) (79.5, 2.1, -175.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - Overworld Swamp Lower Entry Grass (1096) (78.4, 2.2, -171.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - Overworld Swamp Lower Entry Grass (1097) (77.5, 2.0, -171.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - Overworld Swamp Lower Entry Grass (1099) (77.4, 2.2, -170.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - Overworld Swamp Lower Entry Grass (1098) (78.5, 2.6, -170.6)": TunicLocationData( + "Overworld Swamp Lower Entry", "Overworld Swamp Lower Entry"), + "Overworld - After Ruined Passage Grass (327) (53.0, 20.0, -144.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (296) (52.0, 20.0, -144.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (297) (51.0, 20.0, -144.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (326) (54.0, 20.0, -144.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (295) (52.0, 20.0, -145.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (265) (51.0, 20.0, -145.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (325) (53.0, 20.0, -145.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (298) (54.0, 20.0, -145.0)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (661) (47.5, 20.0, -142.5)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (328) (47.5, 20.0, -141.5)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (662) (46.5, 20.0, -142.5)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - After Ruined Passage Grass (660) (46.5, 20.0, -141.5)": TunicLocationData("After Ruined Passage", + "After Ruined Passage"), + "Overworld - Above Ruined Passage Grass (31) (66.0, 28.0, -120.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (29) (67.0, 28.0, -120.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (28) (67.0, 28.0, -119.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (26) (67.0, 28.0, -118.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (30) (66.0, 28.0, -119.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (21) (67.0, 28.0, -116.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (27) (67.0, 28.0, -117.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (25) (66.0, 28.0, -117.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (24) (66.0, 28.0, -118.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (20) (67.0, 28.0, -115.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (23) (66.0, 28.0, -116.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (22) (66.0, 28.0, -115.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (12) (56.0, 28.0, -126.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (10) (56.0, 28.0, -128.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (13) (56.0, 28.0, -127.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (14) (55.0, 28.0, -126.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (15) (55.0, 28.0, -127.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (5) (55.0, 28.0, -128.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (11) (57.0, 28.0, -128.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (9) (57.0, 28.0, -129.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (8) (56.0, 28.0, -129.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (18) (54.0, 28.0, -127.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (4) (54.0, 28.0, -128.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (6) (54.0, 28.0, -129.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (17) (53.0, 28.0, -126.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (16) (53.0, 28.0, -127.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (3) (53.0, 28.0, -128.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (2) (53.0, 28.0, -129.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (1) (52.0, 28.0, -128.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (52.0, 28.0, -129.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (7) (55.0, 28.0, -129.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - Above Ruined Passage Grass (19) (54.0, 28.0, -126.0)": TunicLocationData("Above Ruined Passage", + "Above Ruined Passage"), + "Overworld - East Overworld Grass (1118) (98.5, 36.0, -136.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1119) (98.5, 36.0, -137.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1116) (99.5, 36.0, -136.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1115) (98.5, 36.0, -139.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1114) (98.5, 36.0, -138.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1112) (99.5, 36.0, -138.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1117) (99.5, 36.0, -137.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1113) (99.5, 36.0, -139.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1109) (95.0, 36.0, -127.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1104) (95.0, 36.0, -128.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1108) (95.0, 36.0, -126.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1111) (94.0, 36.0, -127.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1110) (94.0, 36.0, -126.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1106) (94.0, 36.0, -128.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1107) (94.0, 36.0, -129.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1105) (95.0, 36.0, -129.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (331) (86.0, 36.0, -128.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (329) (85.0, 36.0, -128.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (655) (85.0, 36.0, -129.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (657) (84.0, 36.0, -129.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (658) (84.0, 36.0, -128.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (330) (86.0, 36.0, -129.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (656) (83.0, 36.0, -128.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (659) (83.0, 36.0, -129.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1120) (86.0, 36.0, -123.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1124) (86.0, 36.0, -122.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1126) (83.0, 36.0, -120.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1127) (82.0, 36.0, -120.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (309) (81.5, 36.0, -118.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (308) (81.5, 36.0, -119.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (307) (80.5, 36.0, -118.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (324) (80.5, 36.0, -119.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (305) (79.5, 36.0, -118.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (304) (79.5, 36.0, -119.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (300) (79.5, 36.0, -121.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (301) (79.5, 36.0, -120.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1128) (82.0, 36.0, -121.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (303) (78.5, 36.0, -118.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (306) (78.5, 36.0, -119.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (299) (78.5, 36.0, -120.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1122) (77.5, 36.0, -120.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1123) (77.5, 36.0, -121.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1121) (76.5, 36.0, -121.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (302) (78.5, 36.0, -121.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Bush (18) (82.5, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (20) (82.5, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (92) (84.5, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (19) (82.5, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (78) (79.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (83) (80.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (85) (80.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (84) (81.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (80) (79.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (87) (82.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (82) (81.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (86) (83.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (89) (82.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (88) (83.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (81) (78.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (52) (76.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (50) (76.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (53) (75.0, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (79) (78.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (51) (75.0, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (57) (78.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (21) (80.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (56) (76.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (54) (76.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (55) (75.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (57) (75.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (103) (90.0, 44.0, -113.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (105) (90.0, 44.0, -112.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (102) (91.0, 44.0, -112.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (104) (91.0, 44.0, -113.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Bush (44) (93.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (45) (95.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (1150) (94.5, 44.0, -111.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1149) (95.5, 44.0, -111.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1151) (94.5, 44.0, -110.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Bush (50) (97.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (56) (97.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (1148) (95.5, 44.0, -110.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (96) (94.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (95) (93.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (101) (95.5, 44.0, -109.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (94) (94.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (97) (93.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (99) (95.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (46) (95.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (22) (93.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (90) (91.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (55) (97.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (49) (97.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (92) (91.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (91) (90.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (93) (90.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (46) (71.0, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (15) (72.5, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (48) (71.0, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (61) (70.5, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (10) (70.5, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (49) (70.0, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (62) (69.0, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (63) (68.5, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (65) (68.0, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (58) (67.0, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (45) (68.0, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (43) (68.0, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (44) (69.0, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (42) (69.0, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (47) (70.0, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (64) (69.0, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (63) (68.0, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (60) (67.0, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (59) (66.0, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (61) (66.0, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (60) (66.5, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (83) (64.5, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (62) (66.5, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (80) (66.5, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (58) (58.0, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (30) (56.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (59) (58.0, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (34) (56.5, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (36) (56.5, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (14) (58.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (32) (56.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (64) (56.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (37) (55.5, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (31) (55.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (33) (55.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (35) (55.5, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (38) (54.5, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (40) (54.5, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (41) (53.5, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (81) (54.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (39) (53.5, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (26) (52.5, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (65) (54.0, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (28) (52.5, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (16) (52.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (14) (52.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (17) (51.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (27) (51.5, 44.0, -110.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (29) (51.5, 44.0, -111.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (12) (58.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (66) (54.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (11) (52.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (12) (51.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (15) (51.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (24) (50.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (18) (50.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (22) (50.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (25) (49.5, 44.0, -109.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (21) (49.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (23) (49.5, 44.0, -108.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (13) (51.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (10) (52.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (20) (50.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (19) (49.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (69) (48.0, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (68) (48.0, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (67) (48.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (72) (46.0, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (70) (46.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (71) (46.0, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (76) (44.0, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (73) (44.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (66) (46.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (69) (45.5, 44.0, -107.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (67) (45.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (82) (44.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (68) (46.5, 44.0, -106.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (79) (42.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (78) (42.0, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (74) (40.0, 44.0, -109.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (77) (42.0, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (75) (42.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (88) (40.0, 44.0, -107.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (1006) (33.5, 44.0, -109.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1008) (33.5, 44.0, -108.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Bush (89) (33.0, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (72) (34.5, 44.0, -112.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Bush (90) (33.0, 44.0, -113.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (984) (35.5, 44.0, -112.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (985) (34.5, 44.0, -113.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (71) (35.5, 44.0, -113.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (1009) (32.5, 44.0, -109.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1007) (32.5, 44.0, -108.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (986) (31.5, 44.0, -109.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Bush (91) (31.0, 44.0, -111.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (989) (30.5, 44.0, -109.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (987) (30.5, 44.0, -108.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (988) (31.5, 44.0, -108.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1000) (31.5, 44.0, -106.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (998) (31.5, 44.0, -107.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1001) (30.5, 44.0, -107.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (999) (30.5, 44.0, -106.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1005) (30.5, 44.0, -105.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1002) (31.5, 44.0, -105.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1004) (31.5, 44.0, -104.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1003) (30.5, 44.0, -104.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (993) (36.5, 44.0, -105.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (990) (37.5, 44.0, -105.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (991) (36.5, 44.0, -104.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (992) (37.5, 44.0, -104.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (994) (37.5, 44.0, -103.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (996) (37.5, 44.0, -102.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (997) (36.5, 44.0, -103.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (995) (36.5, 44.0, -102.5)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (881) (27.8, 44.0, -74.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (864) (28.8, 44.0, -75.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (863) (28.8, 44.0, -74.0)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (1012) (23.5, 44.0, -98.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1011) (22.5, 44.0, -98.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1013) (22.5, 44.0, -99.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (1010) (23.5, 44.0, -99.0)": TunicLocationData("East Overworld", + "East Overworld"), + "Overworld - East Overworld Grass (319) (36.5, 44.0, -40.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (318) (35.5, 44.0, -40.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (315) (35.5, 44.0, -41.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (316) (34.5, 44.0, -41.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (882) (65.3, 44.0, -15.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (317) (65.3, 44.0, -14.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - East Overworld Grass (883) (64.3, 44.0, -14.5)": TunicLocationData("East Overworld", "East Overworld"), + "Overworld - Upper Overworld Grass (904) (30.3, 66.0, 26.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (901) (29.3, 66.0, 27.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (903) (29.3, 66.0, 26.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (902) (28.3, 66.0, 27.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (898) (17.5, 66.0, 25.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (899) (17.5, 66.0, 26.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (900) (16.5, 66.0, 26.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (897) (16.5, 66.0, 25.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (927) (-30.8, 66.0, 34.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (924) (-30.8, 66.0, 35.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (925) (-31.8, 66.0, 34.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (926) (-31.8, 66.0, 35.3)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (922) (-40.3, 66.0, 33.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (919) (-40.3, 66.0, 34.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (923) (-41.3, 66.0, 33.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (918) (-40.3, 66.0, 35.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (921) (-41.3, 66.0, 35.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Upper Overworld Grass (920) (-41.3, 66.0, 34.5)": TunicLocationData("Upper Overworld", + "Upper Overworld"), + "Overworld - Overworld at Patrol Cave Grass (1094) (65.0, 44.0, 17.5)": TunicLocationData( + "Overworld at Patrol Cave", "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (885) (65.0, 44.0, 18.5)": TunicLocationData("Overworld at Patrol Cave", + "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (314) (66.0, 44.0, 19.5)": TunicLocationData("Overworld at Patrol Cave", + "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (1095) (66.0, 44.0, 18.5)": TunicLocationData( + "Overworld at Patrol Cave", "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (884) (65.0, 44.0, 19.5)": TunicLocationData("Overworld at Patrol Cave", + "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (888) (57.0, 44.0, 18.3)": TunicLocationData("Overworld at Patrol Cave", + "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (887) (57.0, 44.0, 19.3)": TunicLocationData("Overworld at Patrol Cave", + "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (893) (56.0, 44.0, 19.3)": TunicLocationData("Overworld at Patrol Cave", + "Overworld at Patrol Cave"), + "Overworld - Overworld at Patrol Cave Grass (892) (56.0, 44.0, 18.3)": TunicLocationData("Overworld at Patrol Cave", + "Overworld at Patrol Cave"), + "Overworld - Overworld above Patrol Cave Grass (895) (44.0, 55.0, 23.5)": TunicLocationData( + "Overworld above Patrol Cave", "Overworld above Patrol Cave"), + "Overworld - Overworld above Patrol Cave Grass (896) (43.0, 55.0, 23.5)": TunicLocationData( + "Overworld above Patrol Cave", "Overworld above Patrol Cave"), + "Overworld - Overworld above Patrol Cave Grass (886) (37.3, 55.0, 23.5)": TunicLocationData( + "Overworld above Patrol Cave", "Overworld above Patrol Cave"), + "Overworld - Overworld above Patrol Cave Grass (889) (37.3, 55.0, 22.5)": TunicLocationData( + "Overworld above Patrol Cave", "Overworld above Patrol Cave"), + "Overworld - Overworld above Patrol Cave Grass (891) (36.3, 55.0, 23.5)": TunicLocationData( + "Overworld above Patrol Cave", "Overworld above Patrol Cave"), + "Overworld - Overworld above Patrol Cave Grass (890) (36.3, 55.0, 22.5)": TunicLocationData( + "Overworld above Patrol Cave", "Overworld above Patrol Cave"), + "Overworld - Overworld above Patrol Cave Grass (894) (35.3, 55.0, 23.5)": TunicLocationData( + "Overworld above Patrol Cave", "Overworld above Patrol Cave"), + "Overworld - Overworld to West Garden from Furnace Grass (1145) (-182.5, 4.0, -45.5)": TunicLocationData( + "West Garden", "Overworld to West Garden from Furnace"), + "Overworld - Overworld to West Garden from Furnace Grass (1143) (-181.5, 4.0, -44.5)": TunicLocationData( + "West Garden", "Overworld to West Garden from Furnace"), + "Overworld - Overworld to West Garden from Furnace Grass (1144) (-182.5, 4.0, -44.5)": TunicLocationData( + "West Garden", "Overworld to West Garden from Furnace"), + "Overworld - Overworld to West Garden from Furnace Grass (1146) (-183.5, 4.0, -45.5)": TunicLocationData( + "West Garden", "Overworld to West Garden from Furnace"), + "Overworld - Overworld to West Garden from Furnace Grass (1147) (-183.5, 4.0, -44.5)": TunicLocationData( + "West Garden", "Overworld to West Garden from Furnace"), + "Overworld - Overworld Beach Grass (1032) (-118.5, 3.5, -144.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1031) (-118.5, 3.5, -143.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1036) (-118.5, 3.5, -142.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1033) (-119.5, 3.5, -144.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1037) (-119.5, 3.5, -142.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1034) (-119.5, 3.5, -141.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1030) (-119.5, 3.5, -143.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1035) (-118.5, 3.5, -141.0)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1023) (-118.5, 3.5, -136.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1024) (-118.5, 3.5, -137.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1025) (-119.5, 3.5, -137.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1027) (-118.5, 3.5, -134.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1028) (-118.5, 3.5, -135.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1022) (-119.5, 3.5, -136.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1029) (-119.5, 3.5, -135.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1026) (-119.5, 3.5, -134.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1016) (-120.5, 3.5, -135.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1017) (-121.5, 3.5, -135.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1040) (-118.5, 3.5, -131.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1041) (-119.5, 3.5, -131.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1015) (-120.5, 3.5, -134.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1038) (-119.5, 3.5, -130.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1020) (-120.5, 3.5, -133.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1019) (-120.5, 3.5, -132.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1018) (-121.5, 3.5, -132.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1021) (-121.5, 3.5, -133.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1014) (-121.5, 3.5, -134.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1039) (-118.5, 3.5, -130.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1131) (-167.0, 1.0, -88.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1125) (-166.0, 1.0, -87.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1130) (-167.0, 1.0, -87.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1129) (-166.0, 1.0, -86.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1132) (-168.0, 1.0, -88.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Overworld - Overworld Beach Grass (1133) (-168.0, 1.0, -87.5)": TunicLocationData("Overworld Beach", + "Overworld Beach"), + "Stick House - Stick House Grass (1) (14.0, 0.0, 9.0)": TunicLocationData("Stick House", "Stick House"), + "Stick House - Stick House Grass (4) (15.0, 0.0, 10.0)": TunicLocationData("Stick House", "Stick House"), + "Stick House - Stick House Grass (3) (15.0, 0.0, 8.0)": TunicLocationData("Stick House", "Stick House"), + "Stick House - Stick House Grass (15.0, 0.0, 9.0)": TunicLocationData("Stick House", "Stick House"), + "Stick House - Stick House Grass (2) (14.0, 0.0, 10.0)": TunicLocationData("Stick House", "Stick House"), + "Ruined Passage - Ruined Passage Grass (2) (186.5, 16.8, 40.3)": TunicLocationData("Ruined Passage", + "Ruined Passage"), + "Ruined Passage - Ruined Passage Grass (4) (187.7, 16.5, 39.3)": TunicLocationData("Ruined Passage", + "Ruined Passage"), + "Ruined Passage - Ruined Passage Grass (1) (187.7, 16.8, 40.3)": TunicLocationData("Ruined Passage", + "Ruined Passage"), + "Ruined Passage - Ruined Passage Grass (3) (186.5, 17.0, 41.5)": TunicLocationData("Ruined Passage", + "Ruined Passage"), + "Ruined Passage - Ruined Passage Grass (187.7, 17.0, 41.4)": TunicLocationData("Ruined Passage", "Ruined Passage"), + "Forest Belltower - Forest Belltower Upper Grass (65) (592.5, 62.0, 114.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (64) (593.5, 62.0, 114.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (62) (592.5, 62.0, 115.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (66) (591.5, 62.0, 114.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (56) (593.5, 62.0, 115.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (68) (591.5, 62.0, 115.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (72) (600.8, 62.3, 112.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (74) (601.8, 62.3, 112.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (75) (601.8, 62.3, 113.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (70) (600.8, 62.3, 114.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (73) (600.8, 62.3, 113.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (67) (599.8, 62.3, 114.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (69) (599.8, 62.3, 115.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (71) (600.8, 62.3, 115.5)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (55) (601.5, 62.0, 107.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (54) (601.5, 62.0, 106.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (52) (602.5, 62.0, 106.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (53) (602.5, 62.0, 107.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (58) (603.5, 62.0, 108.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (60) (602.5, 62.0, 108.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (59) (603.5, 62.0, 109.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (61) (602.5, 62.0, 109.3)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (79) (602.8, 62.0, 102.1)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (76) (603.8, 62.0, 103.1)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (78) (603.8, 62.0, 102.1)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (77) (602.8, 62.0, 103.1)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (593.0, 14.0, 91.0)": TunicLocationData("Forest Belltower Upper", + "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (3) (592.0, 14.0, 91.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (10) (591.0, 14.0, 91.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (1) (593.0, 14.0, 90.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (2) (592.0, 14.0, 90.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (9) (591.0, 14.0, 90.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (11) (590.0, 14.0, 91.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (8) (590.0, 14.0, 90.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (7) (592.0, 14.0, 89.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (6) (592.0, 14.0, 88.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (5) (593.0, 14.0, 89.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (4) (593.0, 14.0, 88.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (35) (589.0, 14.0, 84.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (30) (589.0, 14.0, 85.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (31) (589.0, 14.0, 86.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (29) (588.0, 14.0, 85.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (39) (591.0, 14.0, 84.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (36) (590.0, 14.0, 84.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (28) (588.0, 14.0, 86.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (34) (589.0, 14.0, 83.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (33) (588.0, 14.0, 83.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (32) (588.0, 14.0, 84.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (37) (590.0, 14.0, 83.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (43) (589.0, 14.0, 82.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (38) (591.0, 14.0, 83.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (40) (588.0, 14.0, 82.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (41) (588.0, 14.0, 81.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (42) (589.0, 14.0, 81.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (50) (583.0, 14.0, 92.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (13) (584.0, 14.0, 92.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (51) (583.0, 14.0, 93.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (14) (585.0, 14.0, 92.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (15) (585.0, 14.0, 93.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (12) (584.0, 14.0, 93.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (49) (582.0, 14.0, 92.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (48) (582.0, 14.0, 93.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (47) (581.0, 14.0, 93.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (46) (581.0, 14.0, 92.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (44) (580.0, 14.0, 93.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (45) (580.0, 14.0, 92.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (27) (592.0, 14.0, 76.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (20) (593.0, 14.0, 78.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (21) (593.0, 14.0, 77.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (24) (591.0, 14.0, 76.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (19) (594.0, 14.0, 76.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (22) (594.0, 14.0, 77.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (16) (593.0, 14.0, 76.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (17) (593.0, 14.0, 75.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (23) (594.0, 14.0, 78.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (26) (592.0, 14.0, 75.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (18) (594.0, 14.0, 75.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Upper Grass (25) (591.0, 14.0, 75.0)": TunicLocationData( + "Forest Belltower Upper", "Forest Belltower Upper"), + "Forest Belltower - Forest Belltower Main Bush (3) (469.0, 38.0, 118.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "Forest Belltower - Forest Belltower Main Bush (4) (467.0, 38.0, 118.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "Forest Belltower - Forest Belltower Main Bush (469.0, 38.0, 120.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "Forest Belltower - Forest Belltower Main Bush (1) (467.0, 38.0, 120.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "Forest Belltower - Forest Belltower Main Bush (8) (465.0, 38.0, 119.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "Forest Belltower - Forest Belltower Main Bush (7) (477.0, 38.0, 117.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "Forest Belltower - Forest Belltower Main Bush (6) (476.0, 38.0, 119.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "Forest Belltower - Forest Belltower Main Bush (5) (460.0, 38.0, 116.0)": TunicLocationData("Forest Belltower Main", + "Forest Belltower Main"), + "East Forest - East Forest Grass (486) (78.0, 8.0, 71.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (488) (78.0, 8.0, 72.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (482) (77.0, 8.0, 73.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (487) (79.0, 8.0, 71.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (489) (79.0, 8.0, 72.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (483) (78.0, 8.0, 73.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (484) (77.0, 8.0, 74.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (485) (78.0, 8.0, 74.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (454) (82.5, 8.0, 62.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (457) (83.5, 8.0, 62.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (455) (82.5, 8.0, 63.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (456) (83.5, 8.0, 63.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (450) (80.8, 4.0, 56.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (453) (81.8, 4.0, 56.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (451) (80.8, 4.0, 57.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (448) (83.3, 4.0, 54.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (447) (82.3, 4.0, 54.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (452) (81.8, 4.0, 57.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (446) (82.3, 4.0, 53.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (449) (83.3, 4.0, 53.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (458) (78.8, 0.0, 47.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (357) (84.0, 0.0, 48.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (356) (84.0, 0.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (367) (83.0, 0.0, 50.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (366) (83.0, 0.0, 51.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (365) (82.0, 0.0, 51.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (359) (85.0, 0.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (358) (85.0, 0.0, 48.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (361) (87.0, 0.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (74) (86.5, 0.0, 48.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (363) (88.0, 0.0, 45.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (362) (88.0, 0.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (360) (87.0, 0.0, 45.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (461) (77.8, 0.0, 47.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (460) (77.8, 0.0, 46.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (459) (78.8, 0.0, 46.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (389) (71.5, 0.0, 38.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (387) (70.5, 0.0, 37.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (388) (70.5, 0.0, 38.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (390) (71.5, 0.0, 37.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (393) (71.5, 0.0, 36.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (392) (70.5, 0.0, 36.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (391) (70.5, 0.0, 35.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (394) (71.5, 0.0, 35.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (396) (71.5, 0.0, 34.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (397) (72.5, 0.0, 34.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (81) (69.0, 0.0, 37.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (80) (69.0, 0.0, 39.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (401) (69.5, 0.0, 35.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (439) (67.5, 0.0, 37.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (400) (68.5, 0.0, 35.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (399) (68.5, 0.0, 34.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (440) (67.5, 0.0, 36.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (82) (67.0, 0.0, 35.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (402) (69.5, 0.0, 34.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (438) (66.5, 0.0, 36.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (443) (67.5, 0.0, 33.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (445) (66.5, 0.0, 33.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (442) (66.5, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (444) (67.5, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (436) (67.5, 0.0, 38.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (435) (67.5, 0.0, 39.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (379) (68.5, 0.0, 40.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (380) (68.5, 0.0, 41.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (382) (69.5, 0.0, 40.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (381) (69.5, 0.0, 41.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (437) (66.5, 0.0, 39.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (434) (66.5, 0.0, 38.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (441) (66.5, 0.0, 37.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (375) (68.5, 0.0, 42.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (376) (68.5, 0.0, 43.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (432) (67.5, 0.0, 43.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (433) (67.5, 0.0, 42.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (378) (69.5, 0.0, 42.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (377) (69.5, 0.0, 43.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (383) (70.5, 0.0, 42.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (418) (67.5, 0.0, 44.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (429) (67.5, 0.0, 44.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (78) (69.0, 0.0, 45.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (428) (67.5, 0.0, 45.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (417) (67.5, 0.0, 45.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (431) (66.5, 0.0, 42.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (427) (66.5, 0.0, 44.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (430) (66.5, 0.0, 43.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (415) (66.5, 0.0, 44.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (384) (70.5, 0.0, 43.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (386) (71.5, 0.0, 42.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (385) (71.5, 0.0, 43.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (371) (70.5, 0.0, 44.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (374) (71.5, 0.0, 44.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (373) (71.5, 0.0, 45.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (372) (70.5, 0.0, 45.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (76) (69.0, 0.0, 47.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (77) (71.0, 0.0, 47.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (416) (66.5, 0.0, 45.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (364) (72.5, 0.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (370) (73.5, 0.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (369) (73.5, 0.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (368) (72.5, 0.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (79) (67.0, 0.0, 47.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (422) (65.5, 0.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (421) (65.5, 0.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (83) (65.0, 0.0, 45.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (419) (64.5, 0.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (420) (64.5, 0.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (426) (67.5, 0.0, 48.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (423) (66.5, 0.0, 48.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (425) (67.5, 0.0, 49.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (424) (66.5, 0.0, 49.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (398) (72.5, 0.0, 33.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (395) (71.5, 0.0, 33.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (404) (72.5, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (405) (73.5, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (413) (72.5, 0.0, 30.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (403) (72.5, 0.0, 31.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (412) (71.5, 0.0, 30.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (406) (73.5, 0.0, 31.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (408) (73.5, 0.0, 30.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (411) (71.5, 0.0, 29.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (414) (72.5, 0.0, 29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (407) (73.5, 0.0, 29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (409) (74.5, 0.0, 30.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (410) (74.5, 0.0, 29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (341) (100.3, 0.0, 30.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (340) (100.3, 0.0, 29.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (343) (101.3, 0.0, 29.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (342) (101.3, 0.0, 30.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (345) (102.3, 0.0, 30.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (346) (103.3, 0.0, 30.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (352) (103.3, 0.0, 31.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (347) (103.3, 0.0, 29.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (344) (102.3, 0.0, 29.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (350) (105.3, 0.0, 30.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (351) (105.3, 0.0, 29.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (348) (104.3, 0.0, 29.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (349) (104.3, 0.0, 30.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (355) (104.3, 0.0, 31.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (354) (104.3, 0.0, 32.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (353) (103.3, 0.0, 32.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (463) (106.5, 0.0, 46.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (465) (106.5, 0.0, 45.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (462) (107.5, 0.0, 45.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (339) (109.8, 0.0, 47.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (464) (107.5, 0.0, 46.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (336) (108.8, 0.0, 47.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (337) (108.8, 0.0, 48.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (338) (109.8, 0.0, 48.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (330) (104.3, 0.0, 49.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (331) (104.3, 0.0, 48.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (328) (103.3, 0.0, 48.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (329) (103.3, 0.0, 49.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (327) (102.3, 0.0, 48.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (326) (102.3, 0.0, 49.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (324) (101.3, 0.0, 48.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (325) (101.3, 0.0, 49.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (72) (101.8, 0.0, 50.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (71) (99.5, 0.0, 50.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (67) (97.5, 0.0, 50.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (316) (97.0, 0.0, 49.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (323) (96.0, 0.0, 50.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (317) (98.0, 0.0, 49.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (73) (99.5, 0.0, 48.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (318) (98.0, 0.0, 48.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (333) (98.0, 0.0, 47.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (319) (97.0, 0.0, 48.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (334) (99.0, 0.0, 47.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (332) (98.0, 0.0, 46.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (335) (99.0, 0.0, 46.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (322) (96.0, 0.0, 51.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (321) (95.0, 0.0, 51.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (320) (95.0, 0.0, 50.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (309) (127.3, 0.0, 43.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (308) (128.3, 0.0, 43.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (70) (129.3, 0.0, 43.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (306) (128.3, 0.0, 44.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (307) (127.2, 0.0, 44.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (278) (131.8, 0.0, 38.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (280) (131.8, 0.0, 37.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (279) (132.8, 0.0, 38.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (281) (132.8, 0.0, 37.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (276) (133.8, 0.0, 37.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (274) (133.8, 0.0, 38.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (284) (133.8, 0.0, 39.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (285) (134.8, 0.0, 39.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (277) (134.8, 0.0, 37.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (275) (134.8, 0.0, 38.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (283) (134.8, 0.0, 40.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (282) (133.8, 0.0, 40.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (271) (133.8, 0.0, 36.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (270) (132.8, 0.0, 36.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (273) (133.8, 0.0, 35.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (272) (132.8, 0.0, 35.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (267) (131.8, 0.0, 34.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (69) (133.3, 0.0, 34.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (66) (135.3, 0.0, 36.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (266) (130.8, 0.0, 34.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (269) (131.8, 0.0, 33.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (255) (132.8, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (262) (131.8, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (252) (133.8, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (268) (130.8, 0.0, 33.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (68) (135.3, 0.0, 32.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (265) (130.8, 0.0, 32.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (264) (131.8, 0.0, 31.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (254) (132.8, 0.0, 31.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (253) (133.8, 0.0, 31.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (260) (132.8, 0.0, 29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (261) (132.8, 0.0, 30.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (256) (134.8, 0.0, 30.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (258) (134.8, 0.0, 29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (259) (133.8, 0.0, 30.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (257) (133.8, 0.0, 29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (299) (135.8, 0.0, 27.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (263) (130.8, 0.0, 31.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (295) (135.8, 0.0, 25.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (301) (135.8, 0.0, 26.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (294) (134.8, 0.0, 25.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (300) (134.8, 0.0, 26.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (296) (134.8, 0.0, 24.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (298) (134.8, 0.0, 27.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (302) (131.8, 0.0, 23.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (304) (131.8, 0.0, 22.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (290) (133.8, 0.0, 23.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (303) (132.8, 0.0, 23.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (305) (132.8, 0.0, 22.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (292) (133.8, 0.0, 22.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (297) (135.8, 0.0, 24.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (291) (134.8, 0.0, 23.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (289) (134.8, 0.0, 20.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (293) (134.8, 0.0, 22.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (287) (134.8, 0.0, 21.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (286) (133.8, 0.0, 21.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (288) (133.8, 0.0, 20.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (466) (117.5, 0.0, 13.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (469) (117.5, 0.0, 12.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (470) (117.5, 0.0, 11.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (468) (116.5, 0.0, 13.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (467) (116.5, 0.0, 12.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (472) (116.5, 0.0, 11.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (471) (116.5, 0.0, 10.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (473) (117.5, 0.0, 10.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (315) (109.3, -1.3, 0.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (310) (110.3, -0.8, 2.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (314) (110.3, -1.3, 0.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (313) (108.3, 0.0, 3.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (311) (108.3, 0.0, 4.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (312) (107.3, 0.0, 3.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (497) (105.8, 0.0, 8.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (501) (103.5, 0.0, 7.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (502) (103.5, 0.0, 6.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (495) (104.8, 0.0, 8.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (493) (105.8, 0.0, 10.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (494) (105.8, 0.0, 9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (496) (104.8, 0.0, 9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (498) (103.5, 0.0, 8.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (490) (105.8, 0.0, 11.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (491) (104.8, 0.0, 10.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (492) (104.8, 0.0, 11.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (505) (103.5, 0.0, 5.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (499) (102.5, 0.0, 7.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (504) (102.5, 0.0, 6.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (500) (102.5, 0.0, 8.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (503) (102.5, 0.0, 5.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (507) (87.3, -4.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (509) (88.3, -4.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (513) (86.3, -4.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (506) (88.3, -4.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (508) (87.3, -4.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (510) (86.3, -4.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (512) (85.3, -4.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (511) (77.3, -4.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (514) (77.3, -4.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (516) (76.3, -4.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (515) (76.3, -4.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (519) (88.5, -4.0, -11.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (520) (88.5, -4.0, -12.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (524) (89.8, -4.0, -10.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (517) (89.5, -4.0, -12.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (518) (89.5, -4.0, -11.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (523) (89.8, -4.0, -9.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (521) (90.8, -4.0, -10.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (522) (90.8, -4.0, -9.8)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (89) (131.5, 0.0, -5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (87) (132.5, 0.0, -6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (84) (132.5, 0.0, -7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (85) (133.5, 0.0, -7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (88) (130.5, 0.0, -5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (86) (133.5, 0.0, -6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (78) (133.5, 0.0, -4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (77) (133.5, 0.0, -5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (76) (132.5, 0.0, -5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (90) (131.5, 0.0, -4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (91) (130.5, 0.0, -4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (79) (132.5, 0.0, -4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (80) (132.5, 0.0, -3.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (93) (131.5, 0.0, -2.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (92) (130.5, 0.0, -2.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (83) (132.5, 0.0, -2.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (94) (131.5, 0.0, -1.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (95) (130.5, 0.0, -1.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (81) (133.5, 0.0, -3.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (43) (135.0, 0.0, -5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (82) (133.5, 0.0, -2.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (44) (135.0, 0.0, -7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (58) (137.5, 0.0, -7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (73) (137.5, 0.0, -8.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (74) (136.5, 0.0, -8.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (75) (136.5, 0.0, -9.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (59) (136.5, 0.0, -7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (56) (137.5, 0.0, -6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (57) (136.5, 0.0, -6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (98) (135.5, 0.0, -12.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (46) (135.0, 0.0, -11.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (99) (134.5, 0.0, -12.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (96) (134.5, 0.0, -13.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (55) (136.5, 0.0, -11.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (52) (136.5, 0.0, -10.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (97) (135.5, 0.0, -13.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (33) (137.0, 0.0, -13.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (32) (139.0, 0.0, -13.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (54) (137.5, 0.0, -11.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (38) (139.0, 0.0, -11.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (53) (137.5, 0.0, -10.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (72) (137.5, 0.0, -9.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (29) (141.0, 0.0, -13.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (68) (142.5, 0.0, -10.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (35) (141.0, 0.0, -11.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (70) (139.5, 0.0, -9.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (37) (141.0, 0.0, -9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (65) (139.5, 0.0, -8.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (71) (138.5, 0.0, -9.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (66) (138.5, 0.0, -8.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (42) (143.0, 0.0, -9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (63) (142.5, 0.0, -7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (60) (143.5, 0.0, -7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (62) (142.5, 0.0, -6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (39) (141.0, 0.0, -7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (69) (143.5, 0.0, -10.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (67) (144.5, 0.0, -8.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (64) (144.5, 0.0, -9.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (41) (145.0, 0.0, -7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (61) (143.5, 0.0, -6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (40) (143.0, 0.0, -5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (102) (135.5, 0.0, -18.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (100) (134.5, 0.0, -19.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (103) (134.5, 0.0, -18.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (101) (135.5, 0.0, -19.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (34) (137.0, 0.0, -19.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (107) (138.5, 0.0, -20.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (31) (139.0, 0.0, -19.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (104) (138.5, 0.0, -21.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (106) (139.5, 0.0, -20.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (105) (139.5, 0.0, -21.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (36) (141.0, 0.0, -21.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (30) (141.0, 0.0, -19.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (115) (138.0, 0.0, -24.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (112) (138.0, 0.0, -25.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (114) (139.0, 0.0, -24.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (113) (139.0, 0.0, -25.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (111) (140.5, 0.0, -26.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (118) (133.5, 0.0, -26.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (117) (133.5, 0.0, -27.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (119) (132.5, 0.0, -26.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (116) (132.5, 0.0, -27.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (110) (141.5, 0.0, -26.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (108) (140.5, 0.0, -27.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (109) (141.5, 0.0, -27.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (123) (142.5, 0.0, -28.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (120) (142.5, 0.0, -29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (122) (143.5, 0.0, -28.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (121) (143.5, 0.0, -29.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (244) (135.5, 8.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (247) (135.5, 8.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (246) (134.5, 8.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (245) (134.5, 8.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (250) (140.5, 8.0, -2.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (249) (140.5, 8.0, -3.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (251) (141.5, 8.0, -3.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (248) (141.5, 8.0, -2.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (213) (147.5, 8.0, 0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (215) (146.5, 8.0, 0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (212) (146.5, 8.0, 1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (203) (146.5, 8.0, 2.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (207) (143.5, 8.0, 4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (61) (143.0, 8.0, 3.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (237) (141.5, 8.0, 2.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (205) (142.5, 8.0, 4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (238) (141.5, 8.0, 3.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (239) (140.5, 8.0, 2.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (236) (140.5, 8.0, 3.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (1) (141.0, 8.0, 5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (7) (139.0, 8.0, 5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (206) (142.5, 8.0, 5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (204) (143.5, 8.0, 5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (60) (145.0, 8.0, 5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (3) (143.0, 8.0, 9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (2) (141.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (242) (137.5, 8.0, 5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (5) (137.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (4) (139.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (240) (136.5, 8.0, 5.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (243) (136.5, 8.0, 4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (241) (137.5, 8.0, 4.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (137.0, 8.0, 9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (6) (135.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (211) (144.5, 8.0, 6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (208) (144.5, 8.0, 7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (209) (145.5, 8.0, 6.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (210) (145.5, 8.0, 7.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (56) (149.0, 8.0, 5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (59) (147.0, 8.0, 5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (58) (147.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (15) (149.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (9) (145.0, 8.0, 9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (201) (146.5, 8.0, 3.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (200) (147.5, 8.0, 3.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (202) (147.5, 8.0, 2.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (57) (149.0, 8.0, 3.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (63) (151.0, 8.0, 1.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (214) (147.5, 8.0, 1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (62) (149.0, 8.0, 1.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (224) (153.5, 8.0, 1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (225) (152.5, 8.0, 0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (226) (152.5, 8.0, 1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (65) (151.0, 8.0, 5.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (64) (151.0, 8.0, 3.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (17) (153.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (16) (151.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (18) (155.0, 8.0, 7.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (233) (157.5, 8.0, 10.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (20) (155.0, 8.0, 9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (235) (156.5, 8.0, 10.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (232) (156.5, 8.0, 11.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (23) (155.0, 8.0, 11.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (22) (153.0, 8.0, 11.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (19) (153.0, 8.0, 9.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (234) (157.5, 8.0, 11.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (230) (154.5, 8.0, 1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (228) (155.5, 8.0, 1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (229) (154.5, 8.0, 0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (227) (153.5, 8.0, 0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (231) (155.5, 8.0, 0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (218) (149.5, 8.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (217) (149.5, 8.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (219) (148.5, 8.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (216) (148.5, 8.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (221) (150.5, 8.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (222) (150.5, 8.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (220) (151.5, 8.0, -0.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (223) (151.5, 8.0, -1.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (546) (167.0, 7.8, -23.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (545) (167.0, 7.8, -22.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (543) (166.0, 7.8, -22.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (544) (166.0, 7.8, -23.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (167) (130.0, 24.0, 52.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (164) (130.0, 24.0, 53.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (165) (131.0, 24.0, 52.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (166) (131.0, 24.0, 53.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (135) (125.5, 24.0, 52.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (133) (124.5, 24.0, 52.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (49) (123.0, 24.0, 53.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (131) (121.5, 24.0, 52.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (128) (121.5, 24.0, 53.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (129) (120.5, 24.0, 52.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (176) (119.5, 24.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (178) (118.5, 24.0, 47.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (177) (118.5, 24.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (179) (119.5, 24.0, 46.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (134) (124.5, 24.0, 53.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (132) (125.5, 24.0, 53.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (137) (124.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (139) (125.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (48) (123.0, 24.0, 57.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (45) (121.0, 24.0, 55.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (130) (120.5, 24.0, 53.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (149) (119.5, 24.0, 54.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (145) (119.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (47) (121.0, 24.0, 57.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (150) (119.5, 24.0, 55.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (146) (119.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (144) (118.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (147) (118.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (148) (118.5, 24.0, 55.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (173) (117.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (151) (118.5, 24.0, 54.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (174) (117.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (172) (116.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (175) (116.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Bush (50) (115.0, 24.0, 57.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (170) (113.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (126) (113.5, 24.0, 58.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (125) (113.5, 24.0, 59.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (169) (113.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (127) (112.5, 24.0, 58.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (124) (112.5, 24.0, 59.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (168) (112.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (171) (112.5, 24.0, 56.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (141) (121.5, 24.0, 58.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (155) (123.5, 24.0, 58.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (153) (122.5, 24.0, 58.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (142) (121.5, 24.0, 59.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (152) (123.5, 24.0, 59.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (154) (122.5, 24.0, 59.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (143) (120.5, 24.0, 58.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (140) (120.5, 24.0, 59.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (159) (126.0, 24.0, 62.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (163) (128.0, 24.0, 60.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (157) (125.0, 24.0, 62.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (161) (127.0, 24.0, 60.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (162) (127.0, 24.0, 61.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (160) (128.0, 24.0, 61.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (156) (126.0, 24.0, 63.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (158) (125.0, 24.0, 63.0)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (136) (125.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (138) (124.5, 24.0, 57.5)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (476) (130.0, 0.0, 8.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (474) (131.0, 0.0, 8.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (477) (131.0, 0.0, 7.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (475) (130.0, 0.0, 7.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (479) (132.5, 0.0, 9.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (481) (133.5, 0.0, 9.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (478) (133.5, 0.0, 10.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Grass (480) (132.5, 0.0, 10.3)": TunicLocationData("East Forest", "East Forest"), + "East Forest - East Forest Dance Fox Spot Grass (548) (95.5, 16.0, 75.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (550) (96.5, 16.0, 75.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (547) (95.5, 16.0, 76.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (549) (96.5, 16.0, 76.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (180) (88.0, 16.0, 65.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (181) (88.0, 16.0, 64.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (182) (87.0, 16.0, 64.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (183) (87.0, 16.0, 65.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Bush (52) (89.5, 16.0, 64.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Bush (55) (89.5, 16.0, 62.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (189) (85.0, 16.0, 61.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (190) (84.0, 16.0, 60.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (188) (84.0, 16.0, 61.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (191) (85.0, 16.0, 60.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Bush (51) (89.5, 16.0, 60.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Bush (54) (95.5, 16.0, 62.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Bush (53) (95.5, 16.0, 64.5)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (197) (91.5, 16.0, 56.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (198) (90.5, 16.0, 55.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (196) (90.5, 16.0, 56.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (199) (91.5, 16.0, 55.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (187) (90.5, 16.0, 54.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (184) (91.5, 16.0, 54.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (186) (91.5, 16.0, 53.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (185) (90.5, 16.0, 53.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (194) (92.5, 16.0, 53.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (192) (92.5, 16.0, 54.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (193) (93.5, 16.0, 54.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - East Forest Dance Fox Spot Grass (195) (93.5, 16.0, 53.0)": TunicLocationData( + "East Forest Dance Fox Spot", "East Forest Dance Fox Spot"), + "East Forest - Lower Forest Grass (528) (86.5, -12.0, -15.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (529) (87.5, -12.0, -16.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (525) (87.5, -12.0, -15.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (527) (86.5, -12.0, -14.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (526) (87.5, -12.0, -14.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (533) (86.0, -20.3, -21.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (530) (87.0, -20.3, -21.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (531) (87.0, -20.3, -20.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (532) (86.0, -20.3, -20.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (14) (99.0, -26.0, -53.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (8) (99.0, -26.0, -49.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (13) (99.0, -26.0, -51.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (10) (104.0, -26.0, -49.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (1) (98.0, -26.0, -57.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (15) (98.0, -26.0, -56.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (12) (98.0, -26.0, -55.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (16) (97.0, -26.0, -57.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (13) (99.0, -26.0, -56.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (99.0, -26.0, -57.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (14) (99.0, -26.0, -55.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (31) (105.0, -26.0, -50.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (26) (105.0, -26.0, -51.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (29) (106.0, -26.0, -50.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (24) (106.0, -26.0, -51.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (23) (106.0, -26.0, -54.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (27) (106.0, -26.0, -52.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (20) (106.0, -26.0, -53.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (22) (105.0, -26.0, -53.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (25) (105.0, -26.0, -52.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (28) (105.0, -26.0, -55.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (21) (105.0, -26.0, -54.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (30) (106.0, -26.0, -55.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (5) (99.0, -26.0, -60.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (24) (105.0, -26.0, -61.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (26) (105.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (25) (107.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (38) (109.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (37) (109.0, -26.0, -60.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (39) (110.0, -26.0, -60.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (36) (110.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (35) (112.0, -26.0, -60.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (41) (112.0, -26.0, -62.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (42) (112.0, -26.0, -61.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (40) (111.0, -26.0, -61.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (33) (111.0, -26.0, -60.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (43) (111.0, -26.0, -62.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (32) (112.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (34) (111.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (6) (99.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (2) (98.0, -26.0, -58.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (7) (98.0, -26.0, -60.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (4) (98.0, -26.0, -59.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (3) (99.0, -26.0, -58.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (10) (99.0, -26.0, -61.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (9) (99.0, -26.0, -62.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (8) (98.0, -26.0, -61.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (11) (98.0, -26.0, -62.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (19) (97.0, -26.0, -58.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (17) (96.0, -26.0, -58.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (18) (96.0, -26.0, -57.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (50) (99.0, -26.0, -66.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (48) (98.0, -26.0, -66.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (44) (96.0, -26.0, -66.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (46) (97.0, -26.0, -66.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (45) (97.0, -26.0, -67.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (47) (96.0, -26.0, -67.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (49) (99.0, -26.0, -67.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (51) (98.0, -26.0, -67.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (27) (91.0, -26.0, -52.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Bush (28) (91.0, -26.0, -54.0)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (68) (100.3, -30.5, -69.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (73) (100.3, -30.5, -70.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (65) (100.3, -30.5, -68.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (67) (101.3, -30.5, -69.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (74) (101.3, -30.5, -70.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (66) (101.3, -30.5, -68.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (71) (99.3, -30.5, -69.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (70) (99.3, -30.5, -68.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (69) (98.3, -30.5, -68.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (72) (98.3, -30.5, -69.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (75) (101.3, -30.5, -71.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (534) (100.3, -30.5, -71.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (541) (85.3, -30.5, -52.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (536) (88.8, -30.5, -55.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (535) (87.8, -30.5, -55.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (542) (84.3, -30.5, -52.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (540) (85.3, -30.5, -51.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (539) (84.3, -30.5, -51.8)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (538) (87.8, -30.5, -56.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (537) (88.8, -30.5, -56.3)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (53) (142.8, -26.0, -52.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (54) (142.8, -26.0, -51.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (52) (141.8, -26.0, -52.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (55) (141.8, -26.0, -51.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (56) (141.8, -26.0, -35.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (57) (142.8, -26.0, -35.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (60) (141.8, -26.0, -34.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (59) (142.8, -26.0, -34.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (62) (130.5, -26.0, -34.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (63) (130.5, -26.0, -33.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (64) (129.5, -26.0, -33.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "East Forest - Lower Forest Grass (61) (129.5, -26.0, -34.5)": TunicLocationData("Lower Forest", "Lower Forest"), + "Guardhouse 1 - Guard House 1 West Grass (40) (129.0, 0.0, 50.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (44) (127.0, 0.0, 52.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (46) (127.0, 0.0, 51.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (36) (127.0, 0.0, 50.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (45) (128.0, 0.0, 51.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (47) (128.0, 0.0, 52.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (39) (128.0, 0.0, 50.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (43) (130.0, 0.0, 50.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (32) (125.0, 0.0, 49.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (34) (125.0, 0.0, 50.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (33) (126.0, 0.0, 50.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (35) (126.0, 0.0, 49.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (38) (127.0, 0.0, 49.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (42) (129.0, 0.0, 49.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (37) (128.0, 0.0, 49.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (41) (130.0, 0.0, 49.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (24) (118.0, 0.0, 55.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (26) (118.0, 0.0, 56.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (30) (118.0, 0.0, 54.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (27) (119.0, 0.0, 55.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (25) (119.0, 0.0, 56.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (29) (119.0, 0.0, 54.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (31) (119.0, 0.0, 53.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (28) (118.0, 0.0, 53.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (22) (130.0, 0.0, 69.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (9) (128.0, 0.0, 69.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (10) (128.0, 0.0, 68.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (21) (129.0, 0.0, 70.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (20) (129.0, 0.0, 69.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (11) (127.0, 0.0, 68.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (14) (133.0, 0.0, 72.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (15) (132.0, 0.0, 71.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (12) (132.0, 0.0, 72.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (23) (130.0, 0.0, 70.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (8) (127.0, 0.0, 69.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (13) (133.0, 0.0, 71.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (18) (134.0, 0.0, 73.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (16) (133.0, 0.0, 73.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (19) (134.0, 0.0, 74.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (17) (133.0, 0.0, 74.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (3) (116.0, 16.0, 78.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (1) (117.0, 16.0, 79.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (2) (117.0, 16.0, 78.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (116.0, 16.0, 79.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (5) (117.0, 16.0, 74.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (7) (118.0, 16.0, 73.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (4) (118.0, 16.0, 74.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 1 - Guard House 1 West Grass (6) (117.0, 16.0, 73.0)": TunicLocationData("Guard House 1 West", + "Guard House 1 West"), + "Guardhouse 2 - Guard House 2 Upper Grass (25) (150.5, 0.0, -15.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (11) (150.5, 0.0, -13.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (26) (150.5, 0.0, -14.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (24) (151.5, 0.0, -14.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (9) (151.5, 0.0, -13.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (27) (151.5, 0.0, -15.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (7) (155.0, 0.0, -17.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (5) (153.0, 0.0, -15.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (6) (153.0, 0.0, -17.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (7) (152.5, 0.0, -13.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (6) (153.5, 0.0, -12.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (5) (153.5, 0.0, -13.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (1) (154.5, 0.0, -12.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (2) (154.5, 0.0, -13.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (4) (155.0, 0.0, -15.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (155.5, 0.0, -12.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (3) (155.5, 0.0, -13.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (32) (156.5, 0.0, -14.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (9) (153.0, 0.0, -11.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (4) (152.5, 0.0, -12.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (10) (151.5, 0.0, -12.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (13) (151.5, 0.0, -9.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (8) (151.0, 0.0, -11.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (8) (150.5, 0.0, -12.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (15) (150.5, 0.0, -9.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (35) (156.5, 0.0, -15.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (29) (155.5, 0.0, -19.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (30) (155.5, 0.0, -18.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (31) (154.5, 0.0, -19.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (28) (154.5, 0.0, -18.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (33) (157.5, 0.0, -15.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (34) (157.5, 0.0, -14.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (3) (157.0, 0.0, -13.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (37) (157.5, 0.0, -11.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (38) (157.5, 0.0, -10.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (39) (156.5, 0.0, -11.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (36) (156.5, 0.0, -10.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (2) (155.0, 0.0, -11.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (41) (154.5, 0.0, -9.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (43) (155.5, 0.0, -9.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (40) (155.5, 0.0, -8.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (42) (154.5, 0.0, -8.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (14) (151.5, 0.0, -8.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (19) (151.5, 0.0, -7.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (16) (151.5, 0.0, -6.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (18) (150.5, 0.0, -6.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (153.0, 0.0, -7.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Bush (1) (153.0, 0.0, -9.0)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (17) (150.5, 0.0, -7.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (12) (150.5, 0.0, -8.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (23) (149.5, 0.0, -7.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (20) (149.5, 0.0, -6.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (22) (148.5, 0.0, -6.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Guardhouse 2 - Guard House 2 Upper Grass (21) (148.5, 0.0, -7.5)": TunicLocationData("Guard House 2 Upper after bushes", + "Guard House 2 Upper after bushes"), + "Forest Grave Path - Forest Grave Path Main Bush (110) (-70.0, -4.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (112) (-66.0, -4.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (111) (-64.0, -4.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (113) (-64.0, -4.0, -183.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (76) (-62.8, -4.0, -182.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (82) (-59.8, -4.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (83) (-60.8, -4.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (78) (-61.8, -4.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (77) (-61.8, -4.0, -182.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (79) (-62.8, -4.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (119) (-65.0, -4.0, -193.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (118) (-65.0, -4.0, -195.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (120) (-63.0, -4.0, -195.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (90) (-59.5, -4.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (121) (-59.0, -4.0, -197.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (122) (-57.0, -4.0, -191.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (91) (-58.5, -4.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (86) (-57.5, -4.0, -189.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (89) (-57.5, -4.0, -188.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (87) (-56.5, -4.0, -189.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (88) (-56.5, -4.0, -188.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (106) (-53.0, -4.0, -191.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (107) (-55.0, -4.0, -191.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (104) (-53.0, -4.0, -187.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (115) (-55.0, -4.0, -187.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (108) (-55.0, -4.0, -189.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (105) (-53.0, -4.0, -189.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (117) (-55.0, -4.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (109) (-57.0, -4.0, -187.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (92) (-58.5, -4.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (93) (-59.5, -4.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (103) (-53.0, -4.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (81) (-52.5, -4.0, -181.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (116) (-53.0, -4.0, -183.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (85) (-53.5, -4.0, -180.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (80) (-53.5, -4.0, -181.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (84) (-52.5, -4.0, -180.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (133) (-45.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (136) (-43.0, 0.0, -189.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (135) (-43.0, 0.0, -187.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (42) (-42.5, 0.0, -190.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (47) (-41.5, 0.0, -188.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (56) (-41.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (44) (-41.5, 0.0, -189.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (45) (-40.5, 0.0, -189.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (33) (-46.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (134) (-43.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (43) (-43.5, 0.0, -190.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (34) (-46.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (35) (-47.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (32) (-47.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (59) (-41.5, 0.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (137) (-41.0, 0.0, -191.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (40) (-43.5, 0.0, -191.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (138) (-43.0, 0.0, -193.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (41) (-42.5, 0.0, -191.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (61) (-40.5, 0.0, -195.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (36) (-41.5, 0.0, -193.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (39) (-41.5, 0.0, -192.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (60) (-41.5, 0.0, -195.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (63) (-41.5, 0.0, -194.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (62) (-40.5, 0.0, -194.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (38) (-40.5, 0.0, -192.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (37) (-40.5, 0.0, -193.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (53) (-38.5, 0.0, -189.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (50) (-38.5, 0.0, -190.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (49) (-38.5, 0.0, -191.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (48) (-39.5, 0.0, -191.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (52) (-39.5, 0.0, -189.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (51) (-39.5, 0.0, -190.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (46) (-40.5, 0.0, -188.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (54) (-38.5, 0.0, -188.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (55) (-39.5, 0.0, -188.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (57) (-40.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (58) (-40.5, 0.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (141) (-47.0, 0.0, -195.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (139) (-43.0, 0.0, -195.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (140) (-45.0, 0.0, -195.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (66) (-43.0, 0.0, -200.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (67) (-44.0, 0.0, -200.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (64) (-44.0, 0.0, -201.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (65) (-43.0, 0.0, -201.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (68) (-40.0, 0.0, -201.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (71) (-40.0, 0.0, -200.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (70) (-39.0, 0.0, -200.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (69) (-39.0, 0.0, -201.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (75) (-31.5, 0.0, -192.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (72) (-31.5, 0.0, -193.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (73) (-30.5, 0.0, -193.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (74) (-30.5, 0.0, -192.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (147) (-35.0, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (146) (-33.0, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (28) (-33.5, 0.0, -184.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (29) (-32.5, 0.0, -184.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (23) (-31.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (20) (-31.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (21) (-30.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (26) (-32.5, 0.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (30) (-32.5, 0.0, -183.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (25) (-32.5, 0.0, -182.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (31) (-33.5, 0.0, -183.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (24) (-33.5, 0.0, -182.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (27) (-33.5, 0.0, -181.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (148) (-35.0, 0.0, -183.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (22) (-30.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (12) (-29.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (13) (-28.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (10) (-27.5, 0.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (11) (-27.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (15) (-29.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (3) (-23.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (132) (-25.0, 0.0, -187.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (8) (-26.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (9) (-26.5, 0.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (130) (-25.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (131) (-27.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (14) (-28.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (-23.5, 0.0, -186.5)": TunicLocationData("Forest Grave Path Main", + "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (2) (-22.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (1) (-22.5, 0.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (126) (-19.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (6) (-20.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (4) (-20.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (7) (-21.5, 0.0, -185.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (5) (-21.5, 0.0, -184.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (129) (-23.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (19) (-17.5, 0.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (16) (-17.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (18) (-16.5, 0.0, -186.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (17) (-16.5, 0.0, -187.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (125) (-15.0, 0.0, -187.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (124) (-15.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (123) (-17.0, 0.0, -185.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (127) (-14.0, 0.0, -194.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (116) (-23.8, -4.3, -205.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (97) (-27.3, -6.3, -210.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (96) (-26.3, -6.3, -210.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (117) (-22.8, -4.3, -205.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (119) (-22.8, -4.3, -204.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (95) (-26.3, -6.3, -211.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (118) (-23.8, -4.3, -204.8)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (123) (-20.5, -4.3, -208.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (121) (-20.5, -4.3, -209.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (114) (-15.5, -4.3, -212.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (112) (-15.5, -4.3, -213.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (115) (-14.5, -4.3, -212.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (113) (-14.5, -4.3, -213.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (110) (-13.5, -4.3, -213.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (111) (-12.5, -4.3, -213.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (109) (-12.5, -4.3, -212.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (108) (-13.5, -4.3, -212.3)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (106) (-24.3, -6.2, -215.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (102) (-24.3, -6.3, -214.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (103) (-23.3, -6.3, -214.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (99) (-25.3, -6.3, -213.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (101) (-26.3, -6.3, -212.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (98) (-26.3, -6.3, -213.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (94) (-27.3, -6.3, -211.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (107) (-23.3, -6.3, -215.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (105) (-24.3, -6.3, -213.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (100) (-25.3, -6.3, -212.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Grass (104) (-23.3, -6.3, -213.5)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (144) (-21.5, 8.0, -179.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (145) (-23.5, 8.0, -179.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path Main Bush (149) (-25.5, 8.0, -179.0)": TunicLocationData( + "Forest Grave Path Main", "Forest Grave Path Main"), + "Forest Grave Path - Forest Grave Path by Grave Grass (58) (8.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (57) (8.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (102) (9.0, 4.0, -189.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (59) (9.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (56) (9.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (52) (12.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (55) (12.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (54) (13.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (53) (13.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (47) (14.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (44) (14.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (49) (13.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (50) (13.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (51) (12.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (48) (12.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (100) (11.0, 4.0, -189.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (99) (15.0, 4.0, -191.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (45) (15.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (7) (16.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (5) (16.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (21) (19.5, 4.0, -193.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (30) (19.5, 4.0, -194.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (22) (19.5, 4.0, -192.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (14) (18.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (20) (18.5, 4.0, -192.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (28) (18.5, 4.0, -194.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (23) (18.5, 4.0, -193.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (98) (17.0, 4.0, -193.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (6) (17.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (9) (19.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (15) (19.5, 4.0, -191.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (11) (19.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (13) (19.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (8) (18.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (12) (18.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (10) (18.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (2) (17.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (4) (17.5, 4.0, -190.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (1) (17.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (3) (16.5, 4.0, -189.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (97) (17.0, 4.0, -187.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (16.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (46) (15.5, 4.0, -188.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (89) (21.0, 4.0, -195.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (31) (18.5, 4.0, -195.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (29) (19.5, 4.0, -195.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (26) (23.5, 4.0, -192.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (25) (23.5, 4.0, -193.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (90) (23.0, 4.0, -195.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (27) (22.5, 4.0, -193.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (24) (22.5, 4.0, -192.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (88) (21.0, 4.0, -193.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (75) (21.0, 4.0, -191.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (71) (21.0, 4.0, -189.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (37) (22.5, 4.0, -187.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (91) (25.0, 4.0, -195.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (93) (29.0, 4.0, -195.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (92) (27.0, 4.0, -195.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (35) (23.5, 4.0, -185.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (33) (22.5, 4.0, -185.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (38) (22.5, 4.0, -186.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (36) (23.5, 4.0, -186.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (39) (23.5, 4.0, -187.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (95) (27.0, 4.0, -185.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (96) (25.0, 4.0, -185.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (32) (23.5, 4.0, -184.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (40) (21.5, 4.0, -184.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (43) (21.5, 4.0, -185.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (34) (22.5, 4.0, -184.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (42) (20.5, 4.0, -184.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (41) (20.5, 4.0, -185.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Bush (94) (29.0, 4.0, -185.0)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (17) (17.5, 4.0, -184.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (19) (17.5, 4.0, -185.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (16) (16.5, 4.0, -184.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "Forest Grave Path - Forest Grave Path by Grave Grass (18) (16.5, 4.0, -185.5)": TunicLocationData( + "Forest Grave Path by Grave", "Forest Grave Path by Grave"), + "West Garden - West Garden Grass (297) (-115.0, 4.0, 159.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (300) (-113.8, 4.0, 159.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (296) (-115.0, 4.0, 160.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (298) (-116.0, 4.0, 160.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (187) (-125.5, 4.0, 160.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (189) (-124.5, 4.0, 160.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (185) (-131.0, 4.0, 160.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (206) (-131.0, 4.0, 159.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (188) (-131.0, 4.0, 159.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (186) (-132.0, 4.0, 160.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (218) (-131.8, 2.3, 151.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (219) (-131.8, 1.8, 150.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (217) (-130.5, 2.3, 151.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (216) (-130.5, 2.8, 152.8)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (241) (-161.6, 2.0, 124.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (192) (-158.0, 1.5, 122.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (191) (-158.0, 1.5, 123.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (193) (-157.0, 1.5, 122.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (190) (-157.0, 1.5, 123.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (239) (-159.7, 1.5, 117.7)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (235) (-159.8, 1.5, 116.7)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (236) (-160.8, 1.5, 116.7)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (237) (-161.8, 1.5, 116.7)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (194) (-165.4, 2.0, 121.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (196) (-162.5, 2.0, 123.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (238) (-162.5, 2.0, 124.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (195) (-165.4, 2.0, 120.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (240) (-162.5, 2.0, 125.4)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (20) (-162.0, 10.0, 139.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (18) (-160.0, 10.0, 139.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (19) (-160.0, 10.0, 141.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (295) (-159.5, 9.8, 160.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (21) (-180.0, 10.0, 139.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (23) (-180.0, 10.0, 141.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (22) (-178.0, 10.0, 139.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (212) (-174.5, 2.0, 123.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (213) (-174.5, 2.0, 124.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (214) (-174.5, 2.0, 125.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (215) (-175.5, 2.0, 124.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (24) (-185.0, 1.9, 143.9)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (198) (-185.0, 2.5, 148.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (197) (-185.0, 2.5, 149.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (202) (-185.0, 2.5, 150.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (201) (-186.0, 2.5, 150.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (200) (-186.0, 2.5, 149.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (216) (-192.3, 1.0, 145.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (217) (-192.3, 1.0, 146.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (211) (-193.3, 0.9, 145.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (406) (-190.8, 1.3, 149.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (405) (-189.8, 1.3, 149.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (25) (-196.0, 0.8, 152.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (203) (-198.5, 1.0, 150.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (199) (-198.5, 1.0, 151.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (205) (-199.5, 1.0, 151.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (204) (-199.5, 1.0, 150.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (213) (-196.0, 4.0, 160.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (214) (-197.0, 4.0, 159.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (212) (-197.0, 4.0, 160.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (211) (-198.0, 4.0, 160.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (215) (-198.0, 4.0, 159.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (31) (-250.5, 4.0, 147.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (34) (-251.5, 4.0, 147.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (10) (-253.5, 3.8, 150.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (7) (-252.5, 3.8, 150.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (8) (-253.5, 3.8, 151.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (40) (-261.0, 4.0, 151.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (42) (-261.0, 4.0, 150.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (37) (-262.0, 4.0, 151.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (36) (-263.0, 4.0, 151.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (35) (-262.0, 4.0, 150.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (38) (-263.0, 4.0, 150.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (5) (-256.1, 4.0, 160.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (4) (-255.1, 4.0, 160.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (6) (-256.1, 4.0, 161.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (3) (-255.1, 4.0, 161.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (11) (-262.5, 4.0, 172.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (13) (-262.5, 4.0, 173.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (12) (-263.5, 4.0, 173.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (14) (-263.5, 4.0, 172.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (18) (-256.0, 4.0, 173.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (17) (-255.0, 4.0, 174.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (15) (-255.0, 4.0, 173.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (16) (-256.0, 4.0, 174.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (22) (-260.5, 4.0, 177.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (19) (-259.5, 4.0, 177.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (21) (-259.5, 4.0, 178.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (20) (-260.5, 4.0, 178.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (75) (-254.0, 4.0, 183.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (30) (-253.0, 4.0, 183.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (28) (-253.0, 4.0, 181.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (29) (-252.0, 4.0, 181.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (26) (-265.3, 4.0, 167.8)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (27) (-267.3, 4.0, 167.8)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Bush (28) (-271.8, 4.0, 162.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (41) (-278.0, 1.0, 168.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (39) (-278.0, 1.0, 167.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (207) (-310.8, 1.3, 164.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (210) (-310.8, 1.3, 165.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (209) (-312.0, 1.3, 165.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (208) (-312.0, 1.3, 164.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (103) (-323.5, 4.0, 128.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (101) (-323.5, 4.0, 129.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (102) (-324.5, 4.0, 129.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (104) (-324.5, 4.0, 128.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (95) (-332.0, 4.0, 127.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (348) (-331.0, 4.0, 128.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (94) (-331.0, 4.0, 127.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (343) (-331.0, 4.0, 129.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (353) (-330.1, 4.0, 129.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (354) (-330.1, 4.0, 128.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (344) (-332.0, 4.0, 129.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (347) (-332.0, 4.0, 128.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (349) (-333.0, 4.0, 129.3)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (90) (-323.5, 4.0, 113.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (89) (-323.5, 4.0, 112.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (92) (-322.5, 4.0, 113.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (93) (-322.5, 4.0, 112.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (91) (-324.5, 4.0, 113.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (1) (-324.5, 4.0, 112.5)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (115) (-334.0, 4.0, 109.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (116) (-333.0, 4.0, 109.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (117) (-334.0, 4.0, 108.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (100) (-339.5, 4.0, 114.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (99) (-339.5, 4.0, 115.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (98) (-340.5, 4.0, 115.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (171) (-348.5, 4.0, 124.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (167) (-348.5, 4.0, 123.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (114) (-349.5, 4.0, 123.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (170) (-349.5, 4.0, 124.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (168) (-348.5, 4.0, 122.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (169) (-349.5, 4.0, 122.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (341) (-345.6, 4.0, 127.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (119) (-348.5, 4.0, 129.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (120) (-348.5, 4.0, 128.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (118) (-349.5, 4.0, 129.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (340) (-344.6, 4.0, 126.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (338) (-345.6, 4.0, 126.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (342) (-344.6, 4.0, 127.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (346) (-342.6, 4.0, 127.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (345) (-343.6, 4.0, 127.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (44) (-325.0, 4.0, 88.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (45) (-325.0, 4.0, 87.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (74) (-327.9, 4.0, 88.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (73) (-326.9, 4.0, 88.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (49) (-326.0, 4.0, 88.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (48) (-326.0, 4.0, 87.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (43) (-324.0, 4.0, 88.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (46) (-324.0, 4.0, 87.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (51) (-324.5, 4.0, 78.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (54) (-324.5, 4.0, 77.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (52) (-323.5, 4.0, 77.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (53) (-323.5, 4.0, 78.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (397) (-328.9, 4.0, 68.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (398) (-329.9, 4.0, 67.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (396) (-327.9, 4.0, 67.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (395) (-327.9, 4.0, 68.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (393) (-328.9, 4.0, 67.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (55) (-342.5, 4.0, 78.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (57) (-341.5, 4.0, 78.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (56) (-341.5, 4.0, 77.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (58) (-342.5, 4.0, 77.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (97) (-346.8, 4.0, 72.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (394) (-346.8, 4.0, 73.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (392) (-345.8, 4.0, 72.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (96) (-345.8, 4.0, 71.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (76) (-346.8, 4.0, 71.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Bush (30) (-285.5, 0.5, 74.9)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Bush (29) (-283.4, 0.5, 74.9)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (153) (-295.5, 0.8, 70.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (264) (-295.5, 0.8, 69.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (152) (-296.5, 0.8, 70.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (154) (-296.5, 0.8, 69.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Bush (32) (-291.4, 0.5, 69.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Bush (33) (-293.1, 0.5, 67.1)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Bush (31) (-289.5, 0.5, 69.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (133) (-261.0, 0.3, 61.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (132) (-261.0, 0.3, 62.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (135) (-262.3, 0.3, 62.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (134) (-262.3, 0.3, 61.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (429) (-249.3, 4.0, 113.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (427) (-250.3, 4.0, 112.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (426) (-250.3, 4.0, 113.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (425) (-251.3, 4.0, 113.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (428) (-249.3, 4.0, 112.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (424) (-251.3, 4.0, 112.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (434) (-241.3, 4.0, 117.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (435) (-240.3, 4.0, 117.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (431) (-241.3, 4.0, 118.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (430) (-240.3, 4.0, 118.5)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (141) (-273.5, 0.0, 37.8)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (140) (-272.5, 0.0, 37.8)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (142) (-273.5, 0.3, 36.8)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (180) (-275.8, 0.8, 37.8)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (177) (-275.8, 0.8, 38.8)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (221) (-274.8, 0.6, 37.8)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (219) (-271.9, 0.0, 35.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (220) (-271.9, 0.3, 34.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (218) (-270.9, 0.0, 35.4)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (139) (-283.0, 2.0, 41.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (138) (-284.0, 2.0, 41.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (137) (-284.0, 2.0, 42.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (136) (-283.0, 2.0, 42.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (126) (-308.5, 2.0, 39.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (355) (-308.5, 2.0, 42.1)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (127) (-308.5, 2.0, 40.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (352) (-308.5, 2.0, 41.1)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (351) (-309.5, 2.0, 41.1)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (124) (-309.5, 2.0, 40.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (125) (-309.5, 2.0, 39.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (350) (-309.5, 2.0, 42.1)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (359) (-300.4, 2.0, 24.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (356) (-301.4, 2.0, 24.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (357) (-301.4, 2.0, 23.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (358) (-300.4, 2.0, 23.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (112) (-322.0, 2.0, 43.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (110) (-322.0, 2.0, 44.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (113) (-321.0, 2.0, 43.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (108) (-321.0, 2.0, 45.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (109) (-321.0, 2.0, 44.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (111) (-322.0, 2.0, 45.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (360) (-323.0, 2.0, 45.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (414) (-337.8, 2.0, 44.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (413) (-338.8, 2.0, 44.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (412) (-338.8, 2.0, 45.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (411) (-337.8, 2.0, 45.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (416) (-343.8, 2.0, 42.3)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (415) (-344.8, 2.0, 42.3)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (106) (-359.0, 1.5, 45.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (105) (-359.0, 1.5, 46.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (407) (-358.0, 1.8, 46.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (408) (-358.0, 1.8, 45.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (409) (-358.0, 1.8, 47.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (410) (-359.0, 1.5, 47.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (107) (-360.0, 1.3, 45.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (123) (-322.5, 1.8, 14.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (121) (-321.5, 1.8, 15.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (122) (-322.5, 1.8, 15.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (251) (-313.8, 2.0, 12.3)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (250) (-313.8, 2.0, 13.3)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (253) (-312.8, 2.0, 13.3)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (173) (-308.5, 2.0, 14.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (172) (-309.5, 2.0, 14.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (175) (-309.5, 2.0, 13.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (252) (-310.6, 2.0, 13.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (128) (-308.5, 2.0, -4.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (130) (-309.5, 2.0, -5.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (129) (-309.5, 2.0, -4.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (364) (-291.4, 2.0, -6.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (365) (-291.4, 2.0, -5.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (363) (-292.4, 2.0, -6.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (362) (-292.4, 2.0, -5.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (361) (-293.4, 2.0, -5.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (249) (-287.3, 2.0, -8.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (254) (-286.3, 2.0, -8.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (255) (-286.3, 2.0, -9.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (256) (-285.3, 1.8, -9.9)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (257) (-285.3, 1.8, -8.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (367) (-284.3, 1.5, -10.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (368) (-283.3, 1.4, -10.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (369) (-283.3, 1.4, -9.6)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (366) (-284.3, 1.5, -9.8)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (131) (-279.0, 2.0, -4.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (143) (-278.0, 2.0, -4.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (146) (-278.0, 2.0, -5.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (145) (-277.0, 2.0, -5.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (144) (-277.0, 2.0, -4.5)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (374) (-245.5, 1.0, 1.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (371) (-243.5, 1.0, 1.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (373) (-244.5, 1.0, 2.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (372) (-244.5, 1.0, 1.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (375) (-245.5, 1.0, 2.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (149) (-246.5, 1.0, 3.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (148) (-245.5, 1.0, 3.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (150) (-246.5, 1.0, 4.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (147) (-245.5, 1.0, 4.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (370) (-243.5, 1.0, 2.0)": TunicLocationData("none", "West Garden West Combat"), + "West Garden - West Garden Grass (377) (-256.8, 1.9, 16.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (376) (-256.8, 1.9, 15.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (378) (-257.8, 1.9, 15.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (382) (-256.8, 1.9, 17.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (379) (-257.8, 1.9, 16.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (380) (-257.8, 1.9, 17.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (384) (-255.8, 1.9, 17.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (386) (-254.8, 1.9, 17.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (383) (-256.8, 1.9, 18.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (381) (-257.8, 1.9, 18.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (229) (-234.6, 8.0, 8.6)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (230) (-234.6, 8.0, 7.6)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (225) (-233.6, 8.0, 7.6)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (227) (-233.6, 8.0, 8.6)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (228) (-233.6, 8.0, 9.6)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (181) (-240.5, 8.0, 5.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (184) (-240.5, 8.0, 4.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (182) (-241.5, 8.0, 5.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (183) (-241.5, 8.0, 4.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (223) (-228.5, 8.0, 37.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (226) (-228.5, 8.0, 36.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (419) (-228.5, 8.0, 35.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (417) (-227.5, 8.0, 36.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (25) (-226.0, 8.0, 35.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (423) (-226.5, 8.0, 36.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (222) (-227.5, 8.0, 37.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (418) (-227.5, 8.0, 35.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (420) (-225.5, 8.0, 36.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (421) (-225.5, 8.0, 37.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (422) (-226.5, 8.0, 37.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (224) (-229.5, 8.0, 37.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (26) (-224.3, 8.0, 36.8)": TunicLocationData("none", "West Garden South Checkpoint"), + # these 4 are above the magic dagger house, choosing south checkpoint based on vibes + "West Garden - West Garden Grass (157) (-193.0, 8.0, 40.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (156) (-192.0, 8.0, 40.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (151) (-192.0, 8.0, 41.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (158) (-193.0, 8.0, 41.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (248) (-197.4, 1.0, 22.3)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (245) (-195.4, 1.0, 23.3)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (246) (-196.4, 1.0, 23.3)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (247) (-197.4, 1.0, 23.3)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (162) (-206.5, 1.0, 28.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (159) (-205.5, 1.0, 28.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (160) (-206.5, 1.0, 29.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (161) (-205.5, 1.0, 29.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (163) (-211.5, 1.0, 35.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (166) (-212.5, 1.0, 35.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (165) (-211.5, 1.0, 36.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (164) (-212.5, 1.0, 36.0)": TunicLocationData("none", "West Garden at Dagger House"), + "West Garden - West Garden Grass (318) (-243.8, 8.0, 72.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (319) (-244.8, 8.0, 72.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (313) (-247.5, 8.0, 67.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (62) (-244.0, 8.0, 65.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (61) (-245.0, 8.0, 64.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (64) (-244.0, 8.0, 64.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (63) (-245.0, 8.0, 65.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (314) (-246.5, 8.0, 68.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (317) (-244.8, 8.0, 71.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (315) (-247.5, 8.0, 68.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (320) (-243.8, 8.0, 71.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (316) (-246.5, 8.0, 67.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (50) (-247.5, 8.0, 83.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (59) (-246.5, 8.0, 83.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (47) (-247.5, 8.0, 84.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (60) (-246.5, 8.0, 84.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (65) (-226.0, 8.0, 67.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (68) (-225.0, 8.0, 67.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (67) (-226.0, 8.0, 68.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (66) (-225.0, 8.0, 68.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (69) (-226.0, 8.0, 72.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (72) (-225.0, 8.0, 72.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (71) (-226.0, 8.0, 73.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (70) (-225.0, 8.0, 73.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (303) (-215.3, 8.0, 83.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (17) (-215.0, 8.0, 85.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (27) (-217.0, 8.0, 81.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (24) (-217.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (301) (-215.3, 8.0, 82.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (13) (-213.0, 8.0, 83.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (304) (-214.3, 8.0, 82.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (302) (-214.3, 8.0, 83.8)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (16) (-211.0, 8.0, 85.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (12) (-213.0, 8.0, 85.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (14) (-213.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (15) (-211.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (309) (-203.5, 8.0, 86.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (11) (-203.0, 8.0, 85.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (312) (-202.5, 8.0, 86.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (2) (-199.0, 8.0, 83.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (308) (-200.5, 8.0, 84.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (305) (-201.5, 8.0, 84.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (307) (-201.5, 8.0, 85.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (-199.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (306) (-200.5, 8.0, 85.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (7) (-201.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (310) (-202.5, 8.0, 87.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (311) (-203.5, 8.0, 87.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (1) (-199.0, 8.0, 85.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (4) (-197.0, 8.0, 85.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (5) (-197.0, 8.0, 83.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (3) (-197.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (6) (-197.0, 8.0, 81.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (10) (-191.0, 8.0, 81.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (8) (-191.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Bush (9) (-193.0, 8.0, 87.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (333) (-226.0, 8.0, 92.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (336) (-225.0, 8.0, 92.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (334) (-225.0, 8.0, 93.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (339) (-226.0, 8.0, 97.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (337) (-225.0, 8.0, 97.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (335) (-225.0, 8.0, 98.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (329) (-229.3, 8.0, 101.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (332) (-228.3, 8.0, 101.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (331) (-229.3, 8.0, 102.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (328) (-229.3, 8.0, 103.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (330) (-228.3, 8.0, 102.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (325) (-230.3, 8.0, 103.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (326) (-229.3, 8.0, 104.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (327) (-230.3, 8.0, 104.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (321) (-232.8, 8.0, 109.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (324) (-231.8, 8.0, 109.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (323) (-232.8, 8.0, 110.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (322) (-231.8, 8.0, 110.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (399) (-233.8, 8.0, 111.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (400) (-234.8, 8.0, 111.3)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (84) (-244.0, 8.0, 101.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (81) (-245.0, 8.0, 101.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (82) (-244.0, 8.0, 100.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (83) (-245.0, 8.0, 100.5)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (77) (-247.5, 8.0, 98.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (80) (-246.5, 8.0, 98.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (79) (-247.5, 8.0, 97.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (78) (-246.5, 8.0, 97.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (88) (-246.5, 8.0, 109.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (85) (-247.5, 8.0, 109.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (86) (-246.5, 8.0, 110.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (87) (-247.5, 8.0, 110.0)": TunicLocationData("none", "West Garden South Checkpoint"), + "West Garden - West Garden Grass (283) (-225.4, 20.0, 172.9)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (284) (-225.4, 20.0, 173.9)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (282) (-226.4, 20.0, 172.9)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (285) (-226.4, 20.0, 173.9)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (279) (-222.3, 20.0, 177.6)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (278) (-222.3, 20.0, 178.6)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (32) (-221.3, 20.0, 178.8)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (33) (-221.3, 20.0, 177.8)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (280) (-221.3, 20.0, 176.6)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (275) (-222.3, 20.0, 179.8)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (9) (-221.3, 20.0, 179.8)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (281) (-223.3, 20.0, 179.8)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (385) (-246.6, 20.0, 172.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (294) (-247.6, 20.0, 172.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (291) (-247.6, 20.0, 173.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (290) (-247.6, 20.0, 174.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (292) (-246.6, 20.0, 174.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (293) (-246.6, 20.0, 173.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (287) (-244.8, 20.0, 176.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (288) (-244.8, 20.0, 175.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (286) (-245.8, 20.0, 175.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (289) (-245.8, 20.0, 176.0)": TunicLocationData("none", "West Garden before Boss"), + "West Garden - West Garden Grass (-287.0, 4.0, 117.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (2) (-287.0, 4.0, 118.0)": TunicLocationData("none", "West Garden before Terry"), + "West Garden - West Garden Grass (174) (-243.9, 0.5, 52.1)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (262) (-244.8, 0.5, 51.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (263) (-244.8, 0.5, 52.3)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (179) (-334.0, 4.0, 103.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (176) (-335.0, 4.0, 103.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Grass (178) (-334.0, 4.0, 102.0)": TunicLocationData("none", "West Garden after Terry"), + "West Garden - West Garden Portal Grass (243) (-202.5, 8.0, -19.9)": TunicLocationData("none", "West Garden Portal"), + "West Garden - West Garden Portal Grass (244) (-203.4, 8.0, -20.9)": TunicLocationData("none", "West Garden Portal"), + "West Garden - West Garden Portal Grass (242) (-203.6, 8.0, -19.9)": TunicLocationData("none", "West Garden Portal"), + "West Garden - West Garden Portal Grass (233) (-197.4, 8.0, -20.9)": TunicLocationData("none", "West Garden Portal"), + "West Garden - West Garden Portal Grass (232) (-198.4, 8.0, -19.9)": TunicLocationData("none", "West Garden Portal"), + "West Garden - West Garden Portal Grass (234) (-197.4, 8.0, -19.9)": TunicLocationData("none", "West Garden Portal"), + "West Garden - West Garden Portal Grass (231) (-196.4, 8.0, -19.9)": TunicLocationData("none", "West Garden Portal"), + "West Garden - West Garden Laurels Exit Grass (261) (-182.8, 2.0, 75.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (259) (-183.8, 2.0, 75.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (258) (-184.8, 2.0, 75.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (260) (-183.8, 2.0, 74.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (404) (-172.1, 2.0, 80.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (402) (-172.1, 2.0, 82.5)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (299) (-172.1, 2.0, 81.5)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (403) (-173.4, 2.0, 81.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (401) (-173.4, 2.0, 82.5)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (269) (-162.5, 2.0, 75.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (267) (-161.3, 2.0, 75.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (268) (-161.3, 2.0, 74.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (273) (-152.8, 2.0, 73.5)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (271) (-154.0, 2.0, 72.5)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (272) (-152.8, 2.0, 72.5)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (270) (-154.0, 2.0, 71.3)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (274) (-137.0, 2.0, 75.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (277) (-136.0, 2.0, 74.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "West Garden - West Garden Laurels Exit Grass (276) (-136.0, 2.0, 75.0)": TunicLocationData("none", "West Garden Laurels Exit Region"), + "Ruined Atoll - Ruined Atoll Grass beach (132) (-17.0, 0.3, 59.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (133) (-17.0, 0.3, 60.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (131) (-16.0, 0.0, 59.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (130) (-16.0, 0.0, 60.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (129) (-15.0, 0.0, 60.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (134) (-15.0, 0.3, 61.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (139) (-20.0, 0.5, 47.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (140) (-20.0, 0.5, 48.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (138) (-19.0, 0.0, 46.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (137) (-19.0, 0.0, 47.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (136) (-19.0, 0.0, 48.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (141) (-20.0, 0.5, 49.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (135) (-19.0, 0.0, 49.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (109) (-30.3, 2.0, 40.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (106) (-31.3, 2.0, 40.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (107) (-31.3, 1.8, 39.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (110) (-32.3, 2.0, 39.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (108) (-30.3, 1.8, 39.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (111) (-31.3, 1.5, 38.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (123) (-27.8, 1.5, 61.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (121) (-27.8, 1.5, 62.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (118) (-27.8, 1.5, 63.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (122) (-26.8, 1.8, 62.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (117) (-26.8, 1.8, 63.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (115) (-26.8, 2.0, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (114) (-25.8, 2.3, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (113) (-25.8, 2.8, 65.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (112) (-26.8, 2.3, 65.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (119) (-27.8, 1.8, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (120) (-27.8, 1.8, 65.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (179) (-30.3, 0.0, 23.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (176) (-31.3, 0.0, 22.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (178) (-31.3, 0.0, 23.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (177) (-30.3, 0.3, 22.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (174) (-31.3, 0.5, 21.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (180) (-30.3, 0.3, 21.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (182) (-32.0, 0.5, 17.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (183) (-31.0, 0.8, 17.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (184) (-31.0, 0.8, 16.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (185) (-32.0, 0.5, 16.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (186) (-32.0, 0.5, 15.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (187) (-33.0, 0.3, 15.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (126) (-29.3, 2.0, 3.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (116) (-28.3, 2.0, 3.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (128) (-28.3, 2.3, 4.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (127) (-29.3, 2.3, 4.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (143) (-27.3, 2.3, 5.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (142) (-28.3, 2.3, 5.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (147) (-26.3, 2.3, 5.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (146) (-26.3, 2.3, 6.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (145) (-27.3, 2.3, 6.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (171) (-34.3, 0.0, -6.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (170) (-34.3, 0.0, -7.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (156) (-33.3, 0.5, -8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (173) (-33.3, 0.5, -7.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (172) (-33.3, 0.5, -6.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (157) (-34.3, 0.0, -8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (144) (-32.3, 0.5, -8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (125) (-32.3, 0.5, -9.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (155) (-32.3, 0.5, -8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (124) (-33.3, 0.5, -9.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (152) (-19.3, 1.5, -5.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (151) (-19.3, 1.5, -4.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (158) (-17.3, 1.3, -6.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (159) (-17.3, 1.5, -5.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (161) (-16.3, 1.3, -5.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (153) (-20.3, 1.5, -5.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (150) (-20.3, 1.5, -4.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (149) (-21.3, 1.8, -4.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (154) (-21.3, 1.8, -5.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (148) (-22.3, 2.0, -4.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (166) (-16.3, 1.3, -8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (169) (-15.3, 1.5, -9.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (162) (-16.3, 1.3, -7.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (165) (-15.3, 1.5, -8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (163) (-15.3, 1.5, -7.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (160) (-16.3, 1.3, -6.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (164) (-15.3, 1.3, -6.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (168) (-14.3, 1.8, -9.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (167) (-14.3, 1.8, -8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (181) (-20.5, 0.5, -16.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (188) (-19.5, 0.5, -16.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (189) (-19.5, 0.5, -17.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (175) (-20.5, 0.3, -17.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (192) (-20.5, 0.0, -18.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (190) (-21.5, 0.3, -17.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (191) (-21.5, -0.3, -18.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (21) (32.0, 0.9, 9.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (81) (30.0, 0.8, 7.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (82) (31.0, 0.8, 7.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (79) (31.0, 0.8, 9.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (19) (31.0, 0.6, 10.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (80) (30.0, 0.8, 9.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (83) (29.0, 0.8, 7.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (84) (29.0, 0.8, 8.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (20) (32.0, 0.8, 10.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (75) (41.0, 0.5, 9.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (77) (41.0, 0.5, 8.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (22) (42.0, 0.5, 9.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (78) (42.0, 0.5, 8.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (23) (42.0, 0.3, 10.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (76) (41.0, 0.5, 10.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (74) (42.0, 0.5, 11.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (25) (43.0, 0.3, 11.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (26) (43.0, 0.3, 10.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (91) (21.0, 1.3, 41.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (89) (22.0, 1.3, 40.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (28) (23.0, 1.0, 41.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (27) (23.0, 1.3, 40.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (93) (22.0, 1.0, 42.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (90) (22.0, 1.3, 41.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (92) (21.0, 1.0, 42.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (24) (24.0, 1.3, 40.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (29) (15.5, 0.8, 47.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (30) (15.5, 0.8, 48.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (33) (15.5, 0.8, 49.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (34) (15.5, 0.8, 50.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (31) (14.5, 0.8, 48.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (32) (14.5, 0.8, 49.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (86) (10.5, 3.0, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (14) (9.5, 3.0, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (35) (9.5, 2.5, 63.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (85) (8.5, 2.5, 63.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (15) (8.5, 3.0, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (87) (24.0, 1.5, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (18) (25.0, 1.5, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (16) (25.0, 1.5, 65.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (17) (24.0, 1.5, 65.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (88) (23.0, 2.0, 65.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (237) (-99.0, 0.3, 61.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (393) (-100.0, 0.0, 62.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (226) (-100.0, 0.0, 61.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (228) (-99.0, 0.3, 60.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (227) (-100.0, 0.0, 60.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (390) (-99.0, 0.3, 59.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (260) (-83.7, 2.0, 19.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (261) (-83.7, 1.8, 18.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (259) (-82.5, 1.5, 18.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (257) (-82.5, 1.8, 19.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (258) (-81.2, 1.3, 18.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (256) (-81.2, 1.5, 19.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (255) (-80.5, 1.5, 14.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (254) (-80.5, 1.8, 13.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (249) (-79.5, 2.0, 12.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (248) (-79.5, 1.8, 13.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (251) (-80.5, 1.8, 11.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (252) (-80.5, 1.8, 12.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (247) (-79.5, 1.8, 14.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (246) (-79.5, 1.5, 15.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (253) (-79.5, 2.0, 10.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (250) (-79.5, 2.0, 11.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (264) (-53.8, 1.3, 14.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (265) (-53.8, 1.0, 13.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (263) (-52.8, 1.0, 14.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (266) (-53.8, 0.8, 12.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (262) (-52.8, 0.5, 13.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (267) (-53.3, 1.3, 20.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (270) (-54.3, 1.8, 20.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (268) (-53.3, 1.0, 21.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (269) (-54.3, 1.5, 21.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (272) (-69.5, 1.8, -23.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (273) (-69.5, 1.8, -23.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (271) (-69.5, 1.8, -22.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (274) (-70.2, 1.0, -33.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (275) (-70.2, 0.8, -34.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (277) (-69.2, 1.0, -33.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (278) (-69.2, 0.5, -34.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (276) (-69.2, 1.0, -34.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (279) (-68.2, 0.5, -34.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (193) (-88.2, 1.8, -52.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (194) (-88.2, 1.8, -53.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (195) (-88.2, 2.0, -54.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (197) (-87.2, 1.8, -53.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (196) (-87.2, 1.8, -54.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (192) (-97.2, 1.5, -66.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (191) (-96.5, 1.5, -66.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (189) (-96.5, 1.5, -67.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (190) (-95.5, 1.5, -67.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (187) (-95.5, 1.5, -68.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (188) (-96.5, 1.5, -68.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (186) (-95.5, 1.5, -69.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (185) (-96.0, 1.8, -72.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (184) (-96.0, 2.0, -73.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (183) (-96.5, 2.0, -73.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (169) (-100.5, 1.5, -74.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (165) (-99.5, 1.5, -75.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (167) (-101.5, 1.3, -75.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (168) (-101.5, 1.3, -74.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (170) (-102.5, 1.3, -74.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (166) (-100.5, 1.5, -75.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (176) (-103.5, 1.0, -68.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (172) (-103.5, 1.3, -69.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (179) (-102.5, 1.3, -67.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (180) (-101.5, 1.3, -67.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (181) (-101.5, 1.3, -66.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (177) (-103.5, 1.0, -67.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (182) (-102.5, 1.3, -66.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (171) (-103.5, 1.3, -70.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (173) (-104.5, 1.3, -69.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (175) (-104.5, 1.0, -68.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (178) (-104.5, 1.0, -67.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (174) (-104.5, 1.3, -70.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (153) (-98.0, 1.8, -80.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (156) (-99.0, 1.8, -80.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (148) (-96.7, 1.8, -82.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (151) (-96.7, 1.8, -83.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (152) (-96.7, 1.8, -84.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (150) (-95.7, 1.8, -83.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (149) (-95.7, 1.8, -82.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (155) (-95.7, 1.8, -84.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (154) (-95.7, 1.8, -85.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (145) (-91.5, 3.0, -87.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (146) (-91.5, 3.3, -86.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (144) (-90.5, 3.3, -87.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (143) (-89.5, 3.5, -87.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (147) (-90.5, 3.8, -86.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (142) (-89.5, 4.0, -86.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (158) (-102.8, 1.0, -91.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (157) (-102.8, 1.0, -92.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (159) (-104.0, 1.0, -92.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (160) (-104.0, 1.0, -93.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (161) (-102.0, 1.8, -97.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (162) (-101.0, 1.8, -97.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (163) (-102.0, 0.8, -98.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (122) (-85.7, 2.8, -94.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (141) (-85.5, 3.3, -89.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (139) (-85.5, 3.3, -90.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (140) (-84.5, 3.3, -90.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (121) (-84.7, 3.0, -94.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (118) (-83.7, 3.3, -94.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (120) (-84.7, 2.8, -95.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (119) (-83.7, 2.8, -95.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (125) (-78.2, 3.5, -94.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (128) (-78.2, 3.3, -95.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (127) (-78.2, 3.0, -96.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (126) (-79.2, 3.0, -96.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (123) (-79.2, 3.5, -95.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (124) (-79.2, 3.5, -94.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (113) (-83.7, 1.3, -104.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (114) (-83.7, 0.8, -105.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (115) (-82.7, 0.8, -105.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (112) (-82.7, 1.3, -104.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (109) (-80.7, 1.3, -104.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (116) (-80.7, 1.5, -103.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (111) (-81.7, 1.3, -104.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (117) (-81.7, 1.5, -103.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (17) (-37.0, 1.9, -82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (18) (-36.0, 1.9, -82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (22) (-35.0, 1.9, -82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (24) (-35.0, 1.9, -81.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (20) (-36.0, 1.9, -81.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (19) (-37.0, 1.9, -81.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (21) (-34.0, 1.9, -81.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (27) (-34.0, 1.9, -80.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (23) (-34.0, 1.9, -82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (26) (-35.0, 1.9, -80.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (28) (-35.0, 1.9, -79.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (25) (-34.0, 2.4, -79.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (30) (-29.0, 1.9, -85.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (31) (-28.0, 1.9, -85.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (38) (-28.0, 1.9, -86.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (39) (-28.0, 2.4, -87.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (32) (-29.0, 1.9, -84.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (35) (-27.0, 1.9, -85.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (37) (-27.0, 1.9, -86.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (40) (-27.0, 2.3, -87.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (29) (-28.0, 1.9, -84.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (34) (-27.0, 1.9, -84.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (33) (-26.0, 1.9, -84.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (36) (-26.0, 1.9, -85.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (80) (-26.2, 3.6, -74.6)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (78) (-26.2, 3.6, -73.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (81) (-25.2, 3.1, -74.6)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (77) (-25.2, 3.1, -73.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (79) (-27.3, 4.4, -73.6)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (82) (-24.1, 2.4, -73.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (10) (-14.0, 2.7, -76.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (9) (-14.0, 2.9, -77.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (1) (-12.0, 2.9, -77.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (4) (-13.0, 2.9, -77.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (3) (-13.0, 2.9, -76.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (8) (-13.0, 2.9, -78.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (2) (-12.0, 2.9, -78.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (-12.0, 2.9, -76.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (7) (-11.0, 3.1, -78.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (12) (-11.0, 2.8, -79.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (5) (-12.0, 2.9, -79.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (11) (-11.0, 2.6, -80.9)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (6) (-12.0, 2.4, -80.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (90) (-10.0, 1.9, -95.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (93) (-10.0, 1.9, -96.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (94) (-10.0, 1.9, -97.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (83) (-9.0, 1.9, -96.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (89) (-9.0, 1.9, -95.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (86) (-9.0, 1.9, -97.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (87) (-9.0, 1.9, -98.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (84) (-8.0, 1.9, -96.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (88) (-8.0, 1.9, -98.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (91) (-7.0, 1.9, -96.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (92) (-7.0, 1.9, -97.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (85) (-8.0, 1.9, -97.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (95) (-18.8, 0.8, -97.4)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (96) (-18.8, 0.9, -96.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (98) (-17.8, 0.9, -97.4)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (97) (-17.7, 1.1, -96.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (101) (-18.0, 0.7, -98.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (100) (-18.9, 0.6, -98.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (99) (-19.9, 0.7, -97.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (164) (-101.0, 1.5, -98.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (74) (-89.5, 7.8, -82.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (75) (-89.5, 7.8, -81.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (70) (-84.5, 8.0, -84.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (71) (-84.5, 8.0, -85.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (73) (-82.5, 8.0, -85.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (69) (-82.5, 8.0, -84.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (68) (-83.5, 8.0, -84.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (72) (-83.5, 8.0, -85.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (65) (-82.5, 8.0, -83.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (66) (-82.5, 8.0, -84.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (64) (-83.5, 8.0, -83.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (67) (-83.5, 8.0, -84.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (63) (-85.7, 13.3, -70.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (60) (-88.5, 12.8, -72.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (62) (-85.7, 13.8, -69.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (58) (-88.5, 13.3, -70.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (59) (-88.5, 12.8, -71.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (78) (-81.7, 15.0, -61.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (77) (-82.7, 15.0, -61.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (76) (-83.7, 15.0, -61.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (202) (-83.0, 15.0, -62.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (203) (-84.0, 15.0, -62.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (79) (-79.7, 18.3, -78.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (80) (-79.7, 18.0, -79.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (87) (-77.5, 25.0, -69.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (88) (-77.5, 25.0, -70.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (86) (-78.5, 25.0, -69.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (85) (-70.2, 25.0, -77.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (83) (-71.2, 25.0, -78.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (82) (-70.2, 25.0, -78.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (81) (-69.2, 25.0, -78.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (84) (-69.2, 25.0, -77.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (297) (-99.0, 0.8, 7.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (296) (-98.0, 0.8, 7.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (103) (-8.0, 1.8, -40.4)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (102) (-8.0, 1.8, -39.4)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (104) (-9.0, 1.8, -40.4)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (197) (-11.3, 1.5, -30.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (196) (-12.3, 1.3, -30.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (195) (-12.3, 1.0, -31.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (199) (-12.3, 1.0, -29.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (194) (-13.3, 0.8, -31.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (193) (-13.3, 0.8, -30.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (198) (-11.3, 1.3, -29.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (201) (-12.0, 0.0, -46.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (202) (-12.0, 0.3, -45.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (204) (-13.0, 0.0, -46.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (200) (-11.0, 0.0, -46.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (203) (-11.0, 0.3, -45.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (206) (-30.0, 0.3, -33.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (205) (-30.0, 0.3, -32.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (207) (-29.0, 0.0, -33.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (208) (-29.0, 0.0, -32.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (245) (48.0, 1.0, 51.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (242) (48.0, 0.8, 52.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (244) (47.3, 0.8, 51.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (243) (48.0, 0.8, 53.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (240) (47.3, 0.5, 53.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (241) (47.3, 0.8, 52.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (231) (46.3, 0.5, 53.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (239) (47.3, 0.5, 54.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (238) (46.3, 0.5, 54.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (235) (64.8, 0.8, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (229) (64.8, 0.8, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (234) (65.8, 0.5, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (232) (65.8, 0.8, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (233) (62.8, 0.8, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (230) (63.8, 0.8, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (236) (62.8, 0.8, 55.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (223) (68.5, 1.5, 52.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (224) (68.5, 1.5, 51.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (220) (69.5, 2.0, 52.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (221) (69.5, 2.0, 51.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (222) (68.5, 1.8, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (219) (69.5, 2.0, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (5) (53.5, 6.0, 70.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (4) (53.5, 6.0, 70.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (23) (52.5, 6.0, 70.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (25) (55.8, 6.0, 72.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (27) (56.8, 6.0, 74.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (26) (56.8, 6.0, 73.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (24) (55.8, 6.0, 73.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (43) (67.8, 5.8, 82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (42) (68.8, 5.8, 82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (33) (67.8, 5.8, 83.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (35) (69.8, 5.8, 83.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (41) (69.8, 5.8, 82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (34) (68.8, 5.8, 83.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (49) (69.8, 5.8, 84.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (50) (70.8, 5.8, 84.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (46) (74.8, 5.8, 82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (45) (75.8, 5.8, 82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (44) (76.8, 5.8, 82.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (48) (76.8, 5.8, 83.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (47) (75.8, 5.8, 83.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (113) (72.5, 2.8, 87.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (111) (71.5, 2.8, 86.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (112) (72.5, 2.8, 86.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (114) (71.5, 2.8, 87.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (115) (70.5, 2.8, 87.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (110) (70.5, 2.8, 86.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (90) (69.8, 12.8, 80.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (30) (59.8, 7.8, 62.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (31) (58.8, 7.8, 62.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (32) (58.8, 8.0, 61.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (29) (59.8, 8.0, 61.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (28) (59.8, 8.3, 60.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (38) (68.5, 11.8, 59.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (39) (67.5, 11.8, 60.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (37) (68.5, 11.8, 60.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (108) (61.8, 12.8, 67.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (109) (61.8, 12.8, 68.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (89) (69.8, 12.8, 79.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (51) (68.8, 12.8, 79.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (91) (68.8, 12.8, 80.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (106) (64.5, 13.5, 63.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (107) (65.5, 14.0, 63.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (92) (64.5, 13.5, 64.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (200) (69.8, 15.8, 62.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (198) (70.8, 16.0, 62.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (95) (78.5, 18.8, 64.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (94) (79.5, 18.8, 64.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (93) (79.5, 18.8, 65.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (104) (75.5, 20.8, 66.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (105) (74.5, 20.8, 66.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (97) (63.8, 20.8, 69.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (96) (62.8, 20.8, 69.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (98) (62.8, 20.8, 68.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (103) (68.8, 20.8, 77.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (102) (69.8, 20.8, 77.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (99) (68.8, 20.8, 78.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (100) (69.8, 20.8, 78.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (101) (70.8, 20.8, 78.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (215) (72.3, 0.3, 26.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (216) (72.3, 0.3, 25.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (214) (73.3, 0.3, 26.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (217) (68.5, 1.3, 15.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (211) (68.5, 1.0, 14.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (212) (69.5, 1.3, 14.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (209) (69.5, 1.3, 13.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (213) (69.5, 1.3, 15.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (210) (68.5, 1.0, 13.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (218) (69.5, 1.3, 16.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (62.0, 2.0, 5.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (1) (62.0, 2.0, 4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (2) (63.0, 2.5, 4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (73) (54.5, 0.5, -1.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (72) (53.5, 0.5, -1.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (5) (54.5, 1.0, -2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (6) (53.5, 0.5, -2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (7) (53.5, 0.5, -3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (70) (52.5, 0.5, -3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (71) (52.5, 0.5, -2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (4) (54.5, 0.5, -3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (8) (54.5, 0.5, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (10) (55.5, 1.0, -3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (9) (55.5, 0.5, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (382) (83.5, 3.3, 69.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (381) (83.5, 3.3, 70.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (379) (82.5, 3.5, 69.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (380) (82.5, 3.5, 70.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (372) (85.0, 3.3, 75.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (371) (85.0, 3.3, 76.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (370) (84.0, 3.5, 76.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (373) (84.0, 3.5, 77.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (374) (84.0, 3.5, 78.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (369) (84.0, 3.5, 75.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (378) (83.0, 4.0, 77.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (375) (84.0, 3.3, 79.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (377) (83.0, 4.0, 78.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (376) (83.0, 3.8, 79.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (368) (89.0, 2.0, 79.9)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (367) (88.0, 2.0, 79.9)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (366) (88.0, 2.3, 78.9)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (364) (89.0, 2.3, 78.9)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (365) (90.0, 2.3, 78.9)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (389) (92.6, 1.9, 72.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (388) (92.6, 2.2, 71.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (383) (93.6, 1.4, 72.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (384) (93.6, 1.9, 71.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (386) (94.6, 1.9, 70.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (385) (94.6, 1.7, 71.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (387) (93.6, 1.9, 70.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (357) (98.5, 3.5, 67.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (356) (99.5, 3.5, 67.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (360) (100.5, 3.5, 67.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (358) (99.5, 3.3, 68.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (359) (100.5, 3.3, 68.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (363) (102.5, 3.3, 67.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (355) (102.5, 3.5, 65.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (361) (103.5, 3.0, 65.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (362) (103.5, 2.8, 67.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (292) (68.3, 0.8, -39.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (293) (68.3, 0.8, -40.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (294) (69.5, 1.0, -41.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (290) (69.3, 1.0, -39.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (289) (69.3, 1.3, -40.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (291) (69.3, 0.8, -38.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (295) (70.3, 1.0, -41.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (287) (60.0, 1.0, -29.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (288) (60.0, 1.3, -28.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (286) (59.0, 0.8, -29.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (284) (59.0, 1.0, -28.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (285) (59.0, 1.3, -27.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (282) (58.0, 1.3, -27.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (283) (58.0, 0.8, -28.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (94) (36.5, 1.3, -20.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (36) (37.5, 1.3, -20.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (96) (37.5, 1.3, -21.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (95) (36.5, 1.3, -19.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (37) (37.5, 1.1, -19.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (38) (38.5, 0.9, -20.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (97) (38.5, 1.3, -21.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (50) (21.4, 0.8, -33.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (51) (21.4, 0.8, -34.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (60) (21.4, 0.8, -32.4)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (48) (20.4, 0.4, -34.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (59) (20.4, 0.4, -35.6)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (49) (20.4, 0.4, -33.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (63) (25.0, 0.5, -42.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (64) (24.0, 0.0, -42.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (61) (25.0, 0.4, -43.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (65) (24.0, 0.0, -43.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (62) (25.0, 0.5, -44.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (103) (26.0, 0.6, -44.4)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (104) (26.0, 0.5, -43.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (101) (33.5, 0.8, -38.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (100) (33.5, 0.8, -37.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (99) (32.5, 0.8, -36.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (67) (34.5, 0.6, -37.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (102) (34.5, 0.8, -38.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (66) (34.5, 0.6, -36.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (68) (33.5, 0.8, -36.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (98) (32.5, 0.8, -35.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (69) (33.5, 0.8, -35.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (46) (36.0, 0.1, -49.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (45) (36.0, 0.1, -48.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (47) (35.0, 0.3, -48.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (41) (33.5, 2.6, -72.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (40) (34.5, 3.1, -71.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (39) (34.5, 3.1, -72.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (42) (34.5, 3.1, -73.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (43) (39.0, 2.5, -74.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (44) (40.0, 2.5, -74.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (105) (40.0, 2.5, -74.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (54) (41.4, 1.3, -87.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (56) (40.4, 1.3, -86.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (55) (42.4, 1.0, -87.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (53) (41.4, 1.3, -86.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (52) (42.4, 1.0, -86.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (58) (41.5, 1.1, -85.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (57) (40.4, 1.3, -85.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (105) (30.3, 2.0, -106.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (107) (31.3, 2.0, -106.3)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (110) (30.5, 0.3, -109.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (106) (30.5, 0.5, -108.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (280) (31.5, 1.0, -108.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (108) (31.5, 1.0, -108.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (281) (31.5, 0.3, -109.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (61) (19.1, 2.1, -100.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (59) (19.1, 2.1, -101.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (63) (18.1, 2.1, -100.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (62) (18.1, 2.1, -99.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (64) (19.1, 2.0, -99.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (60) (18.1, 2.1, -101.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (44) (17.1, 2.1, -101.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (41) (16.1, 2.1, -101.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (45) (17.1, 2.1, -102.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (43) (16.1, 2.1, -103.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (42) (16.1, 2.1, -102.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (58) (18.1, 2.1, -102.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (46) (17.1, 2.1, -103.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (57) (19.1, 2.1, -102.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (48) (16.1, 2.1, -104.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (47) (17.1, 2.1, -104.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (52) (18.1, 2.1, -97.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (50) (18.1, 2.1, -96.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (53) (18.1, 2.1, -95.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (55) (18.1, 2.1, -94.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (54) (17.1, 2.1, -95.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (49) (17.1, 2.1, -97.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (51) (17.1, 2.1, -96.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (56) (17.1, 2.1, -94.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (66) (16.1, 2.1, -110.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (68) (16.1, 2.1, -111.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (65) (17.1, 2.1, -110.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (67) (17.1, 2.1, -111.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (72) (18.1, 2.1, -111.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (71) (18.1, 2.1, -110.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (73) (18.1, 2.1, -109.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (74) (19.1, 2.1, -109.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (70) (19.1, 2.1, -110.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (76) (18.1, 2.1, -108.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (75) (19.1, 2.1, -108.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (69) (19.1, 2.1, -111.1)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (130) (-3.5, 0.5, -116.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (131) (-3.5, 0.5, -117.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (129) (-2.5, 0.3, -116.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (132) (-2.5, 0.3, -117.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (133) (-2.5, 0.3, -118.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (138) (8.0, 0.5, -124.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (137) (8.0, 0.0, -125.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (135) (10.0, 0.5, -124.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (136) (9.0, 0.0, -125.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (134) (9.0, 0.5, -124.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (395) (67.8, 2.5, -80.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (394) (67.8, 2.5, -79.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (391) (66.8, 2.5, -79.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (397) (68.8, 2.5, -79.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (396) (66.8, 2.5, -80.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (392) (65.8, 2.5, -79.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (400) (63.3, 2.8, -74.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (399) (64.3, 3.0, -74.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (401) (63.3, 2.8, -73.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (398) (64.3, 3.0, -73.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (402) (62.3, 2.5, -73.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (405) (60.5, 1.3, -68.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (404) (59.5, 0.5, -68.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (406) (60.5, 1.3, -69.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (403) (59.5, 0.5, -69.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (407) (61.5, 1.5, -69.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (325) (-111.8, 1.3, 2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (323) (-111.8, 1.3, 1.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (316) (-110.5, 1.3, 3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (319) (-111.5, 1.3, 4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (317) (-111.5, 1.3, 3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (318) (-110.5, 1.3, 4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (321) (-112.3, 1.3, 4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (320) (-112.3, 1.3, 3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (326) (-112.8, 1.3, 2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (327) (-113.5, 1.3, 2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (324) (-112.8, 1.3, 1.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (322) (-113.5, 1.3, 1.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (328) (-112.0, 0.8, -2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (329) (-112.0, 0.5, -3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (333) (-111.3, 0.8, -2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (331) (-111.3, 0.5, -3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (330) (-110.3, 0.5, -3.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (332) (-110.3, 0.8, -2.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (334) (-111.0, 0.3, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (337) (-110.3, 0.3, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (354) (-113.0, 0.3, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (353) (-112.0, 0.3, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (336) (-109.3, 0.3, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (338) (-109.3, -0.3, -5.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (339) (-110.3, -0.3, -5.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (335) (-111.0, -0.3, -5.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (350) (-112.0, -0.3, -5.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (349) (-113.8, 0.3, -4.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (351) (-113.0, -0.3, -5.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (352) (-113.8, -0.3, -5.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (314) (-112.3, 0.8, 6.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (315) (-112.3, 0.8, 7.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (313) (-111.5, 0.8, 6.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (311) (-111.5, 0.8, 7.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (310) (-110.5, 0.8, 7.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (306) (-110.5, 0.8, 8.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (312) (-110.5, 0.8, 6.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (307) (-109.5, 0.8, 8.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (308) (-111.5, 0.8, 8.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (300) (-107.5, 0.0, 10.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (301) (-107.5, 0.3, 9.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (304) (-108.3, 0.0, 10.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (299) (-108.5, 0.0, 10.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (303) (-110.5, 0.3, 9.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (302) (-109.5, 0.3, 9.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (305) (-109.5, 0.0, 10.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (298) (-108.5, 0.3, 9.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (341) (-113.5, 0.8, 10.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (344) (-113.5, 0.5, 11.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (346) (-113.5, 0.8, 9.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (309) (-111.5, 0.5, 9.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (345) (-112.5, 0.8, 9.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (342) (-112.5, 0.8, 8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (340) (-112.5, 0.8, 10.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (347) (-114.3, 0.8, 8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (348) (-114.3, 0.8, 9.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass beach (343) (-113.5, 0.8, 8.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (191) (-89.5, 6.5, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (190) (-89.5, 6.5, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (189) (-88.5, 6.5, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (188) (-88.5, 6.5, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (197) (-87.0, 13.0, 75.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (194) (-87.0, 13.0, 74.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (184) (-86.0, 13.0, 73.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (183) (-86.0, 13.0, 74.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (181) (-86.0, 13.0, 75.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (185) (-84.7, 13.0, 73.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (182) (-83.0, 13.0, 72.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (199) (-83.0, 13.0, 70.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (201) (-84.0, 13.0, 70.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (135) (-83.5, 13.0, 58.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (128) (-82.5, 13.0, 57.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (130) (-82.5, 13.0, 58.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (147) (-86.0, 13.0, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (132) (-82.5, 13.0, 60.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (134) (-83.5, 13.0, 59.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (131) (-82.5, 13.0, 59.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (136) (-78.5, 13.0, 56.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (139) (-79.5, 13.0, 55.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (133) (-79.5, 13.0, 56.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (138) (-80.5, 13.0, 55.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (137) (-80.5, 13.0, 56.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (143) (-85.0, 13.0, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (142) (-86.0, 13.0, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (145) (-87.0, 13.0, 53.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (146) (-87.0, 13.0, 54.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (140) (-85.0, 13.0, 52.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (141) (-86.0, 13.0, 52.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (144) (-84.0, 13.0, 52.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (192) (-70.5, 13.0, 56.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (186) (-69.5, 13.0, 56.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (187) (-69.5, 13.0, 55.8)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (123) (-82.5, 13.0, 44.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (126) (-82.5, 13.0, 45.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (121) (-83.5, 13.0, 45.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (124) (-83.5, 13.0, 44.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (125) (-83.5, 13.0, 43.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (151) (-82.5, 13.0, 27.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (152) (-82.5, 13.0, 26.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (150) (-81.5, 13.0, 27.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (148) (-81.5, 13.0, 25.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (149) (-81.5, 13.0, 26.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (154) (-79.0, 13.0, 23.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (153) (-78.0, 13.0, 23.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (161) (-68.0, 13.0, 26.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (162) (-68.0, 13.0, 27.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (165) (-69.0, 13.0, 27.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (164) (-69.0, 13.0, 28.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (163) (-68.0, 13.0, 28.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (166) (-68.0, 13.0, 29.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (167) (-63.0, 13.0, 24.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (168) (-62.0, 13.0, 24.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (170) (-61.0, 13.0, 25.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (169) (-62.0, 13.0, 25.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (172) (-62.0, 13.0, 26.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (178) (-61.0, 13.0, 43.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (175) (-60.0, 13.0, 43.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (177) (-61.0, 13.0, 44.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (174) (-59.0, 13.0, 42.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (173) (-59.0, 13.0, 43.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (171) (-59.0, 13.0, 44.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (176) (-60.0, 13.0, 44.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (159) (-83.5, 8.0, 23.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (160) (-83.5, 8.0, 24.5)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (158) (-83.5, 8.0, 22.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (155) (-82.5, 8.0, 24.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (157) (-82.5, 8.0, 22.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Grass (156) (-82.5, 8.0, 23.0)": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (413) (-10.3, 0.3, 128.5)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (414) (-10.3, 0.3, 127.5)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (412) (-11.3, 0.0, 129.5)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (411) (-11.3, 0.0, 128.5)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (410) (-11.3, 0.0, 127.5)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (408) (-4.0, 1.0, 118.0)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (13) (-4.0, 1.0, 116.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (12) (-3.0, 1.0, 116.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (409) (-3.0, 0.8, 115.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (11) (-3.0, 1.0, 117.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (3) (-3.0, 1.0, 118.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass (129) (32.5, 0.8, 84.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass (179) (33.5, 0.8, 84.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass (180) (34.5, 0.8, 84.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass (195) (33.5, 0.3, 85.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass (193) (35.3, 0.8, 84.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass (196) (34.5, 0.3, 85.8)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (418) (54.5, 0.8, 78.3)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (419) (54.5, 0.8, 77.3)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (417) (55.8, 0.8, 78.3)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (416) (55.8, 1.0, 77.3)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Lower Entry Area Grass beach (415) (56.8, 0.8, 78.3)": TunicLocationData( + "Ruined Atoll Lower Entry Area", "Ruined Atoll Lower Entry Area"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (20) (87.5, 12.5, 59.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (17) (86.5, 12.5, 59.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (16) (86.5, 12.5, 60.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (21) (87.5, 12.5, 60.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (15) (91.5, 12.5, 58.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (14) (91.5, 12.5, 57.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (13) (92.5, 12.5, 57.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (12) (92.5, 12.5, 58.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (10) (93.5, 12.5, 57.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Ruined Atoll - Ruined Atoll Frog Mouth Grass (11) (93.5, 12.5, 58.0)": TunicLocationData("Ruined Atoll Frog Mouth", + "Ruined Atoll Frog Mouth"), + "Frog Stairway - Frog Stairs Upper Grass (24) (187.0, 106.0, -65.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (23) (188.0, 106.0, -65.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (22) (189.0, 106.0, -64.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (20) (188.0, 106.0, -64.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (17) (187.0, 106.0, -64.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (14) (191.0, 106.0, -64.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (12) (192.0, 106.0, -63.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (15) (191.0, 106.0, -63.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (13) (192.0, 106.0, -64.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (25) (192.0, 106.0, -65.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (16) (189.0, 106.0, -63.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (21) (188.0, 106.0, -63.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (10) (193.0, 106.0, -64.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (11) (193.0, 106.0, -63.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (26) (193.0, 106.0, -62.0)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Upper Grass (27) (196.6, 106.0, -62.5)": TunicLocationData("Frog Stairs Upper", + "Frog Stairs Upper"), + "Frog Stairway - Frog Stairs Lower Grass (9) (179.8, 61.9, -67.1)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (8) (178.6, 61.9, -67.1)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (7) (204.4, 58.1, -94.1)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (5) (205.5, 58.1, -94.1)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (6) (205.5, 58.1, -93.0)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (2) (205.5, 54.0, -77.0)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (205.5, 54.0, -76.0)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (1) (204.5, 54.0, -76.0)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (4) (201.4, 54.3, -71.3)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Frog Stairway - Frog Stairs Lower Grass (3) (200.4, 54.3, -71.3)": TunicLocationData("Frog Stairs Lower", + "Frog Stairs Lower"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (77) (-8.8, -4.0, -169.5)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (78) (-7.8, -4.0, -169.5)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (81) (-7.8, -4.0, -168.5)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (80) (-6.8, -4.0, -168.5)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (79) (-6.8, -4.0, -169.5)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Bush (8) (-7.3, -4.0, -171.0)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (25) (-5.5, -4.0, -150.0)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (28) (-4.5, -4.0, -151.0)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (26) (-4.5, -4.0, -150.0)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (24) (-3.3, -4.0, -149.0)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (23) (-4.5, -4.0, -149.0)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (22) (-8.3, -4.0, -138.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (21) (-7.3, -4.0, -138.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (18) (-7.3, -4.0, -137.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (20) (-8.3, -4.0, -137.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (13) (-2.0, -4.0, -137.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (17) (-1.0, -4.0, -138.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (14) (-1.0, -4.0, -137.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (16) (0.0, -4.0, -138.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (15) (0.0, -4.0, -137.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Bush (6) (-18.0, -4.0, -145.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (12) (-18.3, -4.0, -144.0)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (10) (-17.0, -4.0, -142.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (11) (-18.3, -4.0, -142.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (76) (-17.3, -4.0, -151.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (74) (-17.3, -4.0, -152.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (438) (-18.3, -4.0, -150.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (75) (-18.3, -4.0, -151.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (73) (-18.3, -4.0, -152.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (32) (-2.5, -4.0, -156.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (29) (-1.5, -4.0, -156.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (31) (-2.5, -4.0, -157.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from East Forest Grass (30) (-1.5, -4.0, -157.8)": TunicLocationData( + "Fortress Exterior from East Forest", "Fortress Exterior from East Forest"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (44) (-26.8, -5.0, -135.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (39) (-26.8, -5.0, -134.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (38) (-26.8, -5.0, -133.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (41) (-28.8, -5.0, -134.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (37) (-27.8, -5.0, -133.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (40) (-27.8, -5.0, -134.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (43) (-27.8, -5.0, -135.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (42) (-28.8, -5.0, -135.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (49) (-21.5, -5.0, -133.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (47) (-20.5, -5.0, -134.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (48) (-21.5, -5.0, -132.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (46) (-20.5, -5.0, -133.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (45) (-20.5, -5.0, -132.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (34) (-16.8, -5.5, -126.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (27) (-17.8, -5.6, -125.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (33) (-17.8, -5.5, -126.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (19) (-16.8, -5.5, -125.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (154) (-20.0, -4.5, -118.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (155) (-19.0, -4.5, -118.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (153) (-20.0, -4.5, -117.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (152) (-19.0, -4.5, -117.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (157) (-26.0, -5.0, -116.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (156) (-26.0, -5.0, -117.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (158) (-25.0, -5.0, -117.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (160) (-26.0, -5.0, -118.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (159) (-25.0, -5.0, -118.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (58) (-24.5, -4.5, -110.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (57) (-24.5, -4.5, -109.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (56) (-24.5, -4.5, -108.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (55) (-25.5, -4.5, -108.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (54) (-25.5, -4.5, -109.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (59) (-25.5, -4.5, -110.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (53) (-26.5, -4.5, -109.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (52) (-18.5, -4.3, -109.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (50) (-18.5, -4.3, -108.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (51) (-19.5, -4.3, -108.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (67) (-14.5, 0.0, -94.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (63) (-15.5, 0.0, -93.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (66) (-13.5, 0.0, -94.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (64) (-14.5, 0.0, -93.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (69) (-16.5, 0.0, -93.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (1) (-17.3, 0.0, -95.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (62) (-15.5, 0.0, -92.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (68) (-16.5, 0.0, -92.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (60) (-13.5, 0.0, -92.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (65) (-13.5, 0.0, -93.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (61) (-14.5, 0.0, -92.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (-12.0, 0.0, -94.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (3) (-7.3, 0.0, -102.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (2) (-9.3, 0.0, -102.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (4) (-7.3, 0.0, -104.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (72) (-5.8, 0.0, -91.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (70) (-4.8, 0.0, -90.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (71) (-5.8, 0.0, -90.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (8) (9.0, 0.0, -90.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (7) (8.0, 0.0, -90.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (9) (7.0, 0.0, -89.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (5) (9.0, 0.0, -89.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (6) (8.0, 0.0, -89.8)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (5) (4.8, 0.0, -90.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (84) (1.8, 0.0, -74.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (122) (3.0, 0.0, -74.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (82) (-1.8, 0.0, -74.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (86) (-1.8, 0.0, -75.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (83) (-2.8, 0.0, -74.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (87) (-2.8, 0.0, -75.3)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (85) (-2.6, 0.0, -71.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (88) (-3.6, 0.0, -71.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (89) (-2.6, 0.0, -70.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (11) (-15.5, 0.0, -70.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (7) (-17.5, 0.0, -68.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (9) (-15.5, 0.0, -68.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (164) (-26.0, 0.0, -74.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (163) (-25.0, 0.0, -74.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (168) (-24.3, 0.0, -74.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (167) (-23.3, 0.0, -74.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (162) (-25.0, 0.0, -75.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (161) (-26.0, 0.0, -75.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (166) (-23.3, 0.0, -75.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (165) (-24.3, 0.0, -75.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (102) (-26.0, 0.0, -82.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (13) (-28.5, 0.0, -83.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (103) (-24.0, 0.0, -83.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (101) (-25.0, 0.0, -82.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (100) (-25.0, 0.0, -83.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (99) (-26.0, 0.0, -83.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (12) (-30.5, 0.0, -85.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Bush (10) (-28.5, 0.0, -85.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (110) (-34.0, 0.0, -85.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (111) (-35.0, 0.0, -84.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (109) (-35.0, 0.0, -85.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (106) (-21.0, 0.0, -85.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (107) (-20.0, 0.0, -85.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (104) (-20.0, 0.0, -86.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (105) (-21.0, 0.0, -86.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (108) (-19.0, 0.0, -86.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (93) (-41.5, 0.0, -61.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (92) (-40.5, 0.0, -61.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (90) (-41.5, 0.0, -60.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (91) (-40.5, 0.0, -60.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (97) (-52.0, 0.0, -63.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (95) (-52.0, 0.0, -62.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (96) (-51.0, 0.0, -62.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (94) (-53.0, 0.0, -62.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (98) (-53.0, 0.0, -63.5)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (2) (11.0, 9.0, -92.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (3) (11.0, 9.0, -93.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior from Overworld Grass (4) (10.0, 9.0, -92.0)": TunicLocationData( + "Fortress Exterior from Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Fortress Exterior near cave Grass (113) (-54.0, 0.0, -34.0)": TunicLocationData( + "Fortress Exterior near cave", "Fortress Exterior near cave"), + "Fortress Courtyard - Fortress Exterior near cave Grass (112) (-54.0, 0.0, -33.0)": TunicLocationData( + "Fortress Exterior near cave", "Fortress Exterior near cave"), + "Fortress Courtyard - Fortress Exterior near cave Grass (114) (-55.0, 0.0, -33.0)": TunicLocationData( + "Fortress Exterior near cave", "Fortress Exterior near cave"), + "Fortress Courtyard - Fortress Exterior near cave Grass (115) (-50.0, 0.0, -43.5)": TunicLocationData( + "Fortress Exterior near cave", "Fortress Exterior near cave"), + "Fortress Courtyard - Fortress Exterior near cave Grass (116) (-50.0, 0.0, -44.5)": TunicLocationData( + "Fortress Exterior near cave", "Fortress Exterior near cave"), + "Fortress Courtyard - Fortress Courtyard Grass (355) (-14.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (353) (-14.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (346) (-13.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (348) (-13.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (344) (-13.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (349) (-12.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (347) (-12.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (354) (-15.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (342) (-15.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (352) (-15.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (340) (-15.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (350) (-15.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (341) (-14.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (343) (-14.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (351) (-14.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (345) (-12.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (339) (-14.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (325) (-13.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (324) (-13.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (315) (-16.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (309) (-16.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (317) (-16.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (316) (-17.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (314) (-17.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (321) (-14.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (323) (-14.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (313) (-14.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (311) (-14.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (319) (-14.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (310) (-15.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (312) (-15.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (318) (-15.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (338) (-15.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (320) (-15.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (322) (-15.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (300) (-17.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (304) (-17.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (302) (-17.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (305) (-16.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (301) (-16.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (303) (-16.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (306) (-15.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (307) (-15.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (308) (-17.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (295) (-16.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (293) (-16.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (288) (-14.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (289) (-14.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (283) (-15.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (287) (-15.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (285) (-15.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (272) (-18.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (278) (-18.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (291) (-18.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (280) (-18.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (274) (-16.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (284) (-16.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (282) (-16.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (286) (-16.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (276) (-16.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (281) (-17.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (294) (-17.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (279) (-17.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (273) (-17.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (292) (-17.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (290) (-19.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (296) (-19.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (299) (-18.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (297) (-18.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (298) (-19.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (277) (-15.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (275) (-15.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (135) (-14.8, 0.0, -6.5)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (133) (-13.8, 0.0, -6.5)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (134) (-13.8, 0.0, -7.5)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (132) (-12.8, 0.0, -7.5)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (131) (-12.8, 0.0, -6.5)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (367) (-29.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (365) (-29.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (363) (-29.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (368) (-28.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (369) (-27.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (373) (-27.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (371) (-27.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (362) (-30.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (364) (-30.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (366) (-30.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (356) (-30.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (357) (-29.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (361) (-29.0, 0.0, -31.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (359) (-29.0, 0.0, -31.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (358) (-30.0, 0.0, -31.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (360) (-30.0, 0.0, -31.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (372) (-28.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (370) (-28.0, 0.0, -30.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (117) (-15.9, 2.9, -44.6)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (120) (-14.9, 3.1, -45.6)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (118) (-14.9, 3.1, -44.6)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (121) (-13.8, 3.4, -44.6)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (328) (7.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (334) (4.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (336) (4.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (335) (5.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (337) (5.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (333) (6.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (332) (6.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (327) (9.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (329) (8.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (331) (8.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (330) (7.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (264) (12.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (262) (12.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (226) (12.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (249) (11.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (326) (9.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (246) (10.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (248) (10.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (247) (11.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (254) (12.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (260) (12.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (252) (12.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (256) (10.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (257) (11.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (228) (12.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (236) (12.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (227) (13.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (237) (13.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (229) (13.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (261) (13.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (259) (11.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (258) (10.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (238) (12.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (239) (13.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (270) (16.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (268) (16.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (233) (15.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (245) (15.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (241) (15.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (243) (15.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (235) (15.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (244) (14.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (232) (14.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (234) (14.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (240) (14.0, 0.0, -28.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (242) (14.0, 0.0, -29.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (269) (17.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (267) (17.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (271) (17.0, 0.0, -27.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (266) (16.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (224) (16.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (222) (16.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (231) (15.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (219) (15.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (230) (14.0, 0.0, -26.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (218) (14.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (265) (13.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (263) (13.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (220) (16.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (217) (15.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (209) (15.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (216) (14.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (208) (14.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (255) (13.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (253) (13.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (207) (15.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (210) (16.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (214) (16.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (212) (16.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (198) (18.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (223) (17.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (221) (17.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (225) (17.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (196) (18.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (195) (21.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (193) (21.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (191) (21.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (194) (20.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (190) (20.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (200) (20.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (192) (20.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (183) (19.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (197) (19.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (185) (19.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (189) (19.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (187) (19.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (184) (18.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (186) (18.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (182) (18.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (188) (18.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (215) (17.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (213) (17.0, 0.0, -23.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (211) (17.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (176) (18.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (180) (18.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (174) (18.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (179) (17.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (35) (17.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (171) (17.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (169) (17.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (16.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (36) (16.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (178) (16.0, 0.0, -21.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (170) (16.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (206) (14.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (251) (13.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (250) (12.0, 0.0, -22.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (199) (19.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (181) (19.0, 0.0, -20.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (173) (19.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (177) (19.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (175) (19.0, 0.0, -19.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (172) (18.0, 0.0, -18.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (202) (20.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (204) (20.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (201) (21.0, 0.0, -24.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (203) (21.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (205) (21.0, 0.0, -25.0)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (126) (26.8, 0.0, -15.8)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (127) (25.8, 0.0, -15.8)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (125) (26.8, 0.0, -14.8)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (128) (25.8, 0.0, -14.8)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (119) (-21.8, 2.0, -51.3)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (130) (-20.8, 2.0, -50.3)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (129) (-20.8, 2.0, -51.3)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (124) (16.5, 0.0, -6.5)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Grass (123) (17.5, 0.0, -6.5)": TunicLocationData("Fortress Courtyard", + "Fortress Courtyard"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (421) (32.5, 8.0, -41.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (143) (32.5, 8.0, -42.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (145) (32.5, 8.0, -43.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (419) (32.5, 8.0, -41.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (382) (36.5, 8.0, -39.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (384) (36.5, 8.0, -39.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (380) (36.5, 8.0, -38.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (383) (37.5, 8.0, -39.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (385) (37.5, 8.0, -39.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (381) (37.5, 8.0, -38.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (144) (31.5, 8.0, -43.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (142) (31.5, 8.0, -42.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (141) (37.5, 8.0, -35.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (375) (37.5, 8.0, -36.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (379) (37.5, 8.0, -37.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (377) (37.5, 8.0, -37.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (374) (36.5, 8.0, -36.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (376) (36.5, 8.0, -37.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (140) (36.5, 8.0, -35.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (378) (36.5, 8.0, -37.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (431) (35.5, 8.0, -38.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (429) (35.5, 8.0, -37.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (433) (35.5, 8.0, -38.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (432) (34.5, 8.0, -38.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (430) (34.5, 8.0, -38.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (415) (32.5, 8.0, -39.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (413) (32.5, 8.0, -39.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (408) (32.5, 8.0, -36.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (411) (32.5, 8.0, -38.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (409) (32.5, 8.0, -37.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (405) (32.5, 8.0, -35.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (407) (31.5, 8.0, -37.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (404) (31.5, 8.0, -36.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (423) (34.5, 8.0, -35.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (427) (34.5, 8.0, -36.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (428) (34.5, 8.0, -37.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (425) (34.5, 8.0, -36.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (424) (33.5, 8.0, -36.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (422) (33.5, 8.0, -35.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (426) (33.5, 8.0, -36.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (416) (31.5, 8.0, -40.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (414) (31.5, 8.0, -39.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (412) (31.5, 8.0, -39.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (410) (31.5, 8.0, -38.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (417) (32.5, 8.0, -40.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (420) (31.5, 8.0, -41.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (418) (31.5, 8.0, -41.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (138) (36.5, 8.0, -34.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (137) (37.5, 8.0, -34.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (136) (37.5, 8.0, -33.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (139) (36.5, 8.0, -33.5)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (406) (31.5, 8.0, -35.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (396) (36.5, 8.0, -22.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (394) (36.5, 8.0, -22.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (389) (36.5, 8.0, -20.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (398) (36.5, 8.0, -23.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (392) (36.5, 8.0, -21.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (397) (37.5, 8.0, -22.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (391) (37.5, 8.0, -20.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (395) (37.5, 8.0, -22.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (393) (37.5, 8.0, -21.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (401) (37.5, 8.0, -24.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (399) (37.5, 8.0, -23.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (436) (37.5, 8.0, -25.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (403) (37.5, 8.0, -24.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (400) (36.5, 8.0, -24.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (402) (36.5, 8.0, -24.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (437) (36.5, 8.0, -25.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (390) (37.5, 8.0, -19.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (387) (37.5, 8.0, -18.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (388) (36.5, 8.0, -18.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (386) (36.5, 8.0, -19.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (435) (37.5, 8.0, -26.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (434) (36.5, 8.0, -26.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (150) (31.8, 8.0, -9.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (146) (31.8, 8.0, -7.8)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (147) (32.8, 8.0, -7.8)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (149) (32.8, 8.0, -6.8)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (151) (32.8, 8.0, -9.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (148) (31.8, 8.0, -6.8)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Fortress Courtyard - Fortress Courtyard Upper Grass (1) (72.0, 8.0, -29.0)": TunicLocationData( + "Fortress Courtyard Upper", "Fortress Courtyard Upper"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (12) (-94.8, 7.0, 41.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (14) (-94.8, 7.0, 42.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (15) (-95.8, 7.0, 41.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (13) (-95.8, 7.0, 42.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (23) (-60.5, -1.0, 38.5)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (20) (-59.5, -1.0, 38.5)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (21) (-60.5, -1.0, 39.5)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (22) (-59.5, -1.0, 39.5)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (10) (-42.0, -1.0, 17.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (9) (-41.0, -1.0, 17.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (11) (-42.0, -1.0, 18.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (8) (-41.0, -1.0, 18.0)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (4) (-3.3, 7.0, 63.8)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (5) (-3.3, 7.0, 62.8)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (6) (-4.3, 7.0, 63.8)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (7) (-4.3, 7.0, 62.8)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (2) (6.3, 7.0, 66.3)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (3) (5.3, 7.0, 66.3)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (1) (6.3, 7.0, 67.3)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Eastern Vault Fortress - Eastern Vault Fortress Grass (5.3, 7.0, 67.3)": TunicLocationData( + "Eastern Vault Fortress", "Eastern Vault Fortress"), + "Fortress Grave Path - Fortress Grave Path Grass (90) (122.0, 0.0, -40.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (88) (121.0, 0.0, -40.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (89) (122.0, 0.0, -41.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (91) (121.0, 0.0, -41.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (95) (121.0, 0.0, -42.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (92) (121.0, 0.0, -43.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (93) (122.0, 0.0, -42.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (94) (122.0, 0.0, -43.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (44) (132.0, 0.0, -42.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (72) (132.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (85) (131.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (46) (133.0, 0.0, -42.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (74) (133.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (47) (132.0, 0.0, -41.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (56) (134.0, 0.0, -43.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (51) (134.0, 0.0, -42.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (59) (134.0, 0.0, -44.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (49) (135.0, 0.0, -42.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (48) (134.0, 0.0, -41.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (45) (133.0, 0.0, -41.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (43) (132.0, 0.0, -40.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (52) (134.0, 0.0, -40.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (41) (133.0, 0.0, -40.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (87) (130.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (86) (131.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (84) (130.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (83) (130.0, 0.0, -48.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (80) (130.0, 0.0, -47.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (75) (132.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (82) (131.0, 0.0, -47.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (81) (131.0, 0.0, -48.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (77) (133.0, 0.0, -47.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (73) (133.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (76) (132.0, 0.0, -48.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (79) (132.0, 0.0, -47.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (60) (134.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (63) (134.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (78) (133.0, 0.0, -48.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (62) (135.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (64) (136.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (67) (136.0, 0.0, -47.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (68) (136.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (61) (135.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (57) (135.0, 0.0, -44.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (109) (136.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (65) (137.0, 0.0, -47.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (66) (137.0, 0.0, -46.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (70) (137.0, 0.0, -45.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (71) (136.0, 0.0, -44.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (69) (137.0, 0.0, -44.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (58) (135.0, 0.0, -43.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (108) (137.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (110) (136.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (111) (137.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (112) (138.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (115) (138.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (113) (139.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (118) (140.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (119) (139.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (114) (139.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (117) (139.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (116) (138.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (120) (138.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (130) (143.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (129) (143.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (128) (142.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (131) (142.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (167) (141.5, 0.0, -47.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (121) (141.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (122) (141.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (165) (141.5, 0.0, -46.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (166) (140.5, 0.0, -46.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (123) (140.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (124) (144.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (127) (144.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (50) (135.0, 0.0, -41.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (54) (135.0, 0.0, -40.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (53) (135.0, 0.0, -39.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (55) (134.0, 0.0, -39.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (42) (133.0, 0.0, -39.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (35) (132.0, 0.0, -38.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (40) (132.0, 0.0, -39.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (34) (133.0, 0.0, -37.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (33) (133.0, 0.0, -38.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (17) (137.0, 0.0, -34.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (38) (133.0, 0.0, -36.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (29) (134.0, 0.0, -34.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (31) (134.0, 0.0, -35.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (26) (134.0, 0.0, -36.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (27) (135.0, 0.0, -35.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (25) (135.0, 0.0, -34.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (28) (135.0, 0.0, -33.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (30) (135.0, 0.0, -36.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (16) (136.0, 0.0, -33.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (23) (136.0, 0.0, -34.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (37) (133.0, 0.0, -35.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (36) (132.0, 0.0, -36.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (39) (132.0, 0.0, -35.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (32) (132.0, 0.0, -37.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (22) (137.0, 0.0, -33.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (24) (134.0, 0.0, -33.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (12) (139.0, 0.0, -31.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (21) (137.0, 0.0, -32.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (14) (138.0, 0.0, -32.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (15) (139.0, 0.0, -32.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (3) (139.0, 0.0, -30.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (2) (138.0, 0.0, -30.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (1) (138.0, 0.0, -29.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (13) (138.0, 0.0, -31.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (18) (137.0, 0.0, -31.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (20) (136.0, 0.0, -32.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (19) (136.0, 0.0, -31.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (139.0, 0.0, -29.0)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (125) (145.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (126) (145.0, 0.0, -51.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (132) (146.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (135) (146.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (133) (147.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (137) (149.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (139) (148.0, 0.0, -50.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (143) (150.0, 0.0, -47.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (140) (150.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (145) (149.0, 0.0, -47.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (138) (149.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (146) (149.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (147) (148.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (136) (148.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (144) (148.0, 0.0, -47.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (134) (147.0, 0.0, -49.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (141) (151.0, 0.0, -47.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (142) (151.0, 0.0, -48.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (148) (151.0, 0.0, -46.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (149) (151.0, 0.0, -45.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (153) (151.0, 0.0, -41.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (152) (151.0, 0.0, -42.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (150) (151.0, 0.0, -43.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (151) (151.0, 0.0, -44.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (164) (150.0, 0.0, -43.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (169) (149.0, 0.0, -43.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (170) (149.0, 0.0, -44.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (168) (150.0, 0.0, -44.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (154) (151.0, 0.0, -39.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (155) (151.0, 0.0, -40.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (157) (151.0, 0.0, -37.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (159) (151.0, 0.0, -36.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (156) (151.0, 0.0, -38.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (162) (150.0, 0.0, -37.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (163) (150.0, 0.0, -36.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (160) (151.0, 0.0, -34.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (158) (151.0, 0.0, -35.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (161) (151.0, 0.0, -33.0)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (4) (148.5, 0.0, -31.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (7) (148.5, 0.0, -32.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (5) (147.5, 0.0, -31.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (6) (147.5, 0.0, -32.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (106) (150.5, 0.0, -31.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (107) (149.5, 0.0, -32.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (104) (149.5, 0.0, -31.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (99) (162.5, 0.0, -49.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (9) (162.5, 0.0, -50.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (96) (162.5, 0.0, -48.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (10) (162.5, 0.0, -51.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (11) (163.5, 0.0, -51.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (8) (163.5, 0.0, -50.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (97) (163.5, 0.0, -49.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (102) (163.5, 0.0, -47.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (98) (163.5, 0.0, -48.5)": TunicLocationData("Fortress Grave Path", + "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (101) (163.5, 0.0, -46.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (100) (162.5, 0.0, -47.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Grass (103) (162.5, 0.0, -46.5)": TunicLocationData( + "Fortress Grave Path", "Fortress Grave Path Combat"), + "Fortress Grave Path - Fortress Grave Path Dusty Entrance Grass (172) (184.5, -1.0, -12.5)": TunicLocationData( + "Fortress Grave", "Fortress Grave Path Dusty Entrance Region"), + "Fortress Grave Path - Fortress Grave Path Dusty Entrance Grass (105) (185.5, -1.0, -13.5)": TunicLocationData( + "Fortress Grave", "Fortress Grave Path Dusty Entrance Region"), + "Fortress Grave Path - Fortress Grave Path Dusty Entrance Grass (171) (185.5, -1.0, -12.5)": TunicLocationData( + "Fortress Grave", "Fortress Grave Path Dusty Entrance Region"), + "Fortress Arena - Fortress Arena Grass (91) (2.0, -4.0, 26.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (90) (3.0, -4.0, 26.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (92) (2.0, -4.0, 25.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (89) (3.0, -4.0, 25.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (60) (2.0, 8.0, 155.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (61) (2.0, 8.0, 154.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (63) (3.0, 8.0, 154.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (62) (3.0, 8.0, 155.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (57) (4.0, 8.0, 154.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (53) (7.0, 8.0, 155.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (52) (7.0, 8.0, 156.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (54) (6.0, 8.0, 156.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (55) (6.0, 8.0, 155.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (59) (5.0, 8.0, 154.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (58) (5.0, 8.0, 155.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (56) (4.0, 8.0, 155.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (25) (3.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (24) (3.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (7) (4.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (17) (4.0, 8.0, 170.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (16) (4.0, 8.0, 171.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (3) (4.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (6) (5.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (27) (2.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (26) (2.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (9) (6.0, 8.0, 170.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (32) (6.0, 8.0, 169.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (8) (6.0, 8.0, 171.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (19) (5.0, 8.0, 170.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (18) (5.0, 8.0, 171.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (12) (8.0, 8.0, 171.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (10) (7.0, 8.0, 171.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (2) (5.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (29) (5.0, 8.0, 176.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (28) (5.0, 8.0, 177.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (1) (5.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (5.0, 8.0, 175.0)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (35) (4.0, 8.0, 176.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (34) (4.0, 8.0, 177.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (4) (4.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (5) (4.0, 8.0, 175.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (20) (3.0, 8.0, 175.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (21) (3.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (22) (2.0, 8.0, 175.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (23) (2.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (33) (6.0, 8.0, 168.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (31) (7.0, 8.0, 168.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (11) (7.0, 8.0, 170.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (30) (7.0, 8.0, 169.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (13) (8.0, 8.0, 170.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (15) (9.0, 8.0, 170.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (14) (9.0, 8.0, 171.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (37) (11.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (39) (12.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (38) (12.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (36) (11.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (68) (5.0, 8.0, 183.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (71) (5.0, 8.0, 182.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (70) (4.0, 8.0, 183.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (69) (4.0, 8.0, 182.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (66) (3.0, 8.0, 182.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (67) (2.0, 8.0, 182.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (75) (5.0, 8.0, 184.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (65) (3.0, 8.0, 183.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (64) (2.0, 8.0, 183.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (72) (5.0, 8.0, 185.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (74) (4.0, 8.0, 185.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (73) (4.0, 8.0, 184.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (78) (-3.0, 8.0, 187.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (77) (-3.0, 8.0, 186.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (85) (-4.0, 8.0, 184.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (86) (-4.0, 8.0, 185.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (83) (-3.0, 8.0, 184.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (80) (-3.0, 8.0, 185.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (79) (-2.0, 8.0, 186.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (82) (-2.0, 8.0, 185.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (81) (-2.0, 8.0, 184.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (76) (-2.0, 8.0, 187.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (84) (-5.0, 8.0, 185.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (87) (-5.0, 8.0, 184.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (50) (-14.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (48) (-13.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (40) (-12.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (44) (-12.0, 8.0, 175.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (45) (-12.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (47) (-11.0, 8.0, 174.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (42) (-11.0, 8.0, 173.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (46) (-11.0, 8.0, 175.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (49) (-13.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (51) (-14.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (43) (-11.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (41) (-12.0, 8.0, 172.0)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-12.4, 8.0, 190.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-11.4, 8.0, 190.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-11.4, 8.0, 191.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-12.4, 8.0, 191.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-12.4, 8.0, 192.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-11.4, 8.0, 192.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-12.4, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-11.4, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-14.4, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-14.4, 8.0, 192.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-14.4, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-14.4, 8.0, 195.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-13.4, 8.0, 195.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-13.4, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-13.4, 8.0, 192.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-13.4, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-2.8, 8.0, 194.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-3.8, 8.0, 194.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-2.8, 8.0, 195.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-3.8, 8.0, 195.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-2.8, 8.0, 199.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-4.8, 8.0, 200.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-3.8, 8.0, 199.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-3.8, 8.0, 200.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-2.8, 8.0, 200.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-1.8, 8.0, 200.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-1.8, 8.0, 199.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-0.8, 8.0, 199.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-3.8, 8.0, 202.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-3.8, 8.0, 201.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-4.8, 8.0, 202.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-4.8, 8.0, 201.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (-0.8, 8.0, 200.5)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (4.6, 8.0, 196.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (1.6, 8.0, 198.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (3.6, 8.0, 196.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (3.6, 8.0, 197.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (4.6, 8.0, 199.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (4.6, 8.0, 198.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (3.6, 8.0, 198.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (3.6, 8.0, 199.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (2.6, 8.0, 199.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (2.6, 8.0, 198.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (1.6, 8.0, 199.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (4.6, 8.0, 197.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (5.6, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (6.6, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (8.6, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (8.6, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (9.6, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (9.6, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (6.6, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (9.6, 8.0, 191.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (9.6, 8.0, 192.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (10.6, 8.0, 191.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (10.6, 8.0, 192.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (11.6, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (11.6, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (10.6, 8.0, 193.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (10.6, 8.0, 194.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (13.6, 8.0, 190.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (13.6, 8.0, 191.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (14.6, 8.0, 191.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (14.6, 8.0, 190.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (15.6, 8.0, 189.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (15.6, 8.0, 190.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (16.6, 8.0, 190.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (16.6, 8.0, 189.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (21.6, 8.0, 189.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (21.6, 8.0, 188.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (22.6, 8.0, 189.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (22.6, 8.0, 188.4)": TunicLocationData("Fortress Arena", "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (94) (-13.0, 8.0, 223.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (96) (-12.0, 8.0, 224.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (99) (-12.0, 8.0, 223.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (97) (-11.0, 8.0, 223.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (98) (-11.0, 8.0, 224.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (103) (-12.0, 8.0, 225.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (100) (-12.0, 8.0, 226.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (101) (-11.0, 8.0, 225.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (102) (-11.0, 8.0, 226.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (88) (-14.0, 8.0, 223.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (93) (-13.0, 8.0, 222.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (95) (-14.0, 8.0, 222.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (117) (-38.5, 8.0, 218.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (120) (-38.5, 8.0, 217.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (116) (-38.5, 8.0, 219.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (121) (-38.5, 8.0, 216.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (118) (-39.5, 8.0, 219.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (122) (-39.5, 8.0, 217.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (119) (-39.5, 8.0, 218.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (123) (-39.5, 8.0, 216.3)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (108) (-33.3, 8.0, 208.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (112) (-35.3, 8.0, 209.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (114) (-36.3, 8.0, 209.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (113) (-35.3, 8.0, 208.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (115) (-36.3, 8.0, 208.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (109) (-33.3, 8.0, 207.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (107) (-34.3, 8.0, 205.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (110) (-34.3, 8.0, 208.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (111) (-34.3, 8.0, 207.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (106) (-34.3, 8.0, 206.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (105) (-33.3, 8.0, 205.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Fortress Arena - Fortress Arena Grass (104) (-33.3, 8.0, 206.8)": TunicLocationData("Fortress Arena", + "Fortress Arena"), + "Quarry - Quarry Back Grass (26) (-50.3, 31.8, 74.3)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (27) (-49.3, 31.8, 74.3)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (20) (-50.3, 31.8, 75.3)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (21) (-49.3, 31.8, 75.3)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (22) (-50.3, 31.8, 76.3)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (23) (-49.3, 31.8, 76.3)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (13) (-44.0, 28.0, 59.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (14) (-45.0, 28.0, 60.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (12) (-45.0, 28.0, 59.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (15) (-44.0, 28.0, 60.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (6) (-40.0, 28.0, 59.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (7) (-39.0, 28.0, 59.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (11) (-37.0, 28.0, 58.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (9) (-37.0, 28.0, 57.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (4) (-40.0, 28.0, 60.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (5) (-39.0, 28.0, 60.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (2) (-38.0, 28.0, 59.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (8) (-38.0, 28.0, 57.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (10) (-38.0, 28.0, 58.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (3) (-37.0, 28.0, 59.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (-37.0, 28.0, 60.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (1) (-38.0, 28.0, 60.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (17) (-23.3, 28.0, 55.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (16) (-24.3, 28.0, 55.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (18) (-24.3, 28.0, 56.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (19) (-23.3, 28.0, 56.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (29) (-57.5, -4.5, 16.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (38) (-56.5, -4.0, 16.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (34) (-56.5, -4.0, 16.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (28) (-57.5, -4.5, 15.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (24) (-58.5, -4.5, 15.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (25) (-58.5, -4.5, 16.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (37) (-55.5, -4.0, 16.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (41) (-55.5, -4.0, 16.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (40) (-56.5, -4.0, 15.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (36) (-56.5, -4.0, 15.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (39) (-55.5, -4.0, 15.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (35) (-55.5, -4.0, 15.0)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (32) (-57.5, -12.0, 11.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (30) (-57.5, -12.0, 10.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (33) (-56.5, -12.0, 10.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (31) (-56.5, -12.0, 11.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (44) (-51.0, -12.0, 11.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (43) (-49.5, -12.0, 11.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (47) (-49.5, -12.0, 12.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (49) (-52.0, -12.0, 12.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (48) (-51.0, -12.0, 12.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (50) (-52.0, -12.0, 13.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (46) (-48.5, -12.0, 11.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (45) (-48.5, -12.0, 12.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Quarry - Quarry Back Grass (42) (-50.3, -12.0, 13.5)": TunicLocationData("Quarry Back", "Quarry Back"), + "Swamp - Swamp Front Grass swamp (36) (-100.0, -0.3, -10.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (37) (-100.0, -0.5, -9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (35) (-99.0, -0.5, -9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (38) (-99.0, -0.8, -10.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (40) (-88.3, 0.3, -18.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (41) (-87.3, -0.3, -19.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (34) (-87.3, 0.5, -18.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (31) (-89.5, -0.3, -10.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (32) (-89.5, -0.5, -9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (33) (-88.5, -0.8, -10.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (30) (-88.5, -0.5, -9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (39) (-88.3, 0.5, -19.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (27) (-82.3, 0.3, -14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (28) (-82.3, 0.3, -13.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (29) (-81.3, -0.5, -14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (26) (-81.3, -0.3, -13.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (24) (-80.3, 0.3, -12.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (23) (-80.3, 0.3, -13.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (22) (-79.3, -0.3, -12.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (25) (-79.3, -0.5, -13.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (56) (-83.3, 0.3, -21.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (54) (-82.3, 0.5, -21.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (57) (-82.3, -1.0, -22.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (55) (-83.3, 0.0, -22.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (43) (-77.3, -1.3, -6.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (45) (-76.3, -1.8, -6.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (42) (-76.3, -1.5, -5.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (44) (-77.3, -1.3, -5.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (19) (-73.5, 0.3, -18.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (21) (-72.5, 0.5, -18.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (18) (-72.5, -0.3, -17.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (20) (-73.5, 0.3, -17.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (15) (-61.8, 0.3, -22.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (16) (-61.8, 0.3, -21.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (17) (-60.8, -0.5, -22.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (14) (-60.8, -0.3, -21.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (60) (-64.0, -1.0, -27.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (58) (-63.0, -1.0, -27.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (61) (-63.0, -1.3, -28.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (59) (-64.0, -1.5, -28.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (63) (-62.0, -0.5, -29.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (64) (-62.0, -0.5, -28.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (449) (-58.5, -0.8, -16.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (451) (-57.5, -0.8, -16.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (448) (-57.5, -1.0, -15.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (450) (-58.5, -0.8, -15.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (445) (-51.5, 0.0, -9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (447) (-50.5, -0.3, -9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (446) (-51.5, 0.0, -8.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (444) (-50.5, -0.5, -8.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (432) (-55.8, -0.5, -2.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (430) (-56.8, -0.5, -2.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (431) (-56.8, -0.5, -1.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (429) (-55.8, -0.8, -1.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (437) (-60.8, -0.3, -2.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (439) (-61.8, 0.0, -2.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (438) (-61.8, 0.0, -3.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (436) (-62.8, -0.3, -4.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (433) (-62.8, -0.5, -3.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (434) (-63.8, -0.3, -4.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (435) (-63.8, -0.3, -3.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (48) (-61.0, -1.0, -8.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (47) (-61.0, -1.3, -9.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (46) (-60.0, -1.3, -8.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (441) (-61.0, -0.3, 5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (443) (-60.0, -0.3, 5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (440) (-60.0, -0.5, 6.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (442) (-61.0, -0.3, 6.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (204) (-70.0, -0.3, 11.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (206) (-69.0, -0.3, 11.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (207) (-69.3, -0.3, 12.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (212) (-70.3, 0.0, 12.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (183) (-70.0, -1.3, 7.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (185) (-71.0, -1.0, 8.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (187) (-72.0, -1.0, 8.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (175) (-72.5, 0.5, 13.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (176) (-72.5, 0.5, 14.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (181) (-69.0, -1.3, 7.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (174) (-71.5, 0.5, 14.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (172) (-71.5, 0.0, 13.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (186) (-72.0, -1.3, 7.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (180) (-69.0, -1.5, 6.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (182) (-70.0, -1.5, 6.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (184) (-71.0, -1.3, 7.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (266) (-77.8, -1.3, 11.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (267) (-78.0, -1.3, 12.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (268) (-78.5, -1.3, 12.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (265) (-78.8, -1.5, 11.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (165) (-84.0, -0.5, 5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (167) (-84.0, 0.0, 4.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (166) (-83.0, -0.5, 5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (56) (-83.0, -0.5, 4.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (169) (-75.3, -0.8, 21.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (171) (-75.3, -0.3, 20.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (168) (-74.3, -0.8, 20.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (170) (-74.3, -0.8, 21.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (199) (-73.8, -0.3, 24.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (196) (-72.8, -0.8, 24.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (197) (-73.8, -0.8, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (198) (-72.8, -0.8, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (200) (-78.3, -1.0, 27.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (203) (-79.3, -0.5, 27.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (201) (-79.3, -0.8, 28.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (202) (-78.3, -0.5, 28.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (192) (-64.3, -0.5, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (194) (-64.3, -0.3, 26.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (205) (-66.3, -0.3, 26.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (211) (-65.3, -0.3, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (195) (-65.3, -0.3, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (193) (-65.3, -0.3, 26.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (209) (-66.3, -0.3, 27.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (208) (-67.3, -0.3, 27.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (210) (-67.3, -0.3, 26.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (178) (-62.3, -0.3, 13.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (179) (-62.3, -0.3, 14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (177) (-61.3, -0.3, 14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (173) (-61.3, -0.3, 13.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (191) (-59.0, -0.3, 20.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (188) (-58.0, -0.8, 20.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (190) (-58.0, -0.8, 21.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (189) (-59.0, -0.8, 21.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (52) (-58.0, 0.0, -35.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (50) (-57.0, -0.3, -35.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (51) (-58.0, -0.3, -36.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (7) (-54.3, -1.3, -38.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (53) (-57.0, -0.8, -36.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (10) (-53.5, 0.0, -30.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (13) (-52.5, -0.5, -31.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (11) (-53.5, 0.0, -29.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (9) (-52.5, -0.3, -29.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (12) (-52.5, -0.5, -30.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (5) (-53.3, -1.5, -38.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (4) (-51.0, -1.5, -37.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1) (-51.0, -1.0, -36.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (8) (-53.3, -2.0, -39.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (6) (-54.3, -1.8, -39.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (3) (-50.0, -1.8, -37.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (2) (-50.0, -1.3, -36.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (272) (-46.5, -1.0, -11.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (271) (-46.5, -1.0, -12.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (270) (-45.5, -1.0, -11.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (269) (-45.5, -1.3, -12.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (273) (-44.5, -1.5, -13.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (275) (-43.5, -1.5, -12.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (274) (-43.5, -1.5, -13.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (276) (-44.5, -1.5, -12.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (284) (-36.5, -0.8, -5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (281) (-36.5, -1.0, -7.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (283) (-35.5, -0.8, -5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (282) (-35.5, -1.0, -7.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (280) (-35.3, -1.3, -8.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (278) (-34.3, -1.3, -9.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (279) (-34.3, -1.3, -8.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (277) (-35.3, -1.3, -9.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (234) (-21.0, -0.5, -14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (236) (-21.0, -0.5, -15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (235) (-20.0, -0.5, -14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (233) (-20.0, -0.5, -15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (307) (-24.0, -0.5, -22.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (341) (-24.0, -0.5, -21.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (344) (-22.0, -0.5, -22.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (345) (-21.0, -0.5, -22.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (308) (-25.0, -0.5, -21.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (342) (-25.0, -0.5, -22.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (343) (-21.0, -0.5, -23.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (346) (-22.0, -0.5, -23.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (108) (-12.5, -2.0, -19.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (110) (-12.5, -1.8, -20.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (107) (-11.5, -1.8, -20.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (109) (-11.5, -2.0, -19.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (350) (-12.5, -0.5, -28.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (348) (-12.5, -0.3, -27.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (349) (-11.5, -0.3, -27.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (347) (-11.5, -0.5, -28.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (78) (-6.3, 0.0, -21.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (80) (-6.3, 0.0, -22.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (79) (-5.3, 0.0, -21.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (77) (-5.3, 0.0, -22.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (76) (-5.3, 0.0, -20.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (73) (-4.3, 0.0, -20.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (75) (-4.3, 0.0, -19.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (74) (-5.3, 0.0, -19.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (238) (-3.3, -1.0, -31.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (239) (-2.3, -1.0, -31.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (240) (-3.3, -1.3, -32.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (243) (-3.3, -1.5, -33.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (237) (-2.3, -1.3, -32.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (242) (-4.3, -1.5, -33.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (241) (-3.3, -1.8, -34.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (244) (-4.3, -1.8, -34.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (21) (4.3, -2.0, -18.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (24) (3.3, -2.0, -18.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (23) (4.3, -1.8, -17.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (22) (3.3, -1.8, -17.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (69) (2.8, -0.3, -14.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (28) (8.5, -1.8, -17.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (26) (8.5, -1.5, -16.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (25) (9.5, -1.8, -17.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (32) (9.5, -1.3, -15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (27) (9.5, -1.5, -16.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (35) (12.5, -1.3, -15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (33) (12.5, -1.5, -16.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (36) (11.5, -1.5, -16.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (34) (11.5, -1.3, -15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (29) (10.5, -1.3, -15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (31) (10.5, -1.0, -14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (30) (9.5, -1.0, -14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (112) (15.3, 0.3, -4.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (114) (15.3, 0.3, -5.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (111) (16.3, 0.3, -5.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (113) (16.3, 0.3, -4.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (118) (19.5, 0.0, -5.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (116) (19.5, 0.0, -4.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (38) (14.0, 0.0, -10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (37) (15.0, 0.0, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (39) (15.0, 0.0, -10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (40) (14.0, 0.0, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (115) (20.5, 0.0, -5.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (117) (20.5, 0.0, -4.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (123) (21.8, 0.0, -9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (124) (21.8, 0.0, -8.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (381) (21.8, 0.0, -17.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (379) (21.8, 0.0, -18.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (376) (19.8, 0.0, -27.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (378) (19.8, -0.3, -28.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (375) (20.8, 0.0, -28.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (377) (20.8, 0.0, -27.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (372) (16.0, -1.3, -32.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (373) (17.0, -1.3, -32.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (367) (17.0, -1.3, -33.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (374) (16.0, -1.5, -33.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (6.3, 0.0, -4.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1) (6.3, 0.0, -5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (4) (5.3, 0.0, -5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (2) (5.3, 0.0, -5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (3) (5.3, 0.0, -4.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (62) (-2.3, 0.0, -10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (63) (-1.3, 0.0, -10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (61) (-1.3, 0.0, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (64) (-2.3, 0.0, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (68) (-0.3, 0.0, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (66) (-0.3, 0.0, -10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (67) (0.8, 0.0, -10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (65) (0.8, 0.0, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (70) (1.8, 0.0, -13.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (72) (1.8, 0.0, -14.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (71) (2.8, -0.3, -13.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (59) (-4.5, 0.0, -5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (57) (-4.5, 0.0, -6.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (58) (-5.5, 0.0, -5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (60) (-5.5, 0.0, -6.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (53) (-6.5, 0.0, -5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (55) (-6.5, 0.0, -4.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (54) (-7.5, 0.0, -4.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (47) (-10.8, 0.0, 2.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (48) (-11.8, 0.0, 1.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (46) (-11.8, 0.0, 2.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (45) (-10.8, 0.0, 1.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (16) (-7.3, 0.0, 4.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (13) (-6.3, 0.0, 4.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (15) (-6.3, 0.0, 5.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (14) (-7.3, 0.0, 5.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (17) (-8.5, 0.0, 8.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (49) (-11.8, 0.0, 3.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (51) (-11.8, 0.0, 4.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (52) (-12.8, 0.0, 3.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (50) (-12.8, 0.0, 4.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (20) (-9.5, 0.0, 8.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (19) (-8.5, 0.0, 9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (18) (-9.5, 0.0, 9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (12) (-2.5, 0.0, 10.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (44) (-1.5, 0.0, 8.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (42) (-1.5, 0.0, 9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (41) (-0.5, 0.0, 8.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (43) (-0.5, 0.0, 9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (9) (-3.5, 0.0, 10.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (7) (1.5, 0.0, 10.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (5) (1.5, 0.0, 9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (6) (0.5, 0.0, 10.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (8) (0.5, 0.0, 9.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (10) (-2.5, 0.0, 11.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (11) (-3.5, 0.0, 11.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (82) (13.8, 0.0, 5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (91) (14.8, 0.0, 7.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (81) (14.8, 0.0, 4.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (84) (14.8, 0.0, 5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (83) (13.8, 0.0, 4.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (88) (16.8, 0.0, 6.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (85) (16.8, 0.0, 5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (87) (15.8, 0.0, 5.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (86) (15.8, 0.0, 6.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (92) (15.8, 0.0, 8.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (89) (15.8, 0.0, 7.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (90) (14.8, 0.0, 8.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (101) (19.5, 0.0, 5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (98) (20.5, 0.0, 5.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (99) (19.5, 0.0, 6.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (102) (20.5, 0.0, 6.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (97) (21.5, 0.0, 8.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (100) (21.5, 0.0, 9.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (93) (21.5, 0.0, 10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (95) (20.5, 0.0, 10.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (94) (20.5, 0.0, 11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (96) (21.5, 0.0, 11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (135) (20.8, 0.0, 26.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (138) (21.8, 0.0, 26.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (136) (21.8, 0.0, 27.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (137) (20.8, 0.0, 27.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (140) (15.5, 0.0, 26.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (141) (14.5, 0.0, 26.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (142) (15.5, 0.0, 25.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (139) (14.5, 0.0, 25.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (718) (21.0, -0.5, 30.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (719) (21.0, -0.5, 31.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (721) (22.0, -0.5, 30.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (720) (22.0, -0.5, 31.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (717) (22.0, -0.5, 32.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (714) (21.0, -0.5, 32.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (716) (22.0, -0.5, 33.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (715) (21.0, -0.5, 33.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (705) (15.8, -0.5, 43.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (704) (15.8, -0.5, 44.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (702) (14.8, -0.5, 43.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (703) (14.8, -0.5, 44.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (708) (13.8, -0.5, 44.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (709) (13.8, -0.5, 43.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (707) (12.8, -0.5, 44.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (706) (12.8, -0.5, 43.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (134) (6.5, -0.5, 34.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (132) (6.5, -0.5, 35.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (133) (5.5, -0.5, 35.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (131) (5.5, -0.5, 34.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (149) (2.1, -0.9, 33.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (148) (3.1, -0.9, 33.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (150) (3.1, -1.1, 32.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (147) (2.1, -1.1, 32.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (130) (5.3, -1.0, 31.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (126) (6.3, -1.3, 30.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (129) (6.3, -1.0, 31.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (127) (5.3, -1.3, 30.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (125) (5.3, -1.8, 29.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (128) (6.3, -1.8, 29.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (151) (4.4, -0.5, 42.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (158) (2.5, -0.5, 44.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (156) (2.5, -0.5, 45.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (153) (4.4, -0.5, 43.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (152) (5.4, -0.5, 43.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (161) (-0.4, -0.5, 45.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (157) (1.5, -0.5, 45.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (155) (1.5, -0.5, 44.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (160) (0.6, -0.5, 45.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (154) (5.4, -0.5, 42.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (162) (-5.6, -0.5, 38.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (164) (-5.6, -0.5, 37.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (159) (-6.6, -0.5, 37.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (163) (-6.6, -0.5, 38.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (146) (-2.3, -1.6, 31.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (145) (-1.3, -0.9, 32.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (144) (-2.3, -1.6, 32.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (143) (-1.3, -1.6, 31.4)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (120) (1.5, -1.8, 21.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (121) (2.5, -1.8, 21.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (122) (1.5, -1.8, 20.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (119) (2.5, -1.8, 20.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (411) (-18.8, -0.8, 16.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (409) (-18.8, -0.3, 17.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (405) (-17.8, -0.3, 15.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (410) (-19.8, -0.3, 17.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (412) (-19.8, -0.5, 16.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (406) (-18.8, -0.3, 15.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (408) (-18.8, -0.5, 14.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (407) (-17.8, -0.8, 14.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (415) (-22.0, -0.8, 17.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (413) (-22.0, -0.3, 18.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (414) (-23.0, -0.3, 18.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (416) (-23.0, -0.5, 17.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (400) (-24.5, -0.5, 22.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (398) (-24.5, -0.3, 23.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (399) (-23.5, -0.8, 22.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (397) (-23.5, -0.3, 23.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (401) (-25.5, -0.8, 15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (402) (-26.5, -0.8, 15.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (403) (-25.5, -1.3, 14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (404) (-26.5, -1.3, 14.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (393) (-31.8, -1.0, 22.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (395) (-31.8, -1.5, 21.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (396) (-32.8, -1.8, 21.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (394) (-32.8, -1.5, 22.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (389) (-30.3, -0.3, 32.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (391) (-30.3, -0.3, 31.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (452) (-31.3, -0.3, 30.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (454) (-31.3, -0.3, 29.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (390) (-31.3, -0.5, 32.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (392) (-31.3, -0.5, 31.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (453) (-32.3, -0.3, 30.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (455) (-32.3, -0.5, 29.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (458) (-34.8, -1.0, 32.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (456) (-34.8, -1.3, 33.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (457) (-35.8, -1.3, 33.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (459) (-35.8, -1.3, 32.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (461) (-44.0, -0.3, 26.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (460) (-43.0, -0.3, 26.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (463) (-44.0, -0.8, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (462) (-43.0, -0.3, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (224) (-42.5, -1.0, 42.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (221) (-42.5, -0.5, 43.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (223) (-41.5, -0.3, 43.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (222) (-41.5, -0.8, 42.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (326) (-43.5, -1.3, 47.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (327) (-43.5, -1.0, 48.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (328) (-44.5, -1.3, 47.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (325) (-44.5, -0.8, 48.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (228) (-29.3, -0.5, 44.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (226) (-28.3, -0.8, 44.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (225) (-29.3, -0.8, 45.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (227) (-28.3, -0.8, 45.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (388) (-27.8, -0.5, 37.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (387) (-27.8, -0.3, 38.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (386) (-26.8, -0.5, 38.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (385) (-26.8, -0.8, 37.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (230) (-22.5, -1.0, 41.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (231) (-22.5, -0.5, 42.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (232) (-23.5, -0.8, 41.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (229) (-23.5, -0.3, 42.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (422) (-18.3, -0.8, 45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (421) (-18.3, -1.3, 44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (424) (-19.3, -0.5, 44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (423) (-19.3, 0.0, 45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (219) (-41.0, -1.5, 14.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (217) (-42.0, -1.5, 14.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (220) (-42.0, -1.5, 13.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (218) (-41.0, -2.0, 13.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (215) (-48.5, -1.8, 18.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (213) (-49.5, -1.8, 18.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (216) (-49.5, -1.8, 17.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (214) (-48.5, -2.3, 17.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (286) (-51.0, -1.8, 24.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (292) (-51.0, -1.8, 23.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (289) (-50.0, -1.8, 24.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (287) (-50.0, -2.3, 23.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (320) (-53.0, -1.8, 24.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (318) (-52.0, -2.3, 24.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (317) (-53.0, -1.8, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (319) (-52.0, -1.8, 25.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (338) (-51.0, -0.5, 38.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (337) (-52.0, 0.3, 39.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (339) (-51.0, 0.0, 39.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (340) (-52.0, -0.5, 38.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (330) (-48.0, -0.8, 45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (332) (-49.0, -0.8, 45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (334) (-50.0, -0.5, 44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (333) (-51.0, 0.0, 45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (336) (-51.0, -0.5, 44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (335) (-50.0, -0.3, 45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (329) (-49.0, -0.3, 46.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (331) (-48.0, -0.5, 46.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (104) (-11.3, -1.5, -10.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (106) (-11.3, -1.8, -11.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (103) (-10.3, -1.8, -11.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (105) (-10.3, -1.5, -10.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (248) (0.3, 0.0, -44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (245) (1.3, 0.0, -44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (247) (1.3, -0.3, -43.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (249) (-0.8, -0.3, -45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (251) (-0.8, 0.0, -44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (252) (-1.8, -0.3, -45.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (250) (-1.8, 0.3, -44.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (365) (1.3, -0.5, -49.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (366) (0.3, -0.5, -50.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (364) (0.3, 0.0, -49.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (246) (0.3, 0.0, -43.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (254) (-7.3, -0.5, -49.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (253) (-6.3, -0.8, -50.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (255) (-6.3, -0.5, -49.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (256) (-7.3, -1.0, -50.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (257) (-1.5, -1.8, -60.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (258) (-1.5, -1.8, -61.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (259) (-0.5, -1.8, -60.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (260) (-0.5, -1.5, -61.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (261) (-5.0, -0.5, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (262) (-5.0, -0.5, -67.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (263) (-4.0, -0.5, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (264) (-4.0, -0.3, -67.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (467) (10.8, -0.5, -55.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (465) (10.8, -0.3, -54.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (359) (11.0, -1.0, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (358) (12.0, -0.5, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (357) (12.0, -0.8, -62.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (466) (11.8, -0.5, -54.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (464) (11.8, -0.5, -55.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (362) (10.0, -1.3, -62.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (361) (10.0, -1.5, -63.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (356) (11.0, -1.0, -62.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (363) (9.0, -1.8, -62.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (360) (9.0, -1.8, -63.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (368) (13.0, -1.5, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (371) (13.0, -1.5, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (370) (14.0, -1.0, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (369) (14.0, -1.3, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (354) (21.0, 0.0, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (355) (22.0, 0.0, -65.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (353) (22.0, 0.0, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (382) (21.2, -0.2, -63.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (383) (21.2, -0.5, -62.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (380) (20.2, -0.7, -63.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (384) (20.2, -0.5, -62.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (351) (21.0, 0.0, -67.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (352) (22.0, 0.0, -67.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (316) (20.8, -0.3, -72.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (313) (20.8, -0.6, -73.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (315) (21.8, -0.3, -72.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (314) (21.8, -0.6, -73.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (545) (34.8, 0.0, -92.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (546) (34.8, -0.5, -93.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (542) (35.8, -0.5, -93.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (543) (35.8, -0.3, -92.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (571) (30.8, 0.0, -88.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (572) (30.8, 0.0, -87.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (574) (29.8, 0.0, -88.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (573) (29.8, 0.3, -87.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (541) (27.5, -0.3, -88.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (544) (26.5, -0.5, -88.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (529) (25.5, -0.8, -88.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (530) (25.5, -0.8, -87.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (531) (24.5, -0.5, -87.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (532) (24.5, -0.8, -88.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (538) (27.5, -0.3, -89.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (539) (26.5, -0.3, -89.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (533) (25.5, -0.8, -90.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (534) (25.5, -0.8, -89.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (535) (24.5, -0.5, -89.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (540) (26.5, -0.5, -90.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (537) (27.5, -0.3, -90.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (536) (24.5, -0.8, -90.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (578) (33.3, 0.0, -80.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (575) (34.3, 0.0, -80.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (570) (34.3, 0.0, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (569) (34.3, 0.3, -81.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (567) (35.3, 0.0, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (568) (35.3, 0.0, -81.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (576) (34.3, 0.0, -79.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (577) (33.3, 0.3, -79.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (549) (27.5, 0.3, -81.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (548) (28.5, 0.0, -81.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (547) (28.5, 0.0, -82.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (550) (27.5, 0.0, -82.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (525) (25.8, 0.0, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (521) (26.8, 0.0, -77.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (524) (25.8, 0.0, -77.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (523) (25.8, 0.3, -76.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (522) (26.8, 0.0, -76.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (526) (25.8, 0.0, -78.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (527) (24.8, 0.3, -78.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (528) (24.8, 0.0, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (579) (34.0, 0.0, -74.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (580) (34.0, 0.0, -73.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (581) (33.0, 0.3, -73.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (582) (33.0, 0.0, -74.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (520) (31.0, 0.0, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (517) (32.0, 0.0, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (518) (32.0, 0.0, -69.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (497) (27.0, 0.0, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (555) (33.5, 0.0, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (556) (33.5, 0.0, -66.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (561) (34.5, 0.3, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (562) (34.5, 0.0, -68.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (559) (35.5, 0.0, -68.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (560) (35.5, 0.0, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (516) (30.0, 0.0, -66.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (510) (29.0, 0.0, -66.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (509) (29.0, 0.0, -67.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (558) (32.5, 0.0, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (519) (31.0, 0.3, -69.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (514) (31.0, 0.0, -65.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (513) (31.0, 0.0, -66.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (505) (29.0, 0.0, -69.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (506) (29.0, 0.0, -68.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (512) (28.0, 0.0, -67.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (507) (28.0, 0.3, -68.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (508) (28.0, 0.0, -69.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (498) (27.0, 0.0, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (515) (30.0, 0.3, -65.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (511) (28.0, 0.3, -66.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (502) (27.0, 0.0, -68.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (557) (32.5, 0.3, -66.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (501) (27.0, 0.0, -69.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (503) (26.0, 0.3, -68.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (504) (26.0, 0.0, -69.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (499) (26.0, 0.3, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (500) (26.0, 0.0, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (551) (37.8, 0.0, -65.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (552) (37.8, 0.0, -64.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (554) (36.8, 0.0, -65.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (553) (36.8, 0.3, -64.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (566) (41.5, 2.5, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (584) (40.5, 2.0, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (565) (41.5, 3.0, -60.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (564) (42.5, 3.0, -60.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (563) (42.5, 2.5, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (615) (44.3, 0.5, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (613) (45.3, 1.0, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (612) (45.3, 0.5, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (614) (44.3, 1.3, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (585) (47.8, 0.5, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (583) (47.8, 0.3, -67.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (587) (46.8, 0.3, -67.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (586) (46.8, 0.8, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (496) (43.0, -1.0, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (493) (44.0, -1.0, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (495) (43.0, -0.5, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (490) (46.0, -1.0, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (486) (46.0, -1.3, -72.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (491) (45.0, -0.8, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (492) (45.0, -1.3, -72.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (494) (44.0, -0.8, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (468) (46.0, -0.5, -83.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (470) (46.0, -0.8, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (471) (45.0, -0.5, -83.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (469) (45.0, -0.5, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (672) (49.8, 0.0, -90.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (673) (49.8, -0.3, -91.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (670) (50.8, -0.3, -90.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (671) (50.8, -0.3, -91.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (668) (51.8, 0.0, -91.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (669) (51.8, -0.3, -92.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (666) (52.8, -0.3, -91.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (667) (52.8, -0.3, -92.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (618) (54.3, -0.3, -95.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (619) (54.3, -0.5, -96.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (616) (55.3, -0.5, -96.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (617) (55.3, -0.5, -95.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (674) (46.3, -0.3, -95.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (676) (45.3, 0.0, -95.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (675) (46.3, -0.3, -96.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (677) (45.3, -0.3, -96.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (682) (58.0, -0.5, -78.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (683) (58.0, -0.5, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (680) (59.0, 0.0, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (681) (59.0, -0.3, -80.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (685) (57.0, -0.5, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (679) (60.0, -0.3, -80.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (678) (60.0, -0.3, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (684) (57.0, -0.3, -78.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (591) (57.3, -0.8, -76.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (588) (57.3, -0.8, -77.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (599) (56.3, -1.0, -77.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (598) (56.3, -0.8, -76.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (600) (56.8, -0.5, -72.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (601) (56.8, -0.5, -71.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (603) (55.8, -0.8, -72.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (602) (55.8, -0.5, -71.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (607) (60.8, -0.3, -68.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (606) (60.8, 0.3, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (611) (62.8, 0.3, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (605) (61.8, 0.3, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (604) (61.8, -0.3, -68.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (608) (63.8, 0.3, -67.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (610) (62.8, 0.8, -66.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (609) (63.8, 0.8, -66.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (693) (66.8, 0.5, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (690) (67.8, 0.5, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (691) (67.8, 0.8, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (686) (66.8, 1.0, -64.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (692) (66.8, 1.0, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (687) (66.8, 1.0, -63.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (688) (65.8, 1.3, -63.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (689) (65.8, 1.0, -64.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (592) (55.3, 1.3, -65.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (597) (56.3, 1.3, -65.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (596) (57.3, 1.3, -65.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (589) (53.3, 1.5, -64.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (595) (54.3, 1.3, -65.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (594) (54.3, 1.8, -64.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (593) (55.3, 1.5, -64.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (590) (52.3, 1.8, -64.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (699) (77.0, 0.8, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (701) (76.0, 0.5, -71.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (700) (76.0, 1.0, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (698) (77.0, 1.0, -70.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (694) (73.0, 0.0, -68.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (695) (73.0, 0.0, -69.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (697) (72.0, 0.0, -69.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (696) (72.0, 0.3, -68.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1489) (89.0, -0.8, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (664) (90.0, -1.0, -74.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (665) (90.0, -1.5, -75.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (663) (91.0, -1.3, -74.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1486) (90.0, -0.8, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (660) (92.0, -1.3, -74.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1481) (93.0, -0.8, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (661) (92.0, -1.0, -73.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (662) (91.0, -0.8, -73.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1380) (94.0, -0.8, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1479) (93.0, -0.3, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1478) (94.0, -0.8, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1487) (90.0, -0.8, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1488) (89.0, -0.3, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (658) (96.0, -1.3, -81.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (657) (97.0, -1.5, -81.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (659) (96.0, -1.5, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (656) (97.0, -1.5, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (655) (109.5, -1.5, -85.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (652) (110.5, -1.5, -85.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (654) (109.5, -1.3, -84.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (653) (110.5, -1.5, -84.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (638) (116.3, -0.3, -88.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (639) (116.3, -0.5, -89.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (637) (117.3, -0.5, -88.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (636) (117.3, -0.5, -89.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (649) (111.8, -0.5, -94.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (650) (110.8, -0.3, -94.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (648) (111.8, -0.5, -95.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (651) (110.8, -0.5, -95.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (645) (107.0, -0.3, -98.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (647) (106.0, -0.5, -99.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (646) (106.0, -0.3, -98.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (644) (107.0, -0.5, -99.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (641) (105.0, -0.5, -95.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (642) (104.0, -0.3, -95.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (643) (104.0, -0.5, -96.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (640) (105.0, -0.5, -96.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (478) (117.5, 0.0, -78.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (479) (117.5, -0.3, -79.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (483) (116.5, -0.3, -77.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (476) (118.5, -0.3, -79.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (480) (117.5, -0.3, -77.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (477) (118.5, -0.3, -78.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (475) (118.5, -0.3, -77.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (482) (116.5, 0.0, -76.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (485) (115.5, -0.3, -77.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (474) (118.5, 0.0, -76.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (481) (117.5, -0.3, -76.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (484) (115.5, 0.0, -76.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (472) (119.5, -0.3, -77.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (473) (119.5, -0.3, -76.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (633) (128.0, -1.0, -85.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (632) (128.0, -1.3, -86.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (634) (127.0, -0.8, -85.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (635) (127.0, -1.3, -86.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (628) (122.5, -0.3, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (629) (122.5, -0.3, -81.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (630) (121.5, 0.0, -81.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (631) (121.5, -0.3, -82.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (489) (135.8, -2.0, -90.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (488) (135.8, -1.8, -89.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (487) (136.8, -2.0, -89.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (733) (163.8, -0.8, -85.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (732) (163.8, -0.3, -84.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (730) (164.8, -0.8, -85.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (731) (164.8, -0.5, -84.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (737) (165.0, -0.3, -80.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (734) (166.0, -0.3, -80.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (729) (167.5, -0.3, -82.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (727) (168.5, -0.5, -81.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (726) (168.5, -0.5, -82.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (728) (167.5, 0.0, -81.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (735) (166.0, -0.5, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (736) (165.0, -0.3, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (725) (146.3, -1.3, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (724) (146.3, -0.8, -78.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (723) (147.3, -1.0, -78.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (722) (147.3, -1.3, -79.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1087) (131.0, 4.3, -85.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1081) (132.0, 4.0, -85.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1398) (133.0, 4.3, -84.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1395) (131.0, 4.0, -86.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1079) (132.0, 4.0, -86.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1396) (134.0, 4.0, -85.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1399) (133.0, 4.0, -85.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1397) (134.0, 4.0, -84.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1403) (138.3, 4.0, -77.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1400) (139.3, 4.0, -77.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1402) (138.3, 4.3, -76.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1401) (139.3, 4.0, -76.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1415) (132.3, 4.0, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1412) (133.3, 4.0, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1413) (133.3, 4.0, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1414) (132.3, 4.3, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1417) (131.3, 4.0, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1416) (131.3, 4.0, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1418) (130.3, 4.3, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1419) (130.3, 4.0, -73.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1420) (129.3, 4.0, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1421) (128.3, 4.3, -72.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1408) (139.8, 4.0, -69.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1409) (139.8, 4.0, -68.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1407) (140.8, 4.0, -69.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1404) (141.8, 4.0, -69.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1515) (141.8, 4.3, -70.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1411) (138.8, 4.0, -69.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1511) (142.8, 4.0, -70.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1516) (142.8, 4.0, -71.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1517) (141.8, 4.0, -71.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1405) (141.8, 4.0, -68.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1406) (140.8, 4.3, -68.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1410) (138.8, 4.3, -68.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1425) (131.0, 7.8, -69.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1424) (132.0, 7.8, -68.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1423) (132.0, 7.8, -69.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1422) (131.0, 7.8, -68.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1518) (127.3, 7.8, -62.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1520) (127.3, 7.8, -61.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1519) (126.3, 7.8, -61.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1521) (126.3, 7.8, -62.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1432) (116.8, 7.8, -64.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1427) (114.8, 7.8, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1428) (114.8, 7.8, -64.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1431) (115.8, 7.8, -64.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1426) (113.8, 7.8, -64.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1429) (113.8, 7.8, -65.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1430) (112.8, 7.8, -64.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1438) (105.3, 7.8, -62.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1439) (105.3, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1436) (106.3, 7.8, -62.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1437) (104.3, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1435) (107.3, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1434) (107.3, 7.8, -62.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1433) (106.3, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1441) (94.1, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1440) (93.1, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1456) (86.5, 7.8, -60.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1455) (86.5, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1457) (85.5, 7.8, -61.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1454) (85.5, 7.8, -60.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1444) (88.0, 7.8, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1442) (87.0, 7.8, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1445) (87.0, 7.8, -67.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1524) (89.0, 7.8, -67.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1443) (88.0, 7.8, -67.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1522) (93.1, 7.8, -66.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1525) (93.1, 7.8, -67.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1523) (94.1, 7.8, -67.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1451) (73.5, 4.0, -61.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1452) (73.5, 4.0, -60.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1450) (72.5, 4.0, -60.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1453) (72.5, 4.0, -61.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1449) (82.3, 4.0, -65.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1447) (83.3, 4.0, -65.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1446) (82.3, 4.0, -64.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1448) (83.3, 4.0, -64.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1480) (96.0, 4.0, -68.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1485) (97.0, 4.0, -69.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1482) (97.0, 4.0, -68.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1484) (98.0, 4.0, -68.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1483) (98.0, 4.0, -69.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1319) (123.5, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1321) (122.5, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1322) (122.5, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1320) (121.5, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1317) (124.5, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1316) (123.5, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1323) (121.5, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1318) (124.5, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1512) (114.9, 12.0, -48.7)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1513) (114.9, 12.0, -47.7)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1514) (113.9, 12.0, -48.7)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1295) (136.8, 12.0, -53.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1296) (136.8, 12.0, -52.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1297) (135.8, 12.0, -53.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1298) (137.8, 12.0, -52.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1294) (135.8, 12.0, -52.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1299) (138.8, 12.0, -52.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1300) (140.0, 12.0, -58.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1302) (141.0, 12.0, -58.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1303) (140.0, 12.0, -59.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1301) (141.0, 12.0, -59.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1307) (146.3, 12.0, -53.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1304) (146.3, 12.0, -52.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1306) (147.3, 12.0, -52.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1305) (147.3, 12.0, -53.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1309) (144.8, 12.0, -62.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1310) (144.8, 12.0, -61.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1308) (143.8, 12.0, -61.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1311) (143.8, 12.0, -62.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1312) (133.3, 12.0, -65.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1315) (133.3, 12.0, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1313) (134.3, 12.0, -66.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1314) (134.3, 12.0, -65.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1327) (96.8, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1326) (97.8, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1325) (97.8, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1329) (99.8, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1328) (98.8, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1324) (96.8, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1331) (104.8, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1330) (103.8, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1335) (84.0, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1332) (84.0, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1333) (85.0, 12.0, -46.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1334) (85.0, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1369) (68.5, 12.0, -58.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1372) (68.5, 12.0, -59.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1371) (69.5, 12.0, -58.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1370) (69.5, 12.0, -59.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1375) (65.0, 12.0, -60.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1373) (64.0, 12.0, -60.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1374) (65.0, 12.0, -61.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1376) (64.0, 12.0, -61.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1348) (60.0, 12.0, -50.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1345) (60.0, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1346) (61.0, 12.0, -50.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1347) (61.0, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1343) (53.3, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1344) (54.3, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1341) (51.3, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1342) (52.3, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1340) (50.3, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1337) (49.3, 12.0, -50.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1338) (49.3, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1336) (48.3, 12.0, -49.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1339) (48.3, 12.0, -50.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1367) (51.5, 12.0, -62.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1368) (50.5, 12.0, -63.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1365) (50.5, 12.0, -62.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1366) (51.5, 12.0, -63.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1363) (37.3, 12.0, -58.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1361) (36.3, 12.0, -58.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1364) (36.3, 12.0, -59.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1362) (37.3, 12.0, -59.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1356) (33.3, 12.0, -54.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1353) (33.3, 12.0, -53.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1354) (34.3, 12.0, -54.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1355) (34.3, 12.0, -53.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1351) (33.3, 12.0, -51.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1350) (33.3, 12.0, -52.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1349) (32.3, 12.0, -51.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1352) (32.3, 12.0, -52.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1359) (31.0, 12.0, -44.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1358) (31.0, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1357) (30.0, 12.0, -44.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1360) (30.0, 12.0, -45.5)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1390) (42.3, 12.0, -34.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1387) (42.3, 12.0, -33.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1388) (43.3, 12.0, -34.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1389) (43.3, 12.0, -33.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1392) (40.0, 12.0, -26.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1394) (39.0, 12.0, -26.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1393) (40.0, 12.0, -25.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1391) (39.0, 12.0, -25.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1385) (31.8, 7.5, -29.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1383) (31.8, 7.5, -26.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1382) (31.8, 7.5, -27.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1384) (30.8, 7.5, -27.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1381) (30.8, 7.5, -26.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (1386) (31.8, 7.5, -28.3)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (425) (-85.0, -0.3, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (428) (-85.0, -0.5, -12.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (427) (-86.0, 0.0, -11.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (426) (-86.0, 0.0, -12.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (623) (70.5, -0.5, -92.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (620) (71.5, -0.5, -92.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (622) (70.5, -0.3, -91.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (621) (71.5, -0.3, -91.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (741) (76.8, -0.8, -98.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (742) (77.8, -0.5, -98.0)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (627) (67.0, -1.0, -83.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (624) (68.0, -1.0, -83.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (625) (68.0, -1.5, -82.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Front Grass swamp (626) (67.0, -1.0, -82.8)": TunicLocationData("Swamp Front", "Swamp Front"), + "Swamp - Swamp Mid Grass swamp (925) (34.5, 0.0, -7.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (922) (35.5, 0.0, -7.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (924) (34.5, 0.3, -6.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (923) (35.5, 0.3, -6.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (920) (42.3, -0.3, -7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (921) (42.3, -0.8, -8.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (918) (43.3, -1.0, -8.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (919) (43.3, -0.8, -7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (914) (45.3, -1.3, -7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (916) (44.3, -0.5, -6.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (917) (44.3, -1.0, -7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (915) (45.3, -1.0, -6.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (908) (47.8, -0.8, 6.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (909) (47.8, -1.0, 5.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (906) (48.8, -1.3, 5.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (907) (48.8, -1.3, 6.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (905) (51.5, -1.8, 13.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (902) (51.5, -0.5, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (903) (51.5, -1.0, 14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (900) (52.5, -1.0, 14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (904) (52.5, -1.8, 13.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (897) (54.5, -0.5, 16.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (896) (54.5, -0.8, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (898) (53.5, -0.3, 16.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (901) (52.5, -0.8, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (899) (53.5, -0.8, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (926) (39.0, 0.0, 10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (927) (39.0, 0.3, 11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (931) (38.0, 0.0, 13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (930) (38.0, 0.0, 12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (928) (38.0, 0.3, 11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (932) (37.0, 0.3, 13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (933) (37.0, 0.0, 12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (929) (38.0, 0.0, 10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (935) (39.8, 0.0, 25.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (934) (39.8, 0.0, 24.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (936) (38.8, 0.3, 25.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (937) (38.8, 0.0, 24.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (893) (63.5, 0.0, 12.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (895) (62.5, 0.0, 11.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (894) (62.5, 0.3, 12.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (889) (61.5, 0.0, 11.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (890) (60.5, 0.3, 11.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (891) (60.5, 0.0, 10.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (892) (63.5, 0.0, 11.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (888) (61.5, 0.0, 10.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (881) (60.5, 0.0, -4.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (880) (60.5, 0.0, -5.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (884) (61.5, 0.0, -3.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (887) (60.5, 0.0, -3.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (886) (60.5, 0.3, -2.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (885) (61.5, 0.0, -2.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (883) (59.5, -0.3, -5.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (882) (59.5, 0.0, -4.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (877) (67.0, 0.0, -12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (874) (68.0, 0.3, -11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (875) (68.0, 0.0, -12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (873) (69.0, 0.0, -11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (872) (69.0, 0.0, -12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (878) (66.0, 0.3, -12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (879) (66.0, -0.3, -13.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (876) (67.0, -0.3, -13.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (743) (82.5, 0.0, -3.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (738) (83.5, 0.0, -3.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (740) (82.5, 0.3, -2.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (739) (83.5, 0.0, -2.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (910) (77.5, 0.0, 1.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (911) (77.5, 0.0, 2.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (913) (76.5, 0.0, 1.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (912) (76.5, 0.3, 2.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (756) (76.0, -1.3, 6.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (754) (77.0, -1.0, 8.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (755) (77.0, -1.3, 7.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (757) (76.0, -1.3, 7.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (759) (75.0, -1.3, 6.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (758) (75.0, -1.3, 7.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (752) (78.0, -1.0, 7.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (753) (78.0, -1.3, 8.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (786) (95.8, 0.3, 15.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (785) (96.8, 0.0, 15.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (784) (96.8, 0.0, 14.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (787) (95.8, 0.0, 14.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (776) (100.8, 0.0, 14.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (777) (100.8, 0.0, 15.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (779) (99.8, 0.0, 14.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (778) (99.8, 0.3, 15.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (788) (97.3, 0.0, 19.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (789) (97.3, 0.0, 20.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (791) (96.3, 0.0, 19.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (790) (96.3, 0.3, 20.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (792) (98.3, 0.0, 22.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (796) (103.0, 0.0, 22.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (795) (103.0, 0.0, 21.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (798) (102.0, 0.0, 21.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (793) (98.3, 0.0, 23.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (794) (97.3, 0.3, 23.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (782) (101.8, 0.3, 16.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (781) (102.8, 0.0, 16.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (783) (101.8, 0.0, 15.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (780) (102.8, 0.0, 15.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (833) (108.5, 0.0, 20.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (830) (109.5, 0.0, 20.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (831) (109.5, 0.0, 21.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (832) (108.5, 0.3, 21.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (945) (112.3, 0.3, 12.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (946) (112.3, 0.0, 11.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (944) (113.3, 0.0, 12.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (943) (113.3, 0.0, 11.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (772) (114.3, 0.0, 9.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (771) (112.3, 0.0, 7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (770) (112.3, 0.3, 8.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (774) (113.3, 0.3, 10.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (775) (113.3, 0.0, 9.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (768) (113.3, 0.0, 7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (769) (113.3, 0.0, 8.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (773) (114.3, 0.0, 10.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (767) (104.5, 0.0, 3.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (766) (104.5, 0.3, 4.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (765) (105.5, 0.0, 4.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (764) (105.5, 0.0, 3.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (761) (103.5, 0.0, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (762) (102.5, 0.3, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (763) (102.5, 0.0, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (760) (103.5, 0.0, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (971) (104.8, 0.3, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (970) (105.8, 0.0, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (967) (106.8, 0.3, -9.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (963) (106.8, 0.3, -11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (968) (106.8, 0.0, -10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (961) (107.8, 0.0, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (964) (106.8, 0.0, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (969) (105.8, 0.0, -13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (972) (104.8, 0.0, -13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (965) (107.8, 0.0, -10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (962) (107.8, 0.0, -11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (966) (107.8, 0.0, -9.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (747) (88.3, 0.0, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (744) (89.3, 0.0, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (745) (89.3, 0.0, -11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (746) (88.3, 0.3, -11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (751) (94.5, 0.0, -10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (748) (95.5, 0.0, -10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (749) (95.5, 0.0, -9.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (750) (94.5, 0.3, -9.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (975) (118.5, 0.3, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (976) (118.5, 0.0, -13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (974) (119.5, 0.0, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (973) (119.5, 0.0, -13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (856) (120.8, -1.5, -1.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (857) (120.8, -1.5, -0.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (859) (119.8, -1.0, -1.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (858) (119.8, -0.8, -0.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (871) (126.0, -1.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (868) (127.0, -1.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (869) (127.0, -1.8, 1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (870) (126.0, -1.5, 1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (951) (132.3, -0.3, 11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (952) (132.3, -0.3, 12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (947) (130.3, -0.5, 11.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (953) (131.3, -0.3, 12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (954) (131.3, -0.5, 11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (852) (128.5, -1.0, 8.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (948) (130.3, -0.5, 12.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (949) (129.3, -0.5, 12.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (950) (129.3, -0.8, 11.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (853) (127.5, -1.0, 8.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (851) (128.5, -1.0, 7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (854) (127.5, -1.3, 7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (855) (126.5, -1.3, 7.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (988) (140.0, -1.3, 6.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (985) (141.0, -1.3, 6.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (986) (140.0, -1.0, 7.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (987) (141.0, -1.0, 7.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (862) (134.3, -1.0, -4.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (861) (135.3, -0.8, -4.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (865) (133.3, -1.5, -3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (864) (133.3, -1.5, -4.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (867) (132.3, -1.8, -4.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (866) (132.3, -1.8, -3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (860) (135.3, -0.8, -5.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (863) (134.3, -1.0, -5.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (982) (139.3, 0.3, -10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (984) (139.3, 0.0, -11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (983) (140.3, 0.0, -10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (979) (139.3, 0.0, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (980) (138.3, 0.0, -13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (978) (138.3, 0.3, -12.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (981) (140.3, 0.0, -11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (977) (139.3, 0.0, -13.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (960) (151.0, 0.0, -3.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (956) (152.0, 0.5, -3.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (955) (151.0, 0.0, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (959) (151.0, 0.3, -2.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (958) (150.0, 0.0, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (957) (150.0, 0.3, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1238) (160.3, 1.8, -12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1244) (159.3, 0.3, -14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1245) (160.3, 0.3, -14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1243) (160.3, 0.8, -13.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1237) (161.3, 2.3, -11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1236) (160.3, 2.5, -11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1235) (162.0, 3.8, -5.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1239) (162.0, 3.8, -4.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1201) (162.0, 3.8, -0.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1222) (162.0, 3.8, 0.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1223) (161.0, 3.8, -0.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1221) (161.0, 4.0, 0.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1227) (156.5, 3.8, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1224) (157.5, 3.8, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1228) (158.5, 3.8, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1226) (157.5, 3.8, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1225) (156.5, 4.0, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1232) (148.8, 3.8, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1233) (148.8, 3.8, 14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1231) (149.8, 3.8, 14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1229) (149.8, 3.8, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1230) (148.8, 4.0, 16.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (837) (145.0, 0.0, 17.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (836) (145.0, 0.3, 18.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (844) (145.0, 0.0, 20.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (843) (145.0, 0.0, 19.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (845) (144.0, 0.3, 20.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (846) (144.0, 0.0, 19.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1234) (145.3, 0.0, 15.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (847) (145.3, 0.0, 13.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (848) (145.3, 0.0, 14.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (849) (144.3, 0.3, 14.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (850) (144.3, 0.0, 13.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (834) (146.0, 0.0, 17.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (835) (146.0, 0.0, 18.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (842) (142.3, 1.0, 23.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (841) (141.3, 1.0, 24.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (838) (142.3, 1.3, 24.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (839) (142.3, 1.8, 25.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (840) (141.3, 1.8, 25.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (828) (132.5, 1.5, 35.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (829) (132.5, 1.0, 34.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (826) (133.5, 1.3, 34.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (827) (133.5, 1.3, 35.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (822) (131.5, -0.3, 44.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (818) (131.5, 0.0, 43.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (823) (130.5, 0.3, 44.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (824) (130.5, 0.0, 43.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (825) (129.5, 0.3, 44.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (819) (126.3, 0.0, 41.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (821) (126.3, 0.0, 42.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (815) (124.3, 0.0, 41.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (820) (125.3, 0.3, 41.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (814) (124.3, 0.0, 40.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (817) (123.3, -0.3, 40.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (816) (123.3, 0.0, 41.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (812) (120.5, -0.3, 33.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (810) (121.5, -0.3, 32.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (811) (121.5, -0.3, 33.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (808) (119.5, 0.0, 31.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (813) (120.5, -0.5, 32.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (807) (120.5, 0.0, 31.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (806) (120.5, 0.0, 30.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (809) (119.5, -0.3, 30.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (804) (120.8, 0.3, 26.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (805) (120.8, 0.0, 25.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (802) (121.8, 0.0, 25.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (803) (121.8, 0.0, 26.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (800) (122.8, 0.3, 25.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (801) (122.8, 0.0, 24.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (797) (123.8, 0.0, 24.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (799) (123.8, 0.0, 25.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1379) (88.3, -0.5, 43.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1458) (88.3, -0.8, 44.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1377) (89.3, -0.8, 42.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1378) (89.3, -0.8, 43.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1459) (88.3, -0.8, 45.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1462) (90.8, 0.0, 55.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1463) (90.8, -0.3, 54.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1460) (91.8, -0.3, 54.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1461) (91.8, -0.3, 55.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1466) (88.3, -0.5, 71.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1467) (88.3, -0.8, 70.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1465) (89.3, -0.5, 71.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1464) (89.3, -0.5, 70.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1468) (88.3, -0.3, 82.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1471) (87.3, -0.3, 82.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1469) (88.3, -0.3, 83.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1470) (87.3, 0.0, 83.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1476) (86.5, -0.3, 88.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1477) (86.5, -0.3, 89.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1472) (86.5, -0.3, 90.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1474) (85.5, 0.0, 91.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1475) (85.5, -0.3, 90.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1261) (156.8, 4.0, -60.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1264) (156.8, 4.0, -61.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1262) (157.8, 4.0, -61.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1208) (160.8, 7.5, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1207) (160.8, 7.5, 16.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1216) (158.8, 7.5, 18.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1203) (163.8, 7.5, 14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1202) (162.8, 7.5, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1204) (162.8, 7.5, 14.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1206) (161.8, 7.5, 15.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1205) (161.8, 7.5, 16.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1210) (161.8, 7.5, 17.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1209) (161.8, 7.5, 18.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1212) (160.8, 7.5, 17.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1211) (160.8, 7.5, 18.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1214) (159.8, 7.5, 18.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1213) (159.8, 7.5, 19.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1215) (158.8, 7.5, 19.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1200) (163.0, 7.5, 9.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1198) (163.0, 7.5, 10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1199) (164.0, 7.5, 9.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1197) (164.0, 7.5, 10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1219) (155.3, 7.5, 11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1217) (156.3, 7.5, 11.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1218) (156.3, 7.5, 10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1220) (155.3, 7.5, 10.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1240) (165.8, 7.5, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1241) (165.8, 7.5, 1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1270) (157.0, 15.8, -43.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1272) (157.0, 15.8, -42.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1273) (158.0, 15.8, -42.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1269) (157.0, 15.8, -44.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1268) (156.0, 15.8, -43.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1271) (156.0, 15.8, -44.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1248) (168.5, 15.8, -40.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1246) (169.5, 15.8, -40.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1247) (169.5, 15.8, -39.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1242) (168.5, 15.8, -39.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1249) (168.5, 15.8, -50.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1252) (168.5, 15.8, -51.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1251) (169.5, 15.8, -50.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1250) (169.5, 15.8, -51.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1255) (172.3, 15.8, -54.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1253) (171.3, 15.8, -54.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1256) (171.3, 15.8, -55.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1254) (172.3, 15.8, -55.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1257) (166.8, 15.8, -58.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1260) (166.8, 15.8, -59.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1259) (167.8, 15.8, -58.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1258) (167.8, 15.8, -59.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1266) (158.5, 15.8, -57.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1265) (158.5, 15.8, -58.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1263) (157.5, 15.8, -57.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1267) (157.5, 15.8, -58.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1285) (140.5, 15.8, -45.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1282) (140.5, 15.8, -44.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1283) (141.5, 15.8, -45.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1284) (141.5, 15.8, -44.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1288) (132.5, 15.8, -48.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1293) (129.5, 15.8, -48.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1290) (129.5, 15.8, -47.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1289) (131.5, 15.8, -49.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1286) (131.5, 15.8, -48.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1291) (130.5, 15.8, -48.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1292) (130.5, 15.8, -47.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1287) (132.5, 15.8, -49.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1281) (169.5, 15.8, -28.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1275) (168.3, 15.8, -26.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1279) (170.5, 15.8, -28.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1280) (170.5, 15.8, -27.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1278) (169.5, 15.8, -27.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1276) (168.3, 15.8, -25.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1277) (167.3, 15.8, -26.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1274) (167.3, 15.8, -25.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1167) (170.0, 15.8, -18.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1169) (170.0, 15.8, -19.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1166) (171.0, 15.8, -18.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1168) (171.0, 15.8, -19.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1163) (171.0, 15.8, -20.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1165) (171.0, 15.8, -21.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1164) (172.0, 15.8, -21.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1162) (172.0, 15.8, -20.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1148) (183.8, 15.8, -18.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1161) (180.0, 15.8, -14.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1157) (181.0, 15.8, -13.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1160) (181.0, 15.8, -14.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1159) (180.0, 15.8, -13.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1146) (183.8, 15.8, -17.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1152) (184.8, 15.8, -20.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1150) (184.8, 15.8, -19.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1145) (184.8, 15.8, -17.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1147) (184.8, 15.8, -18.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1151) (185.8, 15.8, -20.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1149) (185.8, 15.8, -19.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1156) (187.8, 15.8, -24.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1154) (188.8, 15.8, -24.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1158) (187.8, 15.8, -25.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1155) (192.8, 15.8, -15.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1153) (192.8, 15.8, -14.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1093) (192.0, 15.8, -9.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1098) (193.0, 15.8, -8.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1099) (193.0, 15.8, -9.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1094) (193.0, 15.8, -9.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1102) (193.0, 15.8, -5.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1101) (193.0, 15.8, -4.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1096) (192.0, 15.8, -10.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1095) (193.0, 15.8, -10.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1097) (193.0, 15.8, -2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1018) (193.0, 15.8, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1100) (193.0, 15.8, -3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1019) (192.0, 15.8, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1017) (193.0, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1022) (193.0, 15.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1027) (192.0, 15.8, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1023) (192.0, 15.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1020) (192.0, 15.8, 1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1016) (192.0, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1026) (193.0, 15.8, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1021) (193.0, 15.8, 1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1133) (190.0, 15.8, 1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1135) (190.0, 15.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1136) (189.0, 15.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1134) (189.0, 15.8, 1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1137) (185.3, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1139) (185.3, 15.8, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1028) (191.0, 15.8, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1029) (191.0, 15.8, 2.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1025) (193.0, 15.8, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1024) (192.0, 15.8, 3.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1031) (193.0, 15.8, 5.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1032) (193.0, 15.8, 4.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1138) (184.3, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1140) (184.3, 15.8, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1131) (173.0, 15.8, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1127) (171.0, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1130) (172.0, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1132) (172.0, 15.8, -1.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1129) (173.0, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1142) (176.8, 15.8, -7.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1141) (177.8, 15.8, -7.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1143) (177.8, 15.8, -8.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1144) (176.8, 15.8, -8.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1128) (170.0, 15.8, -0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1125) (171.0, 15.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1126) (170.0, 15.8, 0.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1121) (177.8, 15.8, 5.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1123) (177.8, 15.8, 4.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1122) (176.8, 15.8, 5.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1124) (176.8, 15.8, 4.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1010) (173.8, 15.8, 9.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1011) (172.8, 15.8, 9.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1013) (175.8, 15.8, 11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1014) (175.8, 15.8, 10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1012) (174.8, 15.8, 11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1015) (174.8, 15.8, 10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1008) (172.8, 15.8, 10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1009) (173.8, 15.8, 10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1001) (168.3, 15.8, 15.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1003) (169.3, 15.8, 15.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1006) (168.3, 15.8, 14.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (999) (168.3, 15.8, 17.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1000) (168.3, 15.8, 16.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1004) (169.3, 15.8, 16.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1005) (169.3, 15.8, 17.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1007) (167.3, 15.8, 14.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1002) (167.3, 15.8, 15.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1188) (164.3, 15.8, 21.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1186) (163.3, 15.8, 22.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1189) (163.3, 15.8, 21.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1110) (180.8, 15.8, 13.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1109) (180.8, 15.8, 14.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1107) (181.8, 15.8, 14.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1108) (181.8, 15.8, 13.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1105) (181.3, 15.8, 11.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1103) (182.3, 15.8, 11.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1112) (182.8, 15.8, 15.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1111) (182.8, 15.8, 16.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1114) (181.8, 15.8, 15.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1113) (181.8, 15.8, 16.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1106) (181.3, 15.8, 10.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1104) (182.3, 15.8, 10.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1115) (182.3, 15.8, 9.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1116) (181.3, 15.8, 9.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1117) (187.8, 15.8, 10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1118) (186.8, 15.8, 10.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1120) (186.8, 15.8, 9.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1119) (187.8, 15.8, 9.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1036) (192.0, 15.8, 13.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1039) (192.0, 15.8, 12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1042) (189.3, 15.8, 16.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1043) (188.3, 15.8, 16.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1040) (193.0, 15.8, 11.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1038) (193.0, 15.8, 12.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1037) (193.0, 15.8, 13.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1034) (193.0, 15.8, 14.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1033) (193.0, 15.8, 15.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1030) (192.0, 15.8, 15.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1035) (192.0, 15.8, 14.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1047) (187.0, 15.8, 18.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1048) (186.0, 15.8, 18.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1041) (188.3, 15.8, 17.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1045) (187.0, 15.8, 19.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1046) (186.0, 15.8, 19.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1044) (186.0, 15.8, 20.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Bush (1) (182.3, 16.0, 33.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Bush (184.3, 16.0, 33.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1173) (184.8, 15.8, 30.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1170) (184.8, 15.8, 31.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1171) (185.8, 15.8, 31.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1172) (185.8, 15.8, 30.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1088) (188.8, 15.8, 33.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1078) (187.8, 15.8, 32.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1077) (186.8, 15.8, 32.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1075) (186.8, 15.8, 33.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1074) (186.8, 15.8, 34.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1080) (186.8, 15.8, 31.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1076) (185.8, 15.8, 33.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1073) (185.8, 15.8, 34.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1072) (185.8, 15.8, 35.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1069) (185.8, 15.8, 36.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1059) (184.8, 15.8, 37.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1051) (184.8, 15.8, 35.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1050) (184.8, 15.8, 36.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1057) (183.8, 15.8, 38.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1052) (183.8, 15.8, 35.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1060) (183.8, 15.8, 37.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1049) (183.8, 15.8, 36.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1055) (182.8, 15.8, 35.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1054) (182.8, 15.8, 36.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1053) (181.8, 15.8, 36.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1056) (181.8, 15.8, 35.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1176) (179.5, 15.8, 36.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1071) (186.8, 15.8, 35.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1070) (186.8, 15.8, 36.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1092) (187.8, 15.8, 35.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1085) (188.8, 15.8, 34.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1086) (189.8, 15.8, 34.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1090) (188.8, 15.8, 36.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1091) (188.8, 15.8, 35.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1089) (187.8, 15.8, 36.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1067) (186.8, 15.8, 39.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1066) (186.8, 15.8, 40.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1068) (185.8, 15.8, 39.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1062) (184.8, 15.8, 40.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1058) (184.8, 15.8, 38.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1063) (184.8, 15.8, 39.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1064) (183.8, 15.8, 39.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1061) (183.8, 15.8, 40.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1065) (185.8, 15.8, 40.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1175) (179.5, 15.8, 37.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1177) (178.5, 15.8, 36.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1174) (178.5, 15.8, 37.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Bush (2) (178.3, 16.0, 39.0)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1179) (176.8, 15.8, 40.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1180) (176.8, 15.8, 39.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1178) (175.8, 15.8, 40.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1181) (175.8, 15.8, 39.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1192) (169.0, 15.8, 38.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1191) (170.0, 15.8, 38.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1190) (170.0, 15.8, 39.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1187) (169.0, 15.8, 39.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1183) (165.3, 15.8, 33.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1182) (164.3, 15.8, 33.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1185) (164.3, 15.8, 32.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1184) (165.3, 15.8, 32.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1510) (165.0, 16.5, 42.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1509) (166.0, 16.0, 42.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1508) (166.0, 16.0, 43.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1507) (165.0, 16.5, 43.5)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1196) (153.8, 15.8, 40.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1195) (154.8, 15.8, 40.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1194) (154.8, 15.8, 41.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1193) (153.8, 15.8, 41.8)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1505) (148.0, 15.8, 31.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1504) (148.0, 15.8, 30.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1503) (147.0, 15.8, 31.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Swamp Mid Grass swamp (1506) (147.0, 15.8, 30.3)": TunicLocationData("Swamp Mid", "Swamp Mid"), + "Swamp - Back of Swamp Grass swamp (1494) (83.8, -0.3, 129.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1495) (83.8, -0.3, 130.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1496) (82.8, 0.0, 130.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1497) (82.8, -0.3, 129.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1501) (82.8, -0.3, 131.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1498) (83.8, -0.3, 131.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1499) (83.8, -0.3, 132.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1500) (83.0, -1.0, 141.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Grass swamp (1502) (83.0, -1.0, 142.5)": TunicLocationData("Back of Swamp", "Back of Swamp"), + "Swamp - Back of Swamp Laurels Area Grass swamp (991) (34.5, 8.3, 31.8)": TunicLocationData( + "Back of Swamp Laurels Area", "Back of Swamp Laurels Area"), + "Swamp - Back of Swamp Laurels Area Grass swamp (992) (34.5, 8.0, 30.8)": TunicLocationData( + "Back of Swamp Laurels Area", "Back of Swamp Laurels Area"), + "Swamp - Back of Swamp Laurels Area Grass swamp (989) (35.5, 8.0, 30.8)": TunicLocationData( + "Back of Swamp Laurels Area", "Back of Swamp Laurels Area"), + "Swamp - Back of Swamp Laurels Area Grass swamp (990) (35.5, 8.0, 31.8)": TunicLocationData( + "Back of Swamp Laurels Area", "Back of Swamp Laurels Area"), + "Swamp - Back of Swamp Laurels Area Grass swamp (995) (32.5, 8.3, 31.8)": TunicLocationData( + "Back of Swamp Laurels Area", "Back of Swamp Laurels Area"), + "Swamp - Back of Swamp Laurels Area Grass swamp (994) (33.5, 8.0, 31.8)": TunicLocationData( + "Back of Swamp Laurels Area", "Back of Swamp Laurels Area"), +} + +excluded_grass_locations = { + "Overworld - Overworld Bush (7) (-39.0, 40.0, -41.0)", + "Overworld - Overworld Bush (2) (-41.0, 40.0, -41.0)", + "Overworld - Overworld Bush (16) (53.0, 12.0, -151.0)", + "Overworld - Overworld Bush (9) (-19.0, 28.0, -103.0)", + "Overworld - Overworld Bush (23) (-19.0, 28.0, -105.0)", + "Overworld - Overworld Bush (26) (-19.0, 28.0, -107.0)", + "Overworld - Overworld Bush (47) (91.0, 12.0, -155.0)", + "Overworld - Overworld Bush (42) (91.0, 12.0, -157.0)", + "Overworld - East Overworld Bush (58) (58.0, 44.0, -109.0)", + "Overworld - East Overworld Bush (62) (66.5, 44.0, -111.0)", + "Overworld - East Overworld Bush (64) (56.0, 44.0, -107.0)", +} + +grass_location_name_to_id: Dict[str, int] = {name: location_base_id + 302 + index for index, name in enumerate(grass_location_table)} + +grass_location_name_groups: Dict[str, Set[str]] = {} +for loc_name, loc_data in grass_location_table.items(): + area_name = loc_name.split(" - ", 1)[0] + # adding it to the normal location group and a grass-only one + grass_location_name_groups.setdefault(area_name, set()).add(loc_name) + grass_location_name_groups.setdefault(area_name + " Grass", set()).add(loc_name) + + +def can_break_grass(state: CollectionState, world: "TunicWorld") -> bool: + player = world.player + # no gun or wand because they're extremely tedious + return (has_sword(state, player) + or (has_melee(state, player) and state.has("Glass Cannon", player))) + + +def set_grass_location_rules(world: "TunicWorld") -> None: + player = world.player + + if not world.options.start_with_sword: + for location in grass_location_table.keys(): + set_rule(world.get_location(location), + lambda state: can_break_grass(state, world)) + + set_rule(world.get_location("Fortress Courtyard - Fortress Courtyard Upper Grass (1) (72.0, 8.0, -29.0)"), + lambda state: state.has("Magic Wand", player)) + + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (325) (-111.8, 1.3, 2.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (323) (-111.8, 1.3, 1.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (316) (-110.5, 1.3, 3.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (319) (-111.5, 1.3, 4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (317) (-111.5, 1.3, 3.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (318) (-110.5, 1.3, 4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (321) (-112.3, 1.3, 4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (320) (-112.3, 1.3, 3.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (326) (-112.8, 1.3, 2.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (327) (-113.5, 1.3, 2.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (324) (-112.8, 1.3, 1.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (322) (-113.5, 1.3, 1.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (328) (-112.0, 0.8, -2.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (329) (-112.0, 0.5, -3.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (333) (-111.3, 0.8, -2.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (331) (-111.3, 0.5, -3.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (330) (-110.3, 0.5, -3.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (332) (-110.3, 0.8, -2.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (334) (-111.0, 0.3, -4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (337) (-110.3, 0.3, -4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (354) (-113.0, 0.3, -4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (353) (-112.0, 0.3, -4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (336) (-109.3, 0.3, -4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (338) (-109.3, -0.3, -5.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (339) (-110.3, -0.3, -5.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (335) (-111.0, -0.3, -5.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (350) (-112.0, -0.3, -5.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (349) (-113.8, 0.3, -4.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (351) (-113.0, -0.3, -5.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (352) (-113.8, -0.3, -5.0)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (314) (-112.3, 0.8, 6.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (315) (-112.3, 0.8, 7.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (313) (-111.5, 0.8, 6.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (311) (-111.5, 0.8, 7.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (310) (-110.5, 0.8, 7.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (306) (-110.5, 0.8, 8.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (312) (-110.5, 0.8, 6.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (307) (-109.5, 0.8, 8.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (308) (-111.5, 0.8, 8.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (300) (-107.5, 0.0, 10.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (301) (-107.5, 0.3, 9.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (304) (-108.3, 0.0, 10.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (299) (-108.5, 0.0, 10.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (303) (-110.5, 0.3, 9.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (302) (-109.5, 0.3, 9.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (305) (-109.5, 0.0, 10.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (298) (-108.5, 0.3, 9.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (341) (-113.5, 0.8, 10.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (344) (-113.5, 0.5, 11.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (346) (-113.5, 0.8, 9.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (309) (-111.5, 0.5, 9.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (345) (-112.5, 0.8, 9.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (342) (-112.5, 0.8, 8.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (340) (-112.5, 0.8, 10.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (347) (-114.3, 0.8, 8.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (348) (-114.3, 0.8, 9.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (343) (-113.5, 0.8, 8.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (297) (-99.0, 0.8, 7.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass beach (296) (-98.0, 0.8, 7.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (191) (-89.5, 6.5, 53.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (190) (-89.5, 6.5, 54.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (189) (-88.5, 6.5, 54.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (188) (-88.5, 6.5, 53.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (197) (-87.0, 13.0, 75.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (194) (-87.0, 13.0, 74.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (184) (-86.0, 13.0, 73.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (183) (-86.0, 13.0, 74.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (181) (-86.0, 13.0, 75.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (185) (-84.7, 13.0, 73.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (182) (-83.0, 13.0, 72.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (199) (-83.0, 13.0, 70.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (201) (-84.0, 13.0, 70.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (135) (-83.5, 13.0, 58.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (128) (-82.5, 13.0, 57.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (130) (-82.5, 13.0, 58.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (147) (-86.0, 13.0, 54.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (132) (-82.5, 13.0, 60.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (134) (-83.5, 13.0, 59.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (131) (-82.5, 13.0, 59.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (136) (-78.5, 13.0, 56.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (139) (-79.5, 13.0, 55.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (133) (-79.5, 13.0, 56.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (138) (-80.5, 13.0, 55.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (137) (-80.5, 13.0, 56.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (143) (-85.0, 13.0, 53.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (142) (-86.0, 13.0, 53.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (145) (-87.0, 13.0, 53.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (146) (-87.0, 13.0, 54.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (140) (-85.0, 13.0, 52.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (141) (-86.0, 13.0, 52.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (144) (-84.0, 13.0, 52.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (192) (-70.5, 13.0, 56.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (186) (-69.5, 13.0, 56.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (187) (-69.5, 13.0, 55.8)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (123) (-82.5, 13.0, 44.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (126) (-82.5, 13.0, 45.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (121) (-83.5, 13.0, 45.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (124) (-83.5, 13.0, 44.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (125) (-83.5, 13.0, 43.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (151) (-82.5, 13.0, 27.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (152) (-82.5, 13.0, 26.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (150) (-81.5, 13.0, 27.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (148) (-81.5, 13.0, 25.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (149) (-81.5, 13.0, 26.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (154) (-79.0, 13.0, 23.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (153) (-78.0, 13.0, 23.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (161) (-68.0, 13.0, 26.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (162) (-68.0, 13.0, 27.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (165) (-69.0, 13.0, 27.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (164) (-69.0, 13.0, 28.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (163) (-68.0, 13.0, 28.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (166) (-68.0, 13.0, 29.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (167) (-63.0, 13.0, 24.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (168) (-62.0, 13.0, 24.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (170) (-61.0, 13.0, 25.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (169) (-62.0, 13.0, 25.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (172) (-62.0, 13.0, 26.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (178) (-61.0, 13.0, 43.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (175) (-60.0, 13.0, 43.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (177) (-61.0, 13.0, 44.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (174) (-59.0, 13.0, 42.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (173) (-59.0, 13.0, 43.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (171) (-59.0, 13.0, 44.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (176) (-60.0, 13.0, 44.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (159) (-83.5, 8.0, 23.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (160) (-83.5, 8.0, 24.5)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (158) (-83.5, 8.0, 22.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (155) (-82.5, 8.0, 24.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (157) (-82.5, 8.0, 22.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Ruined Atoll - Ruined Atoll Grass (156) (-82.5, 8.0, 23.0)"), lambda state: state.has_any(("Hero's Laurels", "Magic Orb"), player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (9) (179.8, 61.9, -67.1)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (8) (178.6, 61.9, -67.1)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (7) (204.4, 58.1, -94.1)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (5) (205.5, 58.1, -94.1)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (6) (205.5, 58.1, -93.0)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (2) (205.5, 54.0, -77.0)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (205.5, 54.0, -76.0)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (1) (204.5, 54.0, -76.0)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (4) (201.4, 54.3, -71.3)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("Frog Stairway - Frog Stairs Lower Grass (3) (200.4, 54.3, -71.3)"), lambda state: state.has("Magic Orb", player)) + add_rule(world.get_location("West Garden - West Garden Grass (207) (-310.8, 1.3, 164.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("West Garden - West Garden Grass (210) (-310.8, 1.3, 165.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("West Garden - West Garden Grass (209) (-312.0, 1.3, 165.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("West Garden - West Garden Grass (208) (-312.0, 1.3, 164.5)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("West Garden - West Garden Grass (174) (-243.9, 0.5, 52.1)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("West Garden - West Garden Grass (262) (-244.8, 0.5, 51.3)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("West Garden - West Garden Grass (263) (-244.8, 0.5, 52.3)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Swamp - Back of Swamp Laurels Area Grass swamp (991) (34.5, 8.3, 31.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Swamp - Back of Swamp Laurels Area Grass swamp (992) (34.5, 8.0, 30.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Swamp - Back of Swamp Laurels Area Grass swamp (989) (35.5, 8.0, 30.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Swamp - Back of Swamp Laurels Area Grass swamp (990) (35.5, 8.0, 31.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Swamp - Back of Swamp Laurels Area Grass swamp (995) (32.5, 8.3, 31.8)"), lambda state: state.has("Hero's Laurels", player)) + add_rule(world.get_location("Swamp - Back of Swamp Laurels Area Grass swamp (994) (33.5, 8.0, 31.8)"), lambda state: state.has("Hero's Laurels", player)) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index f30c1d5d24..20696eb511 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -48,6 +48,7 @@ item_table: Dict[str, TunicItemData] = { "Gun": TunicItemData(IC.progression | IC.useful, 1, 30, "Weapons"), "Shield": TunicItemData(IC.useful, 1, 31, combat_ic=IC.progression | IC.useful), "Dath Stone": TunicItemData(IC.useful, 1, 32), + "Torch": TunicItemData(IC.useful, 0, 156), "Hourglass": TunicItemData(IC.useful, 1, 33), "Old House Key": TunicItemData(IC.progression, 1, 34, "Keys"), "Key": TunicItemData(IC.progression, 2, 35, "Keys"), @@ -166,6 +167,7 @@ item_table: Dict[str, TunicItemData] = { "Ladders in Library": TunicItemData(IC.progression, 0, 148, "Ladders"), "Ladders in Lower Quarry": TunicItemData(IC.progression, 0, 149, "Ladders"), "Ladders in Swamp": TunicItemData(IC.progression, 0, 150, "Ladders"), + "Grass": TunicItemData(IC.filler, 0, 151), } # items to be replaced by fool traps @@ -210,11 +212,11 @@ slot_data_item_names = [ combat_items: List[str] = [name for name, data in item_table.items() if data.combat_ic and IC.progression in data.combat_ic] -combat_items.extend(["Stick", "Sword", "Sword Upgrade", "Magic Wand", "Hero's Laurels"]) +combat_items.extend(["Stick", "Sword", "Sword Upgrade", "Magic Wand", "Hero's Laurels", "Gun"]) item_name_to_id: Dict[str, int] = {name: item_base_id + data.item_id_offset for name, data in item_table.items()} -filler_items: List[str] = [name for name, data in item_table.items() if data.classification == IC.filler] +filler_items: List[str] = [name for name, data in item_table.items() if data.classification == IC.filler and name != "Grass"] def get_item_group(item_name: str) -> str: diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index c44852e8aa..d3c23406ed 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -1,4 +1,5 @@ -from typing import Dict, NamedTuple, Set, Optional +from typing import Dict, NamedTuple, Set, Optional, List +from .grass import grass_location_table class TunicLocationData(NamedTuple): @@ -205,7 +206,7 @@ location_table: Dict[str, TunicLocationData] = { "Fountain Cross Door - Page Pickup": TunicLocationData("Overworld Holy Cross", "Fountain Cross Room", location_group="Holy Cross"), "Secret Gathering Place - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Secret Gathering Place", location_group="Holy Cross"), "Top of the Mountain - Page At The Peak": TunicLocationData("Overworld Holy Cross", "Top of the Mountain", location_group="Holy Cross"), - "Monastery - Monastery Chest": TunicLocationData("Monastery", "Monastery Back"), + "Monastery - Monastery Chest": TunicLocationData("Monastery Back", "Monastery Back"), "Quarry - [Back Entrance] Bushes Holy Cross": TunicLocationData("Quarry Back", "Quarry Back", location_group="Holy Cross"), "Quarry - [Back Entrance] Chest": TunicLocationData("Quarry Back", "Quarry Back"), "Quarry - [Central] Near Shortcut Ladder": TunicLocationData("Quarry Back", "Quarry Back"), @@ -219,12 +220,12 @@ location_table: Dict[str, TunicLocationData] = { "Quarry - [Central] Obscured Below Entry Walkway": TunicLocationData("Quarry Back", "Quarry Back"), "Quarry - [Central] Top Floor Overhang": TunicLocationData("Quarry", "Quarry"), "Quarry - [East] Near Bridge": TunicLocationData("Quarry", "Quarry"), - "Quarry - [Central] Above Ladder": TunicLocationData("Quarry", "Quarry Monastery Entry"), + "Quarry - [Central] Above Ladder": TunicLocationData("Monastery", "Quarry Monastery Entry"), "Quarry - [Central] Obscured Behind Staircase": TunicLocationData("Quarry", "Quarry"), - "Quarry - [Central] Above Ladder Dash Chest": TunicLocationData("Quarry", "Quarry Monastery Entry"), + "Quarry - [Central] Above Ladder Dash Chest": TunicLocationData("Monastery", "Quarry Monastery Entry"), "Quarry - [West] Upper Area Bombable Wall": TunicLocationData("Quarry Back", "Quarry Back"), "Quarry - [East] Bombable Wall": TunicLocationData("Quarry", "Quarry"), - "Hero's Grave - Ash Relic": TunicLocationData("Monastery", "Hero Relic - Quarry"), + "Hero's Grave - Ash Relic": TunicLocationData("Monastery Back", "Hero Relic - Quarry"), "Quarry - [West] Shooting Range Secret Path": TunicLocationData("Lower Quarry", "Lower Quarry"), "Quarry - [West] Near Shooting Range": TunicLocationData("Lower Quarry", "Lower Quarry"), "Quarry - [West] Below Shooting Range": TunicLocationData("Lower Quarry", "Lower Quarry"), @@ -320,7 +321,27 @@ hexagon_locations: Dict[str, str] = { "Blue Questagon": "Rooted Ziggurat Lower - Hexagon Blue", } -location_name_to_id: Dict[str, int] = {name: location_base_id + index for index, name in enumerate(location_table)} +sphere_one: List[str] = [ + "Overworld - [Central] Chest Across From Well", + "Overworld - [Northwest] Chest Near Quarry Gate", + "Overworld - [Northwest] Shadowy Corner Chest", + "Overworld - [Southwest] Chest Guarded By Turret", + "Overworld - [Southwest] South Chest Near Guard", + "Overworld - [Southwest] Obscured in Tunnel to Beach", + "Overworld - [Northwest] Chest Near Turret", + "Overworld - [Northwest] Page By Well", + "Overworld - [West] Chest Behind Moss Wall", + "Overworld - [Southwest] Key Pickup", + "Overworld - [West] Key Pickup", + "Overworld - [West] Obscured Behind Windmill", + "Overworld - [West] Obscured Near Well", + "Overworld - [West] Page On Teleporter" +] + +standard_location_name_to_id: Dict[str, int] = {name: location_base_id + index for index, name in enumerate(location_table)} + +all_locations = location_table.copy() +all_locations.update(grass_location_table) location_name_groups: Dict[str, Set[str]] = {} for loc_name, loc_data in location_table.items(): diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index 24247a6cfd..d2ea828037 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Dict, Any from Options import (DefaultOnToggle, Toggle, StartInventoryPool, Choice, Range, TextChoice, PlandoConnections, - PerGameCommonOptions, OptionGroup, Visibility) + PerGameCommonOptions, OptionGroup, Visibility, NamedRange) from .er_data import portal_mapping @@ -29,7 +29,7 @@ class KeysBehindBosses(Toggle): display_name = "Keys Behind Bosses" -class AbilityShuffling(Toggle): +class AbilityShuffling(DefaultOnToggle): """ Locks the usage of Prayer, Holy Cross*, and the Icebolt combo until the relevant pages of the manual have been found. If playing Hexagon Quest, abilities are instead randomly unlocked after obtaining 25%, 50%, and 75% of the required Hexagon goal amount. @@ -154,6 +154,33 @@ class ShuffleLadders(Toggle): display_name = "Shuffle Ladders" +class GrassRandomizer(Toggle): + """ + Turns over 6,000 blades of grass and bushes in the game into checks. + """ + internal_name = "grass_randomizer" + display_name = "Grass Randomizer" + + +class LocalFill(NamedRange): + """ + Choose the percentage of your filler/trap items that will be kept local or distributed to other TUNIC players with this option enabled. + If you have Grass Randomizer enabled, this option must be set to 95% or higher to avoid flooding the item pool. The host can remove this restriction by turning off the limit_grass_rando setting in host.yaml. + This option defaults to 95% if you have Grass Randomizer enabled, and to 0% otherwise. + This option ignores items placed in your local_items or non_local_items. + This option does nothing in single player games. + """ + internal_name = "local_fill" + display_name = "Local Fill Percent" + range_start = 0 + range_end = 98 + special_range_names = { + "default": -1 + } + default = -1 + visibility = Visibility.template | Visibility.complex_ui | Visibility.spoiler + + class TunicPlandoConnections(PlandoConnections): """ Generic connection plando. Format is: @@ -263,18 +290,25 @@ class LogicRules(Choice): @dataclass class TunicOptions(PerGameCommonOptions): start_inventory_from_pool: StartInventoryPool + sword_progression: SwordProgression start_with_sword: StartWithSword keys_behind_bosses: KeysBehindBosses ability_shuffling: AbilityShuffling - shuffle_ladders: ShuffleLadders - entrance_rando: EntranceRando - fixed_shop: FixedShop fool_traps: FoolTraps + laurels_location: LaurelsLocation + hexagon_quest: HexagonQuest hexagon_goal: HexagonGoal extra_hexagon_percentage: ExtraHexagonPercentage - laurels_location: LaurelsLocation + + shuffle_ladders: ShuffleLadders + grass_randomizer: GrassRandomizer + local_fill: LocalFill + + entrance_rando: EntranceRando + fixed_shop: FixedShop + combat_logic: CombatLogic lanternless: Lanternless maskless: Maskless @@ -282,10 +316,11 @@ class TunicOptions(PerGameCommonOptions): ice_grappling: IceGrappling ladder_storage: LadderStorage ladder_storage_without_items: LadderStorageWithoutItems + plando_connections: TunicPlandoConnections logic_rules: LogicRules - + tunic_option_groups = [ OptionGroup("Logic Options", [ diff --git a/worlds/tunic/regions.py b/worlds/tunic/regions.py index 93ec5640e0..f21af11ee4 100644 --- a/worlds/tunic/regions.py +++ b/worlds/tunic/regions.py @@ -1,26 +1,25 @@ -from typing import Dict, Set - -tunic_regions: Dict[str, Set[str]] = { - "Menu": {"Overworld"}, - "Overworld": {"Overworld Holy Cross", "East Forest", "Dark Tomb", "Beneath the Well", "West Garden", +tunic_regions: dict[str, tuple[str]] = { + "Menu": ("Overworld",), + "Overworld": ("Overworld Holy Cross", "East Forest", "Dark Tomb", "Beneath the Well", "West Garden", "Ruined Atoll", "Eastern Vault Fortress", "Beneath the Vault", "Quarry Back", "Quarry", "Swamp", - "Spirit Arena"}, - "Overworld Holy Cross": set(), - "East Forest": set(), - "Dark Tomb": {"West Garden"}, - "Beneath the Well": set(), - "West Garden": set(), - "Ruined Atoll": {"Frog's Domain", "Library"}, - "Frog's Domain": set(), - "Library": set(), - "Eastern Vault Fortress": {"Beneath the Vault"}, - "Beneath the Vault": {"Eastern Vault Fortress"}, - "Quarry Back": {"Quarry"}, - "Quarry": {"Monastery", "Lower Quarry"}, - "Monastery": set(), - "Lower Quarry": {"Rooted Ziggurat"}, - "Rooted Ziggurat": set(), - "Swamp": {"Cathedral"}, - "Cathedral": set(), - "Spirit Arena": set() + "Spirit Arena"), + "Overworld Holy Cross": tuple(), + "East Forest": tuple(), + "Dark Tomb": ("West Garden",), + "Beneath the Well": tuple(), + "West Garden": tuple(), + "Ruined Atoll": ("Frog's Domain", "Library"), + "Frog's Domain": tuple(), + "Library": tuple(), + "Eastern Vault Fortress": ("Beneath the Vault",), + "Beneath the Vault": ("Eastern Vault Fortress",), + "Quarry Back": ("Quarry", "Monastery"), + "Quarry": ("Monastery", "Lower Quarry"), + "Monastery": ("Monastery Back",), + "Monastery Back": tuple(), + "Lower Quarry": ("Rooted Ziggurat",), + "Rooted Ziggurat": tuple(), + "Swamp": ("Cathedral",), + "Cathedral": tuple(), + "Spirit Arena": tuple() } diff --git a/worlds/tunic/rules.py b/worlds/tunic/rules.py index 30b7cee9d0..63f76ac929 100644 --- a/worlds/tunic/rules.py +++ b/worlds/tunic/rules.py @@ -124,6 +124,11 @@ def set_region_rules(world: "TunicWorld") -> None: and (state.has_any({grapple, laurels, gun}, player) or can_ladder_storage(state, world)) world.get_entrance("Quarry Back -> Quarry").access_rule = \ lambda state: has_sword(state, player) or state.has(fire_wand, player) + world.get_entrance("Quarry Back -> Monastery").access_rule = \ + lambda state: state.has(laurels, player) + world.get_entrance("Monastery -> Monastery Back").access_rule = \ + lambda state: (has_sword(state, player) or state.has(fire_wand, player) + or laurels_zip(state, world)) world.get_entrance("Quarry -> Lower Quarry").access_rule = \ lambda state: has_mask(state, world) world.get_entrance("Lower Quarry -> Rooted Ziggurat").access_rule = \ @@ -323,7 +328,7 @@ def set_location_rules(world: "TunicWorld") -> None: # Beneath the Vault set_rule(world.get_location("Beneath the Fortress - Bridge"), - lambda state: has_melee(state, player) or state.has_any({laurels, fire_wand}, player)) + lambda state: has_melee(state, player) or state.has_any((laurels, fire_wand, ice_dagger, gun), player)) set_rule(world.get_location("Beneath the Fortress - Obscured Behind Waterfall"), lambda state: has_melee(state, player) and has_lantern(state, world)) diff --git a/worlds/tunic/test/test_combat.py b/worlds/tunic/test/test_combat.py new file mode 100644 index 0000000000..c0e76ef92b --- /dev/null +++ b/worlds/tunic/test/test_combat.py @@ -0,0 +1,119 @@ +from BaseClasses import ItemClassification +from collections import Counter + +from . import TunicTestBase +from .. import options +from ..combat_logic import (check_combat_reqs, area_data, get_money_count, calc_effective_hp, get_potion_level, + get_hp_level, get_def_level, get_sp_level, has_combat_reqs) +from ..items import item_table +from .. import TunicWorld + + +class TestCombat(TunicTestBase): + options = {options.CombatLogic.internal_name: options.CombatLogic.option_on} + player = 1 + world: TunicWorld + combat_items = [] + # these are items that are progression that do not contribute to combat logic + # it's listed as using skipped items instead of a list of viable items so that if we add/remove some later, + # that this won't require updates most likely + # Stick and Sword are in here because sword progression is the clear determining case here + skipped_items = {"Fairy", "Stick", "Sword", "Magic Dagger", "Magic Orb", "Lantern", "Old House Key", "Key", + "Fortress Vault Key", "Golden Coin", "Red Questagon", "Green Questagon", "Blue Questagon", + "Scavenger Mask", "Pages 24-25 (Prayer)", "Pages 42-43 (Holy Cross)", "Pages 52-53 (Icebolt)"} + # converts golden trophies to their hero relic stat equivalent, for easier parsing + converter = { + "Secret Legend": "Hero Relic - DEF", + "Phonomath": "Hero Relic - DEF", + "Just Some Pals": "Hero Relic - POTION", + "Spring Falls": "Hero Relic - POTION", + "Back To Work": "Hero Relic - POTION", + "Mr Mayor": "Hero Relic - SP", + "Power Up": "Hero Relic - SP", + "Regal Weasel": "Hero Relic - SP", + "Forever Friend": "Hero Relic - SP", + "Sacred Geometry": "Hero Relic - MP", + "Vintage": "Hero Relic - MP", + "Dusty": "Hero Relic - MP", + } + skipped_items.update({item for item in item_table.keys() if item.startswith("Ladder")}) + for item, data in item_table.items(): + if item in skipped_items: + continue + ic = data.combat_ic or data.classification + if item in converter: + item = converter[item] + if ItemClassification.progression in ic: + combat_items += [item] * data.quantity_in_item_pool + + # we had an issue where collecting certain items brought certain areas out of logic + # due to the weirdness of swapping between "you have enough attack that you don't need magic" + # so this will make sure collecting an item doesn't bring something out of logic + def test_combat_doesnt_fail_backwards(self): + combat_items = self.combat_items.copy() + self.multiworld.worlds[1].random.shuffle(combat_items) + curr_statuses = {name: False for name in area_data.keys()} + prev_statuses = curr_statuses.copy() + area_names = list(area_data.keys()) + current_items = Counter() + for current_item_name in combat_items: + current_items[current_item_name] += 1 + current_item = TunicWorld.create_item(self.world, current_item_name) + self.collect(current_item) + self.multiworld.worlds[1].random.shuffle(area_names) + for area in area_names: + curr_statuses[area] = check_combat_reqs(area, self.multiworld.state, self.player) + if curr_statuses[area] < prev_statuses[area]: + data = area_data[area] + state = self.multiworld.state + player = self.player + req_effective_hp = calc_effective_hp(data.hp_level, data.potion_level, data.potion_count) + player_potion, potion_offerings = get_potion_level(state, player) + player_hp, hp_offerings = get_hp_level(state, player) + player_def, def_offerings = get_def_level(state, player) + player_sp, sp_offerings = get_sp_level(state, player) + raise Exception(f"Status for {area} decreased after collecting {current_item_name}.\n" + f"Current items: {current_items}.\n" + f"Total money: {get_money_count(self.multiworld.state, self.player)}.\n" + f"Required Effective HP: {req_effective_hp}.\n" + f"Free HP and Offerings: {player_hp - hp_offerings}, {hp_offerings}\n" + f"Free Potion and Offerings: {player_potion - potion_offerings}, {potion_offerings}\n" + f"Free Def and Offerings: {player_def - def_offerings}, {def_offerings}\n" + f"Free SP and Offerings: {player_sp - sp_offerings}, {sp_offerings}") + prev_statuses[area] = curr_statuses[area] + + # the issue was that a direct check of the logic and the cache had different results + # it was actually due to the combat_items in items.py not having the Gun in it + # but this test is still helpful for verifying the cache + def test_combat_magic_weapons(self): + combat_items = self.combat_items.copy() + combat_items.remove("Magic Wand") + combat_items.remove("Gun") + area_names = list(area_data.keys()) + self.multiworld.worlds[1].random.shuffle(combat_items) + self.multiworld.worlds[1].random.shuffle(area_names) + current_items = Counter() + state = self.multiworld.state.copy() + player = self.player + gun = TunicWorld.create_item(self.world, "Gun") + + for current_item_name in combat_items: + current_item = TunicWorld.create_item(self.world, current_item_name) + state.collect(current_item) + current_items[current_item_name] += 1 + for area in area_names: + if check_combat_reqs(area, state, player) != has_combat_reqs(area, state, player): + raise Exception(f"Cache for {area} does not match a direct check " + f"after collecting {current_item_name}.\n" + f"Current items: {current_items}.\n" + f"Cache {'succeeded' if has_combat_reqs(area, state, player) else 'failed'}\n" + f"Direct {'succeeded' if check_combat_reqs(area, state, player) else 'failed'}") + state.collect(gun) + for area in area_names: + if check_combat_reqs(area, state, player) != has_combat_reqs(area, state, player): + raise Exception(f"Cache for {area} does not match a direct check " + f"after collecting the Gun.\n" + f"Current items: {current_items}.\n" + f"Cache {'succeeded' if has_combat_reqs(area, state, player) else 'failed'}\n" + f"Direct {'succeeded' if check_combat_reqs(area, state, player) else 'failed'}") + state.remove(gun) diff --git a/worlds/zillion/__init__.py b/worlds/zillion/__init__.py index 5a4e2bb48f..d0064b9cb1 100644 --- a/worlds/zillion/__init__.py +++ b/worlds/zillion/__init__.py @@ -9,8 +9,7 @@ import logging from typing_extensions import override -from BaseClasses import ItemClassification, LocationProgressType, \ - MultiWorld, Item, CollectionState, Entrance, Tutorial +from BaseClasses import LocationProgressType, MultiWorld, Item, CollectionState, Entrance, Tutorial from .gen_data import GenData from .logic import ZillionLogicCache @@ -19,12 +18,13 @@ from .options import ZillionOptions, validate, z_option_groups from .id_maps import ZillionSlotInfo, get_slot_info, item_name_to_id as _item_name_to_id, \ loc_name_to_id as _loc_name_to_id, make_id_to_others, \ zz_reg_name_to_reg_name, base_id -from .item import ZillionItem +from .item import ZillionItem, get_classification from .patch import ZillionPatch from zilliandomizer.system import System from zilliandomizer.logic_components.items import RESCUE, items as zz_items, Item as ZzItem from zilliandomizer.logic_components.locations import Location as ZzLocation, Req +from zilliandomizer.map_gen.region_maker import DEAD_END_SUFFIX from zilliandomizer.options import Chars from worlds.AutoWorld import World, WebWorld @@ -119,8 +119,13 @@ class ZillionWorld(World): """ my_locations: list[ZillionLocation] = [] """ This is kind of a cache to avoid iterating through all the multiworld locations in logic. """ - slot_data_ready: threading.Event - """ This event is set in `generate_output` when the data is ready for `fill_slot_data` """ + finalized_gen_data: GenData | None + """ Finalized generation data needed by `generate_output` and by `fill_slot_data`. """ + item_locations_finalization_lock: threading.Lock + """ + This lock is used in `generate_output` and `fill_slot_data` to ensure synchronized access to `finalized_gen_data`, + so that whichever is run first can finalize the item locations while the other waits. + """ logic_cache: ZillionLogicCache | None = None def __init__(self, world: MultiWorld, player: int) -> None: @@ -128,7 +133,8 @@ class ZillionWorld(World): self.logger = logging.getLogger("Zillion") self.lsi = ZillionWorld.LogStreamInterface(self.logger) self.zz_system = System() - self.slot_data_ready = threading.Event() + self.finalized_gen_data = None + self.item_locations_finalization_lock = threading.Lock() def _make_item_maps(self, start_char: Chars) -> None: _id_to_name, _id_to_zz_id, id_to_zz_item = make_id_to_others(start_char) @@ -167,6 +173,7 @@ class ZillionWorld(World): self.logic_cache = logic_cache w = self.multiworld self.my_locations = [] + dead_end_locations: list[ZillionLocation] = [] self.zz_system.randomizer.place_canister_gun_reqs() # low probability that place_canister_gun_reqs() results in empty 1st sphere @@ -219,6 +226,16 @@ class ZillionWorld(World): here.locations.append(loc) self.my_locations.append(loc) + if (( + zz_here.name.endswith(DEAD_END_SUFFIX) + ) or ( + (self.options.map_gen.value != self.options.map_gen.option_full) and + (loc.name in self.options.priority_dead_ends.vanilla_dead_ends) + ) or ( + loc.name in self.options.priority_dead_ends.always_dead_ends + )): + dead_end_locations.append(loc) + for zz_dest in zz_here.connections.keys(): dest_name = "Menu" if zz_dest.name == "start" else zz_reg_name_to_reg_name(zz_dest.name) dest = all_regions[dest_name] @@ -228,6 +245,8 @@ class ZillionWorld(World): queue.append(zz_dest) done.add(here.name) + if self.options.priority_dead_ends.value: + self.options.priority_locations.value |= {loc.name for loc in dead_end_locations} @override def create_items(self) -> None: @@ -305,6 +324,19 @@ class ZillionWorld(World): self.zz_system.post_fill() + def finalize_item_locations_thread_safe(self) -> GenData: + """ + Call self.finalize_item_locations() and cache the result in a thread-safe manner so that either + `generate_output` or `fill_slot_data` can finalize item locations without concern for which of the two functions + is called first. + """ + # The lock is acquired when entering the context manager and released when exiting the context manager. + with self.item_locations_finalization_lock: + # If generation data has yet to be finalized, finalize it. + if self.finalized_gen_data is None: + self.finalized_gen_data = self.finalize_item_locations() + return self.finalized_gen_data + def finalize_item_locations(self) -> GenData: """ sync zilliandomizer item locations with AP item locations @@ -363,12 +395,7 @@ class ZillionWorld(World): def generate_output(self, output_directory: str) -> None: """This method gets called from a threadpool, do not use multiworld.random here. If you need any last-second randomization, use self.random instead.""" - try: - gen_data = self.finalize_item_locations() - except BaseException: - raise - finally: - self.slot_data_ready.set() + gen_data = self.finalize_item_locations_thread_safe() out_file_base = self.multiworld.get_out_file_name_base(self.player) @@ -392,9 +419,7 @@ class ZillionWorld(World): # TODO: tell client which canisters are keywords # so it can open and get those when restoring doors - self.slot_data_ready.wait() - assert self.zz_system.randomizer, "didn't get randomizer from generate_early" - game = self.zz_system.get_game() + game = self.finalize_item_locations_thread_safe().zz_game return get_slot_info(game.regions, game.char_order[0], game.loc_name_2_pretty) # end of ordered Main.py calls @@ -410,12 +435,8 @@ class ZillionWorld(World): self.logger.warning("warning: called `create_item` without calling `generate_early` first") assert self.id_to_zz_item, "failed to get item maps" - classification = ItemClassification.filler zz_item = self.id_to_zz_item[item_id] - if zz_item.required: - classification = ItemClassification.progression - if not zz_item.is_progression: - classification = ItemClassification.progression_skip_balancing + classification = get_classification(name, zz_item, self._item_counts) z_item = ZillionItem(name, classification, item_id, self.player, zz_item) return z_item diff --git a/worlds/zillion/item.py b/worlds/zillion/item.py index fdf0fa8ba2..5fa481ac36 100644 --- a/worlds/zillion/item.py +++ b/worlds/zillion/item.py @@ -1,6 +1,34 @@ +from typing import Counter from BaseClasses import Item, ItemClassification as IC from zilliandomizer.logic_components.items import Item as ZzItem +_useful_thresholds = { + "Apple": 9999, + "Champ": 9999, + "JJ": 9999, + "Win": 9999, + "Empty": 0, + "ID Card": 10, + "Red ID Card": 2, + "Floppy Disk": 7, + "Bread": 0, + "Opa-Opa": 20, + "Zillion": 8, + "Scope": 8, +} +""" make the item useful if the number in the item pool is below this number """ + + +def get_classification(name: str, zz_item: ZzItem, item_counts: Counter[str]) -> IC: + classification = IC.filler + if zz_item.required: + classification = IC.progression + if not zz_item.is_progression: + classification = IC.progression_skip_balancing + if item_counts[name] < _useful_thresholds.get(name, 0): + classification |= IC.useful + return classification + class ZillionItem(Item): game = "Zillion" diff --git a/worlds/zillion/options.py b/worlds/zillion/options.py index 22a6984722..13f3d43ab0 100644 --- a/worlds/zillion/options.py +++ b/worlds/zillion/options.py @@ -272,6 +272,20 @@ class ZillionMapGen(Choice): return "full" +class ZillionPriorityDeadEnds(DefaultOnToggle): + """ + Single locations that are in a dead end behind a door + (example: vanilla Apple location) + are prioritized for progression items. + """ + display_name = "priority dead ends" + + vanilla_dead_ends: ClassVar = frozenset(("E-5 top far right", "J-4 top left")) + """ dead ends when not generating these rooms """ + always_dead_ends: ClassVar = frozenset(("A-6 top right",)) + """ dead ends in rooms that never get generated """ + + @dataclass class ZillionOptions(PerGameCommonOptions): continues: ZillionContinues @@ -293,6 +307,7 @@ class ZillionOptions(PerGameCommonOptions): skill: ZillionSkill starting_cards: ZillionStartingCards map_gen: ZillionMapGen + priority_dead_ends: ZillionPriorityDeadEnds room_gen: Removed diff --git a/worlds/zillion/requirements.txt b/worlds/zillion/requirements.txt index d6b01ac107..4f79626c9a 100644 --- a/worlds/zillion/requirements.txt +++ b/worlds/zillion/requirements.txt @@ -1,2 +1,2 @@ -zilliandomizer @ git+https://github.com/beauxq/zilliandomizer@33045067f626266850f91c8045b9d3a9f52d02b0#0.9.0 +zilliandomizer @ git+https://github.com/beauxq/zilliandomizer@96d9a20f8278cee64bb4db859fbd874e0f332d36#0.9.1 typing-extensions>=4.7, <5 diff --git a/worlds/zillion/test/TestOptions.py b/worlds/zillion/test/TestOptions.py index 3820c32dd0..904063fd3c 100644 --- a/worlds/zillion/test/TestOptions.py +++ b/worlds/zillion/test/TestOptions.py @@ -1,6 +1,7 @@ from . import ZillionTestBase -from ..options import ZillionJumpLevels, ZillionGunLevels, ZillionOptions, validate +from .. import ZillionWorld +from ..options import ZillionJumpLevels, ZillionGunLevels, ZillionOptions, ZillionPriorityDeadEnds, validate from zilliandomizer.options import VBLR_CHOICES @@ -28,3 +29,17 @@ class OptionsTest(ZillionTestBase): assert getattr(zz_options, option_name) in VBLR_CHOICES # TODO: test validate with invalid combinations of options + + +class DeadEndsTest(ZillionTestBase): + def test_vanilla_dead_end_names(self) -> None: + z_world = self.multiworld.worlds[1] + assert isinstance(z_world, ZillionWorld) + for loc_name in ZillionPriorityDeadEnds.vanilla_dead_ends: + assert any(loc.name == loc_name for loc in z_world.my_locations), f"{loc_name=} {z_world.my_locations=}" + + def test_always_dead_end_names(self) -> None: + z_world = self.multiworld.worlds[1] + assert isinstance(z_world, ZillionWorld) + for loc_name in ZillionPriorityDeadEnds.always_dead_ends: + assert any(loc.name == loc_name for loc in z_world.my_locations), f"{loc_name=} {z_world.my_locations=}" diff --git a/worlds/zork_grand_inquisitor/__init__.py b/worlds/zork_grand_inquisitor/__init__.py index 4da257e47b..791f41dd00 100644 --- a/worlds/zork_grand_inquisitor/__init__.py +++ b/worlds/zork_grand_inquisitor/__init__.py @@ -5,7 +5,7 @@ from .world import ZorkGrandInquisitorWorld def launch_client() -> None: from .client import main - LauncherComponents.launch_subprocess(main, name="ZorkGrandInquisitorClient") + LauncherComponents.launch(main, name="ZorkGrandInquisitorClient") LauncherComponents.components.append(