From ac791f299975cdc0ef6ce34f03c215bc6d830992 Mon Sep 17 00:00:00 2001 From: BadMagic100 Date: Wed, 6 Mar 2024 23:24:08 -0800 Subject: [PATCH 01/49] CI: Avoid race condition in labeler workflow (#2910) --- .github/workflows/label-pull-requests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/label-pull-requests.yml b/.github/workflows/label-pull-requests.yml index 42881aa49d..e26f6f34a4 100644 --- a/.github/workflows/label-pull-requests.yml +++ b/.github/workflows/label-pull-requests.yml @@ -18,6 +18,7 @@ jobs: sync-labels: true peer_review: name: 'Apply peer review label' + needs: labeler if: >- (github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'ready_for_review') && !github.event.pull_request.draft @@ -30,6 +31,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} unblock_draft_prs: name: 'Remove waiting-on labels' + needs: labeler if: github.event.action == 'converted_to_draft' || github.event.action == 'closed' runs-on: ubuntu-latest steps: From c6b1039e0fc5a8b41c934ecb96534c9e937985eb Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Thu, 7 Mar 2024 01:40:09 -0600 Subject: [PATCH 02/49] Core: call from_any on the options class when creating item links options (#2783) --- worlds/AutoWorld.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index dd0f46f6a6..4179637199 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -422,9 +422,9 @@ class World(metaclass=AutoWorldRegister): An example case is ItemLinks creating these.""" # TODO remove loop when worlds use options dataclass for option_key, option in cls.options_dataclass.type_hints.items(): - getattr(multiworld, option_key)[new_player_id] = option(option.default) + getattr(multiworld, option_key)[new_player_id] = option.from_any(option.default) group = cls(multiworld, new_player_id) - group.options = cls.options_dataclass(**{option_key: option(option.default) + group.options = cls.options_dataclass(**{option_key: option.from_any(option.default) for option_key, option in cls.options_dataclass.type_hints.items()}) return group From 862d77820d0a2826a8a426869c3b7149173a336a Mon Sep 17 00:00:00 2001 From: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Date: Thu, 7 Mar 2024 02:48:55 -0500 Subject: [PATCH 03/49] Fill: Improve clarity of remaining_fill messages (#2894) * Update Fill.py Make the fill message more descriptive * Removing kwarg --- Fill.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Fill.py b/Fill.py index ae44710469..2d6257eae3 100644 --- a/Fill.py +++ b/Fill.py @@ -208,7 +208,8 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati def remaining_fill(multiworld: MultiWorld, locations: typing.List[Location], - itempool: typing.List[Item]) -> None: + itempool: typing.List[Item], + name: str = "Remaining") -> None: unplaced_items: typing.List[Item] = [] placements: typing.List[Location] = [] swapped_items: typing.Counter[typing.Tuple[int, str]] = Counter() @@ -265,10 +266,10 @@ def remaining_fill(multiworld: MultiWorld, placements.append(spot_to_fill) placed += 1 if not placed % 1000: - _log_fill_progress("Remaining", placed, total) + _log_fill_progress(name, placed, total) if total > 1000: - _log_fill_progress("Remaining", placed, total) + _log_fill_progress(name, placed, total) if unplaced_items and locations: # There are leftover unplaceable items and locations that won't accept them @@ -466,7 +467,7 @@ def distribute_items_restrictive(multiworld: MultiWorld) -> None: inaccessible_location_rules(multiworld, multiworld.state, defaultlocations) - remaining_fill(multiworld, excludedlocations, filleritempool) + remaining_fill(multiworld, excludedlocations, filleritempool, "Remaining Excluded") if excludedlocations: raise FillError( f"Not enough filler items for excluded locations. There are {len(excludedlocations)} more locations than items") From b4bb88fcf7986859bb9efb2d6a159fcebcbab105 Mon Sep 17 00:00:00 2001 From: Silvris <58583688+Silvris@users.noreply.github.com> Date: Thu, 7 Mar 2024 03:18:22 -0600 Subject: [PATCH 04/49] SNIClient: dynamically generate patch file identifier (#2870) Co-authored-by: beauxq --- worlds/AutoSNIClient.py | 45 +++++++++++++++++++++++++++++++++++- worlds/LauncherComponents.py | 4 ---- worlds/alttp/Client.py | 1 + worlds/dkc3/Client.py | 1 + worlds/lufia2ac/Client.py | 1 + worlds/sm/Client.py | 1 + worlds/smw/Client.py | 1 + worlds/smz3/Client.py | 1 + 8 files changed, 50 insertions(+), 5 deletions(-) diff --git a/worlds/AutoSNIClient.py b/worlds/AutoSNIClient.py index a30dbbb46d..2b984d9c88 100644 --- a/worlds/AutoSNIClient.py +++ b/worlds/AutoSNIClient.py @@ -1,11 +1,35 @@ from __future__ import annotations import abc -from typing import TYPE_CHECKING, ClassVar, Dict, Tuple, Any, Optional +from typing import TYPE_CHECKING, ClassVar, Dict, Iterable, Tuple, Any, Optional, Union + +from typing_extensions import TypeGuard + +from worlds.LauncherComponents import Component, SuffixIdentifier, Type, components if TYPE_CHECKING: from SNIClient import SNIContext +component = Component('SNI Client', 'SNIClient', component_type=Type.CLIENT, file_identifier=SuffixIdentifier(".apsoe")) +components.append(component) + + +def valid_patch_suffix(obj: object) -> TypeGuard[Union[str, Iterable[str]]]: + """ make sure this is a valid value for the class variable `patch_suffix` """ + + def valid_individual(one: object) -> TypeGuard[str]: + """ check an individual suffix """ + # TODO: decide: len(one) > 3 and one.startswith(".ap") ? + # or keep it more general? + return isinstance(one, str) and len(one) > 1 and one.startswith(".") + + if isinstance(obj, str): + return valid_individual(obj) + if not isinstance(obj, Iterable): + return False + obj_it: Iterable[object] = obj + return all(valid_individual(each) for each in obj_it) + class AutoSNIClientRegister(abc.ABCMeta): game_handlers: ClassVar[Dict[str, SNIClient]] = {} @@ -15,6 +39,22 @@ class AutoSNIClientRegister(abc.ABCMeta): new_class = super().__new__(cls, name, bases, dct) if "game" in dct: AutoSNIClientRegister.game_handlers[dct["game"]] = new_class() + + if "patch_suffix" in dct: + patch_suffix = dct["patch_suffix"] + assert valid_patch_suffix(patch_suffix), f"class {name} defining invalid {patch_suffix=}" + + existing_identifier = component.file_identifier + assert isinstance(existing_identifier, SuffixIdentifier), f"{existing_identifier=}" + new_suffixes = [*existing_identifier.suffixes] + + if isinstance(patch_suffix, str): + new_suffixes.append(patch_suffix) + else: + new_suffixes.extend(patch_suffix) + + component.file_identifier = SuffixIdentifier(*new_suffixes) + return new_class @staticmethod @@ -27,6 +67,9 @@ class AutoSNIClientRegister(abc.ABCMeta): class SNIClient(abc.ABC, metaclass=AutoSNIClientRegister): + patch_suffix: ClassVar[Union[str, Iterable[str]]] = () + """The file extension(s) this client is meant to open and patch (e.g. ".aplttp")""" + @abc.abstractmethod async def validate_rom(self, ctx: SNIContext) -> bool: """ TODO: interface documentation here """ diff --git a/worlds/LauncherComponents.py b/worlds/LauncherComponents.py index 7814aac5ae..41c0bb8329 100644 --- a/worlds/LauncherComponents.py +++ b/worlds/LauncherComponents.py @@ -85,10 +85,6 @@ components: List[Component] = [ file_identifier=SuffixIdentifier('.archipelago', '.zip')), Component('Generate', 'Generate', cli=True), Component('Text Client', 'CommonClient', 'ArchipelagoTextClient', func=launch_textclient), - # SNI - Component('SNI Client', 'SNIClient', - file_identifier=SuffixIdentifier('.apz3', '.apm3', '.apsoe', '.aplttp', '.apsm', '.apsmz3', '.apdkc3', - '.apsmw', '.apl2ac', '.apkdl3')), Component('Links Awakening DX Client', 'LinksAwakeningClient', file_identifier=SuffixIdentifier('.apladx')), Component('LttP Adjuster', 'LttPAdjuster'), diff --git a/worlds/alttp/Client.py b/worlds/alttp/Client.py index edc68473b9..5b27f559ef 100644 --- a/worlds/alttp/Client.py +++ b/worlds/alttp/Client.py @@ -471,6 +471,7 @@ async def track_locations(ctx, roomid, roomdata) -> bool: class ALTTPSNIClient(SNIClient): game = "A Link to the Past" + patch_suffix = [".aplttp", ".apz3"] async def deathlink_kill_player(self, ctx): from SNIClient import DeathState, snes_read, snes_buffered_write, snes_flush_writes diff --git a/worlds/dkc3/Client.py b/worlds/dkc3/Client.py index 77ed51fecb..efa199e1d0 100644 --- a/worlds/dkc3/Client.py +++ b/worlds/dkc3/Client.py @@ -24,6 +24,7 @@ DEATH_LINK_ACTIVE_ADDR = DKC3_ROMNAME_START + 0x15 # DKC3_TODO: Find a perma class DKC3SNIClient(SNIClient): game = "Donkey Kong Country 3" + patch_suffix = ".apdkc3" async def deathlink_kill_player(self, ctx): pass diff --git a/worlds/lufia2ac/Client.py b/worlds/lufia2ac/Client.py index ac0de19bfd..9025a1137b 100644 --- a/worlds/lufia2ac/Client.py +++ b/worlds/lufia2ac/Client.py @@ -30,6 +30,7 @@ L2AC_RX_ADDR: int = SRAM_START + 0x2800 class L2ACSNIClient(SNIClient): game: str = "Lufia II Ancient Cave" + patch_suffix = ".apl2ac" async def validate_rom(self, ctx: SNIContext) -> bool: from SNIClient import snes_read diff --git a/worlds/sm/Client.py b/worlds/sm/Client.py index 756fd4bf36..ed3f2d5b3d 100644 --- a/worlds/sm/Client.py +++ b/worlds/sm/Client.py @@ -37,6 +37,7 @@ SM_REMOTE_ITEM_FLAG_ADDR = ROM_START + 0x277F06 # 1 byte class SMSNIClient(SNIClient): game = "Super Metroid" + patch_suffix = [".apsm", ".apm3"] async def deathlink_kill_player(self, ctx): from SNIClient import DeathState, snes_buffered_write, snes_flush_writes, snes_read diff --git a/worlds/smw/Client.py b/worlds/smw/Client.py index 92aeac4d4a..50899abe37 100644 --- a/worlds/smw/Client.py +++ b/worlds/smw/Client.py @@ -57,6 +57,7 @@ SMW_UNCOLLECTABLE_LEVELS = [0x25, 0x07, 0x0B, 0x40, 0x0E, 0x1F, 0x20, 0x1B, 0x1A class SMWSNIClient(SNIClient): game = "Super Mario World" + patch_suffix = ".apsmw" async def deathlink_kill_player(self, ctx): from SNIClient import DeathState, snes_buffered_write, snes_flush_writes, snes_read diff --git a/worlds/smz3/Client.py b/worlds/smz3/Client.py index b07aa850c3..0a248aa5d3 100644 --- a/worlds/smz3/Client.py +++ b/worlds/smz3/Client.py @@ -32,6 +32,7 @@ SMZ3_RECV_ITEM_PLAYER_ADDR = SAVEDATA_START + 0x4D3 # 1 byte class SMZ3SNIClient(SNIClient): game = "SMZ3" + patch_suffix = ".apsmz3" async def validate_rom(self, ctx): from SNIClient import snes_buffered_write, snes_flush_writes, snes_read From 3e0ff3f72dc9e3a6bc9817d64def2ada7a00eee8 Mon Sep 17 00:00:00 2001 From: Silvris <58583688+Silvris@users.noreply.github.com> Date: Fri, 8 Mar 2024 00:46:14 -0600 Subject: [PATCH 05/49] KDL3: Post-PR adjustments (#2917) * logic adjustments, add patch_suffix * forgot the other two consumables --- worlds/kdl3/Client.py | 4 +++- worlds/kdl3/Rules.py | 42 +++++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/worlds/kdl3/Client.py b/worlds/kdl3/Client.py index 3fef042900..c10dd6cebb 100644 --- a/worlds/kdl3/Client.py +++ b/worlds/kdl3/Client.py @@ -97,6 +97,7 @@ def cmd_gift(self: "SNIClientCommandProcessor"): class KDL3SNIClient(SNIClient): game = "Kirby's Dream Land 3" + patch_suffix = ".apkdl3" levels = None consumables = None stars = None @@ -406,7 +407,8 @@ class KDL3SNIClient(SNIClient): ctx.locations_checked.add(new_check_id) location = ctx.location_names[new_check_id] snes_logger.info( - f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})') + f'New Check: {location} ({len(ctx.locations_checked)}/' + f'{len(ctx.missing_locations) + len(ctx.checked_locations)})') await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) except Exception as ex: # we crashed, so print log and clean up diff --git a/worlds/kdl3/Rules.py b/worlds/kdl3/Rules.py index 81ad8f1f1f..91abc21d06 100644 --- a/worlds/kdl3/Rules.py +++ b/worlds/kdl3/Rules.py @@ -206,13 +206,19 @@ def set_rules(world: "KDL3World") -> None: lambda state: can_reach_needle(state, world.player)) set_rule(world.multiworld.get_location(LocationName.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))) + (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(LocationName.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))) + (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(LocationName.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))) + (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(LocationName.cloudy_park_6_u1, world.player), lambda state: can_reach_cutter(state, world.player)) @@ -242,7 +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))) + (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)) @@ -267,32 +275,32 @@ def set_rules(world: "KDL3World") -> None: # Kirby cannot eat enemies fully submerged in water. Vast majority of cases, the enemy can be brought to the surface # and eaten by inhaling while falling on top of them set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_2_E3, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_3_E6, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) # Ripple Field 4 E5, E7, and E8 are doable, but too strict to leave in logic set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_4_E5, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_4_E7, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_4_E8, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E1, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E2, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E3, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E4, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E7, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E8, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E9, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player)) set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E10, world.player), - lambda state: can_reach_kine(state, world.player)) + lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(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", From 3e3b4c6732be219f756f7db22e8973540a1ae57a Mon Sep 17 00:00:00 2001 From: Seafo <92278897+Seatori@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:15:36 -0500 Subject: [PATCH 06/49] Minecraft: Add Pickaxes to the documentation (#2688) --- worlds/minecraft/docs/en_Minecraft.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/minecraft/docs/en_Minecraft.md b/worlds/minecraft/docs/en_Minecraft.md index 1ef347983b..bfe10d8cc5 100644 --- a/worlds/minecraft/docs/en_Minecraft.md +++ b/worlds/minecraft/docs/en_Minecraft.md @@ -64,12 +64,15 @@ sequence either by skipping it or watching hit play out. * Diamond Axe * Progessive Tools * Tier I + * Stone Pickaxe * Stone Shovel * Stone Hoe * Tier II + * Iron Pickaxe * Iron Shovel * Iron Hoe * Tier III + * Diamond Pickaxe * Diamond Shovel * Diamond Hoe * Netherite Ingot From 3c4ebb21140e5fd8ec6df63c1033915211ae8b01 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 9 Mar 2024 00:03:02 +0100 Subject: [PATCH 07/49] The Witness: Fix... I don't know how to explain this one (#2920) ``` for hint in generated_hints: hint = generated_hints.pop(0) ``` lmao --- worlds/witness/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index bd877a16ef..635a56796b 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -306,7 +306,6 @@ class WitnessWorld(World): duplicates = min(3, len(audio_logs) // hint_amount) for hint in generated_hints: - hint = generated_hints.pop(0) compact_hint_data = make_compact_hint_data(hint, self.player) for _ in range(0, duplicates): From be802b47231ededcb3d9b289d49c482820191ead Mon Sep 17 00:00:00 2001 From: Remy Jette Date: Sat, 9 Mar 2024 23:12:55 -0800 Subject: [PATCH 08/49] Core: Remove extra " character in /forbid_release help message (#2923) Was pointed out in the Discord: https://discord.com/channels/731205301247803413/731205301818359821/1215882443261870190 --- MultiServer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MultiServer.py b/MultiServer.py index 62dab3298e..c2d8e4ad58 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -1964,7 +1964,7 @@ class ServerCommandProcessor(CommonCommandProcessor): @mark_raw def _cmd_forbid_release(self, player_name: str) -> bool: - """"Disallow the specified player from using the !release command.""" + """Disallow the specified player from using the !release command.""" player = self.resolve_player(player_name) if player: team, slot, name = player From 4ce58c02403f044ba18bbf4640c6abe856d5714a Mon Sep 17 00:00:00 2001 From: axe-y <58866768+axe-y@users.noreply.github.com> Date: Sun, 10 Mar 2024 03:13:52 -0400 Subject: [PATCH 09/49] DLC Quest: AP World Status fix (#2908) --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 3f9a7f0ba6..68cab1d5e2 100644 --- a/setup.py +++ b/setup.py @@ -68,7 +68,6 @@ non_apworlds: set = { "Archipelago", "ChecksFinder", "Clique", - "DLCQuest", "Final Fantasy", "Lufia II Ancient Cave", "Meritous", From 939a5ec959108c35a49b1e12a56ae51f45ebb4fb Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Sun, 10 Mar 2024 01:18:25 -0600 Subject: [PATCH 10/49] LTTP: remove multiworld = None (#2290) --- test/bases.py | 8 +- test/general/test_items.py | 2 +- worlds/AutoWorld.py | 1 + worlds/alttp/Dungeons.py | 86 +++++++++---------- worlds/alttp/ItemPool.py | 46 +++++----- worlds/alttp/Items.py | 8 +- worlds/alttp/Rom.py | 10 +-- worlds/alttp/Rules.py | 4 +- worlds/alttp/test/__init__.py | 1 + worlds/alttp/test/dungeons/TestDungeon.py | 12 +-- worlds/alttp/test/inverted/TestInverted.py | 10 +-- .../TestInvertedMinor.py | 10 +-- .../test/inverted_owg/TestInvertedOWG.py | 12 +-- worlds/alttp/test/minor_glitches/TestMinor.py | 14 +-- worlds/alttp/test/options/TestOpenPyramid.py | 6 +- worlds/alttp/test/owg/TestVanillaOWG.py | 8 +- worlds/alttp/test/vanilla/TestVanilla.py | 6 +- 17 files changed, 122 insertions(+), 122 deletions(-) diff --git a/test/bases.py b/test/bases.py index 2d4111d193..07a3e60086 100644 --- a/test/bases.py +++ b/test/bases.py @@ -10,7 +10,7 @@ from worlds import AutoWorld from worlds.AutoWorld import World, call_all from BaseClasses import Location, MultiWorld, CollectionState, ItemClassification, Item -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory class TestBase(unittest.TestCase): @@ -91,15 +91,15 @@ class TestBase(unittest.TestCase): items = self.multiworld.itempool[:] items = [item for item in items if item.name not in all_except and not ("Bottle" in item.name and "AnyBottle" in all_except)] - items.extend(ItemFactory(item_pool[0], 1)) + items.extend(item_factory(item_pool[0], self.multiworld.worlds[1])) else: - items = ItemFactory(item_pool[0], 1) + items = item_factory(item_pool[0], self.multiworld.worlds[1]) return self.get_state(items) def _get_items_partial(self, item_pool, missing_item): new_items = item_pool[0].copy() new_items.remove(missing_item) - items = ItemFactory(new_items, 1) + items = item_factory(new_items, self.multiworld.worlds[1]) return self.get_state(items) diff --git a/test/general/test_items.py b/test/general/test_items.py index 1612937225..82b6030379 100644 --- a/test/general/test_items.py +++ b/test/general/test_items.py @@ -8,7 +8,7 @@ class TestBase(unittest.TestCase): def test_create_item(self): """Test that a world can successfully create all items in its datapackage""" for game_name, world_type in AutoWorldRegister.world_types.items(): - proxy_world = world_type(None, 0) # this is identical to MultiServer.py creating worlds + proxy_world = setup_solo_multiworld(world_type, ()).worlds[1] for item_name in world_type.item_name_to_id: with self.subTest("Create Item", item_name=item_name, game_name=game_name): item = proxy_world.create_item(item_name) diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index 4179637199..93e4a5c385 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -296,6 +296,7 @@ class World(metaclass=AutoWorldRegister): """path it was loaded from""" def __init__(self, multiworld: "MultiWorld", player: int): + assert multiworld is not None self.multiworld = multiworld self.player = player diff --git a/worlds/alttp/Dungeons.py b/worlds/alttp/Dungeons.py index c886fce920..f0b8c2d971 100644 --- a/worlds/alttp/Dungeons.py +++ b/worlds/alttp/Dungeons.py @@ -7,7 +7,7 @@ from BaseClasses import CollectionState, Region, MultiWorld from Fill import fill_restrictive from .Bosses import BossFactory, Boss -from .Items import ItemFactory +from .Items import item_factory from .Regions import lookup_boss_drops, key_drop_data from .Options import small_key_shuffle @@ -81,90 +81,90 @@ def create_dungeons(world: "ALTTPWorld"): return dungeon ES = make_dungeon('Hyrule Castle', None, ['Hyrule Castle', 'Sewers', 'Sewer Drop', 'Sewers (Dark)', 'Sanctuary'], - ItemFactory('Big Key (Hyrule Castle)', player), - ItemFactory(['Small Key (Hyrule Castle)'] * 4, player), - [ItemFactory('Map (Hyrule Castle)', player)]) + item_factory('Big Key (Hyrule Castle)', world), + item_factory(['Small Key (Hyrule Castle)'] * 4, world), + [item_factory('Map (Hyrule Castle)', world)]) EP = make_dungeon('Eastern Palace', 'Armos Knights', ['Eastern Palace'], - ItemFactory('Big Key (Eastern Palace)', player), - ItemFactory(['Small Key (Eastern Palace)'] * 2, player), - ItemFactory(['Map (Eastern Palace)', 'Compass (Eastern Palace)'], player)) + item_factory('Big Key (Eastern Palace)', world), + item_factory(['Small Key (Eastern Palace)'] * 2, world), + item_factory(['Map (Eastern Palace)', 'Compass (Eastern Palace)'], world)) DP = make_dungeon('Desert Palace', 'Lanmolas', ['Desert Palace North', 'Desert Palace Main (Inner)', 'Desert Palace Main (Outer)', - 'Desert Palace East'], ItemFactory('Big Key (Desert Palace)', player), - ItemFactory(['Small Key (Desert Palace)'] * 4, player), - ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)'], player)) + 'Desert Palace East'], item_factory('Big Key (Desert Palace)', world), + item_factory(['Small Key (Desert Palace)'] * 4, world), + item_factory(['Map (Desert Palace)', 'Compass (Desert Palace)'], world)) ToH = make_dungeon('Tower of Hera', 'Moldorm', ['Tower of Hera (Bottom)', 'Tower of Hera (Basement)', 'Tower of Hera (Top)'], - ItemFactory('Big Key (Tower of Hera)', player), - [ItemFactory('Small Key (Tower of Hera)', player)], - ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)'], player)) + item_factory('Big Key (Tower of Hera)', world), + [item_factory('Small Key (Tower of Hera)', world)], + item_factory(['Map (Tower of Hera)', 'Compass (Tower of Hera)'], world)) PoD = make_dungeon('Palace of Darkness', 'Helmasaur King', ['Palace of Darkness (Entrance)', 'Palace of Darkness (Center)', 'Palace of Darkness (Big Key Chest)', 'Palace of Darkness (Bonk Section)', 'Palace of Darkness (North)', 'Palace of Darkness (Maze)', 'Palace of Darkness (Harmless Hellway)', 'Palace of Darkness (Final Section)'], - ItemFactory('Big Key (Palace of Darkness)', player), - ItemFactory(['Small Key (Palace of Darkness)'] * 6, player), - ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)'], player)) + item_factory('Big Key (Palace of Darkness)', world), + item_factory(['Small Key (Palace of Darkness)'] * 6, world), + item_factory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)'], world)) TT = make_dungeon('Thieves Town', 'Blind', ['Thieves Town (Entrance)', 'Thieves Town (Deep)', 'Blind Fight'], - ItemFactory('Big Key (Thieves Town)', player), - ItemFactory(['Small Key (Thieves Town)'] * 3, player), - ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)'], player)) + item_factory('Big Key (Thieves Town)', world), + item_factory(['Small Key (Thieves Town)'] * 3, world), + item_factory(['Map (Thieves Town)', 'Compass (Thieves Town)'], world)) SW = make_dungeon('Skull Woods', 'Mothula', ['Skull Woods Final Section (Entrance)', 'Skull Woods First Section', 'Skull Woods Second Section', 'Skull Woods Second Section (Drop)', 'Skull Woods Final Section (Mothula)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)'], - ItemFactory('Big Key (Skull Woods)', player), - ItemFactory(['Small Key (Skull Woods)'] * 5, player), - ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)'], player)) + item_factory('Big Key (Skull Woods)', world), + item_factory(['Small Key (Skull Woods)'] * 5, world), + item_factory(['Map (Skull Woods)', 'Compass (Skull Woods)'], world)) SP = make_dungeon('Swamp Palace', 'Arrghus', ['Swamp Palace (Entrance)', 'Swamp Palace (First Room)', 'Swamp Palace (Starting Area)', 'Swamp Palace (West)', 'Swamp Palace (Center)', 'Swamp Palace (North)'], - ItemFactory('Big Key (Swamp Palace)', player), - ItemFactory(['Small Key (Swamp Palace)'] * 6, player), - ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)'], player)) + item_factory('Big Key (Swamp Palace)', world), + item_factory(['Small Key (Swamp Palace)'] * 6, world), + item_factory(['Map (Swamp Palace)', 'Compass (Swamp Palace)'], world)) IP = make_dungeon('Ice Palace', 'Kholdstare', ['Ice Palace (Entrance)', 'Ice Palace (Second Section)', 'Ice Palace (Main)', 'Ice Palace (East)', - 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)', player), - ItemFactory(['Small Key (Ice Palace)'] * 6, player), - ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)'], player)) + 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], item_factory('Big Key (Ice Palace)', world), + item_factory(['Small Key (Ice Palace)'] * 6, world), + item_factory(['Map (Ice Palace)', 'Compass (Ice Palace)'], world)) MM = make_dungeon('Misery Mire', 'Vitreous', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', - 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)', player), - ItemFactory(['Small Key (Misery Mire)'] * 6, player), - ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'], player)) + 'Misery Mire (Vitreous)'], item_factory('Big Key (Misery Mire)', world), + item_factory(['Small Key (Misery Mire)'] * 6, world), + item_factory(['Map (Misery Mire)', 'Compass (Misery Mire)'], world)) TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Pokey Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], - ItemFactory('Big Key (Turtle Rock)', player), - ItemFactory(['Small Key (Turtle Rock)'] * 6, player), - ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player)) + item_factory('Big Key (Turtle Rock)', world), + item_factory(['Small Key (Turtle Rock)'] * 6, world), + item_factory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], world)) if multiworld.mode[player] != 'inverted': AT = make_dungeon('Agahnims Tower', 'Agahnim', ['Agahnims Tower', 'Agahnim 1'], None, - ItemFactory(['Small Key (Agahnims Tower)'] * 4, player), []) + item_factory(['Small Key (Agahnims Tower)'] * 4, world), []) GT = make_dungeon('Ganons Tower', 'Agahnim2', ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], - ItemFactory('Big Key (Ganons Tower)', player), - ItemFactory(['Small Key (Ganons Tower)'] * 8, player), - ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player)) + item_factory('Big Key (Ganons Tower)', world), + item_factory(['Small Key (Ganons Tower)'] * 8, world), + item_factory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], world)) else: AT = make_dungeon('Inverted Agahnims Tower', 'Agahnim', ['Inverted Agahnims Tower', 'Agahnim 1'], None, - ItemFactory(['Small Key (Agahnims Tower)'] * 4, player), []) + item_factory(['Small Key (Agahnims Tower)'] * 4, world), []) GT = make_dungeon('Inverted Ganons Tower', 'Agahnim2', ['Inverted Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', - 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)', player), - ItemFactory(['Small Key (Ganons Tower)'] * 8, player), - ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player)) + 'Agahnim 2'], item_factory('Big Key (Ganons Tower)', world), + item_factory(['Small Key (Ganons Tower)'] * 8, world), + item_factory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], world)) GT.bosses['bottom'] = BossFactory('Armos Knights', player) GT.bosses['middle'] = BossFactory('Lanmolas', player) @@ -259,7 +259,7 @@ def fill_dungeons_restrictive(multiworld: MultiWorld): if not key_drop_shuffle and player not in multiworld.groups: for key_loc in key_drop_data: key_data = key_drop_data[key_loc] - all_state_base.remove(ItemFactory(key_data[3], player)) + all_state_base.remove(item_factory(key_data[3], multiworld.worlds[player])) loc = multiworld.get_location(key_loc, player) if loc in all_state_base.events: diff --git a/worlds/alttp/ItemPool.py b/worlds/alttp/ItemPool.py index bb5bbaa61a..7a82d4c6be 100644 --- a/worlds/alttp/ItemPool.py +++ b/worlds/alttp/ItemPool.py @@ -9,8 +9,8 @@ from .Shops import TakeAny, total_shop_slots, set_up_shops, shop_table_by_locati from .Bosses import place_bosses from .Dungeons import get_dungeon_item_pool_player from .EntranceShuffle import connect_entrance -from .Items import ItemFactory, GetBeemizerItem, trap_replaceable, item_name_groups -from .Options import small_key_shuffle, compass_shuffle, big_key_shuffle, map_shuffle, TriforcePiecesMode +from .Items import item_factory, GetBeemizerItem, trap_replaceable, item_name_groups +from .Options import small_key_shuffle, compass_shuffle, big_key_shuffle, map_shuffle, TriforcePiecesMode, LTTPBosses from .StateHelpers import has_triforce_pieces, has_melee_weapon from .Regions import key_drop_data @@ -240,9 +240,9 @@ def generate_itempool(world): if multiworld.timer[player] in ['ohko', 'timed_ohko']: multiworld.can_take_damage[player] = False if multiworld.goal[player] in ['pedestal', 'triforce_hunt', 'local_triforce_hunt']: - multiworld.push_item(multiworld.get_location('Ganon', player), ItemFactory('Nothing', player), False) + multiworld.push_item(multiworld.get_location('Ganon', player), item_factory('Nothing', world), False) else: - multiworld.push_item(multiworld.get_location('Ganon', player), ItemFactory('Triforce', player), False) + multiworld.push_item(multiworld.get_location('Ganon', player), item_factory('Triforce', world), False) if multiworld.goal[player] in ['triforce_hunt', 'local_triforce_hunt']: region = multiworld.get_region('Light World', player) @@ -252,7 +252,7 @@ def generate_itempool(world): region.locations.append(loc) - multiworld.push_item(loc, ItemFactory('Triforce', player), False) + multiworld.push_item(loc, item_factory('Triforce', world), False) loc.event = True loc.locked = True @@ -271,7 +271,7 @@ def generate_itempool(world): ] for location_name, event_name in event_pairs: location = multiworld.get_location(location_name, player) - event = ItemFactory(event_name, player) + event = item_factory(event_name, world) multiworld.push_item(location, event, False) location.event = location.locked = True @@ -287,7 +287,7 @@ def generate_itempool(world): treasure_hunt_icon, additional_triforce_pieces = get_pool_core(multiworld, player) for item in precollected_items: - multiworld.push_precollected(ItemFactory(item, player)) + multiworld.push_precollected(item_factory(item, world)) if multiworld.mode[player] == 'standard' and not has_melee_weapon(multiworld.state, player): if "Link's Uncle" not in placed_items: @@ -326,9 +326,9 @@ def generate_itempool(world): multiworld.escape_assist[player].append('bombs') for (location, item) in placed_items.items(): - multiworld.get_location(location, player).place_locked_item(ItemFactory(item, player)) + multiworld.get_location(location, player).place_locked_item(item_factory(item, world)) - items = ItemFactory(pool, player) + items = item_factory(pool, world) # convert one Progressive Bow into Progressive Bow (Alt), in ID only, for ganon silvers hint text if multiworld.worlds[player].has_progressive_bows: for item in items: @@ -349,7 +349,7 @@ def generate_itempool(world): for key_loc in key_drop_data: key_data = key_drop_data[key_loc] - drop_item = ItemFactory(key_data[3], player) + drop_item = item_factory(key_data[3], world) if not multiworld.key_drop_shuffle[player]: if drop_item in dungeon_items: dungeon_items.remove(drop_item) @@ -370,7 +370,7 @@ def generate_itempool(world): loc.address = None elif "Small" in key_data[3] and multiworld.small_key_shuffle[player] == small_key_shuffle.option_universal: # key drop shuffle and universal keys are on. Add universal keys in place of key drop keys. - multiworld.itempool.append(ItemFactory(GetBeemizerItem(multiworld, player, 'Small Key (Universal)'), player)) + multiworld.itempool.append(item_factory(GetBeemizerItem(multiworld, player, 'Small Key (Universal)'), world)) dungeon_item_replacements = sum(difficulties[multiworld.difficulty[player]].extras, []) * 2 multiworld.random.shuffle(dungeon_item_replacements) @@ -382,7 +382,7 @@ def generate_itempool(world): or (multiworld.map_shuffle[player] == map_shuffle.option_start_with and item.type == 'Map')): dungeon_items.pop(x) multiworld.push_precollected(item) - multiworld.itempool.append(ItemFactory(dungeon_item_replacements.pop(), player)) + multiworld.itempool.append(item_factory(dungeon_item_replacements.pop(), world)) multiworld.itempool.extend([item for item in dungeon_items]) set_up_shops(multiworld, player) @@ -394,7 +394,7 @@ def generate_itempool(world): location.shop_slot is not None] for location in shop_locations: if location.shop.inventory[location.shop_slot]["item"] == "Single Arrow": - location.place_locked_item(ItemFactory("Single Arrow", player)) + location.place_locked_item(item_factory("Single Arrow", world)) else: shop_items += 1 else: @@ -406,9 +406,9 @@ def generate_itempool(world): multiworld.small_key_shuffle[player] == small_key_shuffle.option_universal) * 0.5 for _ in range(shop_items): if multiworld.random.random() < chance_100: - items.append(ItemFactory(GetBeemizerItem(multiworld, player, "Rupees (100)"), player)) + items.append(item_factory(GetBeemizerItem(multiworld, player, "Rupees (100)"), world)) else: - items.append(ItemFactory(GetBeemizerItem(multiworld, player, "Rupees (50)"), player)) + items.append(item_factory(GetBeemizerItem(multiworld, player, "Rupees (50)"), world)) multiworld.random.shuffle(items) pool_count = len(items) @@ -431,7 +431,7 @@ def generate_itempool(world): new_items += ["Arrow Upgrade (+5)"] * 6 new_items.append("Arrow Upgrade (+5)" if progressive else "Arrow Upgrade (+10)") - items += [ItemFactory(item, player) for item in new_items] + items += [item_factory(item, world) for item in new_items] removed_filler = [] multiworld.random.shuffle(items) # Decide what gets tossed randomly. @@ -444,22 +444,22 @@ def generate_itempool(world): else: # no more junk to remove, condense progressive items def condense_items(items, small_item, big_item, rem, add): - small_item = ItemFactory(small_item, player) + small_item = item_factory(small_item, world) # while (len(items) >= pool_count + rem - 1 # minus 1 to account for the replacement item # and items.count(small_item) >= rem): if items.count(small_item) >= rem: for _ in range(rem): items.remove(small_item) - removed_filler.append(ItemFactory(small_item.name, player)) - items += [ItemFactory(big_item, player) for _ in range(add)] + removed_filler.append(item_factory(small_item.name, world)) + items += [item_factory(big_item, world) for _ in range(add)] return True return False def cut_item(items, item_to_cut, minimum_items): - item_to_cut = ItemFactory(item_to_cut, player) + item_to_cut = item_factory(item_to_cut, world) if items.count(item_to_cut) > minimum_items: items.remove(item_to_cut) - removed_filler.append(ItemFactory(item_to_cut.name, player)) + removed_filler.append(item_factory(item_to_cut.name, world)) return True return False @@ -551,7 +551,7 @@ def set_up_take_anys(world, player): if swords: sword = world.random.choice(swords) world.itempool.remove(sword) - world.itempool.append(ItemFactory('Rupees (20)', player)) + world.itempool.append(item_factory('Rupees (20)', world)) old_man_take_any.shop.add_inventory(0, sword.name, 0, 0) loc_name = "Old Man Sword Cave" location = ALttPLocation(player, loc_name, shop_table_by_location[loc_name], parent=old_man_take_any) @@ -577,7 +577,7 @@ def set_up_take_anys(world, player): location = ALttPLocation(player, take_any.name, shop_table_by_location[take_any.name], parent=take_any) location.shop_slot = 1 take_any.locations.append(location) - location.place_locked_item(ItemFactory("Boss Heart Container", player)) + location.place_locked_item(item_factory("Boss Heart Container", world)) def get_pool_core(world, player: int): diff --git a/worlds/alttp/Items.py b/worlds/alttp/Items.py index 8e513552ad..cb44f35d58 100644 --- a/worlds/alttp/Items.py +++ b/worlds/alttp/Items.py @@ -1,6 +1,7 @@ import typing from BaseClasses import ItemClassification as IC +from worlds.AutoWorld import World def GetBeemizerItem(world, player: int, item): @@ -17,13 +18,10 @@ def GetBeemizerItem(world, player: int, item): if not world.beemizer_trap_chance[player] or world.random.random() > (world.beemizer_trap_chance[player] / 100): return "Bee" if isinstance(item, str) else world.create_item("Bee", player) else: - return "Bee Trap" if isinstance(item, str) else world.create_item("Bee Trap", player) + return "Bee Trap" if isinstance(item, str) else world.create_item("Bee Trap", player) -# should be replaced with direct world.create_item(item) call in the future -def ItemFactory(items: typing.Union[str, typing.Iterable[str]], player: int): - from worlds.alttp import ALTTPWorld - world = ALTTPWorld(None, player) +def item_factory(items: typing.Union[str, typing.Iterable[str]], world: World): ret = [] singleton = False if isinstance(items, str): diff --git a/worlds/alttp/Rom.py b/worlds/alttp/Rom.py index ff4947bb01..6ef1f0db19 100644 --- a/worlds/alttp/Rom.py +++ b/worlds/alttp/Rom.py @@ -34,7 +34,7 @@ from .Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts, Blacksmith DeathMountain_texts, \ LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, \ SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names -from .Items import ItemFactory, item_table, item_name_groups, progression_items +from .Items import item_table, item_name_groups, progression_items from .EntranceShuffle import door_addresses from .Options import small_key_shuffle @@ -996,7 +996,7 @@ def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool): rom.write_byte(0x18003A, 0x01 if world.dark_world_light_cone else 0x00) GREEN_TWENTY_RUPEES = 0x47 - GREEN_CLOCK = ItemFactory('Green Clock', player).code + GREEN_CLOCK = item_table["Green Clock"].item_code rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on @@ -1777,13 +1777,13 @@ def write_custom_shops(rom, world, player): if item['player'] and world.game[item['player']] != "A Link to the Past": # item not native to ALTTP item_code = get_nonnative_item_sprite(world.worlds[item['player']].item_name_to_id[item['item']]) else: - item_code = ItemFactory(item['item'], player).code + item_code = item_table[item["item"]].item_code if item['item'] == 'Single Arrow' and item['player'] == 0 and world.retro_bow[player]: rom.write_byte(0x186500 + shop.sram_offset + slot, arrow_mask) item_data = [shop_id, item_code] + price_data + \ - [item['max'], ItemFactory(item['replacement'], player).code if item['replacement'] else 0xFF] + \ - replacement_price_data + [0 if item['player'] == player else min(ROM_PLAYER_LIMIT, item['player'])] + [item["max"], item_table[item["replacement"]].item_code if item["replacement"] else 0xFF] + \ + replacement_price_data + [0 if item["player"] == player else min(ROM_PLAYER_LIMIT, item["player"])] items_data.extend(item_data) rom.write_bytes(0x184800, shop_data) diff --git a/worlds/alttp/Rules.py b/worlds/alttp/Rules.py index b86a793fb9..c3156116e4 100644 --- a/worlds/alttp/Rules.py +++ b/worlds/alttp/Rules.py @@ -8,7 +8,7 @@ from worlds.generic.Rules import (add_item_rule, add_rule, forbid_item, from . import OverworldGlitchRules from .Bosses import GanonDefeatRule -from .Items import ItemFactory, item_name_groups, item_table, progression_items +from .Items import item_factory, item_name_groups, item_table, progression_items from .Options import small_key_shuffle from .OverworldGlitchRules import no_logic_rules, overworld_glitches_rules from .Regions import LTTPRegionType, location_table @@ -1181,7 +1181,7 @@ def set_trock_key_rules(world, player): forbid_item(world.get_location(location, player), 'Big Key (Turtle Rock)', player) else: # A key is required in the Big Key Chest to prevent a possible softlock. Place an extra key to ensure 100% locations still works - item = ItemFactory('Small Key (Turtle Rock)', player) + item = item_factory('Small Key (Turtle Rock)', world.worlds[player]) location = world.get_location('Turtle Rock - Big Key Chest', player) location.place_locked_item(item) location.event = True diff --git a/worlds/alttp/test/__init__.py b/worlds/alttp/test/__init__.py index 5baaa7e88e..49033a6ce3 100644 --- a/worlds/alttp/test/__init__.py +++ b/worlds/alttp/test/__init__.py @@ -14,3 +14,4 @@ class LTTPTestBase(unittest.TestCase): for name, option in AutoWorldRegister.world_types["A Link to the Past"].options_dataclass.type_hints.items(): setattr(args, name, {1: option.from_any(getattr(option, "default"))}) self.multiworld.set_options(args) + self.world = self.multiworld.worlds[1] diff --git a/worlds/alttp/test/dungeons/TestDungeon.py b/worlds/alttp/test/dungeons/TestDungeon.py index 1f8288ace0..128f8b41b7 100644 --- a/worlds/alttp/test/dungeons/TestDungeon.py +++ b/worlds/alttp/test/dungeons/TestDungeon.py @@ -2,7 +2,7 @@ from BaseClasses import CollectionState, ItemClassification from worlds.alttp.Dungeons import get_dungeon_item_pool from worlds.alttp.EntranceShuffle import mandatory_connections, connect_simple from worlds.alttp.ItemPool import difficulties -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory from worlds.alttp.Regions import create_regions from worlds.alttp.Shops import create_shops from worlds.alttp.test import LTTPTestBase @@ -24,10 +24,10 @@ class TestDungeon(LTTPTestBase): connect_simple(self.multiworld, 'Big Bomb Shop', 'Big Bomb Shop', 1) self.multiworld.get_region('Menu', 1).exits = [] self.multiworld.swamp_patch_required[1] = True - self.multiworld.worlds[1].set_rules() - self.multiworld.worlds[1].create_items() + self.world.set_rules() + self.world.create_items() self.multiworld.itempool.extend(get_dungeon_item_pool(self.multiworld)) - self.multiworld.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) + self.multiworld.itempool.extend(item_factory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], self.world)) def run_tests(self, access_pool): for exit in self.remove_exits: @@ -40,9 +40,9 @@ class TestDungeon(LTTPTestBase): if all_except and len(all_except) > 0: items = self.multiworld.itempool[:] items = [item for item in items if item.name not in all_except and not ("Bottle" in item.name and "AnyBottle" in all_except)] - items.extend(ItemFactory(item_pool[0], 1)) + items.extend(item_factory(item_pool[0], self.world)) else: - items = ItemFactory(items, 1) + items = item_factory(items, self.world) state = CollectionState(self.multiworld) state.reachable_regions[1].add(self.multiworld.get_region('Menu', 1)) for region_name in self.starting_regions: diff --git a/worlds/alttp/test/inverted/TestInverted.py b/worlds/alttp/test/inverted/TestInverted.py index f2c585e465..069639e81b 100644 --- a/worlds/alttp/test/inverted/TestInverted.py +++ b/worlds/alttp/test/inverted/TestInverted.py @@ -2,7 +2,7 @@ from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool from worlds.alttp.EntranceShuffle import link_inverted_entrances from worlds.alttp.InvertedRegions import create_inverted_regions from worlds.alttp.ItemPool import difficulties -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory from worlds.alttp.Regions import mark_light_world_regions from worlds.alttp.Shops import create_shops from test.TestBase import TestBase @@ -18,14 +18,14 @@ class TestInverted(TestBase, LTTPTestBase): self.multiworld.bombless_start[1].value = True self.multiworld.shuffle_capacity_upgrades[1].value = True create_inverted_regions(self.multiworld, 1) - self.multiworld.worlds[1].create_dungeons() + self.world.create_dungeons() create_shops(self.multiworld, 1) link_inverted_entrances(self.multiworld, 1) - self.multiworld.worlds[1].create_items() + self.world.create_items() self.multiworld.required_medallions[1] = ['Ether', 'Quake'] self.multiworld.itempool.extend(get_dungeon_item_pool(self.multiworld)) - self.multiworld.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) + self.multiworld.itempool.extend(item_factory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], self.world)) self.multiworld.get_location('Agahnim 1', 1).item = None self.multiworld.get_location('Agahnim 2', 1).item = None mark_light_world_regions(self.multiworld, 1) - self.multiworld.worlds[1].set_rules() + self.world.set_rules() diff --git a/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py b/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py index 0219332e07..21dbae6933 100644 --- a/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py +++ b/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py @@ -2,7 +2,7 @@ from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool from worlds.alttp.EntranceShuffle import link_inverted_entrances from worlds.alttp.InvertedRegions import create_inverted_regions from worlds.alttp.ItemPool import difficulties -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory from worlds.alttp.Regions import mark_light_world_regions from worlds.alttp.Shops import create_shops from test.TestBase import TestBase @@ -19,14 +19,14 @@ class TestInvertedMinor(TestBase, LTTPTestBase): self.multiworld.shuffle_capacity_upgrades[1].value = True self.multiworld.difficulty_requirements[1] = difficulties['normal'] create_inverted_regions(self.multiworld, 1) - self.multiworld.worlds[1].create_dungeons() + self.world.create_dungeons() create_shops(self.multiworld, 1) link_inverted_entrances(self.multiworld, 1) - self.multiworld.worlds[1].create_items() + self.world.create_items() self.multiworld.required_medallions[1] = ['Ether', 'Quake'] self.multiworld.itempool.extend(get_dungeon_item_pool(self.multiworld)) - self.multiworld.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) + self.multiworld.itempool.extend(item_factory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], self.world)) self.multiworld.get_location('Agahnim 1', 1).item = None self.multiworld.get_location('Agahnim 2', 1).item = None mark_light_world_regions(self.multiworld, 1) - self.multiworld.worlds[1].set_rules() + self.world.set_rules() diff --git a/worlds/alttp/test/inverted_owg/TestInvertedOWG.py b/worlds/alttp/test/inverted_owg/TestInvertedOWG.py index 849f06098a..138324a9ff 100644 --- a/worlds/alttp/test/inverted_owg/TestInvertedOWG.py +++ b/worlds/alttp/test/inverted_owg/TestInvertedOWG.py @@ -2,7 +2,7 @@ from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool from worlds.alttp.EntranceShuffle import link_inverted_entrances from worlds.alttp.InvertedRegions import create_inverted_regions from worlds.alttp.ItemPool import difficulties -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory from worlds.alttp.Regions import mark_light_world_regions from worlds.alttp.Shops import create_shops from test.TestBase import TestBase @@ -19,16 +19,16 @@ class TestInvertedOWG(TestBase, LTTPTestBase): self.multiworld.shuffle_capacity_upgrades[1].value = True self.multiworld.difficulty_requirements[1] = difficulties['normal'] create_inverted_regions(self.multiworld, 1) - self.multiworld.worlds[1].create_dungeons() + self.world.create_dungeons() create_shops(self.multiworld, 1) link_inverted_entrances(self.multiworld, 1) - self.multiworld.worlds[1].create_items() + self.world.create_items() self.multiworld.required_medallions[1] = ['Ether', 'Quake'] self.multiworld.itempool.extend(get_dungeon_item_pool(self.multiworld)) - self.multiworld.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) + self.multiworld.itempool.extend(item_factory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], self.world)) self.multiworld.get_location('Agahnim 1', 1).item = None self.multiworld.get_location('Agahnim 2', 1).item = None self.multiworld.precollected_items[1].clear() - self.multiworld.itempool.append(ItemFactory('Pegasus Boots', 1)) + self.multiworld.itempool.append(item_factory('Pegasus Boots', self.world)) mark_light_world_regions(self.multiworld, 1) - self.multiworld.worlds[1].set_rules() + self.world.set_rules() diff --git a/worlds/alttp/test/minor_glitches/TestMinor.py b/worlds/alttp/test/minor_glitches/TestMinor.py index c7de74d3a6..547509d58c 100644 --- a/worlds/alttp/test/minor_glitches/TestMinor.py +++ b/worlds/alttp/test/minor_glitches/TestMinor.py @@ -1,7 +1,7 @@ from worlds.alttp.Dungeons import get_dungeon_item_pool from worlds.alttp.InvertedRegions import mark_dark_world_regions from worlds.alttp.ItemPool import difficulties -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory from test.TestBase import TestBase from worlds.alttp.test import LTTPTestBase @@ -14,15 +14,15 @@ class TestMinor(TestBase, LTTPTestBase): self.multiworld.bombless_start[1].value = True self.multiworld.shuffle_capacity_upgrades[1].value = True self.multiworld.difficulty_requirements[1] = difficulties['normal'] - self.multiworld.worlds[1].er_seed = 0 - self.multiworld.worlds[1].create_regions() - self.multiworld.worlds[1].create_items() + self.world.er_seed = 0 + self.world.create_regions() + self.world.create_items() self.multiworld.required_medallions[1] = ['Ether', 'Quake'] self.multiworld.itempool.extend(get_dungeon_item_pool(self.multiworld)) - self.multiworld.itempool.extend(ItemFactory( + self.multiworld.itempool.extend(item_factory( ['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', - 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) + 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], self.world)) self.multiworld.get_location('Agahnim 1', 1).item = None self.multiworld.get_location('Agahnim 2', 1).item = None mark_dark_world_regions(self.multiworld, 1) - self.multiworld.worlds[1].set_rules() + self.world.set_rules() diff --git a/worlds/alttp/test/options/TestOpenPyramid.py b/worlds/alttp/test/options/TestOpenPyramid.py index 895ecb95a9..c7912c43d7 100644 --- a/worlds/alttp/test/options/TestOpenPyramid.py +++ b/worlds/alttp/test/options/TestOpenPyramid.py @@ -1,5 +1,5 @@ -from test.TestBase import WorldTestBase -from ...Items import ItemFactory +from test.bases import WorldTestBase +from ...Items import item_factory class PyramidTestBase(WorldTestBase): @@ -32,6 +32,6 @@ class GoalPyramidTest(PyramidTestBase): self.assertFalse(self.can_reach_entrance("Pyramid Hole")) self.collect_by_name(["Hammer", "Progressive Glove", "Moon Pearl"]) self.assertFalse(self.can_reach_entrance("Pyramid Hole")) - self.multiworld.state.collect(ItemFactory("Beat Agahnim 2", 1)) + self.collect(item_factory("Beat Agahnim 2", self.multiworld.worlds[1])) self.assertTrue(self.can_reach_entrance("Pyramid Hole")) diff --git a/worlds/alttp/test/owg/TestVanillaOWG.py b/worlds/alttp/test/owg/TestVanillaOWG.py index 1f8f2707ed..aafc04a77e 100644 --- a/worlds/alttp/test/owg/TestVanillaOWG.py +++ b/worlds/alttp/test/owg/TestVanillaOWG.py @@ -1,7 +1,7 @@ from worlds.alttp.Dungeons import get_dungeon_item_pool from worlds.alttp.InvertedRegions import mark_dark_world_regions from worlds.alttp.ItemPool import difficulties -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory from test.TestBase import TestBase from worlds.alttp.test import LTTPTestBase @@ -19,10 +19,10 @@ class TestVanillaOWG(TestBase, LTTPTestBase): self.multiworld.worlds[1].create_items() self.multiworld.required_medallions[1] = ['Ether', 'Quake'] self.multiworld.itempool.extend(get_dungeon_item_pool(self.multiworld)) - self.multiworld.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) + self.multiworld.itempool.extend(item_factory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], self.world)) self.multiworld.get_location('Agahnim 1', 1).item = None self.multiworld.get_location('Agahnim 2', 1).item = None self.multiworld.precollected_items[1].clear() - self.multiworld.itempool.append(ItemFactory('Pegasus Boots', 1)) + self.multiworld.itempool.append(item_factory('Pegasus Boots', self.world)) mark_dark_world_regions(self.multiworld, 1) - self.multiworld.worlds[1].set_rules() \ No newline at end of file + self.world.set_rules() diff --git a/worlds/alttp/test/vanilla/TestVanilla.py b/worlds/alttp/test/vanilla/TestVanilla.py index 3f4fbad8c2..e79b4f2ea3 100644 --- a/worlds/alttp/test/vanilla/TestVanilla.py +++ b/worlds/alttp/test/vanilla/TestVanilla.py @@ -1,7 +1,7 @@ from worlds.alttp.Dungeons import get_dungeon_item_pool from worlds.alttp.InvertedRegions import mark_dark_world_regions from worlds.alttp.ItemPool import difficulties -from worlds.alttp.Items import ItemFactory +from worlds.alttp.Items import item_factory from test.TestBase import TestBase from worlds.alttp.test import LTTPTestBase @@ -18,8 +18,8 @@ class TestVanilla(TestBase, LTTPTestBase): self.multiworld.worlds[1].create_items() self.multiworld.required_medallions[1] = ['Ether', 'Quake'] self.multiworld.itempool.extend(get_dungeon_item_pool(self.multiworld)) - self.multiworld.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) + self.multiworld.itempool.extend(item_factory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], self.world)) self.multiworld.get_location('Agahnim 1', 1).item = None self.multiworld.get_location('Agahnim 2', 1).item = None mark_dark_world_regions(self.multiworld, 1) - self.multiworld.worlds[1].set_rules() \ No newline at end of file + self.world.set_rules() From 8c11c385f36716edbc15e0e43f667f22b1754a32 Mon Sep 17 00:00:00 2001 From: Zach Parks Date: Sun, 10 Mar 2024 01:56:57 -0600 Subject: [PATCH 11/49] ALTTP: Fix NotImplemented error when using non-`none` values for `timer`. (#2924) --- worlds/alttp/ItemPool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/alttp/ItemPool.py b/worlds/alttp/ItemPool.py index 7a82d4c6be..0e799a61e6 100644 --- a/worlds/alttp/ItemPool.py +++ b/worlds/alttp/ItemPool.py @@ -234,8 +234,8 @@ def generate_itempool(world): raise NotImplementedError(f"Goal {multiworld.goal[player]} for player {player}") if multiworld.mode[player] not in ('open', 'standard', 'inverted'): raise NotImplementedError(f"Mode {multiworld.mode[player]} for player {player}") - if multiworld.timer[player] not in {False, 'display', 'timed', 'timed_ohko', 'ohko', 'timed_countdown'}: - raise NotImplementedError(f"Timer {multiworld.mode[player]} for player {player}") + if multiworld.timer[player] not in (False, 'display', 'timed', 'timed_ohko', 'ohko', 'timed_countdown'): + raise NotImplementedError(f"Timer {multiworld.timer[player]} for player {player}") if multiworld.timer[player] in ['ohko', 'timed_ohko']: multiworld.can_take_damage[player] = False From a4f89396d9a8eafe412bb5a6da7ba8506231e878 Mon Sep 17 00:00:00 2001 From: "Robyn (Reckoner)" Date: Sun, 10 Mar 2024 12:50:25 +0000 Subject: [PATCH 12/49] Docs: Fix typos in Minecraft info page (#2686) Fixed typos in game page --- worlds/minecraft/docs/en_Minecraft.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/minecraft/docs/en_Minecraft.md b/worlds/minecraft/docs/en_Minecraft.md index bfe10d8cc5..c700f59a51 100644 --- a/worlds/minecraft/docs/en_Minecraft.md +++ b/worlds/minecraft/docs/en_Minecraft.md @@ -11,9 +11,9 @@ Some recipes are locked from being able to be crafted and shuffled into the item structures appear in each dimension. Crafting recipes are re-learned when they are received from other players as item checks, and occasionally when completing your own achievements. See below for which recipes are shuffled. -## What is considered a location check in minecraft? +## What is considered a location check in Minecraft? -Location checks in are completed when the player completes various Minecraft achievements. Opening the advancements menu +Location checks are completed when the player completes various Minecraft achievements. Opening the advancements menu in-game by pressing "L" will display outstanding achievements. ## When the player receives an item, what happens? @@ -24,7 +24,7 @@ inventory directly. ## What is the victory condition? Victory is achieved when the player kills the Ender Dragon, enters the portal in The End, and completes the credits -sequence either by skipping it or watching hit play out. +sequence either by skipping it or watching it play out. ## Which recipes are locked? From 5a4d88d554b25b446169d6cf33d1bd7974fe73bd Mon Sep 17 00:00:00 2001 From: qwint Date: Sun, 10 Mar 2024 08:46:44 -0500 Subject: [PATCH 13/49] Clients: add /item_groups and /location_groups (#2822) --- CommonClient.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CommonClient.py b/CommonClient.py index c75ca3fd80..3665b9f177 100644 --- a/CommonClient.py +++ b/CommonClient.py @@ -115,6 +115,15 @@ class ClientCommandProcessor(CommandProcessor): for item_name in AutoWorldRegister.world_types[self.ctx.game].item_name_to_id: self.output(item_name) + def _cmd_item_groups(self): + """List all item group names for the currently running game.""" + if not self.ctx.game: + self.output("No game set, cannot determine existing item groups.") + return False + self.output(f"Item Group Names for {self.ctx.game}") + for group_name in AutoWorldRegister.world_types[self.ctx.game].item_name_groups: + self.output(group_name) + def _cmd_locations(self): """List all location names for the currently running game.""" if not self.ctx.game: @@ -124,6 +133,15 @@ class ClientCommandProcessor(CommandProcessor): for location_name in AutoWorldRegister.world_types[self.ctx.game].location_name_to_id: self.output(location_name) + def _cmd_location_groups(self): + """List all location group names for the currently running game.""" + if not self.ctx.game: + self.output("No game set, cannot determine existing location groups.") + return False + self.output(f"Location Group Names for {self.ctx.game}") + for group_name in AutoWorldRegister.world_types[self.ctx.game].location_name_groups: + self.output(group_name) + def _cmd_ready(self): """Send ready status to server.""" self.ctx.ready = not self.ctx.ready From 37add8ee594582f5a0f06103d152ed368d41f8a1 Mon Sep 17 00:00:00 2001 From: panicbit Date: Sun, 10 Mar 2024 14:48:00 +0100 Subject: [PATCH 14/49] LADX: shuffle instruments (#2804) * ladx: shuffle instruments * set correct default for shuffled instruments --- worlds/ladx/Options.py | 17 +++++++++++++++++ worlds/ladx/__init__.py | 13 +++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/worlds/ladx/Options.py b/worlds/ladx/Options.py index 117242208b..ec45706407 100644 --- a/worlds/ladx/Options.py +++ b/worlds/ladx/Options.py @@ -179,6 +179,22 @@ class ShuffleStoneBeaks(DungeonItemShuffle): display_name = "Shuffle Stone Beaks" ladxr_item = "STONE_BEAK" +class ShuffleInstruments(DungeonItemShuffle): + """ + Shuffle Instruments + [Original Dungeon] The item will be within its original dungeon + [Own Dungeons] The item will be within a dungeon in your world + [Own World] The item will be somewhere in your world + [Any World] The item could be anywhere + [Different World] The item will be somewhere in another world + [Vanilla] The item will be in its vanilla location in your world + """ + display_name = "Shuffle Instruments" + ladxr_item = "INSTRUMENT" + default = 100 + option_vanilla = 100 + alias_false = 100 + class Goal(Choice, LADXROption): """ The Goal of the game @@ -465,6 +481,7 @@ links_awakening_options: typing.Dict[str, typing.Type[Option]] = { 'shuffle_compasses': ShuffleCompasses, 'shuffle_stone_beaks': ShuffleStoneBeaks, 'music': Music, + 'shuffle_instruments': ShuffleInstruments, 'music_change_condition': MusicChangeCondition, 'nag_messages': NagMessages, 'ap_title_screen': APTitleScreen, diff --git a/worlds/ladx/__init__.py b/worlds/ladx/__init__.py index 6742dffd30..9de3462ad0 100644 --- a/worlds/ladx/__init__.py +++ b/worlds/ladx/__init__.py @@ -23,7 +23,7 @@ from .LADXR.settings import Settings as LADXRSettings from .LADXR.worldSetup import WorldSetup as LADXRWorldSetup from .Locations import (LinksAwakeningLocation, LinksAwakeningRegion, create_regions_from_ladxr, get_locations_to_id) -from .Options import DungeonItemShuffle, links_awakening_options +from .Options import DungeonItemShuffle, links_awakening_options, ShuffleInstruments from .Rom import LADXDeltaPatch DEVELOPER_MODE = False @@ -184,7 +184,7 @@ class LinksAwakeningWorld(World): self.pre_fill_items = [] # For any and different world, set item rule instead - for option in ["maps", "compasses", "small_keys", "nightmare_keys", "stone_beaks"]: + for option in ["maps", "compasses", "small_keys", "nightmare_keys", "stone_beaks", "instruments"]: option = "shuffle_" + option option = self.player_options[option] @@ -224,7 +224,10 @@ class LinksAwakeningWorld(World): continue if isinstance(item.item_data, DungeonItemData): - if item.item_data.dungeon_item_type == DungeonItemType.INSTRUMENT: + item_type = item.item_data.ladxr_id[:-1] + shuffle_type = dungeon_item_types[item_type] + + if item.item_data.dungeon_item_type == DungeonItemType.INSTRUMENT and shuffle_type == ShuffleInstruments.option_vanilla: # Find instrument, lock # TODO: we should be able to pinpoint the region we want, save a lookup table please found = False @@ -240,10 +243,8 @@ class LinksAwakeningWorld(World): found = True break if found: - break + break else: - item_type = item.item_data.ladxr_id[:-1] - shuffle_type = dungeon_item_types[item_type] if shuffle_type == DungeonItemShuffle.option_original_dungeon: self.prefill_original_dungeon[item.item_data.dungeon_index - 1].append(item) self.pre_fill_items.append(item) From 3602ed45a48232ea2d0ba6738636b56aaa10a8c4 Mon Sep 17 00:00:00 2001 From: Kappatechy Date: Sun, 10 Mar 2024 08:36:42 -0600 Subject: [PATCH 15/49] Bumper Stickers: logic fixes for "off-by-one" errors (#2855) * Corrected logic error. Per discussion here: https://discord.com/channels/731205301247803413/1148330200891932742/1192138309120577646 At the moment, the logic expects Treasure Bumper 2 to require 1 bumper, Treasure Bumper 3 to require 2, etc., and for Treasure Bumper 1 to be in Sphere 1. This is incorrect, each Bumper check should require 1 Bumper item of it's type. This corrects that. I've verified I was able to generate with it by editing my apworld locally, but I'm also not a programmer and don't know anything about tests. However, I'd think this is a simple change. * Correct logic in Bumper Sticker unit tests Off By One errors were rampant in the Bumper Stickers unit test logic. This should correct those errors. * Correct use of "range" function The function setting the access rules for Treasure and Booster Bumpers was stopping one short of being applied to all the related locations. This has been corrected. * Restoring and clarifying designer's original level access intent The original creator of the AP version of Bumper Stickers intentionally set the Treasure Bumper requirements to logically reach each level 1 higher than the actual game requires, and logic tests were built based on this. This design decision has now been restored. * Revert "Restoring and clarifying designer's original level access intent" This reverts commit 5186c5fcc3229a60569cdb96d774d4ccac721a06. * Correct test logic for level 5 While 33 Treasure Bumpers are generated, only 32 are needed to reach level 5. This push corrects the unit test for the level 5 checks. * Rename generically-named variables Change variables from generic names (x, y, n) to more meaningful names, for ease of readability. --------- Co-authored-by: The T --- worlds/bumpstik/__init__.py | 12 ++++----- worlds/bumpstik/test/TestLogic.py | 42 ++++++++++++++++--------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/worlds/bumpstik/__init__.py b/worlds/bumpstik/__init__.py index d93b25cda5..9fc9fc214e 100644 --- a/worlds/bumpstik/__init__.py +++ b/worlds/bumpstik/__init__.py @@ -116,12 +116,12 @@ class BumpStikWorld(World): self.multiworld.itempool += item_pool def set_rules(self): - for x in range(1, 32): - self.multiworld.get_location(f"Treasure Bumper {x + 1}", self.player).access_rule = \ - lambda state, x = x: state.has("Treasure Bumper", self.player, x) - for x in range(1, 5): - self.multiworld.get_location(f"Bonus Booster {x + 1}", self.player).access_rule = \ - lambda state, x = x: state.has("Booster Bumper", self.player, x) + for treasure_count in range(1, 33): + self.multiworld.get_location(f"Treasure Bumper {treasure_count}", self.player).access_rule = \ + lambda state, treasure_held = treasure_count: state.has("Treasure Bumper", self.player, treasure_held) + for booster_count in range(1, 6): + self.multiworld.get_location(f"Bonus Booster {booster_count}", self.player).access_rule = \ + lambda state, booster_held = booster_count: state.has("Booster Bumper", self.player, booster_held) self.multiworld.get_location("Level 5 - Cleared all Hazards", self.player).access_rule = \ lambda state: state.has("Hazard Bumper", self.player, 25) diff --git a/worlds/bumpstik/test/TestLogic.py b/worlds/bumpstik/test/TestLogic.py index e374b7b1e9..a252f1e584 100644 --- a/worlds/bumpstik/test/TestLogic.py +++ b/worlds/bumpstik/test/TestLogic.py @@ -3,36 +3,38 @@ from . import BumpStikTestBase class TestRuleLogic(BumpStikTestBase): def testLogic(self): - for x in range(1, 33): - if x == 32: + for treasure_bumpers_held in range(1, 33): + if treasure_bumpers_held == 32: self.assertFalse(self.can_reach_location("Level 5 - Cleared all Hazards")) self.collect(self.get_item_by_name("Treasure Bumper")) - if x % 8 == 0: - bb_count = round(x / 8) + if treasure_bumpers_held % 8 == 0: + bb_count = round(treasure_bumpers_held / 8) if bb_count < 4: - self.assertFalse(self.can_reach_location(f"Treasure Bumper {x + 1}")) + self.assertFalse(self.can_reach_location(f"Treasure Bumper {treasure_bumpers_held + 1}")) + # Can't reach Treasure Bumper 9 check until level 2 is unlocked, etc. + # But we don't have enough Treasure Bumpers to reach this check anyway?? elif bb_count == 4: bb_count += 1 + # Level 4 has two new Bonus Booster checks; need to check both - for y in range(self.count("Booster Bumper"), bb_count): - self.assertTrue(self.can_reach_location(f"Bonus Booster {y + 1}"), - f"BB {y + 1} check not reachable with {self.count('Booster Bumper')} BBs") - if y < 4: - self.assertFalse(self.can_reach_location(f"Bonus Booster {y + 2}"), - f"BB {y + 2} check reachable with {self.count('Treasure Bumper')} TBs") - self.collect(self.get_item_by_name("Booster Bumper")) + for booster_bumpers_held in range(self.count("Booster Bumper"), bb_count + 1): + if booster_bumpers_held > 0: + self.assertTrue(self.can_reach_location(f"Bonus Booster {booster_bumpers_held}"), + f"Bonus Booster {booster_bumpers_held} check not reachable with {self.count('Booster Bumper')} Booster Bumpers") + if booster_bumpers_held < 5: + self.assertFalse(self.can_reach_location(f"Bonus Booster {booster_bumpers_held + 1}"), + f"Bonus Booster {booster_bumpers_held + 1} check reachable with {self.count('Treasure Bumper')} Treasure Bumpers and {self.count('Booster Bumper')} Booster Bumpers") + if booster_bumpers_held < bb_count: + self.collect(self.get_item_by_name("Booster Bumper")) - if x < 31: - self.assertFalse(self.can_reach_location(f"Treasure Bumper {x + 2}")) - elif x == 31: - self.assertFalse(self.can_reach_location("Level 5 - 50,000+ Total Points")) + self.assertTrue(self.can_reach_location(f"Treasure Bumper {treasure_bumpers_held}"), + f"Treasure Bumper {treasure_bumpers_held} check not reachable with {self.count('Treasure Bumper')} Treasure Bumpers") - if x < 32: - self.assertTrue(self.can_reach_location(f"Treasure Bumper {x + 1}"), - f"TB {x + 1} check not reachable with {self.count('Treasure Bumper')} TBs") - elif x == 32: + if treasure_bumpers_held < 32: + self.assertFalse(self.can_reach_location(f"Treasure Bumper {treasure_bumpers_held + 1}")) + elif treasure_bumpers_held == 32: self.assertTrue(self.can_reach_location("Level 5 - 50,000+ Total Points")) self.assertFalse(self.can_reach_location("Level 5 - Cleared all Hazards")) self.collect(self.get_items_by_name("Hazard Bumper")) From b8c24def8d96d0dc61daba06074d393cb2511c21 Mon Sep 17 00:00:00 2001 From: Seldom <38388947+Seldom-SE@users.noreply.github.com> Date: Sun, 10 Mar 2024 08:03:44 -0700 Subject: [PATCH 16/49] Terraria: Logic fix: Witch Doctor sells Bewitching Table (#2880) --- worlds/terraria/Rules.dsv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/terraria/Rules.dsv b/worlds/terraria/Rules.dsv index 43a21b4957..38ca4e575f 100644 --- a/worlds/terraria/Rules.dsv +++ b/worlds/terraria/Rules.dsv @@ -207,7 +207,7 @@ Clothier; Npc; Dungeon; ; Skeletron; Dungeon Heist; Achievement; Dungeon; Bone; ; Dungeon | (@calamity & #Skeletron); -Bewitching Table; Minions(1); Dungeon; +Bewitching Table; Minions(1); Dungeon | (Witch Doctor & Wizard); Mechanic; ; Dungeon; Wire; ; Mechanic; Decryption Computer; Calamity; Mysterious Circuitry & Dubious Plating & Wire; From 2e1a5b0e3b0acd0559fc9e2246ad9803d5086da2 Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Sun, 10 Mar 2024 12:47:45 -0500 Subject: [PATCH 17/49] Core: create the per world random object in the world constructor (#2083) * Core: create the per world random object in the world constructor * remove the check that multiworld exists * add a deprecation warning to per_slot_randoms * move random import and fix conflicts * assert worlds don't exist before setting the multiworld seed * fix the dlcq and sdv tests * actually use the seed --- BaseClasses.py | 9 ++++----- test/general/__init__.py | 9 ++++++--- test/general/test_fill.py | 3 +-- worlds/AutoWorld.py | 3 +++ worlds/dlcquest/test/__init__.py | 3 +-- worlds/stardew_valley/test/__init__.py | 3 +-- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 2be9a9820d..446eea5b48 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -85,7 +85,7 @@ class MultiWorld(): game: Dict[int, str] random: random.Random - per_slot_randoms: Dict[int, random.Random] + per_slot_randoms: Utils.DeprecateDict[int, random.Random] """Deprecated. Please use `self.random` instead.""" class AttributeProxy(): @@ -217,7 +217,8 @@ class MultiWorld(): set_player_attr('game', "A Link to the Past") set_player_attr('completion_condition', lambda state: True) self.worlds = {} - self.per_slot_randoms = {} + self.per_slot_randoms = Utils.DeprecateDict("Using per_slot_randoms is now deprecated. Please use the " + "world's random object instead (usually self.random)") self.plando_options = PlandoOptions.none def get_all_ids(self) -> Tuple[int, ...]: @@ -251,14 +252,13 @@ class MultiWorld(): return {group_id for group_id, group in self.groups.items() if player in group["players"]} def set_seed(self, seed: Optional[int] = None, secure: bool = False, name: Optional[str] = None): + assert not self.worlds, "seed needs to be initialized before Worlds" self.seed = get_seed(seed) if secure: self.secure() else: self.random.seed(self.seed) self.seed_name = name if name else str(self.seed) - self.per_slot_randoms = {player: random.Random(self.random.getrandbits(64)) for player in - range(1, self.players + 1)} def set_options(self, args: Namespace) -> None: # TODO - remove this section once all worlds use options dataclasses @@ -275,7 +275,6 @@ class MultiWorld(): for player in self.player_ids: world_type = AutoWorld.AutoWorldRegister.world_types[self.game[player]] self.worlds[player] = world_type(self, player) - self.worlds[player].random = self.per_slot_randoms[player] options_dataclass: typing.Type[Options.PerGameCommonOptions] = world_type.options_dataclass self.worlds[player].options = options_dataclass(**{option_key: getattr(args, option_key)[player] for option_key in options_dataclass.type_hints}) diff --git a/test/general/__init__.py b/test/general/__init__.py index 5e0f22f4ec..2819628dd0 100644 --- a/test/general/__init__.py +++ b/test/general/__init__.py @@ -1,5 +1,5 @@ from argparse import Namespace -from typing import Type, Tuple +from typing import Optional, Tuple, Type from BaseClasses import MultiWorld, CollectionState from worlds.AutoWorld import call_all, World @@ -7,18 +7,21 @@ from worlds.AutoWorld import call_all, World gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill") -def setup_solo_multiworld(world_type: Type[World], steps: Tuple[str, ...] = gen_steps) -> MultiWorld: +def setup_solo_multiworld( + world_type: Type[World], steps: Tuple[str, ...] = gen_steps, seed: Optional[int] = None +) -> MultiWorld: """ Creates a multiworld with a single player of `world_type`, sets default options, and calls provided gen steps. :param world_type: Type of the world to generate a multiworld for :param steps: The gen steps that should be called on the generated multiworld before returning. Default calls steps through pre_fill + :param seed: The seed to be used when creating this multiworld """ multiworld = MultiWorld(1) multiworld.game[1] = world_type.game multiworld.player_name = {1: "Tester"} - multiworld.set_seed() + multiworld.set_seed(seed) multiworld.state = CollectionState(multiworld) args = Namespace() for name, option in world_type.options_dataclass.type_hints.items(): diff --git a/test/general/test_fill.py b/test/general/test_fill.py index 489417771d..70e9e822bf 100644 --- a/test/general/test_fill.py +++ b/test/general/test_fill.py @@ -13,6 +13,7 @@ from worlds.generic.Rules import CollectionRule, add_item_rule, locality_rules, def generate_multiworld(players: int = 1) -> MultiWorld: multiworld = MultiWorld(players) + multiworld.set_seed(0) multiworld.player_name = {} multiworld.state = CollectionState(multiworld) for i in range(players): @@ -32,8 +33,6 @@ def generate_multiworld(players: int = 1) -> MultiWorld: world.options = world.options_dataclass(**{option_key: getattr(multiworld, option_key)[player_id] for option_key in world.options_dataclass.type_hints}) - multiworld.set_seed(0) - return multiworld diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index 93e4a5c385..4d9b31d17d 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -3,6 +3,7 @@ from __future__ import annotations import hashlib import logging import pathlib +import random import re import sys import time @@ -299,6 +300,8 @@ class World(metaclass=AutoWorldRegister): assert multiworld is not None self.multiworld = multiworld self.player = player + self.random = random.Random(multiworld.random.getrandbits(64)) + multiworld.per_slot_randoms[player] = self.random def __getattr__(self, item: str) -> Any: if item == "settings": diff --git a/worlds/dlcquest/test/__init__.py b/worlds/dlcquest/test/__init__.py index e998bd8a5e..8a39b43a2c 100644 --- a/worlds/dlcquest/test/__init__.py +++ b/worlds/dlcquest/test/__init__.py @@ -37,8 +37,7 @@ def setup_dlc_quest_solo_multiworld(test_options=None, seed=None, _cache: Dict[F if frozen_options in _cache: return _cache[frozen_options] - multiworld = setup_base_solo_multiworld(DLCqworld, ()) - multiworld.set_seed(seed) + multiworld = setup_base_solo_multiworld(DLCqworld, (), seed=seed) # print(f"Seed: {multiworld.seed}") # Uncomment to print the seed for every test args = Namespace() for name, option in DLCqworld.options_dataclass.type_hints.items(): diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index ba037f7a65..948fb83b0b 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -124,8 +124,7 @@ def setup_solo_multiworld(test_options=None, seed=None, if frozen_options in _cache: return _cache[frozen_options] - multiworld = setup_base_solo_multiworld(StardewValleyWorld, ()) - multiworld.set_seed(seed) + multiworld = setup_base_solo_multiworld(StardewValleyWorld, (), seed=seed) # print(f"Seed: {multiworld.seed}") # Uncomment to print the seed for every test args = Namespace() for name, option in StardewValleyWorld.options_dataclass.type_hints.items(): From c7e735da15278e75beaa411a65844aae200f3e2e Mon Sep 17 00:00:00 2001 From: axe-y <58866768+axe-y@users.noreply.github.com> Date: Sun, 10 Mar 2024 17:12:55 -0400 Subject: [PATCH 18/49] DLCQuest: progression coin bundle update (#2785) --- worlds/dlcquest/Items.py | 96 +++++--- worlds/dlcquest/Locations.py | 11 + worlds/dlcquest/Options.py | 16 ++ worlds/dlcquest/Regions.py | 13 + worlds/dlcquest/Rules.py | 302 +++++++++++++++--------- worlds/dlcquest/__init__.py | 10 +- worlds/dlcquest/data/items.csv | 16 +- worlds/dlcquest/test/TestItemShuffle.py | 22 +- 8 files changed, 330 insertions(+), 156 deletions(-) diff --git a/worlds/dlcquest/Items.py b/worlds/dlcquest/Items.py index e7008f7b12..65b36fe617 100644 --- a/worlds/dlcquest/Items.py +++ b/worlds/dlcquest/Items.py @@ -25,6 +25,10 @@ class Group(enum.Enum): Item = enum.auto() Coin = enum.auto() Trap = enum.auto() + Twice = enum.auto() + Piece = enum.auto() + Deprecated = enum.auto() + @dataclass(frozen=True) @@ -85,49 +89,75 @@ initialize_item_table() initialize_groups() -def create_trap_items(world, World_Options: Options.DLCQuestOptions, trap_needed: int, random: Random) -> List[Item]: +def create_trap_items(world, world_options: Options.DLCQuestOptions, trap_needed: int, random: Random) -> List[Item]: traps = [] for i in range(trap_needed): trap = random.choice(items_by_group[Group.Trap]) - traps.append(world.create_item(trap)) + traps.append(world.create_item(trap, ItemClassification.trap)) return traps -def create_items(world, World_Options: Options.DLCQuestOptions, locations_count: int, random: Random): +def create_items(world, world_options: Options.DLCQuestOptions, locations_count: int, random: Random): created_items = [] - if World_Options.campaign == Options.Campaign.option_basic or World_Options.campaign == Options.Campaign.option_both: - for item in items_by_group[Group.DLCQuest]: - if item.has_any_group(Group.DLC): - created_items.append(world.create_item(item)) - if item.has_any_group(Group.Item) and World_Options.item_shuffle == Options.ItemShuffle.option_shuffled: - created_items.append(world.create_item(item)) - if World_Options.coinsanity == Options.CoinSanity.option_coin: - coin_bundle_needed = math.floor(825 / World_Options.coinbundlequantity) - for item in items_by_group[Group.DLCQuest]: - if item.has_any_group(Group.Coin): - for i in range(coin_bundle_needed): - created_items.append(world.create_item(item)) - if 825 % World_Options.coinbundlequantity != 0: - created_items.append(world.create_item(item)) + if world_options.campaign == Options.Campaign.option_basic or world_options.campaign == Options.Campaign.option_both: + create_items_basic(world_options, created_items, world) - if (World_Options.campaign == Options.Campaign.option_live_freemium_or_die or - World_Options.campaign == Options.Campaign.option_both): - for item in items_by_group[Group.Freemium]: - if item.has_any_group(Group.DLC): - created_items.append(world.create_item(item)) - if item.has_any_group(Group.Item) and World_Options.item_shuffle == Options.ItemShuffle.option_shuffled: - created_items.append(world.create_item(item)) - if World_Options.coinsanity == Options.CoinSanity.option_coin: - coin_bundle_needed = math.floor(889 / World_Options.coinbundlequantity) - for item in items_by_group[Group.Freemium]: - if item.has_any_group(Group.Coin): - for i in range(coin_bundle_needed): - created_items.append(world.create_item(item)) - if 889 % World_Options.coinbundlequantity != 0: - created_items.append(world.create_item(item)) + if (world_options.campaign == Options.Campaign.option_live_freemium_or_die or + world_options.campaign == Options.Campaign.option_both): + create_items_lfod(world_options, created_items, world) - trap_items = create_trap_items(world, World_Options, locations_count - len(created_items), random) + trap_items = create_trap_items(world, world_options, locations_count - len(created_items), random) created_items += trap_items return created_items + + +def create_items_lfod(world_options, created_items, world): + for item in items_by_group[Group.Freemium]: + if item.has_any_group(Group.DLC): + created_items.append(world.create_item(item)) + if item.has_any_group(Group.Item) and world_options.item_shuffle == Options.ItemShuffle.option_shuffled: + created_items.append(world.create_item(item)) + if item.has_any_group(Group.Twice): + created_items.append(world.create_item(item)) + if world_options.coinsanity == Options.CoinSanity.option_coin: + if world_options.coinbundlequantity == -1: + create_coin_piece(created_items, world, 889, 200, Group.Freemium) + return + create_coin(world_options, created_items, world, 889, 200, Group.Freemium) + + +def create_items_basic(world_options, created_items, world): + for item in items_by_group[Group.DLCQuest]: + if item.has_any_group(Group.DLC): + created_items.append(world.create_item(item)) + if item.has_any_group(Group.Item) and world_options.item_shuffle == Options.ItemShuffle.option_shuffled: + created_items.append(world.create_item(item)) + if item.has_any_group(Group.Twice): + created_items.append(world.create_item(item)) + if world_options.coinsanity == Options.CoinSanity.option_coin: + if world_options.coinbundlequantity == -1: + create_coin_piece(created_items, world, 825, 250, Group.DLCQuest) + return + create_coin(world_options, created_items, world, 825, 250, Group.DLCQuest) + + +def create_coin(world_options, created_items, world, total_coins, required_coins, group): + coin_bundle_required = math.ceil(required_coins / world_options.coinbundlequantity) + coin_bundle_useful = math.ceil((total_coins - coin_bundle_required * world_options.coinbundlequantity) / world_options.coinbundlequantity) + for item in items_by_group[group]: + if item.has_any_group(Group.Coin): + for i in range(coin_bundle_required): + created_items.append(world.create_item(item)) + for i in range(coin_bundle_useful): + created_items.append(world.create_item(item, ItemClassification.useful)) + + +def create_coin_piece(created_items, world, total_coins, required_coins, group): + for item in items_by_group[group]: + if item.has_any_group(Group.Piece): + for i in range(required_coins*10): + created_items.append(world.create_item(item)) + for i in range((total_coins - required_coins) * 10): + created_items.append(world.create_item(item, ItemClassification.useful)) diff --git a/worlds/dlcquest/Locations.py b/worlds/dlcquest/Locations.py index a9fdd00a20..dfc5248529 100644 --- a/worlds/dlcquest/Locations.py +++ b/worlds/dlcquest/Locations.py @@ -76,3 +76,14 @@ for i in range(1, 826): for i in range(1, 890): item_coin_freemium = f"Live Freemium or Die: {i} Coin" location_table[item_coin_freemium] = offset + 825 + 58 + i + + +offset_special = 3829200000 + +for i in range(1, 8251): + item_coin_piece = f"DLC Quest: {i} Coin Piece" + location_table[item_coin_piece] = offset_special + i + +for i in range(1, 8891): + item_coin_piece_freemium = f"Live Freemium or Die: {i} Coin Piece" + location_table[item_coin_piece_freemium] = offset_special + 8250 + i \ No newline at end of file diff --git a/worlds/dlcquest/Options.py b/worlds/dlcquest/Options.py index 769acbec15..067e349b94 100644 --- a/worlds/dlcquest/Options.py +++ b/worlds/dlcquest/Options.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +import datetime from Options import Choice, DeathLink, NamedRange, PerGameCommonOptions @@ -48,6 +49,20 @@ class CoinSanityRange(NamedRange): "normal": 20, "high": 50, } + if datetime.datetime.today().month == 4: + if datetime.datetime.today().day == 1: + special_range_names["surprise"] = -1 + else: + special_range_names["coin piece"] = -1 + + +class PermanentCoins(Choice): + """If purchasing a pack decreases your current coins amounts.""" + internal_name = "permanent_coins" + display_name = "Permanent Coins" + option_false = 0 + option_true = 1 + default = 0 class EndingChoice(Choice): @@ -83,6 +98,7 @@ class DLCQuestOptions(PerGameCommonOptions): double_jump_glitch: DoubleJumpGlitch coinsanity: CoinSanity coinbundlequantity: CoinSanityRange + permanent_coins: PermanentCoins time_is_money: TimeIsMoney ending_choice: EndingChoice campaign: Campaign diff --git a/worlds/dlcquest/Regions.py b/worlds/dlcquest/Regions.py index 6dad9fc10c..5b256afd45 100644 --- a/worlds/dlcquest/Regions.py +++ b/worlds/dlcquest/Regions.py @@ -182,9 +182,22 @@ def create_coinsanity_locations_lfod(has_coinsanity: bool, coin_bundle_size: int def create_coinsanity_locations(has_coinsanity: bool, coin_bundle_size: int, player: int, region: Region, last_coin_number: int, campaign_prefix: str): if not has_coinsanity: return + if coin_bundle_size == -1: + create_coinsanity_piece_locations(player, region, last_coin_number, campaign_prefix) + return + coin_bundle_needed = math.ceil(last_coin_number / coin_bundle_size) for i in range(1, coin_bundle_needed + 1): number_coins = min(last_coin_number, coin_bundle_size * i) item_coin = f"{campaign_prefix}: {number_coins} Coin" region.locations += [DLCQuestLocation(player, item_coin, location_table[item_coin], region)] + + +def create_coinsanity_piece_locations(player: int, region: Region, total_coin: int, campaign_prefix:str): + + pieces_needed = total_coin * 10 + for i in range(1, pieces_needed + 1): + number_piece = i + item_piece = f"{campaign_prefix}: {number_piece} Coin Piece" + region.locations += [DLCQuestLocation(player, item_piece, location_table[item_piece], region)] diff --git a/worlds/dlcquest/Rules.py b/worlds/dlcquest/Rules.py index 5792d9c3ab..3461d0633e 100644 --- a/worlds/dlcquest/Rules.py +++ b/worlds/dlcquest/Rules.py @@ -1,5 +1,4 @@ import math -import re from BaseClasses import ItemClassification from worlds.generic.Rules import add_rule, item_name_in_locations, set_rule @@ -19,23 +18,23 @@ def has_enough_coin_freemium(player: int, coin: int): return lambda state: state.prog_items[player][" coins freemium"] >= coin -def set_rules(world, player, World_Options: Options.DLCQuestOptions): - set_basic_rules(World_Options, player, world) - set_lfod_rules(World_Options, player, world) - set_completion_condition(World_Options, player, world) +def set_rules(world, player, world_options: Options.DLCQuestOptions): + set_basic_rules(world_options, player, world) + set_lfod_rules(world_options, player, world) + set_completion_condition(world_options, player, world) -def set_basic_rules(World_Options, player, world): - if World_Options.campaign == Options.Campaign.option_live_freemium_or_die: +def set_basic_rules(world_options, player, world): + if world_options.campaign == Options.Campaign.option_live_freemium_or_die: return set_basic_entrance_rules(player, world) - set_basic_self_obtained_items_rules(World_Options, player, world) - set_basic_shuffled_items_rules(World_Options, player, world) - set_double_jump_glitchless_rules(World_Options, player, world) - set_easy_double_jump_glitch_rules(World_Options, player, world) - self_basic_coinsanity_funded_purchase_rules(World_Options, player, world) - set_basic_self_funded_purchase_rules(World_Options, player, world) - self_basic_win_condition(World_Options, player, world) + set_basic_self_obtained_items_rules(world_options, player, world) + set_basic_shuffled_items_rules(world_options, player, world) + set_double_jump_glitchless_rules(world_options, player, world) + set_easy_double_jump_glitch_rules(world_options, player, world) + self_basic_coinsanity_funded_purchase_rules(world_options, player, world) + set_basic_self_funded_purchase_rules(world_options, player, world) + self_basic_win_condition(world_options, player, world) def set_basic_entrance_rules(player, world): @@ -49,13 +48,13 @@ def set_basic_entrance_rules(player, world): lambda state: state.has("Double Jump Pack", player)) -def set_basic_self_obtained_items_rules(World_Options, player, world): - if World_Options.item_shuffle != Options.ItemShuffle.option_disabled: +def set_basic_self_obtained_items_rules(world_options, player, world): + if world_options.item_shuffle != Options.ItemShuffle.option_disabled: return set_rule(world.get_entrance("Behind Ogre", player), lambda state: state.has("Gun Pack", player)) - if World_Options.time_is_money == Options.TimeIsMoney.option_required: + if world_options.time_is_money == Options.TimeIsMoney.option_required: set_rule(world.get_entrance("Tree", player), lambda state: state.has("Time is Money Pack", player)) set_rule(world.get_entrance("Cave Tree", player), @@ -70,35 +69,35 @@ def set_basic_self_obtained_items_rules(World_Options, player, world): lambda state: state.has("Time is Money Pack", player)) -def set_basic_shuffled_items_rules(World_Options, player, world): - if World_Options.item_shuffle != Options.ItemShuffle.option_shuffled: +def set_basic_shuffled_items_rules(world_options, player, world): + if world_options.item_shuffle != Options.ItemShuffle.option_shuffled: return set_rule(world.get_entrance("Behind Ogre", player), - lambda state: state.has("Gun", player)) + lambda state: state.has("DLC Quest: Progressive Weapon", player, 2)) set_rule(world.get_entrance("Tree", player), - lambda state: state.has("Sword", player) or state.has("Gun", player)) + lambda state: state.has("DLC Quest: Progressive Weapon", player)) set_rule(world.get_entrance("Cave Tree", player), - lambda state: state.has("Sword", player) or state.has("Gun", player)) + lambda state: state.has("DLC Quest: Progressive Weapon", player)) set_rule(world.get_entrance("True Double Jump", player), lambda state: state.has("Double Jump Pack", player)) set_rule(world.get_location("Shepherd Sheep", player), - lambda state: state.has("Sword", player) or state.has("Gun", player)) + lambda state: state.has("DLC Quest: Progressive Weapon", player)) set_rule(world.get_location("North West Ceiling Sheep", player), - lambda state: state.has("Sword", player) or state.has("Gun", player)) + lambda state: state.has("DLC Quest: Progressive Weapon", player)) set_rule(world.get_location("North West Alcove Sheep", player), - lambda state: state.has("Sword", player) or state.has("Gun", player)) + lambda state: state.has("DLC Quest: Progressive Weapon", player)) set_rule(world.get_location("West Cave Sheep", player), - lambda state: state.has("Sword", player) or state.has("Gun", player)) + lambda state: state.has("DLC Quest: Progressive Weapon", player)) set_rule(world.get_location("Gun", player), lambda state: state.has("Gun Pack", player)) - if World_Options.time_is_money == Options.TimeIsMoney.option_required: + if world_options.time_is_money == Options.TimeIsMoney.option_required: set_rule(world.get_location("Sword", player), lambda state: state.has("Time is Money Pack", player)) -def set_double_jump_glitchless_rules(World_Options, player, world): - if World_Options.double_jump_glitch != Options.DoubleJumpGlitch.option_none: +def set_double_jump_glitchless_rules(world_options, player, world): + if world_options.double_jump_glitch != Options.DoubleJumpGlitch.option_none: return set_rule(world.get_entrance("Cloud Double Jump", player), lambda state: state.has("Double Jump Pack", player)) @@ -106,8 +105,8 @@ def set_double_jump_glitchless_rules(World_Options, player, world): lambda state: state.has("Double Jump Pack", player)) -def set_easy_double_jump_glitch_rules(World_Options, player, world): - if World_Options.double_jump_glitch == Options.DoubleJumpGlitch.option_all: +def set_easy_double_jump_glitch_rules(world_options, player, world): + if world_options.double_jump_glitch == Options.DoubleJumpGlitch.option_all: return set_rule(world.get_entrance("Behind Tree Double Jump", player), lambda state: state.has("Double Jump Pack", player)) @@ -115,71 +114,74 @@ def set_easy_double_jump_glitch_rules(World_Options, player, world): lambda state: state.has("Double Jump Pack", player)) -def self_basic_coinsanity_funded_purchase_rules(World_Options, player, world): - if World_Options.coinsanity != Options.CoinSanity.option_coin: +def self_basic_coinsanity_funded_purchase_rules(world_options, player, world): + if world_options.coinsanity != Options.CoinSanity.option_coin: return - number_of_bundle = math.floor(825 / World_Options.coinbundlequantity) + if world_options.coinbundlequantity == -1: + self_basic_coinsanity_piece_rules(player, world) + return + number_of_bundle = math.floor(825 / world_options.coinbundlequantity) for i in range(number_of_bundle): - item_coin = f"DLC Quest: {World_Options.coinbundlequantity * (i + 1)} Coin" + item_coin = f"DLC Quest: {world_options.coinbundlequantity * (i + 1)} Coin" set_rule(world.get_location(item_coin, player), - has_enough_coin(player, World_Options.coinbundlequantity * (i + 1))) - if 825 % World_Options.coinbundlequantity != 0: + has_enough_coin(player, world_options.coinbundlequantity * (i + 1))) + if 825 % world_options.coinbundlequantity != 0: set_rule(world.get_location("DLC Quest: 825 Coin", player), has_enough_coin(player, 825)) set_rule(world.get_location("Movement Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(4 / World_Options.coinbundlequantity))) + math.ceil(4 / world_options.coinbundlequantity))) set_rule(world.get_location("Animation Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Audio Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Pause Menu Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Time is Money Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(20 / World_Options.coinbundlequantity))) + math.ceil(20 / world_options.coinbundlequantity))) set_rule(world.get_location("Double Jump Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(100 / World_Options.coinbundlequantity))) + math.ceil(100 / world_options.coinbundlequantity))) set_rule(world.get_location("Pet Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Sexy Outfits Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Top Hat Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Map Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(140 / World_Options.coinbundlequantity))) + math.ceil(140 / world_options.coinbundlequantity))) set_rule(world.get_location("Gun Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(75 / World_Options.coinbundlequantity))) + math.ceil(75 / world_options.coinbundlequantity))) set_rule(world.get_location("The Zombie Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Night Map Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(75 / World_Options.coinbundlequantity))) + math.ceil(75 / world_options.coinbundlequantity))) set_rule(world.get_location("Psychological Warfare Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(50 / World_Options.coinbundlequantity))) + math.ceil(50 / world_options.coinbundlequantity))) set_rule(world.get_location("Armor for your Horse Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(250 / World_Options.coinbundlequantity))) + math.ceil(250 / world_options.coinbundlequantity))) set_rule(world.get_location("Finish the Fight Pack", player), lambda state: state.has("DLC Quest: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) -def set_basic_self_funded_purchase_rules(World_Options, player, world): - if World_Options.coinsanity != Options.CoinSanity.option_none: +def set_basic_self_funded_purchase_rules(world_options, player, world): + if world_options.coinsanity != Options.CoinSanity.option_none: return set_rule(world.get_location("Movement Pack", player), has_enough_coin(player, 4)) @@ -215,25 +217,25 @@ def set_basic_self_funded_purchase_rules(World_Options, player, world): has_enough_coin(player, 5)) -def self_basic_win_condition(World_Options, player, world): - if World_Options.ending_choice == Options.EndingChoice.option_any: +def self_basic_win_condition(world_options, player, world): + if world_options.ending_choice == Options.EndingChoice.option_any: set_rule(world.get_location("Winning Basic", player), lambda state: state.has("Finish the Fight Pack", player)) - if World_Options.ending_choice == Options.EndingChoice.option_true: + if world_options.ending_choice == Options.EndingChoice.option_true: set_rule(world.get_location("Winning Basic", player), lambda state: state.has("Armor for your Horse Pack", player) and state.has("Finish the Fight Pack", player)) -def set_lfod_rules(World_Options, player, world): - if World_Options.campaign == Options.Campaign.option_basic: +def set_lfod_rules(world_options, player, world): + if world_options.campaign == Options.Campaign.option_basic: return set_lfod_entrance_rules(player, world) set_boss_door_requirements_rules(player, world) - set_lfod_self_obtained_items_rules(World_Options, player, world) - set_lfod_shuffled_items_rules(World_Options, player, world) - self_lfod_coinsanity_funded_purchase_rules(World_Options, player, world) - set_lfod_self_funded_purchase_rules(World_Options, has_enough_coin_freemium, player, world) + set_lfod_self_obtained_items_rules(world_options, player, world) + set_lfod_shuffled_items_rules(world_options, player, world) + self_lfod_coinsanity_funded_purchase_rules(world_options, player, world) + set_lfod_self_funded_purchase_rules(world_options, has_enough_coin_freemium, player, world) def set_lfod_entrance_rules(player, world): @@ -251,8 +253,6 @@ def set_lfod_entrance_rules(player, world): lambda state: state.has("Death of Comedy Pack", player)) set_rule(world.get_location("Story is Important", player), lambda state: state.has("DLC NPC Pack", player)) - set_rule(world.get_entrance("Pickaxe Hard Cave", player), - lambda state: state.has("Pickaxe", player)) def set_boss_door_requirements_rules(player, world): @@ -280,8 +280,8 @@ def set_boss_door_requirements_rules(player, world): set_rule(world.get_entrance("Boss Door", player), has_3_swords) -def set_lfod_self_obtained_items_rules(World_Options, player, world): - if World_Options.item_shuffle != Options.ItemShuffle.option_disabled: +def set_lfod_self_obtained_items_rules(world_options, player, world): + if world_options.item_shuffle != Options.ItemShuffle.option_disabled: return set_rule(world.get_entrance("Vines", player), lambda state: state.has("Incredibly Important Pack", player)) @@ -292,13 +292,15 @@ def set_lfod_self_obtained_items_rules(World_Options, player, world): state.has("Name Change Pack", player)) -def set_lfod_shuffled_items_rules(World_Options, player, world): - if World_Options.item_shuffle != Options.ItemShuffle.option_shuffled: +def set_lfod_shuffled_items_rules(world_options, player, world): + if world_options.item_shuffle != Options.ItemShuffle.option_shuffled: return set_rule(world.get_entrance("Vines", player), - lambda state: state.has("Wooden Sword", player) or state.has("Pickaxe", player)) + lambda state: state.has("Live Freemium or Die: Progressive Weapon", player)) set_rule(world.get_entrance("Behind Rocks", player), - lambda state: state.has("Pickaxe", player)) + lambda state: state.has("Live Freemium or Die: Progressive Weapon", player, 2)) + set_rule(world.get_entrance("Pickaxe Hard Cave", player), + lambda state: state.has("Live Freemium or Die: Progressive Weapon", player, 2)) set_rule(world.get_location("Wooden Sword", player), lambda state: state.has("Incredibly Important Pack", player)) @@ -311,83 +313,84 @@ def set_lfod_shuffled_items_rules(World_Options, player, world): lambda state: state.can_reach("Cut Content", 'region', player)) -def self_lfod_coinsanity_funded_purchase_rules(World_Options, player, world): - if World_Options.coinsanity != Options.CoinSanity.option_coin: +def self_lfod_coinsanity_funded_purchase_rules(world_options, player, world): + if world_options.coinsanity != Options.CoinSanity.option_coin: return - number_of_bundle = math.floor(889 / World_Options.coinbundlequantity) + if world_options.coinbundlequantity == -1: + self_lfod_coinsanity_piece_rules(player, world) + return + number_of_bundle = math.floor(889 / world_options.coinbundlequantity) for i in range(number_of_bundle): - item_coin_freemium = "Live Freemium or Die: number Coin" - item_coin_loc_freemium = re.sub("number", str(World_Options.coinbundlequantity * (i + 1)), - item_coin_freemium) - set_rule(world.get_location(item_coin_loc_freemium, player), - has_enough_coin_freemium(player, World_Options.coinbundlequantity * (i + 1))) - if 889 % World_Options.coinbundlequantity != 0: + item_coin_freemium = f"Live Freemium or Die: {world_options.coinbundlequantity * (i + 1)} Coin" + set_rule(world.get_location(item_coin_freemium, player), + has_enough_coin_freemium(player, world_options.coinbundlequantity * (i + 1))) + if 889 % world_options.coinbundlequantity != 0: set_rule(world.get_location("Live Freemium or Die: 889 Coin", player), has_enough_coin_freemium(player, 889)) add_rule(world.get_entrance("Boss Door", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(889 / World_Options.coinbundlequantity))) + math.ceil(200 / world_options.coinbundlequantity))) set_rule(world.get_location("Particles Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Day One Patch Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Checkpoint Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Incredibly Important Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(15 / World_Options.coinbundlequantity))) + math.ceil(15 / world_options.coinbundlequantity))) set_rule(world.get_location("Wall Jump Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(35 / World_Options.coinbundlequantity))) + math.ceil(35 / world_options.coinbundlequantity))) set_rule(world.get_location("Health Bar Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Parallax Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(5 / World_Options.coinbundlequantity))) + math.ceil(5 / world_options.coinbundlequantity))) set_rule(world.get_location("Harmless Plants Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(130 / World_Options.coinbundlequantity))) + math.ceil(130 / world_options.coinbundlequantity))) set_rule(world.get_location("Death of Comedy Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(15 / World_Options.coinbundlequantity))) + math.ceil(15 / world_options.coinbundlequantity))) set_rule(world.get_location("Canadian Dialog Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(10 / World_Options.coinbundlequantity))) + math.ceil(10 / world_options.coinbundlequantity))) set_rule(world.get_location("DLC NPC Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(15 / World_Options.coinbundlequantity))) + math.ceil(15 / world_options.coinbundlequantity))) set_rule(world.get_location("Cut Content Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(40 / World_Options.coinbundlequantity))) + math.ceil(40 / world_options.coinbundlequantity))) set_rule(world.get_location("Name Change Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(150 / World_Options.coinbundlequantity))) + math.ceil(150 / world_options.coinbundlequantity))) set_rule(world.get_location("Season Pass", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(199 / World_Options.coinbundlequantity))) + math.ceil(199 / world_options.coinbundlequantity))) set_rule(world.get_location("High Definition Next Gen Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(20 / World_Options.coinbundlequantity))) + math.ceil(20 / world_options.coinbundlequantity))) set_rule(world.get_location("Increased HP Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(10 / World_Options.coinbundlequantity))) + math.ceil(10 / world_options.coinbundlequantity))) set_rule(world.get_location("Remove Ads Pack", player), lambda state: state.has("Live Freemium or Die: Coin Bundle", player, - math.ceil(25 / World_Options.coinbundlequantity))) + math.ceil(25 / world_options.coinbundlequantity))) -def set_lfod_self_funded_purchase_rules(World_Options, has_enough_coin_freemium, player, world): - if World_Options.coinsanity != Options.CoinSanity.option_none: +def set_lfod_self_funded_purchase_rules(world_options, has_enough_coin_freemium, player, world): + if world_options.coinsanity != Options.CoinSanity.option_none: return add_rule(world.get_entrance("Boss Door", player), - has_enough_coin_freemium(player, 889)) + has_enough_coin_freemium(player, 200)) set_rule(world.get_location("Particles Pack", player), has_enough_coin_freemium(player, 5)) @@ -425,11 +428,98 @@ def set_lfod_self_funded_purchase_rules(World_Options, has_enough_coin_freemium, has_enough_coin_freemium(player, 25)) -def set_completion_condition(World_Options, player, world): - if World_Options.campaign == Options.Campaign.option_basic: +def set_completion_condition(world_options, player, world): + if world_options.campaign == Options.Campaign.option_basic: world.completion_condition[player] = lambda state: state.has("Victory Basic", player) - if World_Options.campaign == Options.Campaign.option_live_freemium_or_die: + if world_options.campaign == Options.Campaign.option_live_freemium_or_die: world.completion_condition[player] = lambda state: state.has("Victory Freemium", player) - if World_Options.campaign == Options.Campaign.option_both: + if world_options.campaign == Options.Campaign.option_both: world.completion_condition[player] = lambda state: state.has("Victory Basic", player) and state.has( "Victory Freemium", player) + + +def self_basic_coinsanity_piece_rules(player, world): + for i in range(1,8251): + + item_coin = f"DLC Quest: {i} Coin Piece" + set_rule(world.get_location(item_coin, player), + has_enough_coin(player, math.ceil(i / 10))) + + set_rule(world.get_location("Movement Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 40)) + set_rule(world.get_location("Animation Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + set_rule(world.get_location("Audio Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + set_rule(world.get_location("Pause Menu Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + set_rule(world.get_location("Time is Money Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 200)) + set_rule(world.get_location("Double Jump Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 100)) + set_rule(world.get_location("Pet Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + set_rule(world.get_location("Sexy Outfits Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + set_rule(world.get_location("Top Hat Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + set_rule(world.get_location("Map Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 1400)) + set_rule(world.get_location("Gun Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 750)) + set_rule(world.get_location("The Zombie Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + set_rule(world.get_location("Night Map Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 750)) + set_rule(world.get_location("Psychological Warfare Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 500)) + set_rule(world.get_location("Armor for your Horse Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 2500)) + set_rule(world.get_location("Finish the Fight Pack", player), + lambda state: state.has("DLC Quest: Coin Piece", player, 50)) + + +def self_lfod_coinsanity_piece_rules(player, world): + for i in range(1, 8891): + + item_coin_freemium = f"Live Freemium or Die: {i} Coin Piece" + set_rule(world.get_location(item_coin_freemium, player), + has_enough_coin_freemium(player, math.ceil(i / 10))) + + add_rule(world.get_entrance("Boss Door", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 2000)) + + set_rule(world.get_location("Particles Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50)) + set_rule(world.get_location("Day One Patch Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50)) + set_rule(world.get_location("Checkpoint Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50)) + set_rule(world.get_location("Incredibly Important Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 150)) + set_rule(world.get_location("Wall Jump Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 350)) + set_rule(world.get_location("Health Bar Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50)) + set_rule(world.get_location("Parallax Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50)) + set_rule(world.get_location("Harmless Plants Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 1300)) + set_rule(world.get_location("Death of Comedy Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 150)) + set_rule(world.get_location("Canadian Dialog Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 100)) + set_rule(world.get_location("DLC NPC Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 150)) + set_rule(world.get_location("Cut Content Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 400)) + set_rule(world.get_location("Name Change Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 1500)) + set_rule(world.get_location("Season Pass", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 199)) + set_rule(world.get_location("High Definition Next Gen Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 20)) + set_rule(world.get_location("Increased HP Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 100)) + set_rule(world.get_location("Remove Ads Pack", player), + lambda state: state.has("Live Freemium or Die: Coin Piece", player, 250)) diff --git a/worlds/dlcquest/__init__.py b/worlds/dlcquest/__init__.py index db55b1903b..2200729a32 100644 --- a/worlds/dlcquest/__init__.py +++ b/worlds/dlcquest/__init__.py @@ -1,6 +1,6 @@ from typing import Union -from BaseClasses import Tutorial, CollectionState +from BaseClasses import Tutorial, CollectionState, ItemClassification from worlds.AutoWorld import WebWorld, World from . import Options from .Items import DLCQuestItem, ItemData, create_items, item_table, items_by_group, Group @@ -82,11 +82,13 @@ class DLCqworld(World): if self.options.coinsanity == Options.CoinSanity.option_coin and self.options.coinbundlequantity >= 5: self.multiworld.push_precollected(self.create_item("Movement Pack")) - def create_item(self, item: Union[str, ItemData]) -> DLCQuestItem: + def create_item(self, item: Union[str, ItemData], classification: ItemClassification = None) -> DLCQuestItem: if isinstance(item, str): item = item_table[item] + if classification is None: + classification = item.classification - return DLCQuestItem(item.name, item.classification, item.code, self.player) + return DLCQuestItem(item.name, classification, item.code, self.player) def get_filler_item_name(self) -> str: trap = self.multiworld.random.choice(items_by_group[Group.Trap]) @@ -94,7 +96,7 @@ class DLCqworld(World): def fill_slot_data(self): options_dict = self.options.as_dict( - "death_link", "ending_choice", "campaign", "coinsanity", "item_shuffle" + "death_link", "ending_choice", "campaign", "coinsanity", "item_shuffle", "permanent_coins" ) options_dict.update({ "coinbundlerange": self.options.coinbundlequantity.value, diff --git a/worlds/dlcquest/data/items.csv b/worlds/dlcquest/data/items.csv index cc5ac0bbe4..82150254b3 100644 --- a/worlds/dlcquest/data/items.csv +++ b/worlds/dlcquest/data/items.csv @@ -27,8 +27,8 @@ id,name,classification,groups 25,Canadian Dialog Pack,filler,"DLC,Freemium" 26,DLC NPC Pack,progression,"DLC,Freemium" 27,Cut Content Pack,progression,"DLC,Freemium" -28,Name Change Pack,progression,"DLC,Freemium" -29,Pickaxe,progression,"Item,Freemium" +28,Name Change Pack,progression,"DLC,Freemium,Trap" +29,Pickaxe,progression,"Deprecated" 30,Season Pass,progression,"DLC,Freemium" 31,High Definition Next Gen Pack,filler,"DLC,Freemium" 32,Increased HP Pack,useful,"DLC,Freemium" @@ -36,13 +36,17 @@ id,name,classification,groups 34,Big Sword Pack,progression,"DLC,Freemium" 35,Really Big Sword Pack,progression,"DLC,Freemium" 36,Unfathomable Sword Pack,progression,"DLC,Freemium" -37,Gun,progression,"Item,DLCQuest" -38,Sword,progression,"Item,DLCQuest" -39,Wooden Sword,progression,"Item,Freemium" +37,Gun,progression,"Deprecated" +38,Sword,progression,"Deprecated" +39,Wooden Sword,progression,"Deprecated" 40,Box of Various Supplies,progression,"Item,Freemium" 41,Humble Indie Bindle,progression,"Item,Freemium" 42,DLC Quest: Coin Bundle,progression,"Coin,DLCQuest" 43,Live Freemium or Die: Coin Bundle,progression,"Coin,Freemium" 44,Zombie Sheep,trap,Trap 45,Temporary Spike,trap,Trap -46,Loading Screen,trap,Trap \ No newline at end of file +46,Loading Screen,trap,Trap +48,DLC Quest: Progressive Weapon,progression,"Item,Twice,DLCQuest" +49,Live Freemium or Die: Progressive Weapon,progression,"Item,Twice,Freemium" +50,DLC Quest: Coin Piece,progression,"Piece,DLCQuest" +51,Live Freemium or Die: Coin Piece,progression,"Piece,Freemium" \ No newline at end of file diff --git a/worlds/dlcquest/test/TestItemShuffle.py b/worlds/dlcquest/test/TestItemShuffle.py index bfe999246a..7a9e5d95ba 100644 --- a/worlds/dlcquest/test/TestItemShuffle.py +++ b/worlds/dlcquest/test/TestItemShuffle.py @@ -7,7 +7,10 @@ wooden_sword = "Wooden Sword" pickaxe = "Pickaxe" humble_bindle = "Humble Indie Bindle" box_supplies = "Box of Various Supplies" -items = [sword, gun, wooden_sword, pickaxe, humble_bindle, box_supplies] +locations = [sword, gun, wooden_sword, pickaxe, humble_bindle, box_supplies] +prog_weapon_basic = "DLC Quest: Progressive Weapon" +prog_weapon_lfod = "Live Freemium or Die: Progressive Weapon" +items = [prog_weapon_basic, prog_weapon_lfod, humble_bindle, box_supplies] important_pack = "Incredibly Important Pack" @@ -22,9 +25,14 @@ class TestItemShuffle(DLCQuestTestBase): with self.subTest(f"{item}"): self.assertIn(item, item_names) + def test_progressive_weapon_in_pool(self): + item_names = [item.name for item in self.multiworld.get_items()] + self.assertEqual(item_names.count(prog_weapon_basic), 2) + self.assertEqual(item_names.count(prog_weapon_lfod), 2) + def test_item_locations_in_pool(self): location_names = {location.name for location in self.multiworld.get_locations()} - for item_location in items: + for item_location in locations: with self.subTest(f"{item_location}"): self.assertIn(item_location, location_names) @@ -42,7 +50,7 @@ class TestItemShuffle(DLCQuestTestBase): movement_pack = self.multiworld.create_item("Movement Pack", self.player) self.collect(movement_pack) self.assertFalse(self.can_reach_location(gun)) - sword_item = self.multiworld.create_item(sword, self.player) + sword_item = self.multiworld.create_item(prog_weapon_basic, self.player) self.collect(sword_item) self.assertFalse(self.can_reach_location(gun)) gun_pack = self.multiworld.create_item("Gun Pack", self.player) @@ -57,7 +65,7 @@ class TestItemShuffle(DLCQuestTestBase): def test_bindle_location_has_correct_rules(self): self.assertFalse(self.can_reach_location(humble_bindle)) - wooden_sword_item = self.multiworld.create_item(wooden_sword, self.player) + wooden_sword_item = self.multiworld.create_item(prog_weapon_lfod, self.player) self.collect(wooden_sword_item) self.assertFalse(self.can_reach_location(humble_bindle)) plants_pack = self.multiworld.create_item("Harmless Plants Pack", self.player) @@ -78,7 +86,7 @@ class TestItemShuffle(DLCQuestTestBase): def test_box_supplies_location_has_correct_rules(self): self.assertFalse(self.can_reach_location(box_supplies)) - wooden_sword_item = self.multiworld.create_item(wooden_sword, self.player) + wooden_sword_item = self.multiworld.create_item(prog_weapon_lfod, self.player) self.collect(wooden_sword_item) self.assertFalse(self.can_reach_location(box_supplies)) plants_pack = self.multiworld.create_item("Harmless Plants Pack", self.player) @@ -96,7 +104,7 @@ class TestItemShuffle(DLCQuestTestBase): def test_pickaxe_location_has_correct_rules(self): self.assertFalse(self.can_reach_location(pickaxe)) - wooden_sword_item = self.multiworld.create_item(wooden_sword, self.player) + wooden_sword_item = self.multiworld.create_item(prog_weapon_lfod, self.player) self.collect(wooden_sword_item) self.assertFalse(self.can_reach_location(pickaxe)) plants_pack = self.multiworld.create_item("Harmless Plants Pack", self.player) @@ -125,6 +133,6 @@ class TestNoItemShuffle(DLCQuestTestBase): def test_item_locations_not_in_pool(self): location_names = {location.name for location in self.multiworld.get_locations()} - for item_location in items: + for item_location in locations: with self.subTest(f"{item_location}"): self.assertNotIn(item_location, location_names) \ No newline at end of file From 6badc752375630bdd1054fec6d3d89a5f90ba3ae Mon Sep 17 00:00:00 2001 From: Bryce Wilson Date: Mon, 11 Mar 2024 00:16:48 -0600 Subject: [PATCH 19/49] BizHawkClient: Fix error logging in python 3.8 (#2930) --- worlds/_bizhawk/context.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/_bizhawk/context.py b/worlds/_bizhawk/context.py index 4ee6e24f59..85e2c99097 100644 --- a/worlds/_bizhawk/context.py +++ b/worlds/_bizhawk/context.py @@ -7,7 +7,6 @@ checking or launching the client, otherwise it will probably cause circular impo import asyncio import enum import subprocess -import traceback from typing import Any, Dict, Optional from CommonClient import CommonContext, ClientCommandProcessor, get_base_parser, server_loop, logger, gui_enabled @@ -260,7 +259,7 @@ def launch() -> None: try: await watcher_task except Exception as e: - logger.error("".join(traceback.format_exception(e))) + logger.exception(e) await ctx.exit_event.wait() await ctx.shutdown() From fed3d04c8daba1f1de53adc25989493943f701ea Mon Sep 17 00:00:00 2001 From: wildham <64616385+wildham0@users.noreply.github.com> Date: Mon, 11 Mar 2024 04:51:51 -0400 Subject: [PATCH 20/49] FF1: Fix resending items on disconnect/connect (#2817) --- data/lua/connector_ff1.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/lua/connector_ff1.lua b/data/lua/connector_ff1.lua index 455b046961..afae5d3c81 100644 --- a/data/lua/connector_ff1.lua +++ b/data/lua/connector_ff1.lua @@ -322,7 +322,7 @@ function processBlock(block) end end end - if #itemsBlock ~= itemIndex then + if #itemsBlock > itemIndex then wU8(ITEM_INDEX, #itemsBlock) end From 9c920fbc53b15f7759a04021391f69d8d5082be2 Mon Sep 17 00:00:00 2001 From: chandler05 <66492208+chandler05@users.noreply.github.com> Date: Mon, 11 Mar 2024 03:55:22 -0500 Subject: [PATCH 21/49] MultiServer: Improve command response to help troubleshooting (#2833) * Update MultiServer.py * Improve logging again * Add to other log as well * Update MultiServer.py --- MultiServer.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index c2d8e4ad58..c374d6d704 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -1052,17 +1052,19 @@ def get_intended_text(input_text: str, possible_answers) -> typing.Tuple[str, bo if picks[0][1] == 100: return picks[0][0], True, "Perfect Match" elif picks[0][1] < 75: - return picks[0][0], False, f"Didn't find something that closely matches, " \ - f"did you mean {picks[0][0]}? ({picks[0][1]}% sure)" + return picks[0][0], False, f"Didn't find something that closely matches '{input_text}', " \ + f"did you mean '{picks[0][0]}'? ({picks[0][1]}% sure)" elif dif > 5: return picks[0][0], True, "Close Match" else: - return picks[0][0], False, f"Too many close matches, did you mean {picks[0][0]}? ({picks[0][1]}% sure)" + return picks[0][0], False, f"Too many close matches for '{input_text}', " \ + f"did you mean '{picks[0][0]}'? ({picks[0][1]}% sure)" else: if picks[0][1] > 90: return picks[0][0], True, "Only Option Match" else: - return picks[0][0], False, f"Did you mean {picks[0][0]}? ({picks[0][1]}% sure)" + return picks[0][0], False, f"Didn't find something that closely matches '{input_text}', " \ + f"did you mean '{picks[0][0]}'? ({picks[0][1]}% sure)" class CommandMeta(type): From 5fecb7f0433c306b8ddb4b368eb14fdbd0454e3b Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Mon, 11 Mar 2024 04:00:28 -0500 Subject: [PATCH 22/49] LTTP: fix some hashed string comparisons (#2927) --- worlds/alttp/ItemPool.py | 2 +- worlds/alttp/Options.py | 2 +- worlds/alttp/Rules.py | 2 +- worlds/alttp/__init__.py | 21 ++++++++++--------- .../TestInvertedMinor.py | 5 +++-- .../test/inverted_owg/TestInvertedOWG.py | 5 +++-- worlds/alttp/test/minor_glitches/TestMinor.py | 3 ++- worlds/alttp/test/owg/TestVanillaOWG.py | 3 ++- worlds/alttp/test/vanilla/TestVanilla.py | 3 ++- 9 files changed, 26 insertions(+), 20 deletions(-) diff --git a/worlds/alttp/ItemPool.py b/worlds/alttp/ItemPool.py index 0e799a61e6..3929342aa5 100644 --- a/worlds/alttp/ItemPool.py +++ b/worlds/alttp/ItemPool.py @@ -605,7 +605,7 @@ def get_pool_core(world, player: int): placed_items[loc] = item # provide boots to major glitch dependent seeds - if logic in {'overworld_glitches', 'hybrid_major_glitches', 'no_logic'} and world.glitch_boots[player]: + if logic.current_key in {'overworld_glitches', 'hybrid_major_glitches', 'no_logic'} and world.glitch_boots[player]: precollected_items.append('Pegasus Boots') pool.remove('Pegasus Boots') pool.append('Rupees (20)') diff --git a/worlds/alttp/Options.py b/worlds/alttp/Options.py index afd5295545..2b23dc341c 100644 --- a/worlds/alttp/Options.py +++ b/worlds/alttp/Options.py @@ -156,7 +156,7 @@ class OpenPyramid(Choice): return world.goal[player].current_key in {'crystals', 'ganon_triforce_hunt', 'local_ganon_triforce_hunt', 'ganon_pedestal'} elif self.value == self.option_auto: return world.goal[player].current_key in {'crystals', 'ganon_triforce_hunt', 'local_ganon_triforce_hunt', 'ganon_pedestal'} \ - and (world.entrance_shuffle[player] in {'vanilla', 'dungeons_simple', 'dungeons_full', 'dungeons_crossed'} or not + and (world.entrance_shuffle[player].current_key in {'vanilla', 'dungeons_simple', 'dungeons_full', 'dungeons_crossed'} or not world.shuffle_ganon) elif self.value == self.option_open: return True diff --git a/worlds/alttp/Rules.py b/worlds/alttp/Rules.py index c3156116e4..320f9fe6fd 100644 --- a/worlds/alttp/Rules.py +++ b/worlds/alttp/Rules.py @@ -89,7 +89,7 @@ def set_rules(world): if world.mode[player] != 'inverted': set_big_bomb_rules(world, player) - if world.glitches_required[player] in {'overworld_glitches', 'hybrid_major_glitches', 'no_logic'} and world.entrance_shuffle[player] not in {'insanity', 'insanity_legacy', 'madness'}: + if world.glitches_required[player].current_key in {'overworld_glitches', 'hybrid_major_glitches', 'no_logic'} and world.entrance_shuffle[player].current_key not in {'insanity', 'insanity_legacy', 'madness'}: path_to_courtyard = mirrorless_path_to_castle_courtyard(world, player) add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.multiworld.get_entrance('Dark Death Mountain Offset Mirror', player).can_reach(state) and all(rule(state) for rule in path_to_courtyard), 'or') else: diff --git a/worlds/alttp/__init__.py b/worlds/alttp/__init__.py index a7ade61c9e..63c53007d8 100644 --- a/worlds/alttp/__init__.py +++ b/worlds/alttp/__init__.py @@ -642,17 +642,18 @@ class ALTTPWorld(World): return ALttPItem(name, self.player, **item_init_table[name]) @classmethod - def stage_fill_hook(cls, world, progitempool, usefulitempool, filleritempool, fill_locations): + def stage_fill_hook(cls, multiworld, progitempool, usefulitempool, filleritempool, fill_locations): trash_counts = {} - for player in world.get_game_players("A Link to the Past"): - if not world.ganonstower_vanilla[player] or \ - world.glitches_required[player] in {'overworld_glitches', 'hybrid_major_glitches', "no_logic"}: + for player in multiworld.get_game_players("A Link to the Past"): + world = multiworld.worlds[player] + if not multiworld.ganonstower_vanilla[player] or \ + world.options.glitches_required.current_key in {'overworld_glitches', 'hybrid_major_glitches', "no_logic"}: pass - elif 'triforce_hunt' in world.goal[player].current_key and ('local' in world.goal[player].current_key or world.players == 1): - trash_counts[player] = world.random.randint(world.crystals_needed_for_gt[player] * 2, - world.crystals_needed_for_gt[player] * 4) + elif 'triforce_hunt' in world.options.goal.current_key and ('local' in world.options.goal.current_key or world.players == 1): + trash_counts[player] = multiworld.random.randint(world.options.crystals_needed_for_gt * 2, + world.options.crystals_needed_for_gt * 4) else: - trash_counts[player] = world.random.randint(0, world.crystals_needed_for_gt[player] * 2) + trash_counts[player] = multiworld.random.randint(0, world.options.crystals_needed_for_gt * 2) if trash_counts: locations_mapping = {player: [] for player in trash_counts} @@ -662,14 +663,14 @@ class ALTTPWorld(World): for player, trash_count in trash_counts.items(): gtower_locations = locations_mapping[player] - world.random.shuffle(gtower_locations) + multiworld.random.shuffle(gtower_locations) while gtower_locations and filleritempool and trash_count > 0: spot_to_fill = gtower_locations.pop() for index, item in enumerate(filleritempool): if spot_to_fill.item_rule(item): filleritempool.pop(index) # remove from outer fill - world.push_item(spot_to_fill, item, False) + multiworld.push_item(spot_to_fill, item, False) fill_locations.remove(spot_to_fill) # very slow, unfortunately trash_count -= 1 break diff --git a/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py b/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py index 21dbae6933..912cca4390 100644 --- a/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py +++ b/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py @@ -1,8 +1,9 @@ -from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool +from worlds.alttp.Dungeons import get_dungeon_item_pool from worlds.alttp.EntranceShuffle import link_inverted_entrances from worlds.alttp.InvertedRegions import create_inverted_regions from worlds.alttp.ItemPool import difficulties from worlds.alttp.Items import item_factory +from worlds.alttp.Options import GlitchesRequired from worlds.alttp.Regions import mark_light_world_regions from worlds.alttp.Shops import create_shops from test.TestBase import TestBase @@ -14,7 +15,7 @@ class TestInvertedMinor(TestBase, LTTPTestBase): def setUp(self): self.world_setup() self.multiworld.mode[1].value = 2 - self.multiworld.glitches_required[1] = "minor_glitches" + self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches") self.multiworld.bombless_start[1].value = True self.multiworld.shuffle_capacity_upgrades[1].value = True self.multiworld.difficulty_requirements[1] = difficulties['normal'] diff --git a/worlds/alttp/test/inverted_owg/TestInvertedOWG.py b/worlds/alttp/test/inverted_owg/TestInvertedOWG.py index 138324a9ff..fc38437e3e 100644 --- a/worlds/alttp/test/inverted_owg/TestInvertedOWG.py +++ b/worlds/alttp/test/inverted_owg/TestInvertedOWG.py @@ -1,8 +1,9 @@ -from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool +from worlds.alttp.Dungeons import get_dungeon_item_pool from worlds.alttp.EntranceShuffle import link_inverted_entrances from worlds.alttp.InvertedRegions import create_inverted_regions from worlds.alttp.ItemPool import difficulties from worlds.alttp.Items import item_factory +from worlds.alttp.Options import GlitchesRequired from worlds.alttp.Regions import mark_light_world_regions from worlds.alttp.Shops import create_shops from test.TestBase import TestBase @@ -13,7 +14,7 @@ from worlds.alttp.test import LTTPTestBase class TestInvertedOWG(TestBase, LTTPTestBase): def setUp(self): self.world_setup() - self.multiworld.glitches_required[1] = "overworld_glitches" + self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches") self.multiworld.mode[1].value = 2 self.multiworld.bombless_start[1].value = True self.multiworld.shuffle_capacity_upgrades[1].value = True diff --git a/worlds/alttp/test/minor_glitches/TestMinor.py b/worlds/alttp/test/minor_glitches/TestMinor.py index 547509d58c..a7b529382e 100644 --- a/worlds/alttp/test/minor_glitches/TestMinor.py +++ b/worlds/alttp/test/minor_glitches/TestMinor.py @@ -3,6 +3,7 @@ from worlds.alttp.InvertedRegions import mark_dark_world_regions from worlds.alttp.ItemPool import difficulties from worlds.alttp.Items import item_factory from test.TestBase import TestBase +from worlds.alttp.Options import GlitchesRequired from worlds.alttp.test import LTTPTestBase @@ -10,7 +11,7 @@ from worlds.alttp.test import LTTPTestBase class TestMinor(TestBase, LTTPTestBase): def setUp(self): self.world_setup() - self.multiworld.glitches_required[1] = "minor_glitches" + self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches") self.multiworld.bombless_start[1].value = True self.multiworld.shuffle_capacity_upgrades[1].value = True self.multiworld.difficulty_requirements[1] = difficulties['normal'] diff --git a/worlds/alttp/test/owg/TestVanillaOWG.py b/worlds/alttp/test/owg/TestVanillaOWG.py index aafc04a77e..3506154587 100644 --- a/worlds/alttp/test/owg/TestVanillaOWG.py +++ b/worlds/alttp/test/owg/TestVanillaOWG.py @@ -3,6 +3,7 @@ from worlds.alttp.InvertedRegions import mark_dark_world_regions from worlds.alttp.ItemPool import difficulties from worlds.alttp.Items import item_factory from test.TestBase import TestBase +from worlds.alttp.Options import GlitchesRequired from worlds.alttp.test import LTTPTestBase @@ -11,7 +12,7 @@ class TestVanillaOWG(TestBase, LTTPTestBase): def setUp(self): self.world_setup() self.multiworld.difficulty_requirements[1] = difficulties['normal'] - self.multiworld.glitches_required[1] = "overworld_glitches" + self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches") self.multiworld.bombless_start[1].value = True self.multiworld.shuffle_capacity_upgrades[1].value = True self.multiworld.worlds[1].er_seed = 0 diff --git a/worlds/alttp/test/vanilla/TestVanilla.py b/worlds/alttp/test/vanilla/TestVanilla.py index e79b4f2ea3..5865ddf987 100644 --- a/worlds/alttp/test/vanilla/TestVanilla.py +++ b/worlds/alttp/test/vanilla/TestVanilla.py @@ -3,13 +3,14 @@ from worlds.alttp.InvertedRegions import mark_dark_world_regions from worlds.alttp.ItemPool import difficulties from worlds.alttp.Items import item_factory from test.TestBase import TestBase +from worlds.alttp.Options import GlitchesRequired from worlds.alttp.test import LTTPTestBase class TestVanilla(TestBase, LTTPTestBase): def setUp(self): self.world_setup() - self.multiworld.glitches_required[1] = "no_glitches" + self.multiworld.glitches_required[1] = GlitchesRequired.from_any("no_glitches") self.multiworld.difficulty_requirements[1] = difficulties['normal'] self.multiworld.bombless_start[1].value = True self.multiworld.shuffle_capacity_upgrades[1].value = True From 078d7930734066f1766d2f35b5f595b626666c31 Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Mon, 11 Mar 2024 17:22:30 -0500 Subject: [PATCH 23/49] Tests: add test for 2-player-multiworlds (#2386) * Tests: add test for all games multiworld and test for two player multiworld per game * make assertSteps behave like call_all * review improvements * fix stage calling and loc copying in accessibility * add docstrings * lttp is on the options api now * skip the all games multiworld for now. likely needs to be modified to test specific worlds * move skip to the class --- test/general/__init__.py | 35 ++++++++++--- test/multiworld/__init__.py | 0 test/multiworld/test_multiworlds.py | 77 +++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 test/multiworld/__init__.py create mode 100644 test/multiworld/test_multiworlds.py diff --git a/test/general/__init__.py b/test/general/__init__.py index 2819628dd0..fe890e0b34 100644 --- a/test/general/__init__.py +++ b/test/general/__init__.py @@ -1,8 +1,8 @@ from argparse import Namespace -from typing import Optional, Tuple, Type +from typing import List, Optional, Tuple, Type, Union -from BaseClasses import MultiWorld, CollectionState -from worlds.AutoWorld import call_all, World +from BaseClasses import CollectionState, MultiWorld +from worlds.AutoWorld import World, call_all gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill") @@ -18,14 +18,33 @@ def setup_solo_multiworld( steps through pre_fill :param seed: The seed to be used when creating this multiworld """ - multiworld = MultiWorld(1) - multiworld.game[1] = world_type.game - multiworld.player_name = {1: "Tester"} + return setup_multiworld(world_type, steps, seed) + + +def setup_multiworld(worlds: Union[List[Type[World]], Type[World]], steps: Tuple[str, ...] = gen_steps, + seed: Optional[int] = None) -> MultiWorld: + """ + Creates a multiworld with a player for each provided world type, allowing duplicates, setting default options, and + calling the provided gen steps. + + :param worlds: type/s of worlds to generate a multiworld for + :param steps: gen steps that should be called before returning. Default calls through pre_fill + :param seed: The seed to be used when creating this multiworld + """ + if not isinstance(worlds, list): + worlds = [worlds] + players = len(worlds) + multiworld = MultiWorld(players) + multiworld.game = {player: world_type.game for player, world_type in enumerate(worlds, 1)} + multiworld.player_name = {player: f"Tester{player}" for player in multiworld.player_ids} multiworld.set_seed(seed) multiworld.state = CollectionState(multiworld) args = Namespace() - for name, option in world_type.options_dataclass.type_hints.items(): - setattr(args, name, {1: option.from_any(option.default)}) + for player, world_type in enumerate(worlds, 1): + for key, option in world_type.options_dataclass.type_hints.items(): + updated_options = getattr(args, key, {}) + updated_options[player] = option.from_any(option.default) + setattr(args, key, updated_options) multiworld.set_options(args) for step in steps: call_all(multiworld, step) diff --git a/test/multiworld/__init__.py b/test/multiworld/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/multiworld/test_multiworlds.py b/test/multiworld/test_multiworlds.py new file mode 100644 index 0000000000..677f0de829 --- /dev/null +++ b/test/multiworld/test_multiworlds.py @@ -0,0 +1,77 @@ +import unittest +from typing import List, Tuple +from unittest import TestCase + +from BaseClasses import CollectionState, Location, MultiWorld +from Fill import distribute_items_restrictive +from Options import Accessibility +from worlds.AutoWorld import AutoWorldRegister, call_all, call_single +from ..general import gen_steps, setup_multiworld + + +class MultiworldTestBase(TestCase): + multiworld: MultiWorld + + # similar to the implementation in WorldTestBase.test_fill + # but for multiple players and doesn't allow minimal accessibility + def fulfills_accessibility(self) -> bool: + """ + Checks that the multiworld satisfies locations accessibility requirements, failing if all locations are cleared + but not beatable, or some locations are unreachable. + """ + locations = [loc for loc in self.multiworld.get_locations()] + state = CollectionState(self.multiworld) + while locations: + sphere: List[Location] = [] + for n in range(len(locations) - 1, -1, -1): + if locations[n].can_reach(state): + sphere.append(locations.pop(n)) + self.assertTrue(sphere, f"Unreachable locations: {locations}") + if not sphere: + return False + for location in sphere: + if location.item: + state.collect(location.item, True, location) + return self.multiworld.has_beaten_game(state, 1) + + def assertSteps(self, steps: Tuple[str, ...]) -> None: + """Calls each step individually, continuing if a step for a specific world step fails.""" + world_types = {world.__class__ for world in self.multiworld.worlds.values()} + for step in steps: + for player, world in self.multiworld.worlds.items(): + with self.subTest(game=world.game, step=step): + call_single(self.multiworld, step, player) + for world_type in sorted(world_types, key=lambda world: world.__name__): + with self.subTest(game=world_type.game, step=f"stage_{step}"): + stage_callable = getattr(world_type, f"stage_{step}", None) + if stage_callable: + stage_callable(self.multiworld) + + +@unittest.skip("too slow for main") +class TestAllGamesMultiworld(MultiworldTestBase): + def test_fills(self) -> None: + """Tests that a multiworld with one of every registered game world can generate.""" + all_worlds = list(AutoWorldRegister.world_types.values()) + self.multiworld = setup_multiworld(all_worlds, ()) + for world in self.multiworld.worlds.values(): + world.options.accessibility.value = Accessibility.option_locations + self.assertSteps(gen_steps) + with self.subTest("filling multiworld", seed=self.multiworld.seed): + distribute_items_restrictive(self.multiworld) + call_all(self.multiworld, "post_fill") + self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game") + + +class TestTwoPlayerMulti(MultiworldTestBase): + def test_two_player_single_game_fills(self) -> None: + """Tests that a multiworld of two players for each registered game world can generate.""" + for world in AutoWorldRegister.world_types.values(): + self.multiworld = setup_multiworld([world, world], ()) + for world in self.multiworld.worlds.values(): + world.options.accessibility.value = Accessibility.option_locations + self.assertSteps(gen_steps) + with self.subTest("filling multiworld", seed=self.multiworld.seed): + distribute_items_restrictive(self.multiworld) + call_all(self.multiworld, "post_fill") + self.assertTrue(self.fulfills_accessibility(), "Collected all locations, but can't beat the game") From d20d09e68282418cba441ab0217f6a3b30d622f3 Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Mon, 11 Mar 2024 17:23:41 -0500 Subject: [PATCH 24/49] The Messenger: content update (#2823) * map option objects to a `World.options` dict * convert RoR2 to options dict system for testing * add temp behavior for lttp with notes * copy/paste bad * convert `set_default_common_options` to a namespace property * reorganize test call order * have fill_restrictive use the new options system * update world api * update soe tests * fix world api * core: auto initialize a dataclass on the World class with the option results * core: auto initialize a dataclass on the World class with the option results: small tying improvement * add `as_dict` method to the options dataclass * fix namespace issues with tests * have current option updates use `.value` instead of changing the option * update ror2 to use the new options system again * revert the junk pool dict since it's cased differently * fix begin_with_loop typo * write new and old options to spoiler * change factorio option behavior back * fix comparisons * move common and per_game_common options to new system * core: automatically create missing options_dataclass from legacy option_definitions * remove spoiler special casing and add back the Factorio option changing but in new system * give ArchipIDLE the default options_dataclass so its options get generated and spoilered properly * reimplement `inspect.get_annotations` * move option info generation for webhost to new system * need to include Common and PerGame common since __annotations__ doesn't include super * use get_type_hints for the options dictionary * typing.get_type_hints returns the bases too. * forgot to sweep through generate * sweep through all the tests * swap to a metaclass property * move remaining usages from get_type_hints to metaclass property * move remaining usages from __annotations__ to metaclass property * move remaining usages from legacy dictionaries to metaclass property * remove legacy dictionaries * cache the metaclass property * clarify inheritance in world api * move the messenger to new options system * add an assert for my dumb * update the doc * rename o to options * missed a spot * update new messenger options * comment spacing Co-authored-by: Doug Hoskisson * fix tests * fix missing import * make the documentation definition more accurate * use options system for loc creation * type cast MessengerWorld * fix typo and use quotes for cast * LTTP: set random seed in tests * ArchipIdle: remove change here as it's default on AutoWorld * Stardew: Need to set state because `set_default_common_options` used to * The Messenger: update shop rando and helpers to new system; optimize imports * Add a kwarg to `as_dict` to do the casing for you * RoR2: use new kwarg for less code * RoR2: revert some accidental reverts * The Messenger: remove an unnecessary variable * remove TypeVar that isn't used * CommonOptions not abstract * Docs: fix mistake in options api.md Co-authored-by: Doug Hoskisson * create options for item link worlds * revert accidental doc removals * Item Links: set default options on group * Messenger: Limited Movement option first draft * The Messenger: add automated setup through the launcher * drop tomllib * don't uselessly import launcher * The Messenger: fix missing goal requirement for power seal hunt * make hard mode goal harder * make fire seal a bit more lenient * have limited movement force minimal accessibility * add an early meditation option * clean up precollected notes tests a bit * add linux support * add steam deck support * await monokickstart * minor styling cleanup * more minor styling cleanup * Initial implementation of Generic ER * Move ERType to Entrance.Type, fix typing imports * updates based on testing (read: flailing) * Updates from feedback * Various bug fixes in ERCollectionState * Use deque instead of queue.Queue * Allow partial entrances in collection state earlier, doc improvements * Prevent early loops in region graph, improve reusability of ER stage code * Typos, grammar, PEP8, and style "fixes" * use RuntimeError instead of bare Exceptions * return tuples from connect since it's slightly faster for our purposes * move the shuffle to the beginning of find_pairing * do er_state placements within pairing lookups to remove code duplication * requested adjustments * Add some temporary performance logging * Use CollectionState to track available exits and placed regions * remove seal shuffle option * some cleanup stuff * portal rando progress * pre-emptive region creation * seals need to be in the datapackage * put mega shards in old order * fix typos and make it actually work * fix more missed connections and add portal events * fix all the portal rando code * finish initial logic implementation * remove/comment out debug stuff * does not actually support plando yet * typos and fix a crash when 3 available portals was selected * finish initial logic for all connections and remove/rename as necessary * fix typos and add some more leniency * move item classification determination to its own method rather than split between two spots * super complicated solution for handling installing the alpha builds * fix logic bugs and add a test * implement logic to shuffle the cutscene portals even though it's probably not possible * just use the one list * fix some issues with the mod checking/downloading * Core: have webhost slot name links go through the launcher so that components can use them * add uri support to the launcher component function * generate output file under specific conditions * cleanup connections.py * set topology_present to true when portals are shuffled * add requirement for ghost pit loc since it's pretty hard without movement * bring hard logic back * misc cleanup * fix asset grabbing of latest version * implement ER * just use the entrances for the spoiler instead of manipulating the cache * remove test defaults * remove excessive comprehension * cleanup and cater data for the client * add elemental skylands to the shuffle pools * initial attempts at hint text * use network items for offline seeds * change around the offline seed data again * move er after portal shuffle and ensure a minimal sphere 1 * Add a method to automatically disconnect entrances in a coupled-compliant way Update docs and cleanup todos * Make find_placeable_exits deterministic by sorting blocked_connections set * add more ER transitions * fix spoiler output of portal warps * add path to hint_data * rename entrance to tot to be a bit clearer * cleanup imports and update description for hard logic * cleanup for PR to main * missed a spot * cleanup monokickstart * add location_name_groups * update docs for new setup * client can reconnect on its own now, no need for a button. * fix mod download link grabbing the wrong assets * cleanup mod pulling a bit and display version it's trying to update to * plando support * comment out broken steam deck support * supports plando * satisfy flake for currently unused file * fix the items accessibility test * review comments * add searing crags portal to starting portals when disabled like option says * address sliver comments * rip out currently unused transition shuffle * add aerobatics warrior requirement to fire seal --------- Co-authored-by: el-u <109771707+el-u@users.noreply.github.com> Co-authored-by: Doug Hoskisson Co-authored-by: Doug Hoskisson Co-authored-by: Sean Dempsey Co-authored-by: qwint --- worlds/messenger/__init__.py | 272 ++++++-- worlds/messenger/client_setup.py | 164 +++++ worlds/messenger/connections.py | 725 ++++++++++++++++++++++ worlds/messenger/constants.py | 48 ++ worlds/messenger/docs/en_The Messenger.md | 4 +- worlds/messenger/docs/setup_en.md | 35 +- worlds/messenger/options.py | 75 ++- worlds/messenger/portals.py | 290 +++++++++ worlds/messenger/regions.py | 525 +++++++++++++--- worlds/messenger/rules.py | 547 +++++++++++----- worlds/messenger/subclasses.py | 76 +-- worlds/messenger/test/__init__.py | 2 +- worlds/messenger/test/test_access.py | 64 +- worlds/messenger/test/test_logic.py | 14 +- worlds/messenger/test/test_notes.py | 42 +- worlds/messenger/test/test_options.py | 35 ++ worlds/messenger/test/test_portals.py | 33 + worlds/messenger/test/test_shop.py | 19 - worlds/messenger/test/test_shop_chest.py | 17 +- 19 files changed, 2570 insertions(+), 417 deletions(-) create mode 100644 worlds/messenger/client_setup.py create mode 100644 worlds/messenger/connections.py create mode 100644 worlds/messenger/portals.py create mode 100644 worlds/messenger/test/test_options.py create mode 100644 worlds/messenger/test/test_portals.py diff --git a/worlds/messenger/__init__.py b/worlds/messenger/__init__.py index f4a28729f1..c40ca02f42 100644 --- a/worlds/messenger/__init__.py +++ b/worlds/messenger/__init__.py @@ -1,14 +1,33 @@ import logging -from typing import Any, Dict, List, Optional +from typing import Any, ClassVar, Dict, List, Optional, TextIO -from BaseClasses import CollectionState, Item, ItemClassification, Tutorial +from BaseClasses import CollectionState, Entrance, Item, ItemClassification, MultiWorld, Tutorial +from Options import Accessibility +from Utils import output_path +from settings import FilePath, Group from worlds.AutoWorld import WebWorld, World -from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS -from .options import Goal, Logic, MessengerOptions, NotesNeeded, PowerSeals -from .regions import MEGA_SHARDS, REGIONS, REGION_CONNECTIONS, SEALS +from worlds.LauncherComponents import Component, Type, components +from .client_setup import launch_game +from .connections import CONNECTIONS, RANDOMIZED_CONNECTIONS, TRANSITIONS +from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS, PROG_ITEMS, USEFUL_ITEMS +from .options import AvailablePortals, Goal, Logic, MessengerOptions, NotesNeeded, ShuffleTransitions +from .portals import PORTALS, add_closed_portal_reqs, disconnect_portals, shuffle_portals, validate_portals +from .regions import LEVELS, MEGA_SHARDS, LOCATIONS, REGION_CONNECTIONS from .rules import MessengerHardRules, MessengerOOBRules, MessengerRules -from .shop import FIGURINES, SHOP_ITEMS, shuffle_shop_prices -from .subclasses import MessengerItem, MessengerRegion +from .shop import FIGURINES, PROG_SHOP_ITEMS, SHOP_ITEMS, USEFUL_SHOP_ITEMS, shuffle_shop_prices +from .subclasses import MessengerEntrance, MessengerItem, MessengerRegion, MessengerShopLocation + +components.append( + Component("The Messenger", component_type=Type.CLIENT, func=launch_game)#, game_name="The Messenger", supports_uri=True) +) + + +class MessengerSettings(Group): + class GamePath(FilePath): + description = "The Messenger game executable" + is_exe = True + + game_path: GamePath = GamePath("TheMessenger.exe") class MessengerWeb(WebWorld): @@ -35,17 +54,10 @@ class MessengerWorld(World): adventure full of thrills, surprises, and humor. """ game = "The Messenger" - - item_name_groups = { - "Notes": set(NOTES), - "Keys": set(NOTES), - "Crest": {"Sun Crest", "Moon Crest"}, - "Phobe": set(PHOBEKINS), - "Phobekin": set(PHOBEKINS), - } - options_dataclass = MessengerOptions options: MessengerOptions + settings_key = "messenger_settings" + settings: ClassVar[MessengerSettings] base_offset = 0xADD_000 item_name_to_id = {item: item_id @@ -54,58 +66,144 @@ class MessengerWorld(World): for location_id, location in enumerate([ *ALWAYS_LOCATIONS, - *[seal for seals in SEALS.values() for seal in seals], *[shard for shards in MEGA_SHARDS.values() for shard in shards], *BOSS_LOCATIONS, *[f"The Shop - {shop_loc}" for shop_loc in SHOP_ITEMS], *FIGURINES, "Money Wrench", ], base_offset)} + item_name_groups = { + "Notes": set(NOTES), + "Keys": set(NOTES), + "Crest": {"Sun Crest", "Moon Crest"}, + "Phobe": set(PHOBEKINS), + "Phobekin": set(PHOBEKINS), + } + location_name_groups = { + "Notes": { + "Autumn Hills - Key of Hope", + "Searing Crags - Key of Strength", + "Underworld - Key of Chaos", + "Sunken Shrine - Key of Love", + "Elemental Skylands - Key of Symbiosis", + "Corrupted Future - Key of Courage", + }, + "Keys": { + "Autumn Hills - Key of Hope", + "Searing Crags - Key of Strength", + "Underworld - Key of Chaos", + "Sunken Shrine - Key of Love", + "Elemental Skylands - Key of Symbiosis", + "Corrupted Future - Key of Courage", + }, + "Phobe": { + "Catacombs - Necro", + "Bamboo Creek - Claustro", + "Searing Crags - Pyro", + "Cloud Ruins - Acro", + }, + "Phobekin": { + "Catacombs - Necro", + "Bamboo Creek - Claustro", + "Searing Crags - Pyro", + "Cloud Ruins - Acro", + }, + } - required_client_version = (0, 4, 2) + required_client_version = (0, 4, 3) web = MessengerWeb() total_seals: int = 0 required_seals: int = 0 + created_seals: int = 0 total_shards: int = 0 shop_prices: Dict[str, int] figurine_prices: Dict[str, int] _filler_items: List[str] + starting_portals: List[str] + plando_portals: List[str] + spoiler_portal_mapping: Dict[str, str] + portal_mapping: List[int] + transitions: List[Entrance] + reachable_locs: int = 0 def generate_early(self) -> None: if self.options.goal == Goal.option_power_seal_hunt: - self.options.shuffle_seals.value = PowerSeals.option_true self.total_seals = self.options.total_seals.value + if self.options.limited_movement: + self.options.accessibility.value = Accessibility.option_minimal + if self.options.logic_level < Logic.option_hard: + self.options.logic_level.value = Logic.option_hard + + if self.options.early_meditation: + self.multiworld.early_items[self.player]["Meditation"] = 1 + self.shop_prices, self.figurine_prices = shuffle_shop_prices(self) + starting_portals = ["Autumn Hills", "Howling Grotto", "Glacial Peak", "Riviere Turquoise", "Sunken Shrine", "Searing Crags"] + self.starting_portals = [f"{portal} Portal" + for portal in starting_portals[:3] + + self.random.sample(starting_portals[3:], k=self.options.available_portals - 3)] + # super complicated method for adding searing crags to starting portals if it wasn't chosen + # need to add a check for transition shuffle when that gets added back in + if not self.options.shuffle_portals and "Searing Crags Portal" not in self.starting_portals: + self.starting_portals.append("Searing Crags Portal") + if len(self.starting_portals) > 4: + portals_to_strip = [portal for portal in ["Riviere Turquoise Portal", "Sunken Shrine Portal"] + if portal in self.starting_portals] + self.starting_portals.remove(self.random.choice(portals_to_strip)) + + self.plando_portals = [] + self.portal_mapping = [] + self.spoiler_portal_mapping = {} + self.transitions = [] + def create_regions(self) -> None: # MessengerRegion adds itself to the multiworld - for region in [MessengerRegion(reg_name, self) for reg_name in REGIONS]: - if region.name in REGION_CONNECTIONS: - region.add_exits(REGION_CONNECTIONS[region.name]) + # create simple regions + simple_regions = [MessengerRegion(level, self) for level in LEVELS] + # create complex regions that have sub-regions + complex_regions = [MessengerRegion(f"{parent} - {reg_name}", self, parent) + for parent, sub_region in CONNECTIONS.items() + for reg_name in sub_region] + + for region in complex_regions: + region_name = region.name.replace(f"{region.parent} - ", "") + connection_data = CONNECTIONS[region.parent][region_name] + for exit_region in connection_data: + region.connect(self.multiworld.get_region(exit_region, self.player)) + + # all regions need to be created before i can do these connections so we create and connect the complex first + for region in [level for level in simple_regions if level.name in REGION_CONNECTIONS]: + region.add_exits(REGION_CONNECTIONS[region.name]) def create_items(self) -> None: # create items that are always in the item pool + main_movement_items = ["Rope Dart", "Wingsuit"] itempool: List[MessengerItem] = [ self.create_item(item) for item in self.item_name_to_id - if item not in - { - "Power Seal", *NOTES, *FIGURINES, + if "Time Shard" not in item and item not in { + "Power Seal", *NOTES, *FIGURINES, *main_movement_items, *{collected_item.name for collected_item in self.multiworld.precollected_items[self.player]}, - } and "Time Shard" not in item + } ] + if self.options.limited_movement: + itempool.append(self.create_item(self.random.choice(main_movement_items))) + else: + itempool += [self.create_item(move_item) for move_item in main_movement_items] + if self.options.goal == Goal.option_open_music_box: # make a list of all notes except those in the player's defined starting inventory, and adjust the # amount we need to put in the itempool and precollect based on that notes = [note for note in NOTES if note not in self.multiworld.precollected_items[self.player]] self.random.shuffle(notes) precollected_notes_amount = NotesNeeded.range_end - \ - self.options.notes_needed - \ - (len(NOTES) - len(notes)) + self.options.notes_needed - \ + (len(NOTES) - len(notes)) if precollected_notes_amount: for note in notes[:precollected_notes_amount]: self.multiworld.push_precollected(self.create_item(note)) @@ -116,26 +214,27 @@ class MessengerWorld(World): total_seals = min(len(self.multiworld.get_unfilled_locations(self.player)) - len(itempool), self.options.total_seals.value) if total_seals < self.total_seals: - logging.warning(f"Not enough locations for total seals setting " - f"({self.options.total_seals}). Adjusting to {total_seals}") + logging.warning( + f"Not enough locations for total seals setting " + f"({self.options.total_seals}). Adjusting to {total_seals}" + ) self.total_seals = total_seals self.required_seals = int(self.options.percent_seals_required.value / 100 * self.total_seals) seals = [self.create_item("Power Seal") for _ in range(self.total_seals)] - for i in range(self.required_seals): - seals[i].classification = ItemClassification.progression_skip_balancing itempool += seals + self.multiworld.itempool += itempool remaining_fill = len(self.multiworld.get_unfilled_locations(self.player)) - len(itempool) if remaining_fill < 10: self._filler_items = self.random.choices( - list(FILLER)[2:], - weights=list(FILLER.values())[2:], - k=remaining_fill + list(FILLER)[2:], + weights=list(FILLER.values())[2:], + k=remaining_fill ) - itempool += [self.create_filler() for _ in range(remaining_fill)] + filler = [self.create_filler() for _ in range(remaining_fill)] - self.multiworld.itempool += itempool + self.multiworld.itempool += filler def set_rules(self) -> None: logic = self.options.logic_level @@ -144,16 +243,59 @@ class MessengerWorld(World): elif logic == Logic.option_hard: MessengerHardRules(self).set_messenger_rules() else: - MessengerOOBRules(self).set_messenger_rules() + raise ValueError(f"Somehow you have a logic option that's currently invalid." + f" {logic} for {self.multiworld.get_player_name(self.player)}") + # MessengerOOBRules(self).set_messenger_rules() + + add_closed_portal_reqs(self) + # i need portal shuffle to happen after rules exist so i can validate it + attempts = 5 + if self.options.shuffle_portals: + self.portal_mapping = [] + self.spoiler_portal_mapping = {} + for _ in range(attempts): + disconnect_portals(self) + shuffle_portals(self) + if validate_portals(self): + break + # failsafe mostly for invalid plandoed portals with no transition shuffle + else: + raise RuntimeError("Unable to generate valid portal output.") + + def write_spoiler_header(self, spoiler_handle: TextIO) -> None: + if self.options.available_portals < 6: + spoiler_handle.write(f"\nStarting Portals:\n\n") + for portal in self.starting_portals: + spoiler_handle.write(f"{portal}\n") + + spoiler = self.multiworld.spoiler + + if self.options.shuffle_portals: + # sort the portals as they appear left to right in-game + portal_info = sorted( + self.spoiler_portal_mapping.items(), + key=lambda portal: + ["Autumn Hills", "Riviere Turquoise", + "Howling Grotto", "Sunken Shrine", + "Searing Crags", "Glacial Peak"].index(portal[0])) + for portal, output in portal_info: + spoiler.set_entrance(f"{portal} Portal", output, "I can write anything I want here lmao", self.player) def fill_slot_data(self) -> Dict[str, Any]: - return { + slot_data = { "shop": {SHOP_ITEMS[item].internal_name: price for item, price in self.shop_prices.items()}, "figures": {FIGURINES[item].internal_name: price for item, price in self.figurine_prices.items()}, "max_price": self.total_shards, "required_seals": self.required_seals, + "starting_portals": self.starting_portals, + "portal_exits": self.portal_mapping, + "transitions": [[TRANSITIONS.index("Corrupted Future") if transition.name == "Artificer's Portal" + else TRANSITIONS.index(RANDOMIZED_CONNECTIONS[transition.parent_region.name]), + TRANSITIONS.index(transition.connected_region.name)] + for transition in self.transitions], **self.options.as_dict("music_box", "death_link", "logic_level"), } + return slot_data def get_filler_item_name(self) -> str: if not getattr(self, "_filler_items", None): @@ -166,15 +308,35 @@ class MessengerWorld(World): def create_item(self, name: str) -> MessengerItem: item_id: Optional[int] = self.item_name_to_id.get(name, None) - override_prog = getattr(self, "multiworld") is not None and \ - name in {"Windmill Shuriken"} and \ - self.options.logic_level > Logic.option_normal - count = 0 + return MessengerItem( + name, + ItemClassification.progression if item_id is None else self.get_item_classification(name), + item_id, + self.player + ) + + def get_item_classification(self, name: str) -> ItemClassification: if "Time Shard " in name: count = int(name.strip("Time Shard ()")) count = count if count >= 100 else 0 self.total_shards += count - return MessengerItem(name, self.player, item_id, override_prog, count) + return ItemClassification.progression_skip_balancing if count else ItemClassification.filler + + if name == "Windmill Shuriken" and getattr(self, "multiworld", None) is not None: + return ItemClassification.progression if self.options.logic_level else ItemClassification.filler + + if name == "Power Seal": + self.created_seals += 1 + return ItemClassification.progression_skip_balancing \ + if self.required_seals >= self.created_seals else ItemClassification.filler + + if name in {*NOTES, *PROG_ITEMS, *PHOBEKINS, *PROG_SHOP_ITEMS}: + return ItemClassification.progression + + if name in {*USEFUL_ITEMS, *USEFUL_SHOP_ITEMS}: + return ItemClassification.useful + + return ItemClassification.filler def collect(self, state: "CollectionState", item: "Item") -> bool: change = super().collect(state, item) @@ -187,3 +349,25 @@ class MessengerWorld(World): if change and "Time Shard" in item.name: state.prog_items[self.player]["Shards"] -= int(item.name.strip("Time Shard ()")) return change + + @classmethod + def stage_generate_output(cls, multiworld: MultiWorld, output_directory: str) -> None: + # using stage_generate_output because it doesn't increase the logged player count for players without output + # only generate output if there's a single player + if multiworld.players > 1: + return + # the messenger client calls into AP with specific args, so check the out path matches what the client sends + out_path = output_path(multiworld.get_out_file_name_base(1) + ".aptm") + if "The Messenger\\Archipelago\\output" not in out_path: + return + import orjson + data = { + "name": multiworld.get_player_name(1), + "slot_data": multiworld.worlds[1].fill_slot_data(), + "loc_data": {loc.address: {loc.item.name: [loc.item.code, loc.item.flags]} + for loc in multiworld.get_filled_locations() if loc.address}, + } + + output = orjson.dumps(data, option=orjson.OPT_NON_STR_KEYS) + with open(out_path, "wb") as f: + f.write(output) diff --git a/worlds/messenger/client_setup.py b/worlds/messenger/client_setup.py new file mode 100644 index 0000000000..9fd08e52d8 --- /dev/null +++ b/worlds/messenger/client_setup.py @@ -0,0 +1,164 @@ +import io +import logging +import os.path +import subprocess +import urllib.request +from shutil import which +from tkinter.messagebox import askyesnocancel +from typing import Any, Optional +from zipfile import ZipFile +from Utils import open_file + +import requests + +from Utils import is_windows, messagebox, tuplize_version + + +MOD_URL = "https://api.github.com/repos/alwaysintreble/TheMessengerRandomizerModAP/releases/latest" + + +def launch_game(url: Optional[str] = None) -> None: + """Check the game installation, then launch it""" + def courier_installed() -> bool: + """Check if Courier is installed""" + return os.path.exists(os.path.join(game_folder, "TheMessenger_Data", "Managed", "Assembly-CSharp.Courier.mm.dll")) + + def mod_installed() -> bool: + """Check if the mod is installed""" + return os.path.exists(os.path.join(game_folder, "Mods", "TheMessengerRandomizerAP", "courier.toml")) + + def request_data(request_url: str) -> Any: + """Fetches json response from given url""" + logging.info(f"requesting {request_url}") + response = requests.get(request_url) + if response.status_code == 200: # success + try: + data = response.json() + except requests.exceptions.JSONDecodeError: + raise RuntimeError(f"Unable to fetch data. (status code {response.status_code})") + else: + raise RuntimeError(f"Unable to fetch data. (status code {response.status_code})") + return data + + def install_courier() -> None: + """Installs latest version of Courier""" + # can't use latest since courier uses pre-release tags + courier_url = "https://api.github.com/repos/Brokemia/Courier/releases" + latest_download = request_data(courier_url)[0]["assets"][-1]["browser_download_url"] + + with urllib.request.urlopen(latest_download) as download: + with ZipFile(io.BytesIO(download.read()), "r") as zf: + for member in zf.infolist(): + zf.extract(member, path=game_folder) + + os.chdir(game_folder) + # linux and mac handling + if not is_windows: + mono_exe = which("mono") + if not mono_exe: + # steam deck support but doesn't currently work + messagebox("Failure", "Failed to install Courier", True) + raise RuntimeError("Failed to install Courier") + # # download and use mono kickstart + # # this allows steam deck support + # mono_kick_url = "https://github.com/flibitijibibo/MonoKickstart/archive/refs/heads/master.zip" + # target = os.path.join(folder, "monoKickstart") + # os.makedirs(target, exist_ok=True) + # with urllib.request.urlopen(mono_kick_url) as download: + # with ZipFile(io.BytesIO(download.read()), "r") as zf: + # for member in zf.infolist(): + # zf.extract(member, path=target) + # installer = subprocess.Popen([os.path.join(target, "precompiled"), + # os.path.join(folder, "MiniInstaller.exe")], shell=False) + # os.remove(target) + else: + installer = subprocess.Popen([mono_exe, os.path.join(game_folder, "MiniInstaller.exe")], shell=False) + else: + installer = subprocess.Popen(os.path.join(game_folder, "MiniInstaller.exe"), shell=False) + + failure = installer.wait() + if failure: + messagebox("Failure", "Failed to install Courier", True) + os.chdir(working_directory) + raise RuntimeError("Failed to install Courier") + os.chdir(working_directory) + + if courier_installed(): + messagebox("Success!", "Courier successfully installed!") + return + messagebox("Failure", "Failed to install Courier", True) + raise RuntimeError("Failed to install Courier") + + def install_mod() -> None: + """Installs latest version of the mod""" + assets = request_data(MOD_URL)["assets"] + if len(assets) == 1: + release_url = assets[0]["browser_download_url"] + else: + for asset in assets: + if "TheMessengerRandomizerAP" in asset["name"]: + release_url = asset["browser_download_url"] + break + else: + messagebox("Failure", "Failed to find latest mod download", True) + raise RuntimeError("Failed to install Mod") + + mod_folder = os.path.join(game_folder, "Mods") + os.makedirs(mod_folder, exist_ok=True) + with urllib.request.urlopen(release_url) as download: + with ZipFile(io.BytesIO(download.read()), "r") as zf: + for member in zf.infolist(): + zf.extract(member, path=mod_folder) + + messagebox("Success!", "Latest mod successfully installed!") + + def available_mod_update(latest_version: str) -> bool: + """Check if there's an available update""" + latest_version = latest_version.lstrip("v") + toml_path = os.path.join(game_folder, "Mods", "TheMessengerRandomizerAP", "courier.toml") + with open(toml_path, "r") as f: + installed_version = f.read().splitlines()[1].strip("version = \"") + + logging.info(f"Installed version: {installed_version}. Latest version: {latest_version}") + # one of the alpha builds + return "alpha" in latest_version or tuplize_version(latest_version) > tuplize_version(installed_version) + + from . import MessengerWorld + game_folder = os.path.dirname(MessengerWorld.settings.game_path) + working_directory = os.getcwd() + if not courier_installed(): + should_install = askyesnocancel("Install Courier", + "No Courier installation detected. Would you like to install now?") + if not should_install: + return + logging.info("Installing Courier") + install_courier() + if not mod_installed(): + should_install = askyesnocancel("Install Mod", + "No randomizer mod detected. Would you like to install now?") + if not should_install: + return + logging.info("Installing Mod") + install_mod() + else: + latest = request_data(MOD_URL)["tag_name"] + if available_mod_update(latest): + should_update = askyesnocancel("Update Mod", + f"New mod version detected. Would you like to update to {latest} now?") + if should_update: + logging.info("Updating mod") + install_mod() + elif should_update is None: + return + if not is_windows: + if url: + open_file(f"steam://rungameid/764790//{url}/") + else: + open_file("steam://rungameid/764790") + else: + os.chdir(game_folder) + if url: + subprocess.Popen([MessengerWorld.settings.game_path, str(url)]) + else: + subprocess.Popen(MessengerWorld.settings.game_path) + os.chdir(working_directory) diff --git a/worlds/messenger/connections.py b/worlds/messenger/connections.py new file mode 100644 index 0000000000..5e1871e287 --- /dev/null +++ b/worlds/messenger/connections.py @@ -0,0 +1,725 @@ +from typing import Dict, List + +CONNECTIONS: Dict[str, Dict[str, List[str]]] = { + "Ninja Village": { + "Right": [ + "Autumn Hills - Left", + "Ninja Village - Nest", + ], + "Nest": [ + "Ninja Village - Right", + ], + }, + "Autumn Hills": { + "Left": [ + "Ninja Village - Right", + "Autumn Hills - Climbing Claws Shop", + ], + "Right": [ + "Forlorn Temple - Left", + "Autumn Hills - Leaf Golem Shop", + ], + "Bottom": [ + "Catacombs - Bottom Left", + "Autumn Hills - Double Swing Checkpoint", + ], + "Portal": [ + "Tower HQ", + "Autumn Hills - Dimension Climb Shop", + ], + "Climbing Claws Shop": [ + "Autumn Hills - Left", + "Autumn Hills - Hope Path Shop", + "Autumn Hills - Lakeside Checkpoint", + "Autumn Hills - Key of Hope Checkpoint", + ], + "Hope Path Shop": [ + "Autumn Hills - Climbing Claws Shop", + "Autumn Hills - Hope Latch Checkpoint", + "Autumn Hills - Lakeside Checkpoint", + ], + "Dimension Climb Shop": [ + "Autumn Hills - Lakeside Checkpoint", + "Autumn Hills - Portal", + "Autumn Hills - Double Swing Checkpoint", + ], + "Leaf Golem Shop": [ + "Autumn Hills - Spike Ball Swing Checkpoint", + "Autumn Hills - Right", + ], + "Hope Latch Checkpoint": [ + "Autumn Hills - Hope Path Shop", + "Autumn Hills - Key of Hope Checkpoint", + ], + "Key of Hope Checkpoint": [ + "Autumn Hills - Hope Latch Checkpoint", + "Autumn Hills - Lakeside Checkpoint", + ], + "Lakeside Checkpoint": [ + "Autumn Hills - Climbing Claws Shop", + "Autumn Hills - Dimension Climb Shop", + ], + "Double Swing Checkpoint": [ + "Autumn Hills - Dimension Climb Shop", + "Autumn Hills - Spike Ball Swing Checkpoint", + "Autumn Hills - Bottom", + ], + "Spike Ball Swing Checkpoint": [ + "Autumn Hills - Double Swing Checkpoint", + "Autumn Hills - Leaf Golem Shop", + ], + }, + "Forlorn Temple": { + "Left": [ + "Autumn Hills - Right", + "Forlorn Temple - Outside Shop", + ], + "Right": [ + "Bamboo Creek - Top Left", + "Forlorn Temple - Demon King Shop", + ], + "Bottom": [ + "Catacombs - Top Left", + "Forlorn Temple - Outside Shop", + ], + "Outside Shop": [ + "Forlorn Temple - Left", + "Forlorn Temple - Bottom", + "Forlorn Temple - Entrance Shop", + ], + "Entrance Shop": [ + "Forlorn Temple - Outside Shop", + "Forlorn Temple - Sunny Day Checkpoint", + ], + "Climb Shop": [ + "Forlorn Temple - Rocket Maze Checkpoint", + "Forlorn Temple - Rocket Sunset Shop", + ], + "Rocket Sunset Shop": [ + "Forlorn Temple - Climb Shop", + "Forlorn Temple - Descent Shop", + ], + "Descent Shop": [ + "Forlorn Temple - Rocket Sunset Shop", + "Forlorn Temple - Saw Gauntlet Shop", + ], + "Saw Gauntlet Shop": [ + "Forlorn Temple - Demon King Shop", + ], + "Demon King Shop": [ + "Forlorn Temple - Saw Gauntlet Shop", + "Forlorn Temple - Right", + ], + "Sunny Day Checkpoint": [ + "Forlorn Temple - Rocket Maze Checkpoint", + ], + "Rocket Maze Checkpoint": [ + "Forlorn Temple - Sunny Day Checkpoint", + "Forlorn Temple - Climb Shop", + ], + }, + "Catacombs": { + "Top Left": [ + "Forlorn Temple - Bottom", + "Catacombs - Triple Spike Crushers Shop", + ], + "Bottom Left": [ + "Autumn Hills - Bottom", + "Catacombs - Triple Spike Crushers Shop", + "Catacombs - Death Trap Checkpoint", + ], + "Bottom": [ + "Dark Cave - Right", + "Catacombs - Dirty Pond Checkpoint", + ], + "Right": [ + "Bamboo Creek - Bottom Left", + "Catacombs - Ruxxtin Shop", + ], + "Triple Spike Crushers Shop": [ + "Catacombs - Bottom Left", + "Catacombs - Death Trap Checkpoint", + ], + "Ruxxtin Shop": [ + "Catacombs - Right", + "Catacombs - Dirty Pond Checkpoint", + ], + "Death Trap Checkpoint": [ + "Catacombs - Triple Spike Crushers Shop", + "Catacombs - Bottom Left", + "Catacombs - Dirty Pond Checkpoint", + ], + "Crusher Gauntlet Checkpoint": [ + "Catacombs - Dirty Pond Checkpoint", + ], + "Dirty Pond Checkpoint": [ + "Catacombs - Bottom", + "Catacombs - Death Trap Checkpoint", + "Catacombs - Crusher Gauntlet Checkpoint", + "Catacombs - Ruxxtin Shop", + ], + }, + "Bamboo Creek": { + "Bottom Left": [ + "Catacombs - Right", + "Bamboo Creek - Spike Crushers Shop", + ], + "Top Left": [ + "Bamboo Creek - Abandoned Shop", + "Forlorn Temple - Right", + ], + "Right": [ + "Howling Grotto - Left", + "Bamboo Creek - Time Loop Shop", + ], + "Spike Crushers Shop": [ + "Bamboo Creek - Bottom Left", + "Bamboo Creek - Abandoned Shop", + ], + "Abandoned Shop": [ + "Bamboo Creek - Spike Crushers Shop", + "Bamboo Creek - Spike Doors Checkpoint", + ], + "Time Loop Shop": [ + "Bamboo Creek - Right", + "Bamboo Creek - Spike Doors Checkpoint", + ], + "Spike Ball Pits Checkpoint": [ + "Bamboo Creek - Spike Doors Checkpoint", + ], + "Spike Doors Checkpoint": [ + "Bamboo Creek - Abandoned Shop", + "Bamboo Creek - Spike Ball Pits Checkpoint", + "Bamboo Creek - Time Loop Shop", + ], + }, + "Howling Grotto": { + "Left": [ + "Bamboo Creek - Right", + "Howling Grotto - Wingsuit Shop", + ], + "Top": [ + "Howling Grotto - Crushing Pits Shop", + "Quillshroom Marsh - Bottom Left", + ], + "Right": [ + "Howling Grotto - Emerald Golem Shop", + "Quillshroom Marsh - Top Left", + ], + "Bottom": [ + "Howling Grotto - Lost Woods Checkpoint", + "Sunken Shrine - Left", + ], + "Portal": [ + "Howling Grotto - Crushing Pits Shop", + "Tower HQ", + ], + "Wingsuit Shop": [ + "Howling Grotto - Left", + "Howling Grotto - Lost Woods Checkpoint", + ], + "Crushing Pits Shop": [ + "Howling Grotto - Lost Woods Checkpoint", + "Howling Grotto - Portal", + "Howling Grotto - Breezy Crushers Checkpoint", + "Howling Grotto - Top", + ], + "Emerald Golem Shop": [ + "Howling Grotto - Breezy Crushers Checkpoint", + "Howling Grotto - Right", + ], + "Lost Woods Checkpoint": [ + "Howling Grotto - Wingsuit Shop", + "Howling Grotto - Crushing Pits Shop", + "Howling Grotto - Bottom", + ], + "Breezy Crushers Checkpoint": [ + "Howling Grotto - Crushing Pits Shop", + "Howling Grotto - Emerald Golem Shop", + ], + }, + "Quillshroom Marsh": { + "Top Left": [ + "Howling Grotto - Right", + "Quillshroom Marsh - Seashell Checkpoint", + "Quillshroom Marsh - Spikey Window Shop", + ], + "Bottom Left": [ + "Howling Grotto - Top", + "Quillshroom Marsh - Sand Trap Shop", + "Quillshroom Marsh - Bottom Right", + ], + "Top Right": [ + "Quillshroom Marsh - Queen of Quills Shop", + "Searing Crags - Left", + ], + "Bottom Right": [ + "Quillshroom Marsh - Bottom Left", + "Quillshroom Marsh - Sand Trap Shop", + "Searing Crags - Bottom", + ], + "Spikey Window Shop": [ + "Quillshroom Marsh - Top Left", + "Quillshroom Marsh - Seashell Checkpoint", + "Quillshroom Marsh - Quicksand Checkpoint", + ], + "Sand Trap Shop": [ + "Quillshroom Marsh - Quicksand Checkpoint", + "Quillshroom Marsh - Bottom Left", + "Quillshroom Marsh - Bottom Right", + "Quillshroom Marsh - Spike Wave Checkpoint", + ], + "Queen of Quills Shop": [ + "Quillshroom Marsh - Spike Wave Checkpoint", + "Quillshroom Marsh - Top Right", + ], + "Seashell Checkpoint": [ + "Quillshroom Marsh - Top Left", + "Quillshroom Marsh - Spikey Window Shop", + ], + "Quicksand Checkpoint": [ + "Quillshroom Marsh - Spikey Window Shop", + "Quillshroom Marsh - Sand Trap Shop", + ], + "Spike Wave Checkpoint": [ + "Quillshroom Marsh - Sand Trap Shop", + "Quillshroom Marsh - Queen of Quills Shop", + ], + }, + "Searing Crags": { + "Left": [ + "Quillshroom Marsh - Top Right", + "Searing Crags - Rope Dart Shop", + ], + "Top": [ + "Searing Crags - Colossuses Shop", + "Glacial Peak - Bottom", + ], + "Bottom": [ + "Searing Crags - Portal", + "Quillshroom Marsh - Bottom Right", + ], + "Right": [ + "Searing Crags - Portal", + "Underworld - Left", + ], + "Portal": [ + "Searing Crags - Bottom", + "Searing Crags - Right", + "Searing Crags - Before Final Climb Shop", + "Searing Crags - Colossuses Shop", + "Tower HQ", + ], + "Rope Dart Shop": [ + "Searing Crags - Left", + "Searing Crags - Triple Ball Spinner Checkpoint", + ], + "Falling Rocks Shop": [ + "Searing Crags - Triple Ball Spinner Checkpoint", + "Searing Crags - Searing Mega Shard Shop", + ], + "Searing Mega Shard Shop": [ + "Searing Crags - Falling Rocks Shop", + "Searing Crags - Before Final Climb Shop", + "Searing Crags - Key of Strength Shop", + ], + "Before Final Climb Shop": [ + "Searing Crags - Raining Rocks Checkpoint", + "Searing Crags - Portal", + "Searing Crags - Colossuses Shop", + ], + "Colossuses Shop": [ + "Searing Crags - Before Final Climb Shop", + "Searing Crags - Key of Strength Shop", + "Searing Crags - Portal", + "Searing Crags - Top", + ], + "Key of Strength Shop": [ + "Searing Crags - Searing Mega Shard Shop", + ], + "Triple Ball Spinner Checkpoint": [ + "Searing Crags - Rope Dart Shop", + "Searing Crags - Falling Rocks Shop", + ], + "Raining Rocks Checkpoint": [ + "Searing Crags - Searing Mega Shard Shop", + "Searing Crags - Before Final Climb Shop", + ], + }, + "Glacial Peak": { + "Bottom": [ + "Searing Crags - Top", + "Glacial Peak - Ice Climbers' Shop", + ], + "Left": [ + "Elemental Skylands - Air Shmup", + "Glacial Peak - Projectile Spike Pit Checkpoint", + "Glacial Peak - Glacial Mega Shard Shop", + ], + "Top": [ + "Glacial Peak - Tower Entrance Shop", + "Cloud Ruins - Left", + ], + "Portal": [ + "Glacial Peak - Tower Entrance Shop", + "Tower HQ", + ], + "Ice Climbers' Shop": [ + "Glacial Peak - Bottom", + "Glacial Peak - Projectile Spike Pit Checkpoint", + ], + "Glacial Mega Shard Shop": [ + "Glacial Peak - Left", + "Glacial Peak - Air Swag Checkpoint", + ], + "Tower Entrance Shop": [ + "Glacial Peak - Top", + "Glacial Peak - Free Climbing Checkpoint", + "Glacial Peak - Portal", + ], + "Projectile Spike Pit Checkpoint": [ + "Glacial Peak - Ice Climbers' Shop", + "Glacial Peak - Left", + ], + "Air Swag Checkpoint": [ + "Glacial Peak - Glacial Mega Shard Shop", + "Glacial Peak - Free Climbing Checkpoint", + ], + "Free Climbing Checkpoint": [ + "Glacial Peak - Air Swag Checkpoint", + "Glacial Peak - Tower Entrance Shop", + ], + }, + "Tower of Time": { + "Left": [ + "Tower of Time - Final Chance Shop", + ], + "Final Chance Shop": [ + "Tower of Time - First Checkpoint", + ], + "Arcane Golem Shop": [ + "Tower of Time - Sixth Checkpoint", + ], + "First Checkpoint": [ + "Tower of Time - Second Checkpoint", + ], + "Second Checkpoint": [ + "Tower of Time - Third Checkpoint", + ], + "Third Checkpoint": [ + "Tower of Time - Fourth Checkpoint", + ], + "Fourth Checkpoint": [ + "Tower of Time - Fifth Checkpoint", + ], + "Fifth Checkpoint": [ + "Tower of Time - Sixth Checkpoint", + ], + "Sixth Checkpoint": [ + "Tower of Time - Arcane Golem Shop", + ], + }, + "Cloud Ruins": { + "Left": [ + "Glacial Peak - Top", + "Cloud Ruins - Cloud Entrance Shop", + ], + "Cloud Entrance Shop": [ + "Cloud Ruins - Left", + "Cloud Ruins - Spike Float Checkpoint", + ], + "Pillar Glide Shop": [ + "Cloud Ruins - Spike Float Checkpoint", + "Cloud Ruins - Ghost Pit Checkpoint", + "Cloud Ruins - Crushers' Descent Shop", + ], + "Crushers' Descent Shop": [ + "Cloud Ruins - Pillar Glide Shop", + "Cloud Ruins - Toothbrush Alley Checkpoint", + ], + "Seeing Spikes Shop": [ + "Cloud Ruins - Toothbrush Alley Checkpoint", + "Cloud Ruins - Sliding Spikes Shop", + ], + "Sliding Spikes Shop": [ + "Cloud Ruins - Seeing Spikes Shop", + "Cloud Ruins - Saw Pit Checkpoint", + ], + "Final Flight Shop": [ + "Cloud Ruins - Saw Pit Checkpoint", + "Cloud Ruins - Manfred's Shop", + ], + "Manfred's Shop": [ + "Cloud Ruins - Final Flight Shop", + ], + "Spike Float Checkpoint": [ + "Cloud Ruins - Cloud Entrance Shop", + "Cloud Ruins - Pillar Glide Shop", + ], + "Ghost Pit Checkpoint": [ + "Cloud Ruins - Pillar Glide Shop", + ], + "Toothbrush Alley Checkpoint": [ + "Cloud Ruins - Crushers' Descent Shop", + "Cloud Ruins - Seeing Spikes Shop", + ], + "Saw Pit Checkpoint": [ + "Cloud Ruins - Sliding Spikes Shop", + "Cloud Ruins - Final Flight Shop", + ], + }, + "Underworld": { + "Left": [ + "Underworld - Left Shop", + "Searing Crags - Right", + ], + "Left Shop": [ + "Underworld - Left", + "Underworld - Hot Dip Checkpoint", + ], + "Fireball Wave Shop": [ + "Underworld - Hot Dip Checkpoint", + "Underworld - Long Climb Shop", + ], + "Long Climb Shop": [ + "Underworld - Fireball Wave Shop", + "Underworld - Hot Tub Checkpoint", + ], + "Barm'athaziel Shop": [ + "Underworld - Hot Tub Checkpoint", + ], + "Key of Chaos Shop": [ + ], + "Hot Dip Checkpoint": [ + "Underworld - Left Shop", + "Underworld - Fireball Wave Shop", + "Underworld - Lava Run Checkpoint", + ], + "Hot Tub Checkpoint": [ + "Underworld - Long Climb Shop", + "Underworld - Barm'athaziel Shop", + ], + "Lava Run Checkpoint": [ + "Underworld - Hot Dip Checkpoint", + "Underworld - Key of Chaos Shop", + ], + }, + "Dark Cave": { + "Right": [ + "Catacombs - Bottom", + "Dark Cave - Left", + ], + "Left": [ + "Riviere Turquoise - Right", + ], + }, + "Riviere Turquoise": { + "Right": [ + "Riviere Turquoise - Portal", + ], + "Portal": [ + "Riviere Turquoise - Waterfall Shop", + "Tower HQ", + ], + "Waterfall Shop": [ + "Riviere Turquoise - Portal", + "Riviere Turquoise - Flower Flight Checkpoint", + ], + "Launch of Faith Shop": [ + "Riviere Turquoise - Flower Flight Checkpoint", + "Riviere Turquoise - Log Flume Shop", + ], + "Log Flume Shop": [ + "Riviere Turquoise - Log Climb Shop", + ], + "Log Climb Shop": [ + "Riviere Turquoise - Restock Shop", + ], + "Restock Shop": [ + "Riviere Turquoise - Butterfly Matriarch Shop", + ], + "Butterfly Matriarch Shop": [ + ], + "Flower Flight Checkpoint": [ + "Riviere Turquoise - Waterfall Shop", + "Riviere Turquoise - Launch of Faith Shop", + ], + }, + "Elemental Skylands": { + "Air Shmup": [ + "Elemental Skylands - Air Intro Shop", + ], + "Air Intro Shop": [ + "Elemental Skylands - Air Seal Checkpoint", + "Elemental Skylands - Air Generator Shop", + ], + "Air Seal Checkpoint": [ + "Elemental Skylands - Air Intro Shop", + "Elemental Skylands - Air Generator Shop", + ], + "Air Generator Shop": [ + "Elemental Skylands - Earth Shmup", + ], + "Earth Shmup": [ + "Elemental Skylands - Earth Intro Shop", + ], + "Earth Intro Shop": [ + "Elemental Skylands - Earth Generator Shop", + ], + "Earth Generator Shop": [ + "Elemental Skylands - Fire Shmup", + ], + "Fire Shmup": [ + "Elemental Skylands - Fire Intro Shop", + ], + "Fire Intro Shop": [ + "Elemental Skylands - Fire Generator Shop", + ], + "Fire Generator Shop": [ + "Elemental Skylands - Water Shmup", + ], + "Water Shmup": [ + "Elemental Skylands - Water Intro Shop", + ], + "Water Intro Shop": [ + "Elemental Skylands - Water Generator Shop", + ], + "Water Generator Shop": [ + "Elemental Skylands - Right", + ], + "Right": [ + "Glacial Peak - Left", + ], + }, + "Sunken Shrine": { + "Left": [ + "Howling Grotto - Bottom", + "Sunken Shrine - Portal", + ], + "Portal": [ + "Sunken Shrine - Left", + "Sunken Shrine - Above Portal Shop", + "Sunken Shrine - Sun Path Shop", + "Sunken Shrine - Moon Path Shop", + "Tower HQ", + ], + "Above Portal Shop": [ + "Sunken Shrine - Portal", + "Sunken Shrine - Lifeguard Shop", + ], + "Lifeguard Shop": [ + "Sunken Shrine - Above Portal Shop", + "Sunken Shrine - Lightfoot Tabi Checkpoint", + ], + "Sun Path Shop": [ + "Sunken Shrine - Portal", + "Sunken Shrine - Tabi Gauntlet Shop", + ], + "Tabi Gauntlet Shop": [ + "Sunken Shrine - Sun Path Shop", + "Sunken Shrine - Sun Crest Checkpoint", + ], + "Moon Path Shop": [ + "Sunken Shrine - Portal", + "Sunken Shrine - Waterfall Paradise Checkpoint", + ], + "Lightfoot Tabi Checkpoint": [ + "Sunken Shrine - Portal", + ], + "Sun Crest Checkpoint": [ + "Sunken Shrine - Tabi Gauntlet Shop", + "Sunken Shrine - Portal", + ], + "Waterfall Paradise Checkpoint": [ + "Sunken Shrine - Moon Path Shop", + "Sunken Shrine - Moon Crest Checkpoint", + ], + "Moon Crest Checkpoint": [ + "Sunken Shrine - Waterfall Paradise Checkpoint", + "Sunken Shrine - Portal", + ], + }, +} + +RANDOMIZED_CONNECTIONS: Dict[str, str] = { + "Ninja Village - Right": "Autumn Hills - Left", + "Autumn Hills - Left": "Ninja Village - Right", + "Autumn Hills - Right": "Forlorn Temple - Left", + "Autumn Hills - Bottom": "Catacombs - Bottom Left", + "Forlorn Temple - Left": "Autumn Hills - Right", + "Forlorn Temple - Right": "Bamboo Creek - Top Left", + "Forlorn Temple - Bottom": "Catacombs - Top Left", + "Catacombs - Top Left": "Forlorn Temple - Bottom", + "Catacombs - Bottom Left": "Autumn Hills - Bottom", + "Catacombs - Bottom": "Dark Cave - Right", + "Catacombs - Right": "Bamboo Creek - Bottom Left", + "Bamboo Creek - Bottom Left": "Catacombs - Right", + "Bamboo Creek - Right": "Howling Grotto - Left", + "Bamboo Creek - Top Left": "Forlorn Temple - Right", + "Howling Grotto - Left": "Bamboo Creek - Right", + "Howling Grotto - Top": "Quillshroom Marsh - Bottom Left", + "Howling Grotto - Right": "Quillshroom Marsh - Top Left", + "Howling Grotto - Bottom": "Sunken Shrine - Left", + "Quillshroom Marsh - Top Left": "Howling Grotto - Right", + "Quillshroom Marsh - Bottom Left": "Howling Grotto - Top", + "Quillshroom Marsh - Top Right": "Searing Crags - Left", + "Quillshroom Marsh - Bottom Right": "Searing Crags - Bottom", + "Searing Crags - Left": "Quillshroom Marsh - Top Right", + "Searing Crags - Top": "Glacial Peak - Bottom", + "Searing Crags - Bottom": "Quillshroom Marsh - Bottom Right", + "Searing Crags - Right": "Underworld - Left", + "Glacial Peak - Bottom": "Searing Crags - Top", + "Glacial Peak - Top": "Cloud Ruins - Left", + "Glacial Peak - Left": "Elemental Skylands - Air Shmup", + "Cloud Ruins - Left": "Glacial Peak - Top", + "Elemental Skylands - Right": "Glacial Peak - Left", + "Tower HQ": "Tower of Time - Left", + "Artificer": "Corrupted Future", + "Underworld - Left": "Searing Crags - Right", + "Dark Cave - Right": "Catacombs - Bottom", + "Dark Cave - Left": "Riviere Turquoise - Right", + "Sunken Shrine - Left": "Howling Grotto - Bottom", +} + +TRANSITIONS: List[str] = [ + "Ninja Village - Right", + "Autumn Hills - Left", + "Autumn Hills - Right", + "Autumn Hills - Bottom", + "Forlorn Temple - Left", + "Forlorn Temple - Bottom", + "Forlorn Temple - Right", + "Catacombs - Top Left", + "Catacombs - Right", + "Catacombs - Bottom", + "Catacombs - Bottom Left", + "Dark Cave - Right", + "Dark Cave - Left", + "Riviere Turquoise - Right", + "Howling Grotto - Left", + "Howling Grotto - Right", + "Howling Grotto - Top", + "Howling Grotto - Bottom", + "Sunken Shrine - Left", + "Bamboo Creek - Top Left", + "Bamboo Creek - Bottom Left", + "Bamboo Creek - Right", + "Quillshroom Marsh - Top Left", + "Quillshroom Marsh - Bottom Left", + "Quillshroom Marsh - Top Right", + "Quillshroom Marsh - Bottom Right", + "Searing Crags - Left", + "Searing Crags - Bottom", + "Searing Crags - Right", + "Searing Crags - Top", + "Glacial Peak - Bottom", + "Glacial Peak - Top", + "Glacial Peak - Left", + "Elemental Skylands - Air Shmup", + "Elemental Skylands - Right", + "Tower HQ", + "Tower of Time - Left", + "Corrupted Future", + "Cloud Ruins - Left", + "Underworld - Left", +] diff --git a/worlds/messenger/constants.py b/worlds/messenger/constants.py index f05d276cea..0c4d6a944c 100644 --- a/worlds/messenger/constants.py +++ b/worlds/messenger/constants.py @@ -24,6 +24,8 @@ PROG_ITEMS = [ # "Astral Seed", # "Astral Tea Leaves", "Money Wrench", + "Candle", + "Seashell", ] PHOBEKINS = [ @@ -103,6 +105,52 @@ ALWAYS_LOCATIONS = [ "Searing Crags - Pyro", "Bamboo Creek - Claustro", "Cloud Ruins - Acro", + # seals + "Ninja Village Seal - Tree House", + "Autumn Hills Seal - Trip Saws", + "Autumn Hills Seal - Double Swing Saws", + "Autumn Hills Seal - Spike Ball Swing", + "Autumn Hills Seal - Spike Ball Darts", + "Catacombs Seal - Triple Spike Crushers", + "Catacombs Seal - Crusher Gauntlet", + "Catacombs Seal - Dirty Pond", + "Bamboo Creek Seal - Spike Crushers and Doors", + "Bamboo Creek Seal - Spike Ball Pits", + "Bamboo Creek Seal - Spike Crushers and Doors v2", + "Howling Grotto Seal - Windy Saws and Balls", + "Howling Grotto Seal - Crushing Pits", + "Howling Grotto Seal - Breezy Crushers", + "Quillshroom Marsh Seal - Spikey Window", + "Quillshroom Marsh Seal - Sand Trap", + "Quillshroom Marsh Seal - Do the Spike Wave", + "Searing Crags Seal - Triple Ball Spinner", + "Searing Crags Seal - Raining Rocks", + "Searing Crags Seal - Rhythm Rocks", + "Glacial Peak Seal - Ice Climbers", + "Glacial Peak Seal - Projectile Spike Pit", + "Glacial Peak Seal - Glacial Air Swag", + "Tower of Time Seal - Time Waster", + "Tower of Time Seal - Lantern Climb", + "Tower of Time Seal - Arcane Orbs", + "Cloud Ruins Seal - Ghost Pit", + "Cloud Ruins Seal - Toothbrush Alley", + "Cloud Ruins Seal - Saw Pit", + "Cloud Ruins Seal - Money Farm Room", + "Underworld Seal - Sharp and Windy Climb", + "Underworld Seal - Spike Wall", + "Underworld Seal - Fireball Wave", + "Underworld Seal - Rising Fanta", + "Forlorn Temple Seal - Rocket Maze", + "Forlorn Temple Seal - Rocket Sunset", + "Sunken Shrine Seal - Ultra Lifeguard", + "Sunken Shrine Seal - Waterfall Paradise", + "Sunken Shrine Seal - Tabi Gauntlet", + "Riviere Turquoise Seal - Bounces and Balls", + "Riviere Turquoise Seal - Launch of Faith", + "Riviere Turquoise Seal - Flower Power", + "Elemental Skylands Seal - Air", + "Elemental Skylands Seal - Water", + "Elemental Skylands Seal - Fire", ] BOSS_LOCATIONS = [ diff --git a/worlds/messenger/docs/en_The Messenger.md b/worlds/messenger/docs/en_The Messenger.md index 374753b487..f071ba1c14 100644 --- a/worlds/messenger/docs/en_The Messenger.md +++ b/worlds/messenger/docs/en_The Messenger.md @@ -69,8 +69,8 @@ for it. The groups you can use for The Messenger are: * Sometimes upon teleporting back to HQ, Ninja will run left and enter a different portal than the one entered by the player. This may also cause a softlock. * Text entry menus don't accept controller input -* Opening the shop chest in power seal hunt mode from the tower of time HQ will softlock the game. -* If you are unable to reset file slots, load into a save slot, let the game save, and close it. +* In power seal hunt mode, the chest must be opened by entering the shop from a level. Teleporting to HQ and opening the + chest will not work. ## What do I do if I have a problem? diff --git a/worlds/messenger/docs/setup_en.md b/worlds/messenger/docs/setup_en.md index 9617baf3e0..d986b70f9c 100644 --- a/worlds/messenger/docs/setup_en.md +++ b/worlds/messenger/docs/setup_en.md @@ -9,10 +9,20 @@ ## Installation -1. Read the [Game Info Page](/games/The%20Messenger/info/en) for how the game works, caveats and known issues -2. Download and install Courier Mod Loader using the instructions on the release page +Read changes to the base game on the [Game Info Page](/games/The%20Messenger/info/en) + +### Automated Installation + +1. Download and install the latest [Archipelago release](https://github.com/ArchipelagoMW/Archipelago/releases/latest) +2. Launch the Archipelago Launcher (ArchipelagoLauncher.exe) +3. Click on "The Messenger" +4. Follow the prompts + +### Manual Installation + +1. Download and install Courier Mod Loader using the instructions on the release page * [Latest release is currently 0.7.1](https://github.com/Brokemia/Courier/releases) -3. Download and install the randomizer mod +2. Download and install the randomizer mod 1. Download the latest TheMessengerRandomizerAP.zip from [The Messenger Randomizer Mod AP releases page](https://github.com/alwaysintreble/TheMessengerRandomizerModAP/releases) 2. Extract the zip file to `TheMessenger/Mods/` of your game's install location @@ -32,19 +42,17 @@ ## Joining a MultiWorld Game 1. Launch the game -2. Navigate to `Options > Third Party Mod Options` -3. Select `Reset Randomizer File Slots` - * This will set up all of your save slots with new randomizer save files. You can have up to 3 randomizer files at a - time, but must do this step again to start new runs afterward. -4. Enter connection info using the relevant option buttons +2. Navigate to `Options > Archipelago Options` +3. Enter connection info using the relevant option buttons * **The game is limited to alphanumerical characters, `.`, and `-`.** * This defaults to `archipelago.gg` and does not need to be manually changed if connecting to a game hosted on the website. * If using a name that cannot be entered in the in game menus, there is a config file (APConfig.toml) in the game directory. When using this, all connection information must be entered in the file. -5. Select the `Connect to Archipelago` button -6. Navigate to save file selection -7. Select a new valid randomizer save +4. Select the `Connect to Archipelago` button +5. Navigate to save file selection +6. Start a new game + * If you're already connected, deleting a save will not disconnect you and is completely safe. ## Continuing a MultiWorld Game @@ -52,6 +60,5 @@ At any point while playing, it is completely safe to quit. Returning to the titl disconnect you from the server. To reconnect to an in progress MultiWorld, simply load the correct save file for that MultiWorld. -If the reconnection fails, the message on screen will state you are disconnected. If this happens, you can return to the -main menu and connect to the server as in [Joining a Multiworld Game](#joining-a-multiworld-game), then load the correct -save file. +If the reconnection fails, the message on screen will state you are disconnected. If this happens, the game will attempt +to reconnect in the background. An option will also be added to the in game menu to change the port, if necessary. diff --git a/worlds/messenger/options.py b/worlds/messenger/options.py index 6984e21547..c56ee70043 100644 --- a/worlds/messenger/options.py +++ b/worlds/messenger/options.py @@ -17,29 +17,78 @@ class Logic(Choice): """ The level of logic to use when determining what locations in your world are accessible. - Normal: can require damage boosts, but otherwise approachable for someone who has beaten the game. - Hard: has leashing, normal clips, time warps and turtle boosting in logic. - OoB: places everything with the minimum amount of rules possible. Expect to do OoB. Not guaranteed completable. + Normal: Can require damage boosts, but otherwise approachable for someone who has beaten the game. + Hard: Expects more knowledge and tighter execution. Has leashing, normal clips and much tighter d-boosting in logic. """ display_name = "Logic Level" option_normal = 0 option_hard = 1 - option_oob = 2 + alias_oob = 1 alias_challenging = 1 -class PowerSeals(DefaultOnToggle): - """Whether power seal locations should be randomized.""" - display_name = "Shuffle Seals" - - class MegaShards(Toggle): """Whether mega shards should be item locations.""" display_name = "Shuffle Mega Time Shards" +class LimitedMovement(Toggle): + """ + Removes either rope dart or wingsuit from the itempool. Forces logic to at least hard and accessibility to minimal. + """ + display_name = "Limited Movement" + + +class EarlyMed(Toggle): + """Guarantees meditation will be found early""" + display_name = "Early Meditation" + + +class AvailablePortals(Range): + """Number of portals that are available from the start. Autumn Hills, Howling Grotto, and Glacial Peak are always available. If portal outputs are not randomized, Searing Crags will also be available.""" + display_name = "Available Starting Portals" + range_start = 3 + range_end = 6 + default = 6 + + +class ShufflePortals(Choice): + """ + Whether the portals lead to random places. + Entering a portal from its vanilla area will always lead to HQ, and will unlock it if relevant. + Supports plando. + + None: Portals will take you where they're supposed to. + Shops: Portals can lead to any area except Music Box and Elemental Skylands, with each portal output guaranteed to not overlap with another portal's. Will only put you at a portal or a shop. + Checkpoints: Like Shops except checkpoints without shops are also valid drop points. + Anywhere: Like Checkpoints except it's possible for multiple portals to output to the same map. + """ + display_name = "Shuffle Portal Outputs" + option_none = 0 + alias_off = 0 + option_shops = 1 + option_checkpoints = 2 + option_anywhere = 3 + + +class ShuffleTransitions(Choice): + """ + Whether the transitions between the levels should be randomized. + Supports plando. + + None: Level transitions lead where they should. + Coupled: Returning through a transition will take you from whence you came. + Decoupled: Any level transition can take you to any other level transition. + """ + display_name = "Shuffle Level Transitions" + option_none = 0 + alias_off = 0 + option_coupled = 1 + option_decoupled = 2 + + class Goal(Choice): - """Requirement to finish the game. Power Seal Hunt will force power seal locations to be shuffled.""" + """Requirement to finish the game.""" display_name = "Goal" option_open_music_box = 0 option_power_seal_hunt = 1 @@ -137,8 +186,12 @@ class MessengerOptions(DeathLinkMixin, PerGameCommonOptions): accessibility: MessengerAccessibility start_inventory: StartInventoryPool logic_level: Logic - shuffle_seals: PowerSeals shuffle_shards: MegaShards + limited_movement: LimitedMovement + early_meditation: EarlyMed + available_portals: AvailablePortals + shuffle_portals: ShufflePortals + # shuffle_transitions: ShuffleTransitions goal: Goal music_box: MusicBox notes_needed: NotesNeeded diff --git a/worlds/messenger/portals.py b/worlds/messenger/portals.py new file mode 100644 index 0000000000..64438b0184 --- /dev/null +++ b/worlds/messenger/portals.py @@ -0,0 +1,290 @@ +from typing import List, TYPE_CHECKING + +from BaseClasses import CollectionState, PlandoOptions +from .options import ShufflePortals +from ..generic import PlandoConnection + +if TYPE_CHECKING: + from . import MessengerWorld + + +PORTALS = [ + "Autumn Hills", + "Riviere Turquoise", + "Howling Grotto", + "Sunken Shrine", + "Searing Crags", + "Glacial Peak", +] + + +REGION_ORDER = [ + "Autumn Hills", + "Forlorn Temple", + "Catacombs", + "Bamboo Creek", + "Howling Grotto", + "Quillshroom Marsh", + "Searing Crags", + "Glacial Peak", + "Tower of Time", + "Cloud Ruins", + "Underworld", + "Riviere Turquoise", + "Elemental Skylands", + "Sunken Shrine", +] + + +SHOP_POINTS = { + "Autumn Hills": [ + "Climbing Claws", + "Hope Path", + "Dimension Climb", + "Leaf Golem", + ], + "Forlorn Temple": [ + "Outside", + "Entrance", + "Climb", + "Rocket Sunset", + "Descent", + "Saw Gauntlet", + "Demon King", + ], + "Catacombs": [ + "Triple Spike Crushers", + "Ruxxtin", + ], + "Bamboo Creek": [ + "Spike Crushers", + "Abandoned", + "Time Loop", + ], + "Howling Grotto": [ + "Wingsuit", + "Crushing Pits", + "Emerald Golem", + ], + "Quillshroom Marsh": [ + "Spikey Window", + "Sand Trap", + "Queen of Quills", + ], + "Searing Crags": [ + "Rope Dart", + "Falling Rocks", + "Searing Mega Shard", + "Before Final Climb", + "Colossuses", + "Key of Strength", + ], + "Glacial Peak": [ + "Ice Climbers'", + "Glacial Mega Shard", + "Tower Entrance", + ], + "Tower of Time": [ + "Final Chance", + "Arcane Golem", + ], + "Cloud Ruins": [ + "Cloud Entrance", + "Pillar Glide", + "Crushers' Descent", + "Seeing Spikes", + "Final Flight", + "Manfred's", + ], + "Underworld": [ + "Left", + "Fireball Wave", + "Long Climb", + # "Barm'athaziel", # not currently valid + "Key of Chaos", + ], + "Riviere Turquoise": [ + "Waterfall", + "Launch of Faith", + "Log Flume", + "Log Climb", + "Restock", + "Butterfly Matriarch", + ], + "Elemental Skylands": [ + "Air Intro", + "Air Generator", + "Earth Intro", + "Earth Generator", + "Fire Intro", + "Fire Generator", + "Water Intro", + "Water Generator", + ], + "Sunken Shrine": [ + "Above Portal", + "Lifeguard", + "Sun Path", + "Tabi Gauntlet", + "Moon Path", + ] +} + + +CHECKPOINTS = { + "Autumn Hills": [ + "Hope Latch", + "Key of Hope", + "Lakeside", + "Double Swing", + "Spike Ball Swing", + ], + "Forlorn Temple": [ + "Sunny Day", + "Rocket Maze", + ], + "Catacombs": [ + "Death Trap", + "Crusher Gauntlet", + "Dirty Pond", + ], + "Bamboo Creek": [ + "Spike Ball Pits", + "Spike Doors", + ], + "Howling Grotto": [ + "Lost Woods", + "Breezy Crushers", + ], + "Quillshroom Marsh": [ + "Seashell", + "Quicksand", + "Spike Wave", + ], + "Searing Crags": [ + "Triple Ball Spinner", + "Raining Rocks", + ], + "Glacial Peak": [ + "Projectile Spike Pit", + "Air Swag", + "Free Climbing", + ], + "Tower of Time": [ + "First", + "Second", + "Third", + "Fourth", + "Fifth", + "Sixth", + ], + "Cloud Ruins": [ + "Spike Float", + "Ghost Pit", + "Toothbrush Alley", + "Saw Pit", + ], + "Underworld": [ + "Hot Dip", + "Hot Tub", + "Lava Run", + ], + "Riviere Turquoise": [ + "Flower Flight", + ], + "Elemental Skylands": [ + "Air Seal", + ], + "Sunken Shrine": [ + "Lightfoot Tabi", + "Sun Crest", + "Waterfall Paradise", + "Moon Crest", + ] +} + + +def shuffle_portals(world: "MessengerWorld") -> None: + def create_mapping(in_portal: str, warp: str) -> None: + nonlocal available_portals + parent = out_to_parent[warp] + exit_string = f"{parent.strip(' ')} - " + + if "Portal" in warp: + exit_string += "Portal" + world.portal_mapping.append(int(f"{REGION_ORDER.index(parent)}00")) + elif warp_point in SHOP_POINTS[parent]: + exit_string += f"{warp_point} Shop" + world.portal_mapping.append(int(f"{REGION_ORDER.index(parent)}1{SHOP_POINTS[parent].index(warp_point)}")) + else: + exit_string += f"{warp_point} Checkpoint" + world.portal_mapping.append(int(f"{REGION_ORDER.index(parent)}2{CHECKPOINTS[parent].index(warp_point)}")) + + world.spoiler_portal_mapping[in_portal] = exit_string + connect_portal(world, in_portal, exit_string) + + available_portals.remove(warp) + if shuffle_type < ShufflePortals.option_anywhere: + available_portals = [port for port in available_portals if port not in shop_points[parent]] + + def handle_planned_portals(plando_connections: List[PlandoConnection]) -> None: + for connection in plando_connections: + if connection.entrance not in PORTALS: + continue + # let it crash here if input is invalid + create_mapping(connection.entrance, connection.exit) + world.plando_portals.append(connection.entrance) + + shuffle_type = world.options.shuffle_portals + shop_points = SHOP_POINTS.copy() + for portal in PORTALS: + shop_points[portal].append(f"{portal} Portal") + if shuffle_type > ShufflePortals.option_shops: + shop_points.update(CHECKPOINTS) + out_to_parent = {checkpoint: parent for parent, checkpoints in shop_points.items() for checkpoint in checkpoints} + available_portals = [val for zone in shop_points.values() for val in zone] + + plando = world.multiworld.plando_connections[world.player] + if plando and world.multiworld.plando_options & PlandoOptions.connections: + handle_planned_portals(plando) + world.multiworld.plando_connections[world.player] = [connection for connection in plando + if connection.entrance not in PORTALS] + for portal in PORTALS: + warp_point = world.random.choice(available_portals) + create_mapping(portal, warp_point) + + +def connect_portal(world: "MessengerWorld", portal: str, out_region: str) -> None: + entrance = world.multiworld.get_entrance(f"ToTHQ {portal} Portal", world.player) + entrance.connect(world.multiworld.get_region(out_region, world.player)) + + +def disconnect_portals(world: "MessengerWorld") -> None: + for portal in [port for port in PORTALS if port not in world.plando_portals]: + entrance = world.multiworld.get_entrance(f"ToTHQ {portal} Portal", world.player) + entrance.connected_region.entrances.remove(entrance) + entrance.connected_region = None + if portal in world.spoiler_portal_mapping: + del world.spoiler_portal_mapping[portal] + if len(world.portal_mapping) > len(world.spoiler_portal_mapping): + world.portal_mapping = world.portal_mapping[:len(world.spoiler_portal_mapping)] + + +def validate_portals(world: "MessengerWorld") -> bool: + # if world.options.shuffle_transitions: + # return True + new_state = CollectionState(world.multiworld) + new_state.update_reachable_regions(world.player) + reachable_locs = 0 + for loc in world.multiworld.get_locations(world.player): + reachable_locs += loc.can_reach(new_state) + if reachable_locs > 5: + return True + return False + + +def add_closed_portal_reqs(world: "MessengerWorld") -> None: + closed_portals = [entrance for entrance in PORTALS if f"{entrance} Portal" not in world.starting_portals] + for portal in closed_portals: + tower_exit = world.multiworld.get_entrance(f"ToTHQ {portal} Portal", world.player) + tower_exit.access_rule = lambda state: state.has(portal, world.player) diff --git a/worlds/messenger/regions.py b/worlds/messenger/regions.py index 43de4dd1f6..153f8510f1 100644 --- a/worlds/messenger/regions.py +++ b/worlds/messenger/regions.py @@ -1,103 +1,446 @@ -from typing import Dict, List, Set +from typing import Dict, List -REGIONS: Dict[str, List[str]] = { - "Menu": [], - "Tower HQ": [], - "The Shop": [], - "The Craftsman's Corner": [], - "Tower of Time": [], - "Ninja Village": ["Ninja Village - Candle", "Ninja Village - Astral Seed"], - "Autumn Hills": ["Autumn Hills - Climbing Claws", "Autumn Hills - Key of Hope", "Autumn Hills - Leaf Golem"], - "Forlorn Temple": ["Forlorn Temple - Demon King"], - "Catacombs": ["Catacombs - Necro", "Catacombs - Ruxxtin's Amulet", "Catacombs - Ruxxtin"], - "Bamboo Creek": ["Bamboo Creek - Claustro"], - "Howling Grotto": ["Howling Grotto - Wingsuit", "Howling Grotto - Emerald Golem"], - "Quillshroom Marsh": ["Quillshroom Marsh - Seashell", "Quillshroom Marsh - Queen of Quills"], - "Searing Crags": ["Searing Crags - Rope Dart"], - "Searing Crags Upper": ["Searing Crags - Power Thistle", "Searing Crags - Key of Strength", - "Searing Crags - Astral Tea Leaves"], - "Glacial Peak": [], - "Cloud Ruins": [], - "Cloud Ruins Right": ["Cloud Ruins - Acro"], - "Underworld": ["Searing Crags - Pyro", "Underworld - Key of Chaos"], - "Dark Cave": [], - "Riviere Turquoise Entrance": [], - "Riviere Turquoise": ["Riviere Turquoise - Butterfly Matriarch"], - "Sunken Shrine": ["Sunken Shrine - Lightfoot Tabi", "Sunken Shrine - Sun Crest", "Sunken Shrine - Moon Crest", - "Sunken Shrine - Key of Love"], - "Elemental Skylands": ["Elemental Skylands - Key of Symbiosis"], + +LOCATIONS: Dict[str, List[str]] = { + "Ninja Village - Nest": [ + "Ninja Village - Candle", + "Ninja Village - Astral Seed", + "Ninja Village Seal - Tree House", + ], + "Autumn Hills - Climbing Claws Shop": [ + "Autumn Hills - Climbing Claws", + "Autumn Hills Seal - Trip Saws", + ], + "Autumn Hills - Key of Hope Checkpoint": [ + "Autumn Hills - Key of Hope", + ], + "Autumn Hills - Double Swing Checkpoint": [ + "Autumn Hills Seal - Double Swing Saws", + ], + "Autumn Hills - Spike Ball Swing Checkpoint": [ + "Autumn Hills Seal - Spike Ball Swing", + "Autumn Hills Seal - Spike Ball Darts", + ], + "Autumn Hills - Leaf Golem Shop": [ + "Autumn Hills - Leaf Golem", + ], + "Forlorn Temple - Rocket Maze Checkpoint": [ + "Forlorn Temple Seal - Rocket Maze", + ], + "Forlorn Temple - Rocket Sunset Shop": [ + "Forlorn Temple Seal - Rocket Sunset", + ], + "Forlorn Temple - Demon King Shop": [ + "Forlorn Temple - Demon King", + ], + "Catacombs - Top Left": [ + "Catacombs - Necro", + ], + "Catacombs - Triple Spike Crushers Shop": [ + "Catacombs Seal - Triple Spike Crushers", + ], + "Catacombs - Dirty Pond Checkpoint": [ + "Catacombs Seal - Crusher Gauntlet", + "Catacombs Seal - Dirty Pond", + ], + "Catacombs - Ruxxtin Shop": [ + "Catacombs - Ruxxtin's Amulet", + "Catacombs - Ruxxtin", + ], + "Bamboo Creek - Spike Crushers Shop": [ + "Bamboo Creek Seal - Spike Crushers and Doors", + ], + "Bamboo Creek - Spike Ball Pits Checkpoint": [ + "Bamboo Creek Seal - Spike Ball Pits", + ], + "Bamboo Creek - Time Loop Shop": [ + "Bamboo Creek Seal - Spike Crushers and Doors v2", + "Bamboo Creek - Claustro", + ], + "Howling Grotto - Wingsuit Shop": [ + "Howling Grotto - Wingsuit", + "Howling Grotto Seal - Windy Saws and Balls", + ], + "Howling Grotto - Crushing Pits Shop": [ + "Howling Grotto Seal - Crushing Pits", + ], + "Howling Grotto - Breezy Crushers Checkpoint": [ + "Howling Grotto Seal - Breezy Crushers", + ], + "Howling Grotto - Emerald Golem Shop": [ + "Howling Grotto - Emerald Golem", + ], + "Quillshroom Marsh - Seashell Checkpoint": [ + "Quillshroom Marsh - Seashell", + ], + "Quillshroom Marsh - Spikey Window Shop": [ + "Quillshroom Marsh Seal - Spikey Window", + ], + "Quillshroom Marsh - Sand Trap Shop": [ + "Quillshroom Marsh Seal - Sand Trap", + ], + "Quillshroom Marsh - Spike Wave Checkpoint": [ + "Quillshroom Marsh Seal - Do the Spike Wave", + ], + "Quillshroom Marsh - Queen of Quills Shop": [ + "Quillshroom Marsh - Queen of Quills", + ], + "Searing Crags - Rope Dart Shop": [ + "Searing Crags - Rope Dart", + ], + "Searing Crags - Triple Ball Spinner Checkpoint": [ + "Searing Crags Seal - Triple Ball Spinner", + ], + "Searing Crags - Raining Rocks Checkpoint": [ + "Searing Crags Seal - Raining Rocks", + ], + "Searing Crags - Colossuses Shop": [ + "Searing Crags Seal - Rhythm Rocks", + "Searing Crags - Power Thistle", + "Searing Crags - Astral Tea Leaves", + ], + "Searing Crags - Key of Strength Shop": [ + "Searing Crags - Key of Strength", + ], + "Searing Crags - Portal": [ + "Searing Crags - Pyro", + ], + "Glacial Peak - Ice Climbers' Shop": [ + "Glacial Peak Seal - Ice Climbers", + ], + "Glacial Peak - Projectile Spike Pit Checkpoint": [ + "Glacial Peak Seal - Projectile Spike Pit", + ], + "Glacial Peak - Air Swag Checkpoint": [ + "Glacial Peak Seal - Glacial Air Swag", + ], + "Tower of Time - First Checkpoint": [ + "Tower of Time Seal - Time Waster", + ], + "Tower of Time - Fourth Checkpoint": [ + "Tower of Time Seal - Lantern Climb", + ], + "Tower of Time - Fifth Checkpoint": [ + "Tower of Time Seal - Arcane Orbs", + ], + "Cloud Ruins - Ghost Pit Checkpoint": [ + "Cloud Ruins Seal - Ghost Pit", + ], + "Cloud Ruins - Toothbrush Alley Checkpoint": [ + "Cloud Ruins Seal - Toothbrush Alley", + ], + "Cloud Ruins - Saw Pit Checkpoint": [ + "Cloud Ruins Seal - Saw Pit", + ], + "Cloud Ruins - Final Flight Shop": [ + "Cloud Ruins - Acro", + ], + "Cloud Ruins - Manfred's Shop": [ + "Cloud Ruins Seal - Money Farm Room", + ], + "Underworld - Left Shop": [ + "Underworld Seal - Sharp and Windy Climb", + ], + "Underworld - Fireball Wave Shop": [ + "Underworld Seal - Spike Wall", + "Underworld Seal - Fireball Wave", + ], + "Underworld - Hot Tub Checkpoint": [ + "Underworld Seal - Rising Fanta", + ], + "Underworld - Key of Chaos Shop": [ + "Underworld - Key of Chaos", + ], + "Riviere Turquoise - Waterfall Shop": [ + "Riviere Turquoise Seal - Bounces and Balls", + ], + "Riviere Turquoise - Launch of Faith Shop": [ + "Riviere Turquoise Seal - Launch of Faith", + ], + "Riviere Turquoise - Restock Shop": [ + "Riviere Turquoise Seal - Flower Power", + ], + "Riviere Turquoise - Butterfly Matriarch Shop": [ + "Riviere Turquoise - Butterfly Matriarch", + ], + "Sunken Shrine - Lifeguard Shop": [ + "Sunken Shrine Seal - Ultra Lifeguard", + ], + "Sunken Shrine - Lightfoot Tabi Checkpoint": [ + "Sunken Shrine - Lightfoot Tabi", + ], + "Sunken Shrine - Portal": [ + "Sunken Shrine - Key of Love", + ], + "Sunken Shrine - Tabi Gauntlet Shop": [ + "Sunken Shrine Seal - Tabi Gauntlet", + ], + "Sunken Shrine - Sun Crest Checkpoint": [ + "Sunken Shrine - Sun Crest", + ], + "Sunken Shrine - Waterfall Paradise Checkpoint": [ + "Sunken Shrine Seal - Waterfall Paradise", + ], + "Sunken Shrine - Moon Crest Checkpoint": [ + "Sunken Shrine - Moon Crest", + ], + "Elemental Skylands - Air Seal Checkpoint": [ + "Elemental Skylands Seal - Air", + ], + "Elemental Skylands - Water Intro Shop": [ + "Elemental Skylands Seal - Water", + ], + "Elemental Skylands - Fire Intro Shop": [ + "Elemental Skylands Seal - Fire", + ], + "Elemental Skylands - Right": [ + "Elemental Skylands - Key of Symbiosis", + ], "Corrupted Future": ["Corrupted Future - Key of Courage"], "Music Box": ["Rescue Phantom"], } -SEALS: Dict[str, List[str]] = { - "Ninja Village": ["Ninja Village Seal - Tree House"], - "Autumn Hills": ["Autumn Hills Seal - Trip Saws", "Autumn Hills Seal - Double Swing Saws", - "Autumn Hills Seal - Spike Ball Swing", "Autumn Hills Seal - Spike Ball Darts"], - "Catacombs": ["Catacombs Seal - Triple Spike Crushers", "Catacombs Seal - Crusher Gauntlet", - "Catacombs Seal - Dirty Pond"], - "Bamboo Creek": ["Bamboo Creek Seal - Spike Crushers and Doors", "Bamboo Creek Seal - Spike Ball Pits", - "Bamboo Creek Seal - Spike Crushers and Doors v2"], - "Howling Grotto": ["Howling Grotto Seal - Windy Saws and Balls", "Howling Grotto Seal - Crushing Pits", - "Howling Grotto Seal - Breezy Crushers"], - "Quillshroom Marsh": ["Quillshroom Marsh Seal - Spikey Window", "Quillshroom Marsh Seal - Sand Trap", - "Quillshroom Marsh Seal - Do the Spike Wave"], - "Searing Crags": ["Searing Crags Seal - Triple Ball Spinner"], - "Searing Crags Upper": ["Searing Crags Seal - Raining Rocks", "Searing Crags Seal - Rhythm Rocks"], - "Glacial Peak": ["Glacial Peak Seal - Ice Climbers", "Glacial Peak Seal - Projectile Spike Pit", - "Glacial Peak Seal - Glacial Air Swag"], - "Tower of Time": ["Tower of Time Seal - Time Waster", "Tower of Time Seal - Lantern Climb", - "Tower of Time Seal - Arcane Orbs"], - "Cloud Ruins Right": ["Cloud Ruins Seal - Ghost Pit", "Cloud Ruins Seal - Toothbrush Alley", - "Cloud Ruins Seal - Saw Pit", "Cloud Ruins Seal - Money Farm Room"], - "Underworld": ["Underworld Seal - Sharp and Windy Climb", "Underworld Seal - Spike Wall", - "Underworld Seal - Fireball Wave", "Underworld Seal - Rising Fanta"], - "Forlorn Temple": ["Forlorn Temple Seal - Rocket Maze", "Forlorn Temple Seal - Rocket Sunset"], - "Sunken Shrine": ["Sunken Shrine Seal - Ultra Lifeguard", "Sunken Shrine Seal - Waterfall Paradise", - "Sunken Shrine Seal - Tabi Gauntlet"], - "Riviere Turquoise Entrance": ["Riviere Turquoise Seal - Bounces and Balls"], - "Riviere Turquoise": ["Riviere Turquoise Seal - Launch of Faith", "Riviere Turquoise Seal - Flower Power"], - "Elemental Skylands": ["Elemental Skylands Seal - Air", "Elemental Skylands Seal - Water", - "Elemental Skylands Seal - Fire"] + +SUB_REGIONS: Dict[str, List[str]] = { + "Ninja Village": [ + "Right", + ], + "Autumn Hills": [ + "Left", + "Right", + "Bottom", + "Portal", + "Climbing Claws Shop", + "Hope Path Shop", + "Dimension Climb Shop", + "Leaf Golem Shop", + "Hope Path Checkpoint", + "Key of Hope Checkpoint", + "Lakeside Checkpoint", + "Double Swing Checkpoint", + "Spike Ball Swing Checkpoint", + ], + "Forlorn Temple": [ + "Left", + "Right", + "Bottom", + "Outside Shop", + "Entrance Shop", + "Climb Shop", + "Rocket Sunset Shop", + "Descent Shop", + "Final Fall Shop", + "Demon King Shop", + "Sunny Day Checkpoint", + "Rocket Maze Checkpoint", + ], + "Catacombs": [ + "Top Left", + "Bottom Left", + "Bottom", + "Right", + "Triple Spike Crushers Shop", + "Ruxxtin Shop", + "Death Trap Checkpoint", + "Crusher Gauntlet Checkpoint", + "Dirty Pond Checkpoint", + ], + "Bamboo Creek": [ + "Bottom Left", + "Top Left", + "Right", + "Spike Crushers Shop", + "Abandoned Shop", + "Time Loop Shop", + "Spike Ball Pits Checkpoint", + "Spike Doors Checkpoint", + ], + "Howling Grotto": [ + "Left", + "Top", + "Right", + "Bottom", + "Portal", + "Wingsuit Shop", + "Crushing Pits Shop", + "Emerald Golem Shop", + "Lost Woods Checkpoint", + "Breezy Crushers Checkpoint", + ], + "Quillshroom Marsh": [ + "Top Left", + "Bottom Left", + "Top Right", + "Bottom Right", + "Spikey Window Shop", + "Sand Trap Shop", + "Queen of Quills Shop", + "Seashell Checkpoint", + "Quicksand Checkpoint", + "Spike Wave Checkpoint", + ], + "Searing Crags": [ + "Left", + "Top", + "Bottom", + "Right", + "Portal", + "Rope Dart Shop", + "Falling Rocks Shop", + "Searing Mega Shard Shop", + "Before Final Climb Shop", + "Colossuses Shop", + "Key of Strength Shop", + "Triple Ball Spinner Checkpoint", + "Raining Rocks Checkpoint", + ], + "Glacial Peak": [ + "Bottom", + "Top", + "Portal", + "Ice Climbers' Shop", + "Glacial Mega Shard Shop", + "Tower Entrance Shop", + "Projectile Spike Pit Checkpoint", + "Air Swag Checkpoint", + "Free Climbing Checkpoint", + ], + "Tower of Time": [ + "Left", + "Entrance Shop", + "Arcane Golem Shop", + "First Checkpoint", + "Second Checkpoint", + "Third Checkpoint", + "Fourth Checkpoint", + "Fifth Checkpoint", + "Sixth Checkpoint", + ], + "Cloud Ruins": [ + "Left", + "Entrance Shop", + "Pillar Glide Shop", + "Crushers' Descent Shop", + "Seeing Spikes Shop", + "Sliding Spikes Shop", + "Final Flight Shop", + "Manfred's Shop", + "Spike Float Checkpoint", + "Ghost Pit Checkpoint", + "Toothbrush Alley Checkpoint", + "Saw Pit Checkpoint", + ], + "Underworld": [ + "Left", + "Entrance Shop", + "Fireball Wave Shop", + "Long Climb Shop", + "Barm'athaziel Shop", + "Key of Chaos Shop", + "Hot Dip Checkpoint", + "Hot Tub Checkpoint", + "Lava Run Checkpoint", + ], + "Riviere Turquoise": [ + "Right", + "Portal", + "Waterfall Shop", + "Launch of Faith Shop", + "Log Flume Shop", + "Log Climb Shop", + "Restock Shop", + "Butterfly Matriarch Shop", + "Flower Flight Checkpoint", + ], + "Elemental Skylands": [ + "Air Shmup", + "Air Intro Shop", + "Air Seal Checkpoint", + "Air Generator Shop", + "Earth Shmup", + "Earth Intro Shop", + "Earth Generator Shop", + "Fire Shmup", + "Fire Intro Shop", + "Fire Generator Shop", + "Water Shmup", + "Water Intro Shop", + "Water Generator Shop", + "Right", + ], + "Sunken Shrine": [ + "Left", + "Portal", + "Entrance Shop", + "Lifeguard Shop", + "Sun Path Shop", + "Tabi Gauntlet Shop", + "Moon Path Shop", + "Ninja Tabi Checkpoint", + "Sun Crest Checkpoint", + "Waterfall Paradise Checkpoint", + "Moon Crest Checkpoint", + ], } + +# order is slightly funky here for back compat MEGA_SHARDS: Dict[str, List[str]] = { - "Autumn Hills": ["Autumn Hills Mega Shard", "Hidden Entrance Mega Shard"], - "Catacombs": ["Catacombs Mega Shard"], - "Bamboo Creek": ["Above Entrance Mega Shard", "Abandoned Mega Shard", "Time Loop Mega Shard"], - "Howling Grotto": ["Bottom Left Mega Shard", "Near Portal Mega Shard", "Pie in the Sky Mega Shard"], - "Quillshroom Marsh": ["Quillshroom Marsh Mega Shard"], - "Searing Crags Upper": ["Searing Crags Mega Shard"], - "Glacial Peak": ["Glacial Peak Mega Shard"], - "Cloud Ruins": ["Cloud Entrance Mega Shard", "Time Warp Mega Shard"], - "Cloud Ruins Right": ["Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2"], - "Underworld": ["Under Entrance Mega Shard", "Hot Tub Mega Shard", "Projectile Pit Mega Shard"], - "Forlorn Temple": ["Sunny Day Mega Shard", "Down Under Mega Shard"], - "Sunken Shrine": ["Mega Shard of the Moon", "Beginner's Mega Shard", "Mega Shard of the Stars", "Mega Shard of the Sun"], - "Riviere Turquoise Entrance": ["Waterfall Mega Shard"], - "Riviere Turquoise": ["Quick Restock Mega Shard 1", "Quick Restock Mega Shard 2"], - "Elemental Skylands": ["Earth Mega Shard", "Water Mega Shard"], + "Autumn Hills - Lakeside Checkpoint": ["Autumn Hills Mega Shard"], + "Forlorn Temple - Outside Shop": ["Hidden Entrance Mega Shard"], + "Catacombs - Top Left": ["Catacombs Mega Shard"], + "Bamboo Creek - Spike Crushers Shop": ["Above Entrance Mega Shard"], + "Bamboo Creek - Abandoned Shop": ["Abandoned Mega Shard"], + "Bamboo Creek - Time Loop Shop": ["Time Loop Mega Shard"], + "Howling Grotto - Lost Woods Checkpoint": ["Bottom Left Mega Shard"], + "Howling Grotto - Breezy Crushers Checkpoint": ["Near Portal Mega Shard", "Pie in the Sky Mega Shard"], + "Quillshroom Marsh - Spikey Window Shop": ["Quillshroom Marsh Mega Shard"], + "Searing Crags - Searing Mega Shard Shop": ["Searing Crags Mega Shard"], + "Glacial Peak - Glacial Mega Shard Shop": ["Glacial Peak Mega Shard"], + "Cloud Ruins - Cloud Entrance Shop": ["Cloud Entrance Mega Shard", "Time Warp Mega Shard"], + "Cloud Ruins - Manfred's Shop": ["Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2"], + "Underworld - Left Shop": ["Under Entrance Mega Shard"], + "Underworld - Hot Tub Checkpoint": ["Hot Tub Mega Shard", "Projectile Pit Mega Shard"], + "Forlorn Temple - Sunny Day Checkpoint": ["Sunny Day Mega Shard"], + "Forlorn Temple - Demon King Shop": ["Down Under Mega Shard"], + "Sunken Shrine - Waterfall Paradise Checkpoint": ["Mega Shard of the Moon"], + "Sunken Shrine - Portal": ["Beginner's Mega Shard"], + "Sunken Shrine - Above Portal Shop": ["Mega Shard of the Stars"], + "Sunken Shrine - Sun Crest Checkpoint": ["Mega Shard of the Sun"], + "Riviere Turquoise - Waterfall Shop": ["Waterfall Mega Shard"], + "Riviere Turquoise - Restock Shop": ["Quick Restock Mega Shard 1", "Quick Restock Mega Shard 2"], + "Elemental Skylands - Earth Intro Shop": ["Earth Mega Shard"], + "Elemental Skylands - Water Generator Shop": ["Water Mega Shard"], } -REGION_CONNECTIONS: Dict[str, Set[str]] = { - "Menu": {"Tower HQ"}, - "Tower HQ": {"Autumn Hills", "Howling Grotto", "Searing Crags", "Glacial Peak", "Tower of Time", - "Riviere Turquoise Entrance", "Sunken Shrine", "Corrupted Future", "The Shop", - "The Craftsman's Corner", "Music Box"}, - "Autumn Hills": {"Ninja Village", "Forlorn Temple", "Catacombs"}, - "Forlorn Temple": {"Catacombs", "Bamboo Creek"}, - "Catacombs": {"Autumn Hills", "Bamboo Creek", "Dark Cave"}, - "Bamboo Creek": {"Catacombs", "Howling Grotto"}, - "Howling Grotto": {"Bamboo Creek", "Quillshroom Marsh", "Sunken Shrine"}, - "Quillshroom Marsh": {"Howling Grotto", "Searing Crags"}, - "Searing Crags": {"Searing Crags Upper", "Quillshroom Marsh", "Underworld"}, - "Searing Crags Upper": {"Searing Crags", "Glacial Peak"}, - "Glacial Peak": {"Searing Crags Upper", "Tower HQ", "Cloud Ruins", "Elemental Skylands"}, - "Cloud Ruins": {"Cloud Ruins Right"}, - "Cloud Ruins Right": {"Underworld"}, - "Dark Cave": {"Catacombs", "Riviere Turquoise Entrance"}, - "Riviere Turquoise Entrance": {"Riviere Turquoise"}, - "Sunken Shrine": {"Howling Grotto"}, +REGION_CONNECTIONS: Dict[str, Dict[str, str]] = { + "Menu": {"Tower HQ": "Start Game"}, + "Tower HQ": { + "Autumn Hills - Portal": "ToTHQ Autumn Hills Portal", + "Howling Grotto - Portal": "ToTHQ Howling Grotto Portal", + "Searing Crags - Portal": "ToTHQ Searing Crags Portal", + "Glacial Peak - Portal": "ToTHQ Glacial Peak Portal", + "Tower of Time - Left": "Artificer's Challenge", + "Riviere Turquoise - Portal": "ToTHQ Riviere Turquoise Portal", + "Sunken Shrine - Portal": "ToTHQ Sunken Shrine Portal", + "Corrupted Future": "Artificer's Portal", + "The Shop": "Home", + "Music Box": "Shrink Down", + }, + "The Shop": { + "The Craftsman's Corner": "Money Sink", + }, } -"""Vanilla layout mapping with all Tower HQ portals open. from -> to""" +"""Vanilla layout mapping with all Tower HQ portals open. format is source[exit_region][entrance_name]""" + + +# regions that don't have sub-regions +LEVELS: List[str] = [ + "Menu", + "Tower HQ", + "The Shop", + "The Craftsman's Corner", + "Corrupted Future", + "Music Box", +] diff --git a/worlds/messenger/rules.py b/worlds/messenger/rules.py index b13a453f7f..50e1fa113d 100644 --- a/worlds/messenger/rules.py +++ b/worlds/messenger/rules.py @@ -1,7 +1,7 @@ from typing import Dict, TYPE_CHECKING from BaseClasses import CollectionState -from worlds.generic.Rules import add_rule, allow_self_locking_items, CollectionRule +from worlds.generic.Rules import CollectionRule, add_rule, allow_self_locking_items from .constants import NOTES, PHOBEKINS from .options import MessengerAccessibility @@ -12,6 +12,7 @@ if TYPE_CHECKING: class MessengerRules: player: int world: "MessengerWorld" + connection_rules: Dict[str, CollectionRule] region_rules: Dict[str, CollectionRule] location_rules: Dict[str, CollectionRule] maximum_price: int @@ -27,83 +28,286 @@ class MessengerRules: self.maximum_price = min(maximum_price, world.total_shards) self.required_seals = max(1, world.required_seals) - self.region_rules = { - "Ninja Village": self.has_wingsuit, - "Autumn Hills": self.has_wingsuit, - "Catacombs": self.has_wingsuit, - "Bamboo Creek": self.has_wingsuit, - "Searing Crags Upper": self.has_vertical, - "Cloud Ruins": lambda state: self.has_vertical(state) and state.has("Ruxxtin's Amulet", self.player), - "Cloud Ruins Right": lambda state: self.has_wingsuit(state) and - (self.has_dart(state) or self.can_dboost(state)), - "Underworld": self.has_tabi, - "Riviere Turquoise": lambda state: self.has_dart(state) or - (self.has_wingsuit(state) and self.can_destroy_projectiles(state)), - "Forlorn Temple": lambda state: state.has_all({"Wingsuit", *PHOBEKINS}, self.player) and self.can_dboost(state), - "Glacial Peak": self.has_vertical, - "Elemental Skylands": lambda state: state.has("Magic Firefly", self.player) and self.has_wingsuit(state), - "Music Box": lambda state: (state.has_all(NOTES, self.player) - or self.has_enough_seals(state)) and self.has_dart(state), - "The Craftsman's Corner": lambda state: state.has("Money Wrench", self.player) and self.can_shop(state), + # dict of connection names and requirements to traverse the exit + self.connection_rules = { + # from ToTHQ + "Artificer's Portal": + lambda state: state.has_all({"Demon King Crown", "Magic Firefly"}, self.player), + "Shrink Down": + lambda state: state.has_all(NOTES, self.player) or self.has_enough_seals(state), + # the shop + "Money Sink": + lambda state: state.has("Money Wrench", self.player) and self.can_shop(state), + # Autumn Hills + "Autumn Hills - Portal -> Autumn Hills - Dimension Climb Shop": + lambda state: self.has_wingsuit(state) and self.has_dart(state), + "Autumn Hills - Dimension Climb Shop -> Autumn Hills - Portal": + self.has_vertical, + "Autumn Hills - Climbing Claws Shop -> Autumn Hills - Hope Path Shop": + self.has_dart, + "Autumn Hills - Climbing Claws Shop -> Autumn Hills - Key of Hope Checkpoint": + self.false, # hard logic only + "Autumn Hills - Hope Path Shop -> Autumn Hills - Hope Latch Checkpoint": + self.has_dart, + "Autumn Hills - Hope Path Shop -> Autumn Hills - Climbing Claws Shop": + lambda state: self.has_dart(state) and self.can_dboost(state), + "Autumn Hills - Hope Path Shop -> Autumn Hills - Lakeside Checkpoint": + lambda state: self.has_dart(state) and self.can_dboost(state), + "Autumn Hills - Hope Latch Checkpoint -> Autumn Hills - Hope Path Shop": + self.can_dboost, + "Autumn Hills - Hope Latch Checkpoint -> Autumn Hills - Key of Hope Checkpoint": + lambda state: self.has_dart(state) and self.has_wingsuit(state), + # Forlorn Temple + "Forlorn Temple - Outside Shop -> Forlorn Temple - Entrance Shop": + lambda state: state.has_all(PHOBEKINS, self.player), + "Forlorn Temple - Entrance Shop -> Forlorn Temple - Outside Shop": + lambda state: state.has_all(PHOBEKINS, self.player), + "Forlorn Temple - Entrance Shop -> Forlorn Temple - Sunny Day Checkpoint": + lambda state: self.has_vertical(state) and self.can_dboost(state), + "Forlorn Temple - Sunny Day Checkpoint -> Forlorn Temple - Rocket Maze Checkpoint": + self.has_vertical, + "Forlorn Temple - Rocket Sunset Shop -> Forlorn Temple - Descent Shop": + lambda state: self.has_dart(state) and (self.can_dboost(state) or self.has_wingsuit(state)), + "Forlorn Temple - Saw Gauntlet Shop -> Forlorn Temple - Demon King Shop": + self.has_vertical, + "Forlorn Temple - Demon King Shop -> Forlorn Temple - Saw Gauntlet Shop": + self.has_vertical, + # Howling Grotto + "Howling Grotto - Portal -> Howling Grotto - Crushing Pits Shop": + self.has_wingsuit, + "Howling Grotto - Wingsuit Shop -> Howling Grotto - Left": + self.has_wingsuit, + "Howling Grotto - Wingsuit Shop -> Howling Grotto - Lost Woods Checkpoint": + self.has_wingsuit, + "Howling Grotto - Lost Woods Checkpoint -> Howling Grotto - Bottom": + lambda state: state.has("Seashell", self.player), + "Howling Grotto - Crushing Pits Shop -> Howling Grotto - Portal": + lambda state: self.has_wingsuit(state) or self.can_dboost(state), + "Howling Grotto - Breezy Crushers Checkpoint -> Howling Grotto - Emerald Golem Shop": + self.has_wingsuit, + "Howling Grotto - Breezy Crushers Checkpoint -> Howling Grotto - Crushing Pits Shop": + lambda state: (self.has_wingsuit(state) or self.can_dboost( + state + ) or self.can_destroy_projectiles(state)) + and state.multiworld.get_region( + "Howling Grotto - Emerald Golem Shop", self.player + ).can_reach(state), + "Howling Grotto - Emerald Golem Shop -> Howling Grotto - Right": + self.has_wingsuit, + # Searing Crags + "Searing Crags - Rope Dart Shop -> Searing Crags - Triple Ball Spinner Checkpoint": + self.has_vertical, + "Searing Crags - Portal -> Searing Crags - Right": + self.has_tabi, + "Searing Crags - Portal -> Searing Crags - Before Final Climb Shop": + self.has_wingsuit, + "Searing Crags - Portal -> Searing Crags - Colossuses Shop": + self.has_wingsuit, + "Searing Crags - Bottom -> Searing Crags - Portal": + self.has_wingsuit, + "Searing Crags - Right -> Searing Crags - Portal": + lambda state: self.has_tabi(state) and self.has_wingsuit(state), + "Searing Crags - Colossuses Shop -> Searing Crags - Key of Strength Shop": + lambda state: state.has("Power Thistle", self.player) + and (self.has_dart(state) + or (self.has_wingsuit(state) + and self.can_destroy_projectiles(state))), + "Searing Crags - Falling Rocks Shop -> Searing Crags - Searing Mega Shard Shop": + self.has_dart, + "Searing Crags - Searing Mega Shard Shop -> Searing Crags - Before Final Climb Shop": + lambda state: self.has_dart(state) or self.can_destroy_projectiles(state), + "Searing Crags - Searing Mega Shard Shop -> Searing Crags - Falling Rocks Shop": + self.has_dart, + "Searing Crags - Searing Mega Shard Shop -> Searing Crags - Key of Strength Shop": + self.false, + "Searing Crags - Before Final Climb Shop -> Searing Crags - Colossuses Shop": + self.has_dart, + # Glacial Peak + "Glacial Peak - Portal -> Glacial Peak - Tower Entrance Shop": + self.has_vertical, + "Glacial Peak - Left -> Elemental Skylands - Air Shmup": + lambda state: state.has("Magic Firefly", self.player) + and state.multiworld.get_location("Quillshroom Marsh - Queen of Quills", self.player) + .can_reach(state), + "Glacial Peak - Tower Entrance Shop -> Glacial Peak - Top": + lambda state: state.has("Ruxxtin's Amulet", self.player), + "Glacial Peak - Projectile Spike Pit Checkpoint -> Glacial Peak - Left": + lambda state: self.has_dart(state) or (self.can_dboost(state) and self.has_wingsuit(state)), + # Tower of Time + "Tower of Time - Left -> Tower of Time - Final Chance Shop": + self.has_dart, + "Tower of Time - Second Checkpoint -> Tower of Time - Third Checkpoint": + lambda state: self.has_wingsuit(state) and (self.has_dart(state) or self.can_dboost(state)), + "Tower of Time - Third Checkpoint -> Tower of Time - Fourth Checkpoint": + lambda state: self.has_wingsuit(state) or self.can_dboost(state), + "Tower of Time - Fourth Checkpoint -> Tower of Time - Fifth Checkpoint": + lambda state: self.has_wingsuit(state) and self.has_dart(state), + "Tower of Time - Fifth Checkpoint -> Tower of Time - Sixth Checkpoint": + self.has_wingsuit, + # Cloud Ruins + "Cloud Ruins - Cloud Entrance Shop -> Cloud Ruins - Spike Float Checkpoint": + self.has_wingsuit, + "Cloud Ruins - Spike Float Checkpoint -> Cloud Ruins - Cloud Entrance Shop": + lambda state: self.has_vertical(state) or self.can_dboost(state), + "Cloud Ruins - Spike Float Checkpoint -> Cloud Ruins - Pillar Glide Shop": + lambda state: self.has_vertical(state) or self.can_dboost(state), + "Cloud Ruins - Pillar Glide Shop -> Cloud Ruins - Spike Float Checkpoint": + lambda state: self.has_vertical(state) and self.can_double_dboost(state), + "Cloud Ruins - Pillar Glide Shop -> Cloud Ruins - Ghost Pit Checkpoint": + lambda state: self.has_dart(state) and self.has_wingsuit(state), + "Cloud Ruins - Pillar Glide Shop -> Cloud Ruins - Crushers' Descent Shop": + lambda state: self.has_wingsuit(state) and (self.has_dart(state) or self.can_dboost(state)), + "Cloud Ruins - Toothbrush Alley Checkpoint -> Cloud Ruins - Seeing Spikes Shop": + self.has_vertical, + "Cloud Ruins - Seeing Spikes Shop -> Cloud Ruins - Sliding Spikes Shop": + self.has_wingsuit, + "Cloud Ruins - Sliding Spikes Shop -> Cloud Ruins - Seeing Spikes Shop": + self.has_wingsuit, + "Cloud Ruins - Sliding Spikes Shop -> Cloud Ruins - Saw Pit Checkpoint": + self.has_vertical, + "Cloud Ruins - Final Flight Shop -> Cloud Ruins - Manfred's Shop": + lambda state: self.has_wingsuit(state) and self.has_dart(state), + "Cloud Ruins - Manfred's Shop -> Cloud Ruins - Final Flight Shop": + lambda state: self.has_wingsuit(state) and self.can_dboost(state), + # Underworld + "Underworld - Left -> Underworld - Left Shop": + self.has_tabi, + "Underworld - Left Shop -> Underworld - Left": + self.has_tabi, + "Underworld - Hot Dip Checkpoint -> Underworld - Lava Run Checkpoint": + self.has_tabi, + "Underworld - Fireball Wave Shop -> Underworld - Long Climb Shop": + lambda state: self.can_destroy_projectiles(state) or self.has_tabi(state) or self.has_vertical(state), + "Underworld - Long Climb Shop -> Underworld - Hot Tub Checkpoint": + lambda state: self.has_tabi(state) + and (self.can_destroy_projectiles(state) + or self.has_wingsuit(state)) + or (self.has_wingsuit(state) + and (self.has_dart(state) + or self.can_dboost(state) + or self.can_destroy_projectiles(state))), + "Underworld - Hot Tub Checkpoint -> Underworld - Long Climb Shop": + lambda state: self.has_tabi(state) + or self.can_destroy_projectiles(state) + or (self.has_dart(state) and self.has_wingsuit(state)), + # Dark Cave + "Dark Cave - Right -> Dark Cave - Left": + lambda state: state.has("Candle", self.player) and self.has_dart(state), + # Riviere Turquoise + "Riviere Turquoise - Waterfall Shop -> Riviere Turquoise - Flower Flight Checkpoint": + lambda state: self.has_dart(state) or ( + self.has_wingsuit(state) and self.can_destroy_projectiles(state)), + "Riviere Turquoise - Launch of Faith Shop -> Riviere Turquoise - Flower Flight Checkpoint": + lambda state: self.has_dart(state) and self.can_dboost(state), + "Riviere Turquoise - Flower Flight Checkpoint -> Riviere Turquoise - Waterfall Shop": + lambda state: False, + # Elemental Skylands + "Elemental Skylands - Air Intro Shop -> Elemental Skylands - Air Seal Checkpoint": + self.has_wingsuit, + "Elemental Skylands - Air Intro Shop -> Elemental Skylands - Air Generator Shop": + self.has_wingsuit, + # Sunken Shrine + "Sunken Shrine - Portal -> Sunken Shrine - Sun Path Shop": + self.has_tabi, + "Sunken Shrine - Portal -> Sunken Shrine - Moon Path Shop": + self.has_tabi, + "Sunken Shrine - Moon Path Shop -> Sunken Shrine - Waterfall Paradise Checkpoint": + self.has_tabi, + "Sunken Shrine - Waterfall Paradise Checkpoint -> Sunken Shrine - Moon Path Shop": + self.has_tabi, + "Sunken Shrine - Tabi Gauntlet Shop -> Sunken Shrine - Sun Path Shop": + lambda state: self.can_dboost(state) or self.has_dart(state), } self.location_rules = { # ninja village - "Ninja Village Seal - Tree House": self.has_dart, + "Ninja Village Seal - Tree House": + self.has_dart, + "Ninja Village - Candle": + lambda state: state.multiworld.get_location("Searing Crags - Astral Tea Leaves", self.player).can_reach( + state), # autumn hills - "Autumn Hills - Key of Hope": self.has_dart, - "Autumn Hills Seal - Spike Ball Darts": self.is_aerobatic, + "Autumn Hills Seal - Spike Ball Darts": + self.is_aerobatic, + "Autumn Hills Seal - Trip Saws": + self.has_wingsuit, + # forlorn temple + "Forlorn Temple Seal - Rocket Maze": + self.has_vertical, # bamboo creek - "Bamboo Creek - Claustro": lambda state: self.has_dart(state) or self.can_dboost(state), + "Bamboo Creek - Claustro": + lambda state: self.has_wingsuit(state) and (self.has_dart(state) or self.can_dboost(state)), + "Above Entrance Mega Shard": + lambda state: self.has_dart(state) or self.can_dboost(state), + "Bamboo Creek Seal - Spike Ball Pits": + self.has_wingsuit, # howling grotto - "Howling Grotto Seal - Windy Saws and Balls": self.has_wingsuit, - "Howling Grotto Seal - Crushing Pits": lambda state: self.has_wingsuit(state) and self.has_dart(state), - "Howling Grotto - Emerald Golem": self.has_wingsuit, + "Howling Grotto Seal - Windy Saws and Balls": + self.has_wingsuit, + "Howling Grotto Seal - Crushing Pits": + lambda state: self.has_wingsuit(state) and self.has_dart(state), + "Howling Grotto - Emerald Golem": + self.has_wingsuit, # searing crags - "Searing Crags Seal - Triple Ball Spinner": self.has_vertical, "Searing Crags - Astral Tea Leaves": - lambda state: state.can_reach("Ninja Village - Astral Seed", "Location", self.player), - "Searing Crags - Key of Strength": lambda state: state.has("Power Thistle", self.player) - and (self.has_dart(state) - or (self.has_wingsuit(state) - and self.can_destroy_projectiles(state))), + lambda state: state.multiworld.get_location("Ninja Village - Astral Seed", self.player).can_reach(state), + "Searing Crags Seal - Triple Ball Spinner": + self.can_dboost, + "Searing Crags - Pyro": + self.has_tabi, # glacial peak - "Glacial Peak Seal - Ice Climbers": self.has_dart, - "Glacial Peak Seal - Projectile Spike Pit": self.can_destroy_projectiles, - # cloud ruins - "Cloud Ruins Seal - Ghost Pit": self.has_dart, + "Glacial Peak Seal - Ice Climbers": + self.has_dart, + "Glacial Peak Seal - Projectile Spike Pit": + self.can_destroy_projectiles, # tower of time - "Tower of Time Seal - Time Waster": self.has_dart, - "Tower of Time Seal - Lantern Climb": lambda state: self.has_wingsuit(state) and self.has_dart(state), - "Tower of Time Seal - Arcane Orbs": lambda state: self.has_wingsuit(state) and self.has_dart(state), + "Tower of Time Seal - Time Waster": + self.has_dart, + # cloud ruins + "Time Warp Mega Shard": + lambda state: self.has_vertical(state) or self.can_dboost(state), + "Cloud Ruins Seal - Ghost Pit": + self.has_vertical, + "Cloud Ruins Seal - Toothbrush Alley": + self.has_dart, + "Cloud Ruins Seal - Saw Pit": + self.has_vertical, # underworld - "Underworld Seal - Sharp and Windy Climb": self.has_wingsuit, - "Underworld Seal - Fireball Wave": self.is_aerobatic, - "Underworld Seal - Rising Fanta": self.has_dart, + "Underworld Seal - Sharp and Windy Climb": + self.has_wingsuit, + "Underworld Seal - Fireball Wave": + self.is_aerobatic, + "Underworld Seal - Rising Fanta": + self.has_dart, + "Hot Tub Mega Shard": + lambda state: self.has_tabi(state) or self.has_dart(state), # sunken shrine - "Sunken Shrine - Sun Crest": self.has_tabi, - "Sunken Shrine - Moon Crest": self.has_tabi, - "Sunken Shrine - Key of Love": lambda state: state.has_all({"Sun Crest", "Moon Crest"}, self.player), - "Sunken Shrine Seal - Waterfall Paradise": self.has_tabi, - "Sunken Shrine Seal - Tabi Gauntlet": self.has_tabi, - "Mega Shard of the Moon": self.has_tabi, - "Mega Shard of the Sun": self.has_tabi, + "Sunken Shrine - Key of Love": + lambda state: state.has_all({"Sun Crest", "Moon Crest"}, self.player), + "Sunken Shrine Seal - Waterfall Paradise": + self.has_tabi, + "Sunken Shrine Seal - Tabi Gauntlet": + self.has_tabi, + "Mega Shard of the Sun": + self.has_tabi, # riviere turquoise - "Riviere Turquoise Seal - Bounces and Balls": self.can_dboost, - "Riviere Turquoise Seal - Launch of Faith": lambda state: self.can_dboost(state) or self.has_dart(state), + "Riviere Turquoise Seal - Bounces and Balls": + self.can_dboost, + "Riviere Turquoise Seal - Launch of Faith": + lambda state: self.has_vertical(state), # elemental skylands - "Elemental Skylands - Key of Symbiosis": self.has_dart, - "Elemental Skylands Seal - Air": self.has_wingsuit, - "Elemental Skylands Seal - Water": lambda state: self.has_dart(state) and - state.has("Currents Master", self.player), - "Elemental Skylands Seal - Fire": lambda state: self.has_dart(state) and self.can_destroy_projectiles(state), - "Earth Mega Shard": self.has_dart, - "Water Mega Shard": self.has_dart, - # corrupted future - "Corrupted Future - Key of Courage": lambda state: state.has_all({"Demon King Crown", "Magic Firefly"}, - self.player), - # tower hq - "Money Wrench": self.can_shop, + "Elemental Skylands - Key of Symbiosis": + self.has_dart, + "Elemental Skylands Seal - Air": + self.has_wingsuit, + "Elemental Skylands Seal - Water": + lambda state: self.has_dart(state) and state.has("Currents Master", self.player), + "Elemental Skylands Seal - Fire": + lambda state: self.has_dart(state) and self.can_destroy_projectiles(state) and self.is_aerobatic(state), + "Earth Mega Shard": + self.has_dart, + "Water Mega Shard": + self.has_dart, } def has_wingsuit(self, state: CollectionState) -> bool: @@ -128,6 +332,9 @@ class MessengerRules: return state.has_any({"Path of Resilience", "Meditation"}, self.player) and \ state.has("Second Wind", self.player) + def can_double_dboost(self, state: CollectionState) -> bool: + return state.has_all({"Path of Resilience", "Meditation", "Second Wind"}, self.player) + def is_aerobatic(self, state: CollectionState) -> bool: return self.has_wingsuit(state) and state.has("Aerobatics Warrior", self.player) @@ -135,87 +342,147 @@ class MessengerRules: """I know this is stupid, but it's easier to read in the dicts.""" return True + def false(self, state: CollectionState) -> bool: + """It's a bit easier to just always create the connections that are only possible in hard or higher logic.""" + return False + def can_shop(self, state: CollectionState) -> bool: return state.has("Shards", self.player, self.maximum_price) def set_messenger_rules(self) -> None: multiworld = self.world.multiworld - for region in multiworld.get_regions(self.player): - if region.name in self.region_rules: - for entrance in region.entrances: - entrance.access_rule = self.region_rules[region.name] - for loc in region.locations: - if loc.name in self.location_rules: - loc.access_rule = self.location_rules[loc.name] + for entrance_name, rule in self.connection_rules.items(): + entrance = multiworld.get_entrance(entrance_name, self.player) + entrance.access_rule = rule + for loc in multiworld.get_locations(self.player): + if loc.name in self.location_rules: + loc.access_rule = self.location_rules[loc.name] - multiworld.completion_condition[self.player] = lambda state: state.has("Rescue Phantom", self.player) - if multiworld.accessibility[self.player]: # not locations accessibility + if self.world.options.music_box and not self.world.options.limited_movement: + add_rule(multiworld.get_entrance("Shrink Down", self.player), self.has_dart) + multiworld.completion_condition[self.player] = lambda state: state.has("Do the Thing!", self.player) + if self.world.options.accessibility: # not locations accessibility set_self_locking_items(self.world, self.player) class MessengerHardRules(MessengerRules): - extra_rules: Dict[str, CollectionRule] - def __init__(self, world: "MessengerWorld") -> None: super().__init__(world) - self.region_rules.update({ - "Ninja Village": self.has_vertical, - "Autumn Hills": self.has_vertical, - "Catacombs": self.has_vertical, - "Bamboo Creek": self.has_vertical, - "Riviere Turquoise": self.true, - "Forlorn Temple": lambda state: self.has_vertical(state) and state.has_all(PHOBEKINS, self.player), - "Searing Crags Upper": lambda state: self.can_destroy_projectiles(state) or self.has_windmill(state) - or self.has_vertical(state), - "Glacial Peak": lambda state: self.can_destroy_projectiles(state) or self.has_windmill(state) - or self.has_vertical(state), - "Elemental Skylands": lambda state: state.has("Magic Firefly", self.player) or - self.has_windmill(state) or - self.has_dart(state), - }) + self.connection_rules.update( + { + # Autumn Hills + "Autumn Hills - Portal -> Autumn Hills - Dimension Climb Shop": + self.has_dart, + "Autumn Hills - Climbing Claws Shop -> Autumn Hills - Key of Hope Checkpoint": + self.true, # super easy normal clip - also possible with moderately difficult cloud stepping + # Howling Grotto + "Howling Grotto - Portal -> Howling Grotto - Crushing Pits Shop": + self.true, + "Howling Grotto - Lost Woods Checkpoint -> Howling Grotto - Bottom": + self.true, # just memorize the pattern :) + "Howling Grotto - Crushing Pits Shop -> Howling Grotto - Portal": + self.true, + "Howling Grotto - Breezy Crushers Checkpoint -> Howling Grotto - Emerald Golem Shop": + lambda state: self.has_wingsuit(state) or # there's a very easy normal clip here but it's 16-bit only + "Howling Grotto - Breezy Crushers Checkpoint" in self.world.spoiler_portal_mapping.values(), + # Searing Crags + "Searing Crags - Rope Dart Shop -> Searing Crags - Triple Ball Spinner Checkpoint": + lambda state: self.has_vertical(state) or self.can_destroy_projectiles(state), + # it's doable without anything but one jump is pretty hard and time warping is no longer reliable + "Searing Crags - Falling Rocks Shop -> Searing Crags - Searing Mega Shard Shop": + lambda state: self.has_vertical(state) or self.can_destroy_projectiles(state), + "Searing Crags - Searing Mega Shard Shop -> Searing Crags - Falling Rocks Shop": + lambda state: self.has_dart(state) or + (self.can_destroy_projectiles(state) and + (self.has_wingsuit(state) or self.can_dboost(state))), + "Searing Crags - Searing Mega Shard Shop -> Searing Crags - Key of Strength Shop": + lambda state: self.can_leash(state) or self.has_windmill(state), + "Searing Crags - Before Final Climb Shop -> Searing Crags - Colossuses Shop": + self.true, + # Glacial Peak + "Glacial Peak - Left -> Elemental Skylands - Air Shmup": + lambda state: self.has_windmill(state) or + (state.has("Magic Firefly", self.player) and + state.multiworld.get_location( + "Quillshroom Marsh - Queen of Quills", self.player).can_reach(state)) or + (self.has_dart(state) and self.can_dboost(state)), + "Glacial Peak - Projectile Spike Pit Checkpoint -> Glacial Peak - Left": + lambda state: self.has_vertical(state) or self.has_windmill(state), + # Cloud Ruins + "Cloud Ruins - Sliding Spikes Shop -> Cloud Ruins - Saw Pit Checkpoint": + self.true, + # Elemental Skylands + "Elemental Skylands - Air Intro Shop -> Elemental Skylands - Air Generator Shop": + self.true, + # Riviere Turquoise + "Riviere Turquoise - Waterfall Shop -> Riviere Turquoise - Flower Flight Checkpoint": + self.true, + "Riviere Turquoise - Launch of Faith Shop -> Riviere Turquoise - Flower Flight Checkpoint": + self.can_dboost, + "Riviere Turquoise - Flower Flight Checkpoint -> Riviere Turquoise - Waterfall Shop": + self.can_double_dboost, + } + ) - self.location_rules.update({ - "Howling Grotto Seal - Windy Saws and Balls": self.true, - "Searing Crags Seal - Triple Ball Spinner": self.true, - "Searing Crags Seal - Raining Rocks": lambda state: self.has_vertical(state) or self.can_destroy_projectiles(state), - "Searing Crags Seal - Rhythm Rocks": lambda state: self.has_vertical(state) or self.can_destroy_projectiles(state), - "Searing Crags - Power Thistle": lambda state: self.has_vertical(state) or self.can_destroy_projectiles(state), - "Glacial Peak Seal - Ice Climbers": lambda state: self.has_vertical(state) or self.can_dboost(state), - "Glacial Peak Seal - Projectile Spike Pit": self.true, - "Glacial Peak Seal - Glacial Air Swag": lambda state: self.has_windmill(state) or self.has_vertical(state), - "Glacial Peak Mega Shard": lambda state: self.has_windmill(state) or self.has_vertical(state), - "Cloud Ruins Seal - Ghost Pit": self.true, - "Bamboo Creek - Claustro": self.has_wingsuit, - "Tower of Time Seal - Lantern Climb": self.has_wingsuit, - "Elemental Skylands Seal - Water": lambda state: self.has_dart(state) or self.can_dboost(state) - or self.has_windmill(state), - "Elemental Skylands Seal - Fire": lambda state: (self.has_dart(state) or self.can_dboost(state) - or self.has_windmill(state)) and - self.can_destroy_projectiles(state), - "Earth Mega Shard": lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), - "Water Mega Shard": lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), - }) - - self.extra_rules = { - "Searing Crags - Key of Strength": lambda state: self.has_dart(state) or self.has_windmill(state), - "Elemental Skylands - Key of Symbiosis": lambda state: self.has_windmill(state) or self.can_dboost(state), - "Autumn Hills Seal - Spike Ball Darts": lambda state: self.has_dart(state) or self.has_windmill(state), - "Underworld Seal - Fireball Wave": self.has_windmill, - } + self.location_rules.update( + { + "Autumn Hills Seal - Spike Ball Darts": + lambda state: self.has_vertical(state) and self.has_windmill(state) or self.is_aerobatic(state), + "Bamboo Creek - Claustro": + self.has_wingsuit, + "Bamboo Creek Seal - Spike Ball Pits": + self.true, + "Howling Grotto Seal - Windy Saws and Balls": + self.true, + "Searing Crags Seal - Triple Ball Spinner": + self.true, + "Glacial Peak Seal - Ice Climbers": + lambda state: self.has_vertical(state) or self.can_dboost(state), + "Glacial Peak Seal - Projectile Spike Pit": + lambda state: self.can_dboost(state) or self.can_destroy_projectiles(state), + "Glacial Peak Seal - Glacial Air Swag": + lambda state: self.has_windmill(state) or self.has_vertical(state), + "Glacial Peak Mega Shard": + lambda state: self.has_windmill(state) or self.has_vertical(state), + "Cloud Ruins Seal - Ghost Pit": + self.true, + "Cloud Ruins Seal - Toothbrush Alley": + self.true, + "Cloud Ruins Seal - Saw Pit": + self.true, + "Underworld Seal - Fireball Wave": + lambda state: self.is_aerobatic(state) or self.has_windmill(state), + "Riviere Turquoise Seal - Bounces and Balls": + self.true, + "Riviere Turquoise Seal - Launch of Faith": + lambda state: self.can_dboost(state) or self.has_vertical(state), + "Elemental Skylands - Key of Symbiosis": + lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), + "Elemental Skylands Seal - Water": + lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), + "Elemental Skylands Seal - Fire": + lambda state: (self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state)) + and self.can_destroy_projectiles(state), + "Earth Mega Shard": + lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), + "Water Mega Shard": + lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), + } + ) def has_windmill(self, state: CollectionState) -> bool: return state.has("Windmill Shuriken", self.player) - def set_messenger_rules(self) -> None: - super().set_messenger_rules() - for loc, rule in self.extra_rules.items(): - if not self.world.options.shuffle_seals and "Seal" in loc: - continue - if not self.world.options.shuffle_shards and "Shard" in loc: - continue - add_rule(self.world.multiworld.get_location(loc, self.player), rule, "or") + def can_dboost(self, state: CollectionState) -> bool: + return state.has("Second Wind", self.player) # who really needs meditation + + def can_destroy_projectiles(self, state: CollectionState) -> bool: + return super().can_destroy_projectiles(state) or self.has_windmill(state) + + def can_leash(self, state: CollectionState) -> bool: + return self.has_dart(state) and self.can_dboost(state) class MessengerOOBRules(MessengerRules): @@ -226,7 +493,9 @@ class MessengerOOBRules(MessengerRules): self.required_seals = max(1, world.required_seals) self.region_rules = { "Elemental Skylands": - lambda state: state.has_any({"Windmill Shuriken", "Wingsuit", "Rope Dart", "Magic Firefly"}, self.player), + lambda state: state.has_any( + {"Windmill Shuriken", "Wingsuit", "Rope Dart", "Magic Firefly"}, self.player + ), "Music Box": lambda state: state.has_all(set(NOTES), self.player) or self.has_enough_seals(state), } @@ -240,8 +509,10 @@ class MessengerOOBRules(MessengerRules): lambda state: state.has_all({"Demon King Crown", "Magic Firefly"}, self.player), "Autumn Hills Seal - Spike Ball Darts": self.has_dart, "Ninja Village Seal - Tree House": self.has_dart, - "Underworld Seal - Fireball Wave": lambda state: state.has_any({"Wingsuit", "Windmill Shuriken"}, - self.player), + "Underworld Seal - Fireball Wave": lambda state: state.has_any( + {"Wingsuit", "Windmill Shuriken"}, + self.player + ), "Tower of Time Seal - Time Waster": self.has_dart, } @@ -251,18 +522,8 @@ class MessengerOOBRules(MessengerRules): def set_self_locking_items(world: "MessengerWorld", player: int) -> None: - multiworld = world.multiworld - - # do the ones for seal shuffle on and off first - allow_self_locking_items(multiworld.get_location("Searing Crags - Key of Strength", player), "Power Thistle") - allow_self_locking_items(multiworld.get_location("Sunken Shrine - Key of Love", player), "Sun Crest", "Moon Crest") - allow_self_locking_items(multiworld.get_location("Corrupted Future - Key of Courage", player), "Demon King Crown") - - # add these locations when seals are shuffled - if world.options.shuffle_seals: - allow_self_locking_items(multiworld.get_location("Elemental Skylands Seal - Water", player), "Currents Master") - # add these locations when seals and shards aren't shuffled - elif not world.options.shuffle_shards: - for entrance in multiworld.get_region("Cloud Ruins", player).entrances: - entrance.access_rule = lambda state: state.has("Wingsuit", player) or state.has("Rope Dart", player) - allow_self_locking_items(multiworld.get_region("Forlorn Temple", player), *PHOBEKINS) + # locations where these placements are always valid + allow_self_locking_items(world.get_location("Searing Crags - Key of Strength"), "Power Thistle") + allow_self_locking_items(world.get_location("Sunken Shrine - Key of Love"), "Sun Crest", "Moon Crest") + allow_self_locking_items(world.get_location("Corrupted Future - Key of Courage"), "Demon King Crown") + allow_self_locking_items(world.get_location("Elemental Skylands Seal - Water"), "Currents Master") diff --git a/worlds/messenger/subclasses.py b/worlds/messenger/subclasses.py index b6a0b80b21..b60aeb179f 100644 --- a/worlds/messenger/subclasses.py +++ b/worlds/messenger/subclasses.py @@ -1,36 +1,48 @@ from functools import cached_property -from typing import Optional, TYPE_CHECKING, cast +from typing import Optional, TYPE_CHECKING -from BaseClasses import CollectionState, Item, ItemClassification, Location, Region -from .constants import NOTES, PHOBEKINS, PROG_ITEMS, USEFUL_ITEMS -from .regions import MEGA_SHARDS, REGIONS, SEALS -from .shop import FIGURINES, PROG_SHOP_ITEMS, SHOP_ITEMS, USEFUL_SHOP_ITEMS +from BaseClasses import CollectionState, Entrance, Item, ItemClassification, Location, Region +from .regions import LOCATIONS, MEGA_SHARDS +from .shop import FIGURINES, SHOP_ITEMS if TYPE_CHECKING: from . import MessengerWorld +class MessengerEntrance(Entrance): + world: Optional["MessengerWorld"] = None + + class MessengerRegion(Region): - - def __init__(self, name: str, world: "MessengerWorld") -> None: + parent: str + entrance_type = MessengerEntrance + + def __init__(self, name: str, world: "MessengerWorld", parent: Optional[str] = None) -> None: super().__init__(name, world.player, world.multiworld) - locations = [loc for loc in REGIONS[self.name]] - if self.name == "The Shop": + self.parent = parent + locations = [] + if name in LOCATIONS: + locations = [loc for loc in LOCATIONS[name]] + # portal event locations since portals can be opened from their exit regions + if name.endswith("Portal"): + locations.append(name.replace(" -", "")) + + if name == "The Shop": shop_locations = {f"The Shop - {shop_loc}": world.location_name_to_id[f"The Shop - {shop_loc}"] for shop_loc in SHOP_ITEMS} self.add_locations(shop_locations, MessengerShopLocation) - elif self.name == "The Craftsman's Corner": + elif name == "The Craftsman's Corner": self.add_locations({figurine: world.location_name_to_id[figurine] for figurine in FIGURINES}, MessengerLocation) - elif self.name == "Tower HQ": + elif name == "Tower HQ": locations.append("Money Wrench") - if world.options.shuffle_seals and self.name in SEALS: - locations += [seal_loc for seal_loc in SEALS[self.name]] - if world.options.shuffle_shards and self.name in MEGA_SHARDS: - locations += [shard for shard in MEGA_SHARDS[self.name]] + + if world.options.shuffle_shards and name in MEGA_SHARDS: + locations += MEGA_SHARDS[name] loc_dict = {loc: world.location_name_to_id.get(loc, None) for loc in locations} self.add_locations(loc_dict, MessengerLocation) - world.multiworld.regions.append(self) + + self.multiworld.regions.append(self) class MessengerLocation(Location): @@ -39,46 +51,36 @@ class MessengerLocation(Location): def __init__(self, player: int, name: str, loc_id: Optional[int], parent: MessengerRegion) -> None: super().__init__(player, name, loc_id, parent) if loc_id is None: - self.place_locked_item(MessengerItem(name, parent.player, None)) + if name == "Rescue Phantom": + name = "Do the Thing!" + self.place_locked_item(MessengerItem(name, ItemClassification.progression, None, parent.player)) class MessengerShopLocation(MessengerLocation): @cached_property def cost(self) -> int: name = self.name.replace("The Shop - ", "") # TODO use `remove_prefix` when 3.8 finally gets dropped - world = cast("MessengerWorld", self.parent_region.multiworld.worlds[self.player]) + world = self.parent_region.multiworld.worlds[self.player] shop_data = SHOP_ITEMS[name] if shop_data.prerequisite: prereq_cost = 0 if isinstance(shop_data.prerequisite, set): for prereq in shop_data.prerequisite: - prereq_cost +=\ - cast(MessengerShopLocation, - world.multiworld.get_location(prereq, self.player)).cost + loc = world.multiworld.get_location(prereq, self.player) + assert isinstance(loc, MessengerShopLocation) + prereq_cost += loc.cost else: - prereq_cost +=\ - cast(MessengerShopLocation, - world.multiworld.get_location(shop_data.prerequisite, self.player)).cost + loc = world.multiworld.get_location(shop_data.prerequisite, self.player) + assert isinstance(loc, MessengerShopLocation) + prereq_cost += loc.cost return world.shop_prices[name] + prereq_cost return world.shop_prices[name] def access_rule(self, state: CollectionState) -> bool: - world = cast("MessengerWorld", state.multiworld.worlds[self.player]) + world = state.multiworld.worlds[self.player] can_afford = state.has("Shards", self.player, min(self.cost, world.total_shards)) return can_afford class MessengerItem(Item): game = "The Messenger" - - def __init__(self, name: str, player: int, item_id: Optional[int] = None, override_progression: bool = False, - count: int = 0) -> None: - if count: - item_class = ItemClassification.progression_skip_balancing - elif item_id is None or override_progression or name in {*NOTES, *PROG_ITEMS, *PHOBEKINS, *PROG_SHOP_ITEMS}: - item_class = ItemClassification.progression - elif name in {*USEFUL_ITEMS, *USEFUL_SHOP_ITEMS}: - item_class = ItemClassification.useful - else: - item_class = ItemClassification.filler - super().__init__(name, item_class, item_id, player) diff --git a/worlds/messenger/test/__init__.py b/worlds/messenger/test/__init__.py index f3fcd4ae2d..83bb248d64 100644 --- a/worlds/messenger/test/__init__.py +++ b/worlds/messenger/test/__init__.py @@ -1,4 +1,4 @@ -from test.TestBase import WorldTestBase +from test.bases import WorldTestBase from .. import MessengerWorld diff --git a/worlds/messenger/test/test_access.py b/worlds/messenger/test/test_access.py index 7a77a9b066..016f3b57cd 100644 --- a/worlds/messenger/test/test_access.py +++ b/worlds/messenger/test/test_access.py @@ -22,11 +22,27 @@ class AccessTest(MessengerTestBase): def test_dart(self) -> None: """locations that hard require the Rope Dart""" locations = [ - "Ninja Village Seal - Tree House", "Autumn Hills - Key of Hope", "Howling Grotto Seal - Crushing Pits", - "Glacial Peak Seal - Ice Climbers", "Tower of Time Seal - Time Waster", "Tower of Time Seal - Lantern Climb", - "Tower of Time Seal - Arcane Orbs", "Cloud Ruins Seal - Ghost Pit", "Underworld Seal - Rising Fanta", - "Elemental Skylands - Key of Symbiosis", "Elemental Skylands Seal - Water", - "Elemental Skylands Seal - Fire", "Earth Mega Shard", "Water Mega Shard", "Rescue Phantom", + "Ninja Village Seal - Tree House", + "Autumn Hills - Key of Hope", + "Forlorn Temple - Demon King", + "Down Under Mega Shard", + "Howling Grotto Seal - Crushing Pits", + "Glacial Peak Seal - Ice Climbers", + "Tower of Time Seal - Time Waster", + "Tower of Time Seal - Lantern Climb", + "Tower of Time Seal - Arcane Orbs", + "Cloud Ruins Seal - Ghost Pit", + "Cloud Ruins Seal - Money Farm Room", + "Cloud Ruins Seal - Toothbrush Alley", + "Money Farm Room Mega Shard 1", + "Money Farm Room Mega Shard 2", + "Underworld Seal - Rising Fanta", + "Elemental Skylands - Key of Symbiosis", + "Elemental Skylands Seal - Water", + "Elemental Skylands Seal - Fire", + "Earth Mega Shard", + "Water Mega Shard", + "Rescue Phantom", ] items = [["Rope Dart"]] self.assertAccessDependency(locations, items) @@ -136,11 +152,37 @@ class AccessTest(MessengerTestBase): items = [["Demon King Crown"]] self.assertAccessDependency(locations, items) + def test_dboost(self) -> None: + """ + short for damage boosting, d-boosting is a technique in video games where the player intentionally or + unintentionally takes damage and uses the several following frames of invincibility to defeat or get past an + enemy or obstacle, most commonly used in platformers such as the Super Mario games + """ + locations = [ + "Riviere Turquoise Seal - Bounces and Balls", "Searing Crags Seal - Triple Ball Spinner", + "Forlorn Temple - Demon King", "Forlorn Temple Seal - Rocket Maze", "Forlorn Temple Seal - Rocket Sunset", + "Sunny Day Mega Shard", "Down Under Mega Shard", + ] + items = [["Path of Resilience", "Meditation", "Second Wind"]] + self.assertAccessDependency(locations, items) + + def test_currents(self) -> None: + """there's one of these but oh man look at it go""" + self.assertAccessDependency(["Elemental Skylands Seal - Water"], [["Currents Master"]]) + + def test_strike(self) -> None: + """strike is pretty cool but it doesn't block much""" + locations = [ + "Glacial Peak Seal - Projectile Spike Pit", "Elemental Skylands Seal - Fire", + ] + items = [["Strike of the Ninja"]] + self.assertAccessDependency(locations, items) + def test_goal(self) -> None: """Test some different states to verify goal requires the correct items""" - self.collect_all_but([*NOTES, "Rescue Phantom"]) + self.collect_all_but([*NOTES, "Do the Thing!"]) self.assertEqual(self.can_reach_location("Rescue Phantom"), False) - self.collect_all_but(["Key of Love", "Rescue Phantom"]) + self.collect_all_but(["Key of Love", "Do the Thing!"]) self.assertBeatable(False) self.collect_by_name(["Key of Love"]) self.assertEqual(self.can_reach_location("Rescue Phantom"), True) @@ -159,14 +201,12 @@ class ItemsAccessTest(MessengerTestBase): "Searing Crags - Key of Strength": ["Power Thistle"], "Sunken Shrine - Key of Love": ["Sun Crest", "Moon Crest"], "Corrupted Future - Key of Courage": ["Demon King Crown"], - "Cloud Ruins - Acro": ["Ruxxtin's Amulet"], - "Forlorn Temple - Demon King": PHOBEKINS } - self.multiworld.state = self.multiworld.get_all_state(True) - self.remove_by_name(location_lock_pairs.values()) + self.collect_all_but([item for items in location_lock_pairs.values() for item in items]) for loc in location_lock_pairs: for item_name in location_lock_pairs[loc]: item = self.get_item_by_name(item_name) with self.subTest("Fulfills Accessibility", location=loc, item=item_name): - self.assertTrue(self.multiworld.get_location(loc, self.player).can_fill(self.multiworld.state, item, True)) + self.assertTrue(self.multiworld.get_location(loc, self.player).can_fill(self.multiworld.state, item, + True)) diff --git a/worlds/messenger/test/test_logic.py b/worlds/messenger/test/test_logic.py index 15df89b920..c13bd5c5a0 100644 --- a/worlds/messenger/test/test_logic.py +++ b/worlds/messenger/test/test_logic.py @@ -41,7 +41,7 @@ class HardLogicTest(MessengerTestBase): # cloud ruins "Cloud Ruins - Acro", "Cloud Ruins Seal - Ghost Pit", "Cloud Ruins Seal - Toothbrush Alley", "Cloud Ruins Seal - Saw Pit", "Cloud Ruins Seal - Money Farm Room", - "Cloud Entrance Mega Shard", "Time Warp Mega Shard", "Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2", + "Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2", # underworld "Underworld Seal - Rising Fanta", "Underworld Seal - Sharp and Windy Climb", # elemental skylands @@ -80,18 +80,6 @@ class HardLogicTest(MessengerTestBase): self.collect(item) self.assertTrue(self.can_reach_location(special_loc)) - def test_glacial(self) -> None: - """Test Glacial Peak locations.""" - self.assertAccessDependency(["Glacial Peak Seal - Ice Climbers"], - [["Second Wind", "Meditation"], ["Rope Dart"], ["Wingsuit"]], - True) - self.assertAccessDependency(["Glacial Peak Seal - Projectile Spike Pit"], - [["Strike of the Ninja"], ["Windmill Shuriken"], ["Rope Dart"], ["Wingsuit"]], - True) - self.assertAccessDependency(["Glacial Peak Seal - Glacial Air Swag", "Glacial Peak Mega Shard"], - [["Windmill Shuriken"], ["Wingsuit"], ["Rope Dart"]], - True) - class NoLogicTest(MessengerTestBase): options = { diff --git a/worlds/messenger/test/test_notes.py b/worlds/messenger/test/test_notes.py index 46cec5f3c8..fdb1cef1df 100644 --- a/worlds/messenger/test/test_notes.py +++ b/worlds/messenger/test/test_notes.py @@ -2,29 +2,19 @@ from . import MessengerTestBase from ..constants import NOTES -class TwoNoteGoalTest(MessengerTestBase): - options = { - "notes_needed": 2, - } +class PrecollectedNotesTestBase(MessengerTestBase): + starting_notes: int = 0 + + @property + def run_default_tests(self) -> bool: + return False def test_precollected_notes(self) -> None: - self.assertEqual(self.multiworld.state.count_group("Notes", self.player), 4) - - -class FourNoteGoalTest(MessengerTestBase): - options = { - "notes_needed": 4, - } - - def test_precollected_notes(self) -> None: - self.assertEqual(self.multiworld.state.count_group("Notes", self.player), 2) - - -class DefaultGoalTest(MessengerTestBase): - def test_precollected_notes(self) -> None: - self.assertEqual(self.multiworld.state.count_group("Notes", self.player), 0) + self.assertEqual(self.multiworld.state.count_group("Notes", self.player), self.starting_notes) def test_goal(self) -> None: + if self.__class__ is not PrecollectedNotesTestBase: + return self.assertBeatable(False) self.collect_by_name(NOTES) rope_dart = self.get_item_by_name("Rope Dart") @@ -33,3 +23,17 @@ class DefaultGoalTest(MessengerTestBase): self.remove(rope_dart) self.collect_by_name("Wingsuit") self.assertBeatable(True) + + +class TwoNoteGoalTest(PrecollectedNotesTestBase): + options = { + "notes_needed": 2, + } + starting_notes = 4 + + +class FourNoteGoalTest(PrecollectedNotesTestBase): + options = { + "notes_needed": 4, + } + starting_notes = 2 diff --git a/worlds/messenger/test/test_options.py b/worlds/messenger/test/test_options.py new file mode 100644 index 0000000000..ea84af8038 --- /dev/null +++ b/worlds/messenger/test/test_options.py @@ -0,0 +1,35 @@ +from BaseClasses import CollectionState +from Fill import distribute_items_restrictive +from . import MessengerTestBase +from .. import MessengerWorld +from ..options import Logic + + +class LimitedMovementTest(MessengerTestBase): + options = { + "limited_movement": "true", + "shuffle_shards": "true", + } + + @property + def run_default_tests(self) -> bool: + # This test base fails reachability tests. Not sure if the core tests should change to support that + return False + + def test_options(self) -> None: + """Tests that options were correctly changed.""" + assert isinstance(self.multiworld.worlds[self.player], MessengerWorld) + self.assertEqual(Logic.option_hard, self.world.options.logic_level) + + +class EarlyMeditationTest(MessengerTestBase): + options = { + "early_meditation": "true", + } + + def test_option(self) -> None: + """Checks that Meditation gets placed early""" + distribute_items_restrictive(self.multiworld) + sphere1 = self.multiworld.get_reachable_locations(CollectionState(self.multiworld)) + items = [loc.item.name for loc in sphere1] + self.assertIn("Meditation", items) diff --git a/worlds/messenger/test/test_portals.py b/worlds/messenger/test/test_portals.py new file mode 100644 index 0000000000..6ebb183813 --- /dev/null +++ b/worlds/messenger/test/test_portals.py @@ -0,0 +1,33 @@ +from BaseClasses import CollectionState +from . import MessengerTestBase +from ..portals import PORTALS + + +class PortalTestBase(MessengerTestBase): + def test_portal_reqs(self) -> None: + """tests the paths to open a portal if only that portal is closed with vanilla connections.""" + # portal and requirements to reach it if it's the only closed portal + portal_requirements = { + "Autumn Hills Portal": [["Wingsuit"]], # grotto -> bamboo -> catacombs -> hills + "Riviere Turquoise Portal": [["Candle", "Wingsuit", "Rope Dart"]], # hills -> catacombs -> dark cave -> riviere + "Howling Grotto Portal": [["Wingsuit"], ["Meditation", "Second Wind"]], # crags -> quillshroom -> grotto + "Sunken Shrine Portal": [["Seashell"]], # crags -> quillshroom -> grotto -> shrine + "Searing Crags Portal": [["Wingsuit"], ["Rope Dart"]], # grotto -> quillshroom -> crags there's two separate paths + "Glacial Peak Portal": [["Wingsuit", "Second Wind", "Meditation"], ["Rope Dart"]], # grotto -> quillshroom -> crags -> peak or crags -> peak + } + + for portal in PORTALS: + name = f"{portal} Portal" + entrance_name = f"ToTHQ {name}" + with self.subTest(portal=name, entrance_name=entrance_name): + entrance = self.multiworld.get_entrance(entrance_name, self.player) + # this emulates the portal being initially closed + entrance.access_rule = lambda state: state.has(name, self.player) + for grouping in portal_requirements[name]: + test_state = CollectionState(self.multiworld) + self.assertFalse(entrance.can_reach(test_state), "reachable with nothing") + items = self.get_items_by_name(grouping) + for item in items: + test_state.collect(item) + self.assertTrue(entrance.can_reach(test_state), grouping) + entrance.access_rule = lambda state: True diff --git a/worlds/messenger/test/test_shop.py b/worlds/messenger/test/test_shop.py index ee7e82d6cd..971ff1763b 100644 --- a/worlds/messenger/test/test_shop.py +++ b/worlds/messenger/test/test_shop.py @@ -24,25 +24,6 @@ class ShopCostTest(MessengerTestBase): self.assertTrue(loc in SHOP_ITEMS) self.assertEqual(len(prices), len(SHOP_ITEMS)) - def test_dboost(self) -> None: - locations = [ - "Riviere Turquoise Seal - Bounces and Balls", - "Forlorn Temple - Demon King", "Forlorn Temple Seal - Rocket Maze", "Forlorn Temple Seal - Rocket Sunset", - "Sunny Day Mega Shard", "Down Under Mega Shard", - ] - items = [["Path of Resilience", "Meditation", "Second Wind"]] - self.assertAccessDependency(locations, items) - - def test_currents(self) -> None: - self.assertAccessDependency(["Elemental Skylands Seal - Water"], [["Currents Master"]]) - - def test_strike(self) -> None: - locations = [ - "Glacial Peak Seal - Projectile Spike Pit", "Elemental Skylands Seal - Fire", - ] - items = [["Strike of the Ninja"]] - self.assertAccessDependency(locations, items) - class ShopCostMinTest(ShopCostTest): options = { diff --git a/worlds/messenger/test/test_shop_chest.py b/worlds/messenger/test/test_shop_chest.py index f2030c63de..2ac3069726 100644 --- a/worlds/messenger/test/test_shop_chest.py +++ b/worlds/messenger/test/test_shop_chest.py @@ -4,19 +4,14 @@ from . import MessengerTestBase class AllSealsRequired(MessengerTestBase): options = { - "shuffle_seals": "false", "goal": "power_seal_hunt", } - def test_seals_shuffled(self) -> None: - """Shuffle seals should be forced on when shop chest is the goal so test it.""" - self.assertTrue(self.multiworld.shuffle_seals[self.player]) - def test_chest_access(self) -> None: """Defaults to a total of 45 power seals in the pool and required.""" with self.subTest("Access Dependency"): self.assertEqual(len([seal for seal in self.multiworld.itempool if seal.name == "Power Seal"]), - self.multiworld.total_seals[self.player]) + self.world.options.total_seals) locations = ["Rescue Phantom"] items = [["Power Seal"]] self.assertAccessDependency(locations, items) @@ -24,7 +19,7 @@ class AllSealsRequired(MessengerTestBase): self.assertEqual(self.can_reach_location("Rescue Phantom"), False) self.assertBeatable(False) - self.collect_all_but(["Power Seal", "Rescue Phantom"]) + self.collect_all_but(["Power Seal", "Do the Thing!"]) self.assertEqual(self.can_reach_location("Rescue Phantom"), False) self.assertBeatable(False) self.collect_by_name("Power Seal") @@ -40,7 +35,7 @@ class HalfSealsRequired(MessengerTestBase): def test_seals_amount(self) -> None: """Should have 45 power seals in the item pool and half that required""" - self.assertEqual(self.multiworld.total_seals[self.player], 45) + self.assertEqual(self.world.options.total_seals, 45) self.assertEqual(self.world.total_seals, 45) self.assertEqual(self.world.required_seals, 22) total_seals = [seal for seal in self.multiworld.itempool if seal.name == "Power Seal"] @@ -59,7 +54,7 @@ class ThirtyThirtySeals(MessengerTestBase): def test_seals_amount(self) -> None: """Should have 30 power seals in the pool and 33 percent of that required.""" - self.assertEqual(self.multiworld.total_seals[self.player], 30) + self.assertEqual(self.world.options.total_seals, 30) self.assertEqual(self.world.total_seals, 30) self.assertEqual(self.world.required_seals, 10) total_seals = [seal for seal in self.multiworld.itempool if seal.name == "Power Seal"] @@ -77,7 +72,7 @@ class MaxSealsNoShards(MessengerTestBase): def test_seals_amount(self) -> None: """Should set total seals to 70 since shards aren't shuffled.""" - self.assertEqual(self.multiworld.total_seals[self.player], 85) + self.assertEqual(self.world.options.total_seals, 85) self.assertEqual(self.world.total_seals, 70) @@ -90,7 +85,7 @@ class MaxSealsWithShards(MessengerTestBase): def test_seals_amount(self) -> None: """Should have 85 seals in the pool with all required and be a valid seed.""" - self.assertEqual(self.multiworld.total_seals[self.player], 85) + self.assertEqual(self.world.options.total_seals, 85) self.assertEqual(self.world.total_seals, 85) self.assertEqual(self.world.required_seals, 85) total_seals = [seal for seal in self.multiworld.itempool if seal.name == "Power Seal"] From d3019421de80b4aa44739fc836bd75b02a250067 Mon Sep 17 00:00:00 2001 From: Silvris <58583688+Silvris@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:26:21 -0500 Subject: [PATCH 25/49] KDL3: fix invalid inno_setup components and deathlink messages (#2922) * remove component checking * fix missing deathlink messages * move reads under deathlink check --- inno_setup.iss | 8 ++++---- worlds/kdl3/Client.py | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/inno_setup.iss b/inno_setup.iss index c1b634292f..7d089def95 100644 --- a/inno_setup.iss +++ b/inno_setup.iss @@ -131,10 +131,10 @@ Root: HKCR; Subkey: "{#MyAppName}l2acpatch"; ValueData: "Arc Root: HKCR; Subkey: "{#MyAppName}l2acpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Root: HKCR; Subkey: "{#MyAppName}l2acpatch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; -Root: HKCR; Subkey: ".apkdl3"; ValueData: "{#MyAppName}kdl3patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/sni -Root: HKCR; Subkey: "{#MyAppName}kdl3patch"; ValueData: "Archipelago Kirby's Dream Land 3 Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/sni -Root: HKCR; Subkey: "{#MyAppName}kdl3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni -Root: HKCR; Subkey: "{#MyAppName}kdl3patch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/sni +Root: HKCR; Subkey: ".apkdl3"; ValueData: "{#MyAppName}kdl3patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; +Root: HKCR; Subkey: "{#MyAppName}kdl3patch"; ValueData: "Archipelago Kirby's Dream Land 3 Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; +Root: HKCR; Subkey: "{#MyAppName}kdl3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; +Root: HKCR; Subkey: "{#MyAppName}kdl3patch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Root: HKCR; Subkey: ".apmc"; ValueData: "{#MyAppName}mcdata"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Root: HKCR; Subkey: "{#MyAppName}mcdata"; ValueData: "Archipelago Minecraft Data"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; diff --git a/worlds/kdl3/Client.py b/worlds/kdl3/Client.py index c10dd6cebb..a1e68f8b67 100644 --- a/worlds/kdl3/Client.py +++ b/worlds/kdl3/Client.py @@ -309,10 +309,13 @@ class KDL3SNIClient(SNIClient): if current_bgm[0] in (0x00, 0x21, 0x22, 0x23, 0x25, 0x2A, 0x2B): return # null, title screen, opening, save select, true and false endings game_state = await snes_read(ctx, KDL3_GAME_STATE, 1) - current_hp = await snes_read(ctx, KDL3_KIRBY_HP, 1) if "DeathLink" in ctx.tags and game_state[0] == 0x00 and ctx.last_death_link + 1 < time.time(): + current_hp = await snes_read(ctx, KDL3_KIRBY_HP, 1) + current_world = struct.unpack("H", await snes_read(ctx, KDL3_CURRENT_WORLD, 2))[0] + current_level = struct.unpack("H", await snes_read(ctx, KDL3_CURRENT_LEVEL, 2))[0] currently_dead = current_hp[0] == 0x00 - await ctx.handle_deathlink_state(currently_dead) + message = deathlink_messages[self.levels[current_world][current_level - 1]] + await ctx.handle_deathlink_state(currently_dead, f"{ctx.player_names[ctx.slot]}{message}") recv_count = await snes_read(ctx, KDL3_RECV_COUNT, 2) recv_amount = unpack("H", recv_count)[0] From a3125cb06e4bc142161e245a32fb0f34562fab8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Bolduc?= <16137441+Jouramie@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:30:14 -0400 Subject: [PATCH 26/49] Core: Fix OptionList and OptionSet to allow Iterable of Iterable (#2911) * fix, maybe * typegard for iterable of any * wow I'm so tired I just changed the method name without changing what it actually does... * also exclude bytes in is_iterable_but_str * apply pr comments * Update Utils.py Co-authored-by: Doug Hoskisson * Revert "also exclude bytes in is_iterable_but_str" This reverts commit cf087d2ee20727dbbe561c8c0f90aa85ef0a5d4b. --------- Co-authored-by: Doug Hoskisson --- Options.py | 8 ++++---- Utils.py | 11 ++++------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Options.py b/Options.py index ff8ad11c5a..f19c042f33 100644 --- a/Options.py +++ b/Options.py @@ -12,7 +12,7 @@ from dataclasses import dataclass from schema import And, Optional, Or, Schema -from Utils import get_fuzzy_results, is_iterable_of_str +from Utils import get_fuzzy_results, is_iterable_except_str if typing.TYPE_CHECKING: from BaseClasses import PlandoOptions @@ -847,7 +847,7 @@ class OptionList(Option[typing.List[typing.Any]], VerifyKeys): default: typing.Union[typing.List[typing.Any], typing.Tuple[typing.Any, ...]] = () supports_weighting = False - def __init__(self, value: typing.Iterable[str]): + def __init__(self, value: typing.Iterable[typing.Any]): self.value = list(deepcopy(value)) super(OptionList, self).__init__() @@ -857,7 +857,7 @@ class OptionList(Option[typing.List[typing.Any]], VerifyKeys): @classmethod def from_any(cls, data: typing.Any): - if is_iterable_of_str(data): + if is_iterable_except_str(data): cls.verify_keys(data) return cls(data) return cls.from_text(str(data)) @@ -883,7 +883,7 @@ class OptionSet(Option[typing.Set[str]], VerifyKeys): @classmethod def from_any(cls, data: typing.Any): - if is_iterable_of_str(data): + if is_iterable_except_str(data): cls.verify_keys(data) return cls(data) return cls.from_text(str(data)) diff --git a/Utils.py b/Utils.py index cea6405a38..3c63b42ccb 100644 --- a/Utils.py +++ b/Utils.py @@ -713,7 +713,7 @@ def messagebox(title: str, text: str, error: bool = False) -> None: import ctypes style = 0x10 if error else 0x0 return ctypes.windll.user32.MessageBoxW(0, text, title, style) - + # fall back to tk try: import tkinter @@ -969,11 +969,8 @@ class RepeatableChain: return sum(len(iterable) for iterable in self.iterable) -def is_iterable_of_str(obj: object) -> TypeGuard[typing.Iterable[str]]: - """ but not a `str` (because technically, `str` is `Iterable[str]`) """ +def is_iterable_except_str(obj: object) -> TypeGuard[typing.Iterable[typing.Any]]: + """ `str` is `Iterable`, but that's not what we want """ if isinstance(obj, str): return False - if not isinstance(obj, typing.Iterable): - return False - obj_it: typing.Iterable[object] = obj - return all(isinstance(v, str) for v in obj_it) + return isinstance(obj, typing.Iterable) From 3d56f3c096e6bb54e8532eaa2690e14340be5290 Mon Sep 17 00:00:00 2001 From: CubeSoldier <119427944+CubeSoldier@users.noreply.github.com> Date: Tue, 12 Mar 2024 00:42:56 +0100 Subject: [PATCH 27/49] Docs: Added snes9x-nwa as recommended emulator to the setup guides for SNES games (#1778) * Added snes9x-nwa as recommended emulator to the setup guides * Removed snes9x-nwa from the setup guides of DKC3 and SMW * Update worlds/alttp/docs/multiworld_en.md Co-authored-by: Aaron Wagener * Removed duplicate text Minor grammar and spelling fixes * Unified required software for SM, SMZ3 and SoE with ALTTP * Added instructions for usage of BSNES-Plus for ALTTP, SM and SMZ3 --------- Co-authored-by: Aaron Wagener --- worlds/alttp/docs/multiworld_en.md | 19 +++++++++++++---- worlds/sm/docs/multiworld_en.md | 33 +++++++++++++++++++++--------- worlds/smz3/docs/multiworld_en.md | 32 ++++++++++++++++++++--------- worlds/soe/docs/multiworld_en.md | 27 +++++++++++++++--------- 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/worlds/alttp/docs/multiworld_en.md b/worlds/alttp/docs/multiworld_en.md index 7521def36e..5d7fc43e31 100644 --- a/worlds/alttp/docs/multiworld_en.md +++ b/worlds/alttp/docs/multiworld_en.md @@ -5,11 +5,12 @@ - [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). - [SNI](https://github.com/alttpo/sni/releases). This is automatically included with your Archipelago installation above. - SNI is not compatible with (Q)Usb2Snes. -- Hardware or software capable of loading and playing SNES ROM files +- Hardware or software capable of loading and playing SNES ROM files, including: - An emulator capable of connecting to SNI - ([snes9x rr](https://github.com/gocha/snes9x-rr/releases), - [BizHawk](https://tasvideos.org/BizHawk), or - [RetroArch](https://retroarch.com?page=platforms) 1.10.1 or newer). Or, + ([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](http://tasvideos.org/BizHawk.html), or + [RetroArch](https://retroarch.com?page=platforms) 1.10.1 or newer) - An SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), or other compatible hardware. **note: modded SNES minis are currently not supported by SNI. Some users have claimed success with QUsb2Snes for this system, but it is not supported.** @@ -47,6 +48,11 @@ client, and will also create your ROM in the same place as your patch file. When the client launched automatically, SNI should have also automatically launched in the background. If this is its first time launching, you may be prompted to allow it to communicate through the Windows Firewall. +#### snes9x-nwa + +1. Click on the Network Menu and check **Enable Emu Network Control** +2. Load your ROM file if it hasn't already been loaded. + ##### snes9x-rr 1. Load your ROM file if it hasn't already been loaded. @@ -58,6 +64,11 @@ first time launching, you may be prompted to allow it to communicate through the 6. If you see an error while loading the script that states `socket.dll missing` or similar, navigate to the folder of the lua you are using in your file explorer and copy the `socket.dll` to the base folder of your snes9x install. +#### BSNES-Plus + +1. Load your ROM file if it hasn't already been loaded. +2. The emulator should automatically connect while SNI is running. + ##### BizHawk 1. Ensure you have the BSNES core loaded. This is done with the main menubar, under: diff --git a/worlds/sm/docs/multiworld_en.md b/worlds/sm/docs/multiworld_en.md index 0e82be7695..abd9f42f88 100644 --- a/worlds/sm/docs/multiworld_en.md +++ b/worlds/sm/docs/multiworld_en.md @@ -2,16 +2,18 @@ ## Required Software -- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). - - -- Hardware or software capable of loading and playing SNES ROM files - - An emulator capable of connecting to SNI such as: - - snes9x-rr from: [snes9x rr](https://github.com/gocha/snes9x-rr/releases), - - BizHawk from: [TASVideos](https://tasvideos.org/BizHawk) - - RetroArch 1.10.1 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or, - - An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other - compatible hardware +- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). +- [SNI](https://github.com/alttpo/sni/releases). This is automatically included with your Archipelago installation above. +- SNI is not compatible with (Q)Usb2Snes. +- Hardware or software capable of loading and playing SNES ROM files, including: + - An emulator capable of connecting to 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](http://tasvideos.org/BizHawk.html), or + [RetroArch](https://retroarch.com?page=platforms) 1.10.1 or newer) + - An SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), or other compatible hardware. **note: + modded SNES minis are currently not supported by SNI. Some users have claimed success with QUsb2Snes for this system, + but it is not supported.** - Your legally obtained Super Metroid ROM file, probably named `Super Metroid (Japan, USA).sfc` ## Installation Procedures @@ -81,6 +83,11 @@ client, and will also create your ROM in the same place as your patch file. When the client launched automatically, SNI should have also automatically launched in the background. If this is its first time launching, you may be prompted to allow it to communicate through the Windows Firewall. +#### snes9x-nwa + +1. Click on the Network Menu and check **Enable Emu Network Control** +2. Load your ROM file if it hasn't already been loaded. + ##### snes9x-rr 1. Load your ROM file if it hasn't already been loaded. @@ -92,6 +99,12 @@ first time launching, you may be prompted to allow it to communicate through the 6. If you see an error while loading the script that states `socket.dll missing` or similar, navigate to the folder of the lua you are using in your file explorer and copy the `socket.dll` to the base folder of your snes9x install. +#### BSNES-Plus + +1. Load your ROM file if it hasn't already been loaded. +2. The emulator should automatically connect while SNI is running. + + ##### BizHawk 1. Ensure you have the BSNES core loaded. This is done with the main menubar, under: diff --git a/worlds/smz3/docs/multiworld_en.md b/worlds/smz3/docs/multiworld_en.md index fadd55028f..5e226798a3 100644 --- a/worlds/smz3/docs/multiworld_en.md +++ b/worlds/smz3/docs/multiworld_en.md @@ -2,16 +2,18 @@ ## Required Software -- One of the client programs: - - [SNIClient](https://github.com/ArchipelagoMW/Archipelago/releases), included with the main - Archipelago install. -- Hardware or software capable of loading and playing SNES ROM files - - An emulator capable of connecting to SNI such as: - - snes9x-rr from: [snes9x rr](https://github.com/gocha/snes9x-rr/releases), - - BizHawk from: [TASVideos](https://tasvideos.org/BizHawk), or - - RetroArch 1.10.3 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or, - - An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other - compatible hardware +- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). +- [SNI](https://github.com/alttpo/sni/releases). This is automatically included with your Archipelago installation above. +- SNI is not compatible with (Q)Usb2Snes. +- Hardware or software capable of loading and playing SNES ROM files, including: + - An emulator capable of connecting to 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](http://tasvideos.org/BizHawk.html), or + [RetroArch](https://retroarch.com?page=platforms) 1.10.1 or newer) + - An SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), or other compatible hardware. **note: + modded SNES minis are currently not supported by SNI. Some users have claimed success with QUsb2Snes for this system, + but it is not supported.** - Your legally obtained Super Metroid ROM file, probably named `Super Metroid (Japan, USA).sfc` and Your Japanese Zelda3 v1.0 ROM file, probably named `Zelda no Densetsu - Kamigami no Triforce (Japan).sfc` @@ -78,6 +80,11 @@ client, and will also create your ROM in the same place as your patch file. When the client launched automatically, SNI should have also automatically launched in the background. If this is its first time launching, you may be prompted to allow it to communicate through the Windows Firewall. +#### snes9x-nwa + +1. Click on the Network Menu and check **Enable Emu Network Control** +2. Load your ROM file if it hasn't already been loaded. + ##### snes9x-rr 1. Load your ROM file if it hasn't already been loaded. @@ -89,6 +96,11 @@ first time launching, you may be prompted to allow it to communicate through the 6. If you see an error while loading the script that states `socket.dll missing` or similar, navigate to the folder of the lua you are using in your file explorer and copy the `socket.dll` to the base folder of your snes9x install. +#### BSNES-Plus + +1. Load your ROM file if it hasn't already been loaded. +2. The emulator should automatically connect while SNI is running. + ##### BizHawk 1. Ensure you have the BSNES core loaded. This is done with the main menubar, under: diff --git a/worlds/soe/docs/multiworld_en.md b/worlds/soe/docs/multiworld_en.md index 58b9aabf6a..89b1ff9fd9 100644 --- a/worlds/soe/docs/multiworld_en.md +++ b/worlds/soe/docs/multiworld_en.md @@ -2,16 +2,18 @@ ## Required Software -- SNI from: [SNI Releases Page](https://github.com/alttpo/sni/releases) - - v0.0.59 or newer (included in Archipelago 0.2.1 setup) -- Hardware or software capable of loading and playing SNES ROM files - - An emulator capable of connecting to SNI with ROM access. Any one of the following will work: - - snes9x-rr from: [snes9x-rr Releases Page](https://github.com/gocha/snes9x-rr/releases) - - BizHawk from: [TASVideos](https://tasvideos.org/BizHawk) - - bsnes-plus-nwa from: [bsnes-plus GitHub](https://github.com/black-sliver/bsnes-plus) - - RetroArch from: [RetroArch Website](https://retroarch.com?page=platforms). Or, - - Or SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other - compatible hardware. +- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). +- [SNI](https://github.com/alttpo/sni/releases). This is automatically included with your Archipelago installation above. +- SNI is not compatible with (Q)Usb2Snes. +- Hardware or software capable of loading and playing SNES ROM files, including: + - An emulator capable of connecting to 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](http://tasvideos.org/BizHawk.html), or + [RetroArch](https://retroarch.com?page=platforms) 1.10.1 or newer) + - An SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), or other compatible hardware. **note: + modded SNES minis are currently not supported by SNI. Some users have claimed success with QUsb2Snes for this system, + but it is not supported.** - Your legally obtained Secret of Evermore US ROM file, probably named `Secret of Evermore (USA).sfc` ## Create a Config (.yaml) File @@ -63,6 +65,11 @@ page: [Evermizer apbpatch Page](https://evermizer.com/apbpatch) Start SNI either from the Archipelago install folder or the stand-alone version. If this is its first time launching, you may be prompted to allow it to communicate through the Windows Firewall. +#### snes9x-nwa + +1. Click on the Network Menu and check **Enable Emu Network Control** +2. Load your ROM file if it hasn't already been loaded. + ##### snes9x-rr 1. Load your ROM file if it hasn't already been loaded. From a7384b4b63baf82ed1ded7b89b39f244eb7b21f1 Mon Sep 17 00:00:00 2001 From: JaredWeakStrike <96694163+JaredWeakStrike@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:52:16 -0400 Subject: [PATCH 28/49] KH2: Update all instances of multiworld.option_name to option.option_name (#2634) * update the multiworld to options * Update worlds/kh2/Rules.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * does this work * namine sketches * wrong branch :) --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --- worlds/kh2/OpenKH.py | 51 +++++++++++++++++++++--------------------- worlds/kh2/Regions.py | 10 ++++----- worlds/kh2/Rules.py | 41 ++++++++++++++++----------------- worlds/kh2/__init__.py | 26 ++++++++++----------- 4 files changed, 65 insertions(+), 63 deletions(-) diff --git a/worlds/kh2/OpenKH.py b/worlds/kh2/OpenKH.py index 6b0418c997..c30aeec67f 100644 --- a/worlds/kh2/OpenKH.py +++ b/worlds/kh2/OpenKH.py @@ -54,29 +54,30 @@ def patch_kh2(self, output_directory): formName = None levelsetting = list() - if self.multiworld.Keyblade_Minimum[self.player].value > self.multiworld.Keyblade_Maximum[self.player].value: + if self.options.Keyblade_Minimum.value > self.options.Keyblade_Maximum.value: logging.info( f"{self.multiworld.get_file_safe_player_name(self.player)} has Keyblade Minimum greater than Keyblade Maximum") - keyblademin = self.multiworld.Keyblade_Maximum[self.player].value - keyblademax = self.multiworld.Keyblade_Minimum[self.player].value + keyblademin = self.options.Keyblade_Maximum.value + keyblademax = self.options.Keyblade_Minimum.value else: - keyblademin = self.multiworld.Keyblade_Minimum[self.player].value - keyblademax = self.multiworld.Keyblade_Maximum[self.player].value + keyblademin = self.options.Keyblade_Minimum.value + keyblademax = self.options.Keyblade_Maximum.value - if self.multiworld.LevelDepth[self.player] == "level_50": + if self.options.LevelDepth == "level_50": levelsetting.extend(exclusion_table["Level50"]) - elif self.multiworld.LevelDepth[self.player] == "level_99": + elif self.options.LevelDepth == "level_99": levelsetting.extend(exclusion_table["Level99"]) - elif self.multiworld.LevelDepth[self.player] != "level_1": + elif self.options.LevelDepth != "level_1": levelsetting.extend(exclusion_table["Level50Sanity"]) - if self.multiworld.LevelDepth[self.player] == "level_99_sanity": + if self.options.LevelDepth == "level_99_sanity": levelsetting.extend(exclusion_table["Level99Sanity"]) mod_name = f"AP-{self.multiworld.seed_name}-P{self.player}-{self.multiworld.get_file_safe_player_name(self.player)}" all_valid_locations = {location for location, data in all_locations.items()} + for location in self.multiworld.get_filled_locations(self.player): if location.name in all_valid_locations: data = all_locations[location.name] @@ -142,11 +143,11 @@ def patch_kh2(self, output_directory): if data.locid == 2: formDict = {1: "Valor", 2: "Wisdom", 3: "Limit", 4: "Master", 5: "Final"} formDictExp = { - 1: self.multiworld.Valor_Form_EXP[self.player].value, - 2: self.multiworld.Wisdom_Form_EXP[self.player].value, - 3: self.multiworld.Limit_Form_EXP[self.player].value, - 4: self.multiworld.Master_Form_EXP[self.player].value, - 5: self.multiworld.Final_Form_EXP[self.player].value + 1: self.options.Valor_Form_EXP.value, + 2: self.options.Wisdom_Form_EXP.value, + 3: self.options.Limit_Form_EXP.value, + 4: self.options.Master_Form_EXP.value, + 5: self.options.Final_Form_EXP.value } formexp = formDictExp[data.charName] formName = formDict[data.charName] @@ -172,7 +173,7 @@ def patch_kh2(self, output_directory): for x in range(1, 7): self.formattedFmlv["Summon"].append({ "Ability": 123, - "Experience": int(formExp[0][x] / self.multiworld.Summon_EXP[self.player].value), + "Experience": int(formExp[0][x] / self.options.Summon_EXP.value), "FormId": 0, "FormLevel": x, "GrowthAbilityLevel": 0, @@ -192,7 +193,7 @@ def patch_kh2(self, output_directory): increaseStat(self.random.randint(0, 3)) itemcode = 0 self.formattedLvup["Sora"][self.i] = { - "Exp": int(soraExp[self.i] / self.multiworld.Sora_Level_EXP[self.player].value), + "Exp": int(soraExp[self.i] / self.options.Sora_Level_EXP.value), "Strength": self.strength, "Magic": self.magic, "Defense": self.defense, @@ -224,7 +225,7 @@ def patch_kh2(self, output_directory): "Unknown": 0 }) self.formattedLvup["Sora"][1] = { - "Exp": int(soraExp[1] / self.multiworld.Sora_Level_EXP[self.player].value), + "Exp": int(soraExp[1] / self.options.Sora_Level_EXP.value), "Strength": 2, "Magic": 6, "Defense": 2, @@ -379,35 +380,35 @@ def patch_kh2(self, output_directory): } lucky_emblem_text = { 0: "Your Goal is not Lucky Emblem. It is Hitlist or Three Proofs.", - 1: f"Lucky Emblem Required: {self.multiworld.LuckyEmblemsRequired[self.player]} out of {self.multiworld.LuckyEmblemsAmount[self.player]}", + 1: f"Lucky Emblem Required: {self.options.LuckyEmblemsRequired} out of {self.options.LuckyEmblemsAmount}", 2: "Your Goal is not Lucky Emblem. It is Hitlist or Three Proofs.", - 3: f"Lucky Emblem Required: {self.multiworld.LuckyEmblemsRequired[self.player]} out of {self.multiworld.LuckyEmblemsAmount[self.player]}" + 3: f"Lucky Emblem Required: {self.options.LuckyEmblemsRequired} out of {self.options.LuckyEmblemsAmount}" } hitlist_text = { 0: "Your Goal is not Hitlist. It is Lucky Emblem or Three Proofs", 1: "Your Goal is not Hitlist. It is Lucky Emblem or Three Proofs", - 2: f"Bounties Required: {self.multiworld.BountyRequired[self.player]} out of {self.multiworld.BountyAmount[self.player]}", - 3: f"Bounties Required: {self.multiworld.BountyRequired[self.player]} out of {self.multiworld.BountyAmount[self.player]}", + 2: f"Bounties Required: {self.options.BountyRequired} out of {self.options.BountyAmount}", + 3: f"Bounties Required: {self.options.BountyRequired} out of {self.options.BountyAmount}", } self.pooh_text = [ { 'id': 18326, - 'en': f"Your goal is {goal_to_text[self.multiworld.Goal[self.player].value]}" + 'en': f"Your goal is {goal_to_text[self.options.Goal.value]}" }, { 'id': 18327, - 'en': lucky_emblem_text[self.multiworld.Goal[self.player].value] + 'en': lucky_emblem_text[self.options.Goal.value] }, { 'id': 18328, - 'en': hitlist_text[self.multiworld.Goal[self.player].value] + 'en': hitlist_text[self.options.Goal.value] } ] self.level_depth_text = [ { 'id': 0x3BF1, - 'en': f"Your Level Depth is {self.multiworld.LevelDepth[self.player].current_option_name}" + 'en': f"Your Level Depth is {self.options.LevelDepth.current_option_name}" } ] mod_dir = os.path.join(output_directory, mod_name + "_" + Utils.__version__) diff --git a/worlds/kh2/Regions.py b/worlds/kh2/Regions.py index 235500ec89..7fc2ad8a87 100644 --- a/worlds/kh2/Regions.py +++ b/worlds/kh2/Regions.py @@ -935,7 +935,7 @@ def create_regions(self): for level_region_name in level_region_list: KH2REGIONS[level_region_name] = [] - if multiworld.LevelDepth[player] == "level_50": + if self.options.LevelDepth == "level_50": KH2REGIONS[RegionName.LevelsVS1] = [LocationName.Lvl2, LocationName.Lvl4, LocationName.Lvl7, LocationName.Lvl9, LocationName.Lvl10] KH2REGIONS[RegionName.LevelsVS3] = [LocationName.Lvl12, LocationName.Lvl14, LocationName.Lvl15, @@ -949,7 +949,7 @@ def create_regions(self): KH2REGIONS[RegionName.LevelsVS15] = [LocationName.Lvl50] # level 99 - elif multiworld.LevelDepth[player] == "level_99": + elif self.options.LevelDepth == "level_99": KH2REGIONS[RegionName.LevelsVS1] = [LocationName.Lvl7, LocationName.Lvl9] KH2REGIONS[RegionName.LevelsVS3] = [LocationName.Lvl12, LocationName.Lvl15, LocationName.Lvl17, LocationName.Lvl20] @@ -965,7 +965,7 @@ def create_regions(self): KH2REGIONS[RegionName.LevelsVS26] = [LocationName.Lvl99] # level sanity # has to be [] instead of {} for in - elif multiworld.LevelDepth[player] in ["level_50_sanity", "level_99_sanity"]: + elif self.options.LevelDepth in ["level_50_sanity", "level_99_sanity"]: KH2REGIONS[RegionName.LevelsVS1] = [LocationName.Lvl2, LocationName.Lvl3, LocationName.Lvl4, LocationName.Lvl5, LocationName.Lvl6, LocationName.Lvl7, LocationName.Lvl8, LocationName.Lvl9, LocationName.Lvl10] @@ -986,7 +986,7 @@ def create_regions(self): LocationName.Lvl46, LocationName.Lvl47, LocationName.Lvl48, LocationName.Lvl49, LocationName.Lvl50] # level 99 sanity - if multiworld.LevelDepth[player] == "level_99_sanity": + if self.options.LevelDepth == "level_99_sanity": KH2REGIONS[RegionName.LevelsVS15] = [LocationName.Lvl51, LocationName.Lvl52, LocationName.Lvl53, LocationName.Lvl54, LocationName.Lvl55, LocationName.Lvl56, LocationName.Lvl57, @@ -1012,7 +1012,7 @@ def create_regions(self): LocationName.Lvl95, LocationName.Lvl96, LocationName.Lvl97, LocationName.Lvl98, LocationName.Lvl99] KH2REGIONS[RegionName.Summon] = [] - if multiworld.SummonLevelLocationToggle[player]: + if self.options.SummonLevelLocationToggle: KH2REGIONS[RegionName.Summon] = [LocationName.Summonlvl2, LocationName.Summonlvl3, LocationName.Summonlvl4, diff --git a/worlds/kh2/Rules.py b/worlds/kh2/Rules.py index 1124f8109c..4370ad36b5 100644 --- a/worlds/kh2/Rules.py +++ b/worlds/kh2/Rules.py @@ -157,7 +157,7 @@ class KH2Rules: def form_list_unlock(self, state: CollectionState, parent_form_list, level_required, fight_logic=False) -> bool: form_access = {parent_form_list} - if self.multiworld.AutoFormLogic[self.player] and state.has(ItemName.SecondChance, self.player) and not fight_logic: + if self.world.options.AutoFormLogic and state.has(ItemName.SecondChance, self.player) and not fight_logic: if parent_form_list == ItemName.MasterForm: if state.has(ItemName.DriveConverter, self.player): form_access.add(auto_form_dict[parent_form_list]) @@ -170,8 +170,8 @@ class KH2Rules: forms_available = 0 form_list = [ItemName.ValorForm, ItemName.WisdomForm, ItemName.LimitForm, ItemName.MasterForm, ItemName.FinalForm] - if self.world.multiworld.FinalFormLogic[self.player] != "no_light_and_darkness": - if self.world.multiworld.FinalFormLogic[self.player] == "light_and_darkness": + if self.world.options.FinalFormLogic != "no_light_and_darkness": + if self.world.options.FinalFormLogic == "light_and_darkness": if state.has(ItemName.LightDarkness, self.player) and state.has_any(set(form_list), self.player): forms_available += 1 form_list.remove(ItemName.FinalForm) @@ -273,34 +273,35 @@ class KH2WorldRules(KH2Rules): def set_kh2_goal(self): final_xemnas_location = self.multiworld.get_location(LocationName.FinalXemnasEventLocation, self.player) - if self.multiworld.Goal[self.player] == "three_proofs": + if self.world.options.Goal == "three_proofs": final_xemnas_location.access_rule = lambda state: self.kh2_has_all(three_proofs, state) - if self.multiworld.FinalXemnas[self.player]: + if self.world.options.FinalXemnas: self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Victory, self.player, 1) else: self.multiworld.completion_condition[self.player] = lambda state: self.kh2_has_all(three_proofs, state) # lucky emblem hunt - elif self.multiworld.Goal[self.player] == "lucky_emblem_hunt": - final_xemnas_location.access_rule = lambda state: state.has(ItemName.LuckyEmblem, self.player, self.multiworld.LuckyEmblemsRequired[self.player].value) - if self.multiworld.FinalXemnas[self.player]: + elif self.world.options.Goal == "lucky_emblem_hunt": + final_xemnas_location.access_rule = lambda state: state.has(ItemName.LuckyEmblem, self.player, self.world.options.LuckyEmblemsRequired.value) + if self.world.options.FinalXemnas: self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Victory, self.player, 1) else: - self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.LuckyEmblem, self.player, self.multiworld.LuckyEmblemsRequired[self.player].value) + self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.LuckyEmblem, self.player, self.world.options.LuckyEmblemsRequired.value) # hitlist if == 2 - elif self.multiworld.Goal[self.player] == "hitlist": - final_xemnas_location.access_rule = lambda state: state.has(ItemName.Bounty, self.player, self.multiworld.BountyRequired[self.player].value) - if self.multiworld.FinalXemnas[self.player]: + elif self.world.options.Goal == "hitlist": + final_xemnas_location.access_rule = lambda state: state.has(ItemName.Bounty, self.player, self.world.options.BountyRequired.value) + if self.world.options.FinalXemnas: self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Victory, self.player, 1) else: - self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Bounty, self.player, self.multiworld.BountyRequired[self.player].value) + self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Bounty, self.player, self.world.options.BountyRequired.value) else: - final_xemnas_location.access_rule = lambda state: state.has(ItemName.Bounty, self.player, self.multiworld.BountyRequired[self.player].value) and \ - state.has(ItemName.LuckyEmblem, self.player, self.multiworld.LuckyEmblemsRequired[self.player].value) - if self.multiworld.FinalXemnas[self.player]: + + final_xemnas_location.access_rule = lambda state: state.has(ItemName.Bounty, self.player, self.world.options.BountyRequired.value) and \ + state.has(ItemName.LuckyEmblem, self.player, self.world.options.LuckyEmblemsRequired.value) + if self.world.options.FinalXemnas: self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Victory, self.player, 1) else: - self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Bounty, self.player, self.multiworld.BountyRequired[self.player].value) and \ - state.has(ItemName.LuckyEmblem, self.player, self.multiworld.LuckyEmblemsRequired[self.player].value) + self.multiworld.completion_condition[self.player] = lambda state: state.has(ItemName.Bounty, self.player, self.world.options.BountyRequired.value) and \ + state.has(ItemName.LuckyEmblem, self.player, self.world.options.LuckyEmblemsRequired.value) class KH2FormRules(KH2Rules): @@ -409,7 +410,7 @@ class KH2FightRules(KH2Rules): # if skip rules are of return false def __init__(self, world: KH2World) -> None: super().__init__(world) - self.fight_logic = self.multiworld.FightLogic[self.player].current_key + self.fight_logic = world.options.FightLogic.current_key self.fight_region_rules = { RegionName.ShanYu: lambda state: self.get_shan_yu_rules(state), @@ -935,7 +936,7 @@ class KH2FightRules(KH2Rules): def get_cor_skip_first_rules(self, state: CollectionState) -> bool: # if option is not allow skips return false else run rules - if not self.multiworld.CorSkipToggle[self.player]: + if not self.world.options.CorSkipToggle: return False # easy: aerial dodge 3,master form,fire # normal: aerial dodge 2, master form,fire diff --git a/worlds/kh2/__init__.py b/worlds/kh2/__init__.py index d02614d380..4125bcb24c 100644 --- a/worlds/kh2/__init__.py +++ b/worlds/kh2/__init__.py @@ -240,7 +240,7 @@ class KH2World(World): self.hitlist_verify() - prio_hitlist = [location for location in self.multiworld.priority_locations[self.player].value if + prio_hitlist = [location for location in self.options.priority_locations.value if location in self.random_super_boss_list] for bounty in range(self.options.BountyAmount.value): if prio_hitlist: @@ -261,11 +261,11 @@ class KH2World(World): if self.options.WeaponSlotStartHint: for location in all_weapon_slot: - self.multiworld.start_location_hints[self.player].value.add(location) + self.options.start_location_hints.value.add(location) if self.options.FillerItemsLocal: for item in filler_items: - self.multiworld.local_items[self.player].value.add(item) + self.options.local_items.value.add(item) # By imitating remote this doesn't have to be plandoded filler anymore # for location in {LocationName.JunkMedal, LocationName.JunkMedal}: # self.plando_locations[location] = random_stt_item @@ -325,7 +325,7 @@ class KH2World(World): self.item_quantity_dict[random_ability] -= 1 self.total_locations -= 1 self.slot_data_donald_weapon = [item_name.name for item_name in self.donald_weapon_abilities] - if not self.multiworld.DonaldGoofyStatsanity[self.player]: + if not self.options.DonaldGoofyStatsanity: # pre plando donald get bonuses self.donald_get_bonus_abilities += [self.create_item(random_prog_ability)] self.total_locations -= 1 @@ -385,7 +385,7 @@ class KH2World(World): location.place_locked_item(random_ability) self.goofy_weapon_abilities.remove(random_ability) - if not self.multiworld.DonaldGoofyStatsanity[self.player]: + if not self.options.DonaldGoofyStatsanity: # plando goofy get bonuses goofy_get_bonus_location_pool = [self.multiworld.get_location(location, self.player) for location in Goofy_Checks.keys() if Goofy_Checks[location].yml != "Keyblade"] @@ -406,7 +406,7 @@ class KH2World(World): location.place_locked_item(random_ability) self.donald_weapon_abilities.remove(random_ability) - if not self.multiworld.DonaldGoofyStatsanity[self.player]: + if not self.options.DonaldGoofyStatsanity: # plando goofy get bonuses donald_get_bonus_location_pool = [self.multiworld.get_location(location, self.player) for location in Donald_Checks.keys() if Donald_Checks[location].yml != "Keyblade"] @@ -428,7 +428,7 @@ class KH2World(World): """ Making sure the player doesn't put too many abilities in their starting inventory. """ - for item, value in self.multiworld.start_inventory[self.player].value.items(): + for item, value in self.options.start_inventory.value.items(): if item in ActionAbility_Table \ or item in SupportAbility_Table or exclusion_item_table["StatUps"] \ or item in DonaldAbility_Table or item in GoofyAbility_Table: @@ -461,7 +461,7 @@ class KH2World(World): """ Making sure hitlist have amount>=required. """ - for location in self.multiworld.exclude_locations[self.player].value: + for location in self.options.exclude_locations.value: if location in self.random_super_boss_list: self.random_super_boss_list.remove(location) @@ -491,7 +491,7 @@ class KH2World(World): self.options.BountyAmount.value = temp if self.options.BountyStartingHintToggle: - self.multiworld.start_hints[self.player].value.add(ItemName.Bounty) + self.options.start_hints.value.add(ItemName.Bounty) if ItemName.ProofofNonexistence in self.item_quantity_dict: del self.item_quantity_dict[ItemName.ProofofNonexistence] @@ -503,19 +503,19 @@ class KH2World(World): # Option to turn off all superbosses. Can do this individually but its like 20+ checks if not self.options.SuperBosses: for superboss in exclusion_table["SuperBosses"]: - self.multiworld.exclude_locations[self.player].value.add(superboss) + self.options.exclude_locations.value.add(superboss) # Option to turn off Olympus Colosseum Cups. if self.options.Cups == "no_cups": for cup in exclusion_table["Cups"]: - self.multiworld.exclude_locations[self.player].value.add(cup) + self.options.exclude_locations.value.add(cup) # exclude only hades paradox. If cups and hades paradox then nothing is excluded elif self.options.Cups == "cups": - self.multiworld.exclude_locations[self.player].value.add(LocationName.HadesCupTrophyParadoxCups) + self.options.exclude_locations.value.add(LocationName.HadesCupTrophyParadoxCups) if not self.options.AtlanticaToggle: for loc in exclusion_table["Atlantica"]: - self.multiworld.exclude_locations[self.player].value.add(loc) + self.options.exclude_locations.value.add(loc) def level_subtraction(self): """ From 6d3f7865ff238306df8cde0cf446507db5376614 Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Mon, 11 Mar 2024 18:55:28 -0500 Subject: [PATCH 29/49] The Messenger: fix items accessibility reachability bug due to new rules (#2937) --- worlds/messenger/rules.py | 4 ++-- worlds/messenger/test/test_access.py | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/worlds/messenger/rules.py b/worlds/messenger/rules.py index 50e1fa113d..ff1b75d70f 100644 --- a/worlds/messenger/rules.py +++ b/worlds/messenger/rules.py @@ -523,7 +523,7 @@ class MessengerOOBRules(MessengerRules): def set_self_locking_items(world: "MessengerWorld", player: int) -> None: # locations where these placements are always valid - allow_self_locking_items(world.get_location("Searing Crags - Key of Strength"), "Power Thistle") + allow_self_locking_items(world.get_location("Searing Crags - Key of Strength").parent_region, "Power Thistle") allow_self_locking_items(world.get_location("Sunken Shrine - Key of Love"), "Sun Crest", "Moon Crest") - allow_self_locking_items(world.get_location("Corrupted Future - Key of Courage"), "Demon King Crown") + allow_self_locking_items(world.get_location("Corrupted Future - Key of Courage").parent_region, "Demon King Crown") allow_self_locking_items(world.get_location("Elemental Skylands Seal - Water"), "Currents Master") diff --git a/worlds/messenger/test/test_access.py b/worlds/messenger/test/test_access.py index 016f3b57cd..ad2265ffa0 100644 --- a/worlds/messenger/test/test_access.py +++ b/worlds/messenger/test/test_access.py @@ -1,3 +1,5 @@ +import typing + from . import MessengerTestBase from ..constants import NOTES, PHOBEKINS @@ -208,5 +210,8 @@ class ItemsAccessTest(MessengerTestBase): for item_name in location_lock_pairs[loc]: item = self.get_item_by_name(item_name) with self.subTest("Fulfills Accessibility", location=loc, item=item_name): - self.assertTrue(self.multiworld.get_location(loc, self.player).can_fill(self.multiworld.state, item, - True)) + location = self.multiworld.get_location(loc, self.player) + self.assertTrue(location.can_fill(self.multiworld.state, item, True)) + location.item = item + self.multiworld.state.update_reachable_regions(self.player) + self.assertTrue(self.can_reach_location(loc)) From cb2c00f6441793efc93209a6a3ab8d7710562c37 Mon Sep 17 00:00:00 2001 From: BadMagic100 Date: Tue, 12 Mar 2024 01:11:13 -0700 Subject: [PATCH 30/49] CI: Don't auto-remove content based labels (#2941) --- .github/workflows/label-pull-requests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pull-requests.yml b/.github/workflows/label-pull-requests.yml index e26f6f34a4..bc0f6999b6 100644 --- a/.github/workflows/label-pull-requests.yml +++ b/.github/workflows/label-pull-requests.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/labeler@v5 with: - sync-labels: true + sync-labels: false peer_review: name: 'Apply peer review label' needs: labeler From 51243abea1b0ad0aefe076ebdad5484175353297 Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Tue, 12 Mar 2024 03:27:41 -0500 Subject: [PATCH 31/49] Docs: improve AutoWorld method docstrings (#2509) * clarify some autoworld docstrings * revert accidental change --- worlds/AutoWorld.py | 73 +++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index 4d9b31d17d..faf14bed18 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -310,13 +310,15 @@ class World(metaclass=AutoWorldRegister): # overridable methods that get called by Main.py, sorted by execution order # can also be implemented as a classmethod and called "stage_", - # in that case the MultiWorld object is passed as an argument and it gets called once for the entire multiworld. + # in that case the MultiWorld object is passed as an argument, and it gets called once for the entire multiworld. # An example of this can be found in alttp as stage_pre_fill @classmethod def stage_assert_generate(cls, multiworld: "MultiWorld") -> None: - """Checks that a game is capable of generating, usually checks for some base file like a ROM. - This gets called once per present world type. Not run for unittests since they don't produce output""" + """ + Checks that a game is capable of generating, such as checking for some base file like a ROM. + This gets called once per present world type. Not run for unittests since they don't produce output. + """ pass def generate_early(self) -> None: @@ -361,16 +363,21 @@ class World(metaclass=AutoWorldRegister): pass def post_fill(self) -> None: - """Optional Method that is called after regular fill. Can be used to do adjustments before output generation. - This happens before progression balancing, so the items may not be in their final locations yet.""" + """ + Optional Method that is called after regular fill. Can be used to do adjustments before output generation. + This happens before progression balancing, so the items may not be in their final locations yet. + """ 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.""" + """ + This method gets called from a threadpool, do not use multiworld.random here. + If you need any last-second randomization, use self.random instead. + """ pass def fill_slot_data(self) -> Mapping[str, Any]: # json of WebHostLib.models.Slot - """What is returned from this function will be in the `slot_data` field + """ + What is returned from this function will be in the `slot_data` field in the `Connected` network package. It should be a `dict` with `str` keys, and should be serializable with json. @@ -378,15 +385,18 @@ class World(metaclass=AutoWorldRegister): The client will receive this as JSON in the `Connected` response. The generation does not wait for `generate_output` to complete before calling this. - `threading.Event` can be used if you need to wait for something from `generate_output`.""" + `threading.Event` can be used if you need to wait for something from `generate_output`. + """ # The reason for the `Mapping` type annotation, rather than `dict` # is so that type checkers won't worry about the mutability of `dict`, # so you can have more specific typing in your world implementation. return {} def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]): - """Fill in additional entrance information text into locations, which is displayed when hinted. - structure is {player_id: {location_id: text}} You will need to insert your own player_id.""" + """ + Fill in additional entrance information text into locations, which is displayed when hinted. + structure is {player_id: {location_id: text}} You will need to insert your own player_id. + """ pass def modify_multidata(self, multidata: Dict[str, Any]) -> None: # TODO: TypedDict for multidata? @@ -395,13 +405,17 @@ class World(metaclass=AutoWorldRegister): # Spoiler writing is optional, these may not get called. def write_spoiler_header(self, spoiler_handle: TextIO) -> None: - """Write to the spoiler header. If individual it's right at the end of that player's options, - if as stage it's right under the common header before per-player options.""" + """ + Write to the spoiler header. If individual it's right at the end of that player's options, + if as stage it's right under the common header before per-player options. + """ pass def write_spoiler(self, spoiler_handle: TextIO) -> None: - """Write to the spoiler "middle", this is after the per-player options and before locations, - meant for useful or interesting info.""" + """ + Write to the spoiler "middle", this is after the per-player options and before locations, + meant for useful or interesting info. + """ pass def write_spoiler_end(self, spoiler_handle: TextIO) -> None: @@ -411,8 +425,10 @@ class World(metaclass=AutoWorldRegister): # end of ordered Main.py calls def create_item(self, name: str) -> "Item": - """Create an item for this world type and player. - Warning: this may be called with self.world = None, for example by MultiServer""" + """ + Create an item for this world type and player. + Warning: this may be called with self.world = None, for example by MultiServer + """ raise NotImplementedError def get_filler_item_name(self) -> str: @@ -422,8 +438,10 @@ class World(metaclass=AutoWorldRegister): @classmethod def create_group(cls, multiworld: "MultiWorld", new_player_id: int, players: Set[int]) -> World: - """Creates a group, which is an instance of World that is responsible for multiple others. - An example case is ItemLinks creating these.""" + """ + Creates a group, which is an instance of World that is responsible for multiple others. + An example case is ItemLinks creating these. + """ # TODO remove loop when worlds use options dataclass for option_key, option in cls.options_dataclass.type_hints.items(): getattr(multiworld, option_key)[new_player_id] = option.from_any(option.default) @@ -435,21 +453,27 @@ class World(metaclass=AutoWorldRegister): # decent place to implement progressive items, in most cases can stay as-is def collect_item(self, state: "CollectionState", item: "Item", remove: bool = False) -> Optional[str]: - """Collect an item name into state. For speed reasons items that aren't logically useful get skipped. + """ + Collect an item name into state. For speed reasons items that aren't logically useful get skipped. Collect None to skip item. :param state: CollectionState to collect into :param item: Item to decide on if it should be collected into state - :param remove: indicate if this is meant to remove from state instead of adding.""" + :param remove: indicate if this is meant to remove from state instead of adding. + """ if item.advancement: return item.name return None - # called to create all_state, return Items that are created during pre_fill def get_pre_fill_items(self) -> List["Item"]: + """ + Used to return items that need to be collected when creating a fresh all_state, but don't exist in the + multiworld itempool. + """ return [] # these two methods can be extended for pseudo-items on state def collect(self, state: "CollectionState", item: "Item") -> bool: + """Called when an item is collected in to state. Useful for things such as progressive items or currency.""" name = self.collect_item(state, item) if name: state.prog_items[self.player][name] += 1 @@ -457,6 +481,7 @@ class World(metaclass=AutoWorldRegister): return False def remove(self, state: "CollectionState", item: "Item") -> bool: + """Called when an item is removed from to state. Useful for things such as progressive items or currency.""" name = self.collect_item(state, item, True) if name: state.prog_items[self.player][name] -= 1 @@ -465,6 +490,7 @@ class World(metaclass=AutoWorldRegister): return True return False + # following methods should not need to be overridden. def create_filler(self) -> "Item": return self.create_item(self.get_filler_item_name()) @@ -513,7 +539,8 @@ def data_package_checksum(data: "GamesPackage") -> str: def _normalize_description(description): - """Normalizes a description in item_descriptions or location_descriptions. + """ + Normalizes a description in item_descriptions or location_descriptions. This allows authors to write descritions with nice indentation and line lengths in their world definitions without having it affect the rendered format. From 30ad2aa4a8e506728e55dbc47c8e986937e1c987 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:51:10 +0100 Subject: [PATCH 32/49] The Witness: Don't unnecessarily break people's 0.4.4 yamls (#2940) --- worlds/witness/options.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/worlds/witness/options.py b/worlds/witness/options.py index a24896e1d0..f47068d594 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -23,8 +23,11 @@ class EarlyCaves(Choice): If you choose "add_to_pool" and you are already playing a remote Door Shuffle mode, this setting will do nothing.""" display_name = "Early Caves" option_off = 0 + alias_false = 0 option_add_to_pool = 1 option_starting_inventory = 2 + alias_true = 2 + alias_on = 2 class ShuffleSymbols(DefaultOnToggle): @@ -39,8 +42,11 @@ class ShuffleLasers(Choice): be redirected as normal, for both applications of redirection.""" display_name = "Shuffle Lasers" option_off = 0 + alias_false = 0 option_local = 1 option_anywhere = 2 + alias_true = 2 + alias_on = 2 class ShuffleDoors(Choice): From c795c72471b9fe36df362c9ccce712adc0feddde Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Tue, 12 Mar 2024 14:52:57 +0100 Subject: [PATCH 33/49] kvui: allow sorting hints in the hint tab (#2684) --- data/client.kv | 6 ++++++ kvui.py | 57 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/data/client.kv b/data/client.kv index 3b48d216dd..bf98fa1517 100644 --- a/data/client.kv +++ b/data/client.kv @@ -61,36 +61,42 @@ found_text: "Found?" TooltipLabel: id: receiving + sort_key: 'receiving' text: root.receiving_text halign: 'center' valign: 'center' pos_hint: {"center_y": 0.5} TooltipLabel: id: item + sort_key: 'item' text: root.item_text halign: 'center' valign: 'center' pos_hint: {"center_y": 0.5} TooltipLabel: id: finding + sort_key: 'finding' text: root.finding_text halign: 'center' valign: 'center' pos_hint: {"center_y": 0.5} TooltipLabel: id: location + sort_key: 'location' text: root.location_text halign: 'center' valign: 'center' pos_hint: {"center_y": 0.5} TooltipLabel: id: entrance + sort_key: 'entrance' text: root.entrance_text halign: 'center' valign: 'center' pos_hint: {"center_y": 0.5} TooltipLabel: id: found + sort_key: 'found' text: root.found_text halign: 'center' valign: 'center' diff --git a/kvui.py b/kvui.py index 5e1b0fc030..1cd1c99834 100644 --- a/kvui.py +++ b/kvui.py @@ -2,6 +2,7 @@ import os import logging import sys import typing +import re if sys.platform == "win32": import ctypes @@ -72,6 +73,8 @@ if typing.TYPE_CHECKING: else: context_type = object +remove_between_brackets = re.compile(r"\[.*?]") + # I was surprised to find this didn't already exist in kivy :( class HoverBehavior(object): @@ -303,7 +306,6 @@ class HintLabel(RecycleDataViewBehavior, BoxLayout): selected = BooleanProperty(False) striped = BooleanProperty(False) index = None - no_select = [] def __init__(self): super(HintLabel, self).__init__() @@ -321,9 +323,7 @@ class HintLabel(RecycleDataViewBehavior, BoxLayout): def refresh_view_attrs(self, rv, index, data): self.index = index - if "select" in data and not data["select"] and index not in self.no_select: - self.no_select.append(index) - self.striped = data["striped"] + self.striped = data.get("striped", False) self.receiving_text = data["receiving"]["text"] self.item_text = data["item"]["text"] self.finding_text = data["finding"]["text"] @@ -337,24 +337,44 @@ class HintLabel(RecycleDataViewBehavior, BoxLayout): """ Add selection on touch down """ if super(HintLabel, self).on_touch_down(touch): return True - if self.index not in self.no_select: + if self.index: # skip header if self.collide_point(*touch.pos): if self.selected: self.parent.clear_selection() else: - text = "".join([self.receiving_text, "\'s ", self.item_text, " is at ", self.location_text, " in ", + text = "".join((self.receiving_text, "\'s ", self.item_text, " is at ", self.location_text, " in ", self.finding_text, "\'s World", (" at " + self.entrance_text) if self.entrance_text != "Vanilla" - else "", ". (", self.found_text.lower(), ")"]) + else "", ". (", self.found_text.lower(), ")")) temp = MarkupLabel(text).markup text = "".join( part for part in temp if not part.startswith(("[color", "[/color]", "[ref=", "[/ref]"))) Clipboard.copy(escape_markup(text).replace("&", "&").replace("&bl;", "[").replace("&br;", "]")) return self.parent.select_with_touch(self.index, touch) + else: + parent = self.parent + parent.clear_selection() + parent: HintLog = parent.parent + # find correct column + for child in self.children: + if child.collide_point(*touch.pos): + key = child.sort_key + 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 + else: + parent.sort_key = key + parent.reversed = False + break + else: + logging.warning("Did not find clicked header for sorting.") + + App.get_running_app().update_hints() def apply_selection(self, rv, index, is_selected): """ Respond to the selection of items in the view. """ - if self.index not in self.no_select: + if self.index: self.selected = is_selected @@ -646,20 +666,20 @@ class HintLog(RecycleView): "entrance": {"text": "[u]Entrance[/u]"}, "found": {"text": "[u]Status[/u]"}, "striped": True, - "select": False, } + sort_key: str = "" + reversed: bool = False + def __init__(self, parser): super(HintLog, self).__init__() self.data = [self.header] self.parser = parser def refresh_hints(self, hints): - self.data = [self.header] - striped = False + data = [] for hint in hints: - self.data.append({ - "striped": striped, + data.append({ "receiving": {"text": self.parser.handle_node({"type": "player_id", "text": hint["receiving_player"]})}, "item": {"text": self.parser.handle_node( {"type": "item_id", "text": hint["item"], "flags": hint["item_flags"]})}, @@ -672,7 +692,16 @@ class HintLog(RecycleView): "text": self.parser.handle_node({"type": "color", "color": "green" if hint["found"] else "red", "text": "Found" if hint["found"] else "Not Found"})}, }) - striped = not striped + + data.sort(key=self.hint_sorter, reverse=self.reversed) + for i in range(0, len(data), 2): + data[i]["striped"] = True + data.insert(0, self.header) + self.data = data + + @staticmethod + def hint_sorter(element: dict) -> str: + return "" class E(ExceptionHandler): From ae6c16bde19e0f299c60ecd8332435bee5e193e9 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Tue, 12 Mar 2024 19:58:02 +0100 Subject: [PATCH 34/49] MultiServer: send new read_hints datastore values on change (#2558) --- MultiServer.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index c374d6d704..395577b663 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -707,15 +707,18 @@ class Context: self.save() # save goal completion flag def on_new_hint(self, team: int, slot: int): - key: str = f"_read_hints_{team}_{slot}" - targets: typing.Set[Client] = set(self.stored_data_notification_clients[key]) - if targets: - self.broadcast(targets, [{"cmd": "SetReply", "key": key, "value": self.hints[team, slot]}]) + self.on_changed_hints(team, slot) self.broadcast(self.clients[team][slot], [{ "cmd": "RoomUpdate", "hint_points": get_slot_points(self, team, slot) }]) + def on_changed_hints(self, team: int, slot: int): + key: str = f"_read_hints_{team}_{slot}" + targets: typing.Set[Client] = set(self.stored_data_notification_clients[key]) + if targets: + self.broadcast(targets, [{"cmd": "SetReply", "key": key, "value": self.hints[team, slot]}]) + def on_client_status_change(self, team: int, slot: int): key: str = f"_read_client_status_{team}_{slot}" targets: typing.Set[Client] = set(self.stored_data_notification_clients[key]) @@ -975,7 +978,10 @@ def register_location_checks(ctx: Context, team: int, slot: int, locations: typi "hint_points": get_slot_points(ctx, team, slot), "checked_locations": new_locations, # send back new checks only }]) - + old_hints = ctx.hints[team, slot].copy() + ctx.recheck_hints(team, slot) + if old_hints != ctx.hints[team, slot]: + ctx.on_changed_hints(team, slot) ctx.save() From 4bf676e588d3bc814baf345072524174e6b28749 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Tue, 12 Mar 2024 20:04:13 +0100 Subject: [PATCH 35/49] The Witness: Obelisk Keys (#2805) --- worlds/witness/WitnessItems.txt | 7 +++ worlds/witness/__init__.py | 61 +++++++++++++------ worlds/witness/options.py | 9 +++ worlds/witness/player_logic.py | 31 ++++++---- worlds/witness/presets.py | 6 ++ .../settings/Door_Shuffle/Obelisk_Keys.txt | 7 +++ worlds/witness/utils.py | 4 ++ 7 files changed, 94 insertions(+), 31 deletions(-) create mode 100644 worlds/witness/settings/Door_Shuffle/Obelisk_Keys.txt diff --git a/worlds/witness/WitnessItems.txt b/worlds/witness/WitnessItems.txt index 6f63eccc95..28dc4a4d97 100644 --- a/worlds/witness/WitnessItems.txt +++ b/worlds/witness/WitnessItems.txt @@ -265,6 +265,13 @@ Doors: 2165 - Caves Panels - 0x3369D,0x00FF8,0x0A16E,0x335AB,0x335AC 2170 - Tunnels Panels - 0x09E85,0x039B4 +2200 - Desert Obelisk Key - 0x0332B,0x03367,0x28B8A,0x037B6,0x037B2,0x000F7,0x3351D,0x0053C,0x00771,0x335C8,0x335C9,0x337F8,0x037BB,0x220E4,0x220E5,0x334B9,0x334BC,0x22106,0x0A14C,0x0A14D,0x00359 +2201 - Monastery Obelisk Key - 0x03ABC,0x03ABE,0x03AC0,0x03AC4,0x03AC5,0x03BE2,0x03BE3,0x0A409,0x006E5,0x006E6,0x006E7,0x034A7,0x034AD,0x034AF,0x03DAB,0x03DAC,0x03DAD,0x03E01,0x289F4,0x289F5,0x00263 +2202 - Treehouse Obelisk Key - 0x0053D,0x0053E,0x00769,0x33721,0x220A7,0x220BD,0x03B22,0x03B23,0x03B24,0x03B25,0x03A79,0x28ABD,0x28ABE,0x3388F,0x28B29,0x28B2A,0x018B6,0x033BE,0x033BF,0x033DD,0x033E5,0x28AE9,0x3348F,0x00097 +2203 - Mountainside Obelisk Key - 0x001A3,0x335AE,0x000D3,0x035F5,0x09D5D,0x09D5E,0x09D63,0x3370E,0x035DE,0x03601,0x03603,0x03D0D,0x3369A,0x336C8,0x33505,0x03A9E,0x016B2,0x3365F,0x03731,0x036CE,0x03C07,0x03A93,0x03AA6,0x3397C,0x0105D,0x0A304,0x035CB,0x035CF,0x00367 +2204 - Quarry Obelisk Key - 0x28A7B,0x005F6,0x00859,0x17CB9,0x28A4A,0x334B6,0x00614,0x0069D,0x28A4C,0x289CF,0x289D1,0x33692,0x03E77,0x03E7C,0x22073 +2205 - Town Obelisk Key - 0x035C7,0x01848,0x03D06,0x33530,0x33600,0x28A2F,0x28A37,0x334A3,0x3352F,0x33857,0x33879,0x03C19,0x28B30,0x035C9,0x03335,0x03412,0x038A6,0x038AA,0x03E3F,0x03E40,0x28B8E,0x28B91,0x03BCE,0x03BCF,0x03BD1,0x339B6,0x33A20,0x33A29,0x33A2A,0x33B06,0x0A16C + Lasers: 1500 - Symmetry Laser - 0x00509 1501 - Desert Laser - 0x012FB diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index 635a56796b..88de0f3134 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -89,6 +89,46 @@ class WitnessWorld(World): 'entity_to_name': StaticWitnessLogic.ENTITY_ID_TO_NAME, } + def determine_sufficient_progression(self): + """ + Determine whether there are enough progression items in this world to consider it "interactive". + In the case of singleplayer, this just outputs a warning. + In the case of multiplayer, the requirements are a bit stricter and an Exception is raised. + """ + + # A note on Obelisk Keys: + # Obelisk Keys are never relevant in singleplayer, because the locations they lock are irrelevant to in-game + # progress and irrelevant to all victory conditions. Thus, I consider them "fake progression" for singleplayer. + # However, those locations could obviously contain big items needed for other players, so I consider + # "Obelisk Keys only" valid for multiworld. + + # A note on Laser Shuffle: + # In singleplayer, I don't mind "Ice Rod Hunt" type gameplay, so "laser shuffle only" is valid. + # However, I do not want to allow "Ice Rod Hunt" style gameplay in multiworld, so "laser shuffle only" is + # not considered interactive enough for multiworld. + + interacts_sufficiently_with_multiworld = ( + self.options.shuffle_symbols + or self.options.shuffle_doors + or self.options.obelisk_keys and self.options.shuffle_EPs + ) + + has_locally_relevant_progression = ( + self.options.shuffle_symbols + or self.options.shuffle_doors + or self.options.shuffle_lasers + or self.options.shuffle_boat + or self.options.early_caves == "add_to_pool" and self.options.victory_condition == "challenge" + ) + + if not has_locally_relevant_progression and self.multiworld.players == 1: + warning(f"{self.multiworld.get_player_name(self.player)}'s Witness world doesn't have any progression" + f" items. Please turn on Symbol Shuffle, Door Shuffle or Laser Shuffle if that doesn't seem right.") + elif not interacts_sufficiently_with_multiworld and self.multiworld.players > 1: + raise Exception(f"{self.multiworld.get_player_name(self.player)}'s Witness world doesn't have enough" + f" progression items that can be placed in other players' worlds. Please turn on Symbol" + f" Shuffle, Door Shuffle or Obelisk Keys.") + def generate_early(self): disabled_locations = self.options.exclude_locations.value @@ -102,26 +142,9 @@ class WitnessWorld(World): ) self.regio: WitnessRegions = WitnessRegions(self.locat, self) - interacts_with_multiworld = ( - self.options.shuffle_symbols or - self.options.shuffle_doors or - self.options.shuffle_lasers == "anywhere" - ) + self.log_ids_to_hints = dict() - has_progression = ( - interacts_with_multiworld - or self.options.shuffle_lasers == "local" - or self.options.shuffle_boat - or self.options.early_caves == "add_to_pool" - ) - - if not has_progression and self.multiworld.players == 1: - warning(f"{self.multiworld.get_player_name(self.player)}'s Witness world doesn't have any progression" - f" items. Please turn on Symbol Shuffle, Door Shuffle or Laser Shuffle if that doesn't seem right.") - elif not interacts_with_multiworld and self.multiworld.players > 1: - raise Exception(f"{self.multiworld.get_player_name(self.player)}'s Witness world doesn't have enough" - f" progression items that can be placed in other players' worlds. Please turn on Symbol" - f" Shuffle, Door Shuffle or non-local Laser Shuffle.") + self.determine_sufficient_progression() if self.options.shuffle_lasers == "local": self.options.local_items.value |= self.item_name_groups["Lasers"] diff --git a/worlds/witness/options.py b/worlds/witness/options.py index f47068d594..5bce3e3a22 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -120,6 +120,14 @@ class EnvironmentalPuzzlesDifficulty(Choice): option_eclipse = 2 +class ObeliskKeys(DefaultOnToggle): + """ + Add one Obelisk Key item per Obelisk, locking you out of solving any of the associated Environmental Puzzles. + Does nothing if "Shuffle Environmental Puzzles" is set to "off". + """ + display_name = "Obelisk Keys" + + class ShufflePostgame(Toggle): """Adds locations into the pool that are guaranteed to become accessible after or at the same time as your goal. Use this if you don't play with release on victory. IMPORTANT NOTE: The possibility of your second @@ -263,6 +271,7 @@ class TheWitnessOptions(PerGameCommonOptions): disable_non_randomized_puzzles: DisableNonRandomizedPuzzles shuffle_discarded_panels: ShuffleDiscardedPanels shuffle_vault_boxes: ShuffleVaultBoxes + obelisk_keys: ObeliskKeys shuffle_EPs: ShuffleEnvironmentalPuzzles EP_difficulty: EnvironmentalPuzzlesDifficulty shuffle_postgame: ShufflePostgame diff --git a/worlds/witness/player_logic.py b/worlds/witness/player_logic.py index 229da0a287..099a3a64e6 100644 --- a/worlds/witness/player_logic.py +++ b/worlds/witness/player_logic.py @@ -63,26 +63,30 @@ class WitnessPlayerLogic: if panel_hex in self.DOOR_ITEMS_BY_ID: door_items = frozenset({frozenset([item]) for item in self.DOOR_ITEMS_BY_ID[panel_hex]}) - all_options = set() + all_options: Set[FrozenSet[str]] = set() for dependentItem in door_items: self.PROG_ITEMS_ACTUALLY_IN_THE_GAME_NO_MULTI.update(dependentItem) for items_option in these_items: all_options.add(items_option.union(dependentItem)) - # 0x28A0D depends on another entity for *non-power* reasons -> This dependency needs to be preserved, - # except in Expert, where that dependency doesn't exist, but now there *is* a power dependency. - # In the future, it would be wise to make a distinction between "power dependencies" and other dependencies. - if panel_hex == "0x28A0D" and not any("0x28998" in option for option in these_panels): - these_items = all_options + # If this entity is not an EP, and it has an associated door item, ignore the original power dependencies + if StaticWitnessLogic.ENTITIES_BY_HEX[panel_hex]["entityType"] != "EP": + # 0x28A0D depends on another entity for *non-power* reasons -> This dependency needs to be preserved, + # except in Expert, where that dependency doesn't exist, but now there *is* a power dependency. + # In the future, it'd be wise to make a distinction between "power dependencies" and other dependencies. + if panel_hex == "0x28A0D" and not any("0x28998" in option for option in these_panels): + these_items = all_options - # Another dependency that is not power-based: The Symmetry Island Upper Panel latches - elif panel_hex == "0x1C349": - these_items = all_options + # Another dependency that is not power-based: The Symmetry Island Upper Panel latches + elif panel_hex == "0x1C349": + these_items = all_options + + else: + return frozenset(all_options) - # For any other door entity, we just return a set with the item that opens it & disregard power dependencies else: - return frozenset(all_options) + these_items = all_options disabled_eps = {eHex for eHex in self.COMPLETELY_DISABLED_ENTITIES if self.REFERENCE_LOGIC.ENTITIES_BY_HEX[eHex]["entityType"] == "EP"} @@ -429,6 +433,9 @@ class WitnessPlayerLogic: if lasers: adjustment_linesets_in_order.append(get_laser_shuffle()) + if world.options.shuffle_EPs and world.options.obelisk_keys: + adjustment_linesets_in_order.append(get_obelisk_keys()) + if world.options.shuffle_EPs == "obelisk_sides": ep_gen = ((ep_hex, ep_obj) for (ep_hex, ep_obj) in self.REFERENCE_LOGIC.ENTITIES_BY_HEX.items() if ep_obj["entityType"] == "EP") @@ -442,7 +449,7 @@ class WitnessPlayerLogic: adjustment_linesets_in_order.append(["Disabled Locations:"] + get_ep_obelisks()[1:]) if not world.options.shuffle_EPs: - adjustment_linesets_in_order.append(["Irrelevant Locations:"] + get_ep_all_individual()[1:]) + adjustment_linesets_in_order.append(["Disabled Locations:"] + get_ep_all_individual()[1:]) for yaml_disabled_location in self.YAML_DISABLED_LOCATIONS: if yaml_disabled_location not in self.REFERENCE_LOGIC.ENTITIES_BY_NAME: diff --git a/worlds/witness/presets.py b/worlds/witness/presets.py index 0f37fd50a3..2a53484a4c 100644 --- a/worlds/witness/presets.py +++ b/worlds/witness/presets.py @@ -14,6 +14,7 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "door_groupings": DoorGroupings.option_off, "shuffle_boat": True, "shuffle_lasers": ShuffleLasers.option_local, + "obelisk_keys": ObeliskKeys.option_false, "disable_non_randomized_puzzles": True, "shuffle_discarded_panels": False, @@ -35,6 +36,7 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "area_hint_percentage": AreaHintPercentage.default, "laser_hints": LaserHints.default, "death_link": DeathLink.default, + "death_link_amnesty": DeathLinkAmnesty.default, }, # For relative beginners who want to move to the next step. @@ -48,6 +50,7 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "door_groupings": DoorGroupings.option_regional, "shuffle_boat": True, "shuffle_lasers": ShuffleLasers.option_off, + "obelisk_keys": ObeliskKeys.option_false, "disable_non_randomized_puzzles": False, "shuffle_discarded_panels": True, @@ -69,6 +72,7 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "area_hint_percentage": AreaHintPercentage.default, "laser_hints": LaserHints.default, "death_link": DeathLink.default, + "death_link_amnesty": DeathLinkAmnesty.default, }, # Allsanity but without the BS (no expert, no tedious EPs). @@ -82,6 +86,7 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "door_groupings": DoorGroupings.option_off, "shuffle_boat": True, "shuffle_lasers": ShuffleLasers.option_anywhere, + "obelisk_keys": ObeliskKeys.option_true, "disable_non_randomized_puzzles": False, "shuffle_discarded_panels": True, @@ -103,5 +108,6 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "area_hint_percentage": AreaHintPercentage.default, "laser_hints": LaserHints.default, "death_link": DeathLink.default, + "death_link_amnesty": DeathLinkAmnesty.default, }, } diff --git a/worlds/witness/settings/Door_Shuffle/Obelisk_Keys.txt b/worlds/witness/settings/Door_Shuffle/Obelisk_Keys.txt new file mode 100644 index 0000000000..9ebcc9fa2f --- /dev/null +++ b/worlds/witness/settings/Door_Shuffle/Obelisk_Keys.txt @@ -0,0 +1,7 @@ +Items: +Desert Obelisk Key +Monastery Obelisk Key +Treehouse Obelisk Key +Mountainside Obelisk Key +Quarry Obelisk Key +Town Obelisk Key \ No newline at end of file diff --git a/worlds/witness/utils.py b/worlds/witness/utils.py index b1f1b6d831..43e039475d 100644 --- a/worlds/witness/utils.py +++ b/worlds/witness/utils.py @@ -177,6 +177,10 @@ def get_ep_obelisks() -> List[str]: return get_adjustment_file("settings/EP_Shuffle/EP_Sides.txt") +def get_obelisk_keys() -> List[str]: + return get_adjustment_file("settings/Door_Shuffle/Obelisk_Keys.txt") + + def get_ep_easy() -> List[str]: return get_adjustment_file("settings/EP_Shuffle/EP_Easy.txt") From 2692604c091a3e0d87e2535474d1f180c86da3d6 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:40:16 -0500 Subject: [PATCH 36/49] Core: String comparison with FreeText class (#2942) --- Options.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Options.py b/Options.py index f19c042f33..144220c8ee 100644 --- a/Options.py +++ b/Options.py @@ -180,6 +180,14 @@ class FreeText(Option[str]): def get_option_name(cls, value: str) -> str: return value + def __eq__(self, other): + if isinstance(other, self.__class__): + return other.value == self.value + elif isinstance(other, str): + return other == self.value + else: + raise TypeError(f"Can't compare {self.__class__.__name__} with {other.__class__.__name__}") + class NumericOption(Option[int], numbers.Integral, abc.ABC): default = 0 From a6e1ea8c48f7512c33951571dcc57546020f8188 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Tue, 12 Mar 2024 20:40:58 +0100 Subject: [PATCH 37/49] CommonClient: use rich text for /received (#2715) --- CommonClient.py | 15 +++++++++++---- NetUtils.py | 4 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CommonClient.py b/CommonClient.py index 3665b9f177..a7b7828a1d 100644 --- a/CommonClient.py +++ b/CommonClient.py @@ -20,8 +20,8 @@ if __name__ == "__main__": Utils.init_logging("TextClient", exception_logger="Client") from MultiServer import CommandProcessor -from NetUtils import Endpoint, decode, NetworkItem, encode, JSONtoTextParser, \ - ClientStatus, Permission, NetworkSlot, RawJSONtoTextParser +from NetUtils import (Endpoint, decode, NetworkItem, encode, JSONtoTextParser, ClientStatus, Permission, NetworkSlot, + RawJSONtoTextParser, add_json_text, add_json_location, add_json_item, JSONTypes) from Utils import Version, stream_input, async_start from worlds import network_data_package, AutoWorldRegister import os @@ -72,9 +72,16 @@ class ClientCommandProcessor(CommandProcessor): def _cmd_received(self) -> bool: """List all received items""" - self.output(f'{len(self.ctx.items_received)} received items:') + item: NetworkItem + self.output(f'{len(self.ctx.items_received)} received items, sorted by time:') for index, item in enumerate(self.ctx.items_received, 1): - self.output(f"{self.ctx.item_names[item.item]} from {self.ctx.player_names[item.player]}") + parts = [] + add_json_item(parts, item.item, self.ctx.slot, item.flags) + add_json_text(parts, " from ") + add_json_location(parts, item.location, item.player) + add_json_text(parts, " by ") + add_json_text(parts, item.player, type=JSONTypes.player_id) + self.ctx.on_print_json({"data": parts, "cmd": "PrintJSON"}) return True def _cmd_missing(self, filter_text = "") -> bool: diff --git a/NetUtils.py b/NetUtils.py index a2db6a2ac5..8fc3929e60 100644 --- a/NetUtils.py +++ b/NetUtils.py @@ -290,8 +290,8 @@ def add_json_item(parts: list, item_id: int, player: int = 0, item_flags: int = parts.append({"text": str(item_id), "player": player, "flags": item_flags, "type": JSONTypes.item_id, **kwargs}) -def add_json_location(parts: list, item_id: int, player: int = 0, **kwargs) -> None: - parts.append({"text": str(item_id), "player": player, "type": JSONTypes.location_id, **kwargs}) +def add_json_location(parts: list, location_id: int, player: int = 0, **kwargs) -> None: + parts.append({"text": str(location_id), "player": player, "type": JSONTypes.location_id, **kwargs}) class Hint(typing.NamedTuple): From b6b88070be542b6458220f89d7c65f1bec95fab3 Mon Sep 17 00:00:00 2001 From: Remy Jette Date: Tue, 12 Mar 2024 13:13:52 -0700 Subject: [PATCH 38/49] CommonClient: Fix item link group name when member slot name contains brackets (#2794) --- kvui.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kvui.py b/kvui.py index 1cd1c99834..dc8f4f4162 100644 --- a/kvui.py +++ b/kvui.py @@ -750,8 +750,10 @@ class KivyJSONtoTextParser(JSONtoTextParser): text = f"Game: {slot_info.game}
" \ f"Type: {SlotType(slot_info.type).name}" if slot_info.group_members: - text += f"
Members:
" + \ - "
".join(self.ctx.player_names[player] for player in slot_info.group_members) + text += f"
Members:
" + "
".join( + escape_markup(self.ctx.player_names[player]) + for player in slot_info.group_members + ) node.setdefault("refs", []).append(text) return super(KivyJSONtoTextParser, self)._handle_player_id(node) From f8d5fe0e1e5b88b6cc7fb7272a0fd679819f69b4 Mon Sep 17 00:00:00 2001 From: PoryGone <98504756+PoryGone@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:00:13 -0400 Subject: [PATCH 39/49] SMW: v2.0 Content Update (#2762) Changelog: Features: - New optional Location Checks - 3-Up Moons - Hidden 1-Ups - Bonus Blocks - Blocksanity - All blocks that contain coins or items are included, with the exception of: - Blocks in Top Secret Area & Front Door/Bowser Castle - Blocks that are unreachable without glitches/unreasonable movement - New Items - Special Zone Clear - New Filler Items - 1 Coin - 5 Coins - 10 Coins - 50 Coins - New Trap Items - Reverse Trap - Thwimp Trap - SFX Shuffle - Palette Shuffle Overhaul - New Curated Palette can now be used for the Overworld and Level Palette Shuffle options - Foreground and Background Shuffle options have been merged into a single setting - Max possible Yoshi Egg value is 255 - UI in-game is updated to handle 3-digits - New `Display Received Item Popups` option: `progression_minus_yoshi_eggs` Quality of Life: - In-Game Indicators are now displayed on the map screen for location checks and received items - In-level sprites are displayed upon receiving certain items - The Camera Scroll unlocking is now only enabled on levels where it needs to be - SMW can now handle receiving more than 255 items - Significant World Code cleanup - New Options API - Removal of `world: MultiWorld` across the world - The PopTracker pack now has tabs for every level/sublevel, and can automatically swap tabs while playing if connected to the server Bug Fixes: - Several logic tweaks/fixes "Major credit to @TheLX5 for being the driving force for almost all of this update. We've been collaborating on design and polish of the features for the last few months, but all of the heavy lifting was all @TheLX5." --- worlds/smw/Aesthetics.py | 907 ++++++- worlds/smw/Client.py | 264 +- worlds/smw/Items.py | 15 +- worlds/smw/Levels.py | 722 ++++- worlds/smw/Locations.py | 767 +++++- worlds/smw/Names/ItemName.py | 17 +- worlds/smw/Names/LocationName.py | 608 +++++ worlds/smw/Names/TextBox.py | 18 +- worlds/smw/Options.py | 194 +- worlds/smw/Regions.py | 1941 +++++++++---- worlds/smw/Rom.py | 2401 ++++++++++++++++- worlds/smw/Rules.py | 17 +- worlds/smw/__init__.py | 140 +- worlds/smw/data/blocksanity.json | 747 +++++ worlds/smw/data/graphics/indicators.bin | Bin 0 -> 384 bytes .../level/castle_pillars/agnus_castle.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_pillars/cheese.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/chocolate_blue.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/dark_aqua_marine.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/dollhouse.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/gold_caslte.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/keves_castle.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/original_gray.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/original_green.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/original_mustard.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/original_white.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/pink_purple.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/purple_pink.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/sand_gray.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/sand_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_pillars/shenhe.mw3 | Bin 0 -> 514 bytes .../level/castle_pillars/whatsapp.mw3 | Bin 0 -> 514 bytes .../level/castle_small_windows/dark_lava.mw3 | Bin 0 -> 514 bytes .../castle_small_windows/dark_purple.mw3 | Bin 0 -> 514 bytes .../level/castle_small_windows/dollhouse.mw3 | Bin 0 -> 514 bytes .../castle_small_windows/forgotten_temple.mw3 | Bin 0 -> 514 bytes .../castle_small_windows/original_gray.mw3 | Bin 0 -> 514 bytes .../original_volcanic.mw3 | Bin 0 -> 514 bytes .../castle_small_windows/original_water.mw3 | Bin 0 -> 514 bytes .../level/castle_small_windows/sand_gray.mw3 | Bin 0 -> 514 bytes .../level/castle_small_windows/sand_green.mw3 | Bin 0 -> 514 bytes .../level/castle_small_windows/shenhe.mw3 | Bin 0 -> 514 bytes .../level/castle_small_windows/water.mw3 | Bin 0 -> 514 bytes .../level/castle_small_windows/whatsapp.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_wall/cheese.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_wall/dollhouse.mw3 | Bin 0 -> 514 bytes .../level/castle_wall/grand_marshall.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_wall/hot_wall.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_wall/original.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_wall/sand_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_wall/shenhe.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/castle_wall/water.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/brawler_pink.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_windows/cheese.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/dark_aqua_marine.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/dollhouse.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/original_brown.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/original_gray.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/original_water.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/red_castle.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_windows/shenhe.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/underwater.mw3 | Bin 0 -> 514 bytes .../palettes/level/castle_windows/water.mw3 | Bin 0 -> 514 bytes .../level/castle_windows/whatsapp.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/brawler_dark.mw3 | Bin 0 -> 514 bytes .../palettes/level/cave/brawler_purple.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/brawler_red.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/brawler_teal.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/bright_magma.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/cave/dark_red.mw3 | Bin 0 -> 514 bytes .../palettes/level/cave/glowing_mushroom.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/green_depths.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/level/cave/ice.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/magma_cave.mw3 | Bin 0 -> 514 bytes .../level/cave/original_chocolate.mw3 | Bin 0 -> 514 bytes .../palettes/level/cave/original_gray.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/original_ice.mw3 | Bin 0 -> 514 bytes .../palettes/level/cave/original_mustard.mw3 | Bin 0 -> 514 bytes .../palettes/level/cave/original_volcanic.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/level/cave/snow.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/level/cave/toxic.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave/toxic_moss.mw3 | Bin 0 -> 514 bytes .../bocchi_rock_hair_cube_things.mw3 | Bin 0 -> 514 bytes .../level/cave_rocks/brawler_volcanic.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave_rocks/ice.mw3 | Bin 0 -> 514 bytes .../palettes/level/cave_rocks/layer_2.mw3 | Bin 0 -> 514 bytes .../level/cave_rocks/original_gray.mw3 | Bin 0 -> 514 bytes .../level/cave_rocks/original_mustard.mw3 | Bin 0 -> 514 bytes .../cave_rocks/pyra_mythra_ft_pneuma.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave_rocks/snow.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/cave_rocks/toxic.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/clouds/atardecer.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/clouds/charcoal.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/clouds/cloudy.mw3 | Bin 0 -> 514 bytes .../palettes/level/clouds/cotton_candy.mw3 | Bin 0 -> 514 bytes .../palettes/level/clouds/original_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/clouds/original_orange.mw3 | Bin 0 -> 514 bytes .../palettes/level/forest/agnian_queen.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/forest/atardecer.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/forest/frozen.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/forest/halloween.mw3 | Bin 0 -> 514 bytes .../palettes/level/forest/kevesi_queen.mw3 | Bin 0 -> 514 bytes .../palettes/level/forest/original_dark.mw3 | Bin 0 -> 514 bytes .../palettes/level/forest/original_fall.mw3 | Bin 0 -> 514 bytes .../palettes/level/forest/original_green.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/forest/sakura.mw3 | Bin 0 -> 514 bytes .../level/forest/snow_dark_leaves.mw3 | Bin 0 -> 514 bytes .../level/forest/snow_green_leaves.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/brawler_cyan.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/brawler_orange.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/brawler_purple.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/creepypasta.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/crimson_house.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/golden_house.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/halloween_pallet.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/orange_lights.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/original_aqua.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/original_blue.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/original_dark.mw3 | Bin 0 -> 514 bytes .../level/ghost_house/original_white.mw3 | Bin 0 -> 514 bytes .../level/ghost_house_exit/evening_exit.mw3 | Bin 0 -> 514 bytes .../level/ghost_house_exit/golden_house.mw3 | Bin 0 -> 514 bytes .../level/ghost_house_exit/original.mw3 | Bin 0 -> 514 bytes .../ghost_house_exit/original_blue_door.mw3 | Bin 0 -> 514 bytes .../level/ghost_house_exit/underwater.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_clouds/atardecer.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_clouds/crimson.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_clouds/electro.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_clouds/geo.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_clouds/miku.mw3 | Bin 0 -> 514 bytes .../level/grass_clouds/original_blue.mw3 | Bin 0 -> 514 bytes .../level/grass_clouds/original_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_clouds/pizza.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_clouds/sakura.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_clouds/shukfr.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_clouds/snow_day.mw3 | Bin 0 -> 514 bytes .../level/grass_clouds/volcanic_rock.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/atardecer.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/autumn.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/brawler.mw3 | Bin 0 -> 514 bytes .../level/grass_forest/brawler_atardecer.mw3 | Bin 0 -> 514 bytes .../level/grass_forest/brawler_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/crimson.mw3 | Bin 0 -> 514 bytes .../level/grass_forest/deep_forest.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/electro.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_forest/geo.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_forest/miku.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_forest/myon.mw3 | Bin 0 -> 514 bytes .../level/grass_forest/original_aqua.mw3 | Bin 0 -> 514 bytes .../level/grass_forest/original_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/pizza.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/sakura.mw3 | Bin 0 -> 514 bytes .../level/grass_forest/snow_dark_leaves.mw3 | Bin 0 -> 514 bytes .../level/grass_forest/snow_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_forest/winter.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/atardecer.mw3 | Bin 0 -> 514 bytes .../level/grass_hills/brawler_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/crimson.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/electro.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_hills/geo.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_hills/miku.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/mogumogu.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/nocturno.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/original.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/sakura.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_hills/snow.mw3 | Bin 0 -> 514 bytes .../grass_hills/sunsetish_grass_hills.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_hills/toothpaste.mw3 | Bin 0 -> 514 bytes .../grass_mountains/brawler_lifeless.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/classic_sm.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/crimson.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/dry_hills.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/electro.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_mountains/geo.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/late_sandish.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_mountains/miku.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/original_aqua.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/original_blue.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/original_green.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/original_white.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/recksfr.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/sakura_hills.mw3 | Bin 0 -> 514 bytes .../level/grass_mountains/snow_day.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_rocks/atardecer.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_rocks/crimson.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_rocks/dark.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_rocks/electro.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_rocks/geo.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_rocks/ice.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_rocks/miku.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_rocks/napolitano.mw3 | Bin 0 -> 514 bytes .../level/grass_rocks/original_aqua.mw3 | Bin 0 -> 514 bytes .../grass_rocks/original_choco_volcanic.mw3 | Bin 0 -> 514 bytes .../level/grass_rocks/original_ice.mw3 | Bin 0 -> 514 bytes .../level/grass_rocks/original_volcanic.mw3 | Bin 0 -> 514 bytes .../grass_rocks/original_volcanic_green.mw3 | Bin 0 -> 514 bytes .../level/grass_rocks/original_white.mw3 | Bin 0 -> 514 bytes .../level/grass_rocks/original_white_2.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/grass_rocks/recks.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_rocks/sakura.mw3 | Bin 0 -> 514 bytes .../palettes/level/grass_rocks/thanks_doc.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/logs/brawler.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/logs/evening.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/logs/mahogany.mw3 | Bin 0 -> 514 bytes .../level/logs/not_quite_dawnbreak.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/logs/original.mw3 | Bin 0 -> 514 bytes .../level/logs/riesgo_de_chubascos.mw3 | Bin 0 -> 514 bytes .../level/mushroom_cave/argent_cave.mw3 | Bin 0 -> 514 bytes .../level/mushroom_cave/glowing_mushroom.mw3 | Bin 0 -> 514 bytes .../level/mushroom_cave/green_aqua.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/mushroom_cave/ice.mw3 | Bin 0 -> 514 bytes .../palettes/level/mushroom_cave/original.mw3 | Bin 0 -> 514 bytes .../level/mushroom_cave/really_dark.mw3 | Bin 0 -> 514 bytes .../palettes/level/mushroom_cave/toxic.mw3 | Bin 0 -> 514 bytes .../level/mushroom_clouds/atardecer.mw3 | Bin 0 -> 514 bytes .../level/mushroom_clouds/greenshroom.mw3 | Bin 0 -> 514 bytes .../level/mushroom_clouds/oilshroom.mw3 | Bin 0 -> 514 bytes .../level/mushroom_clouds/original_aqua.mw3 | Bin 0 -> 514 bytes .../level/mushroom_clouds/original_blue.mw3 | Bin 0 -> 514 bytes .../level/mushroom_clouds/original_yellow.mw3 | Bin 0 -> 514 bytes .../mushroom_clouds/riesgo_de_chubascos.mw3 | Bin 0 -> 514 bytes .../level/mushroom_forest/atardecer.mw3 | Bin 0 -> 514 bytes .../palettes/level/mushroom_forest/autumn.mw3 | Bin 0 -> 514 bytes .../mushroom_forest/count_shroomcula.mw3 | Bin 0 -> 514 bytes .../level/mushroom_forest/cursed_gold.mw3 | Bin 0 -> 514 bytes .../level/mushroom_forest/dark_green.mw3 | Bin 0 -> 514 bytes .../level/mushroom_forest/lifeless_gray.mw3 | Bin 0 -> 514 bytes .../level/mushroom_forest/original.mw3 | Bin 0 -> 514 bytes .../level/mushroom_forest/snow_dark.mw3 | Bin 0 -> 514 bytes .../level/mushroom_forest/snow_green.mw3 | Bin 0 -> 514 bytes .../level/mushroom_hills/atardecer.mw3 | Bin 0 -> 514 bytes .../mushroom_hills/atardecer_naranjo.mw3 | Bin 0 -> 514 bytes .../level/mushroom_hills/atardecer_verde.mw3 | Bin 0 -> 514 bytes .../palettes/level/mushroom_hills/future.mw3 | Bin 0 -> 514 bytes .../level/mushroom_hills/original.mw3 | Bin 0 -> 514 bytes .../riesgo_de_chubascos_azul.mw3 | Bin 0 -> 514 bytes .../riesgo_de_chubascos_cafe.mw3 | Bin 0 -> 514 bytes .../riesgo_de_chubascos_negro.mw3 | Bin 0 -> 514 bytes .../level/mushroom_hills/watermelon_skies.mw3 | Bin 0 -> 514 bytes .../level/mushroom_rocks/atardecer.mw3 | Bin 0 -> 514 bytes .../level/mushroom_rocks/brightshroom.mw3 | Bin 0 -> 514 bytes .../level/mushroom_rocks/original_green.mw3 | Bin 0 -> 514 bytes .../level/mushroom_rocks/original_ice.mw3 | Bin 0 -> 514 bytes .../mushroom_rocks/original_volcanic.mw3 | Bin 0 -> 514 bytes .../level/mushroom_rocks/original_white.mw3 | Bin 0 -> 514 bytes .../riesgo_de_chubascos_cafe.mw3 | Bin 0 -> 514 bytes .../riesgo_de_chubascos_negro.mw3 | Bin 0 -> 514 bytes .../level/mushroom_rocks/shuk_ft_reyn.mw3 | Bin 0 -> 514 bytes .../level/mushroom_stars/atardecer.mw3 | Bin 0 -> 514 bytes .../palettes/level/mushroom_stars/cool.mw3 | Bin 0 -> 514 bytes .../level/mushroom_stars/dark_night.mw3 | Bin 0 -> 514 bytes .../level/mushroom_stars/halloween.mw3 | Bin 0 -> 514 bytes .../level/mushroom_stars/light_pollution.mw3 | Bin 0 -> 514 bytes .../palettes/level/mushroom_stars/midas.mw3 | Bin 0 -> 514 bytes .../level/mushroom_stars/original_green.mw3 | Bin 0 -> 514 bytes .../level/mushroom_stars/original_night.mw3 | Bin 0 -> 514 bytes .../level/mushroom_stars/purpleish_night.mw3 | Bin 0 -> 514 bytes .../mushroom_stars/riesgo_de_chubascos.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/level/palettes.json | 358 +++ .../level/ship_exterior/blue_purple.mw3 | Bin 0 -> 514 bytes .../palettes/level/ship_exterior/doc_ship.mw3 | Bin 0 -> 514 bytes .../level/ship_exterior/grey_ship.mw3 | Bin 0 -> 514 bytes .../palettes/level/ship_exterior/original.mw3 | Bin 0 -> 514 bytes .../palettes/level/ship_exterior/reddish.mw3 | Bin 0 -> 514 bytes .../level/ship_interior/blue_purple.mw3 | Bin 0 -> 514 bytes .../level/ship_interior/bocchi_hitori.mw3 | Bin 0 -> 514 bytes .../level/ship_interior/bocchi_rock.mw3 | Bin 0 -> 514 bytes .../palettes/level/ship_interior/brawler.mw3 | Bin 0 -> 514 bytes .../level/ship_interior/grey_ship.mw3 | Bin 0 -> 514 bytes .../palettes/level/ship_interior/original.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/blue_grid.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/brawler_brown.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/cafe_claro.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/color_de_gato.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/color_del_gato_2.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/green_grid.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/gris.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/mario_pants.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/monado.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/morado.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/negro.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/onigiria.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/original.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/original_bonus.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/pink.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/red_grid.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/verde.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/verde_agua.mw3 | Bin 0 -> 514 bytes .../level/switch_palace/yellow_grid.mw3 | Bin 0 -> 514 bytes .../palettes/level/switch_palace/youbonus.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/water/dark_water.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/water/deep_aqua.mw3 | Bin 0 -> 514 bytes .../palettes/level/water/deep_chocolate.mw3 | Bin 0 -> 514 bytes .../palettes/level/water/harmless_magma.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/level/water/murky.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/water/oil_spill.mw3 | Bin 0 -> 514 bytes .../palettes/level/water/original_brown.mw3 | Bin 0 -> 514 bytes .../palettes/level/water/original_gray.mw3 | Bin 0 -> 514 bytes .../palettes/level/water/original_green.mw3 | Bin 0 -> 514 bytes .../palettes/level/water/original_mustard.mw3 | Bin 0 -> 514 bytes .../level/water/original_volcanic.mw3 | Bin 0 -> 514 bytes .../palettes/level/water/pickle_juice.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/atardecer.mw3 | Bin 0 -> 514 bytes .../level/yoshi_house/brawler_green.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/yoshi_house/choco.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/crimson.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/yoshi_house/miku.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/mogumogu.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/monocromo.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/yoshi_house/neon.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/yoshi_house/nieve.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/yoshi_house/night.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/nocturno.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/original.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/sakura.mw3 | Bin 0 -> 514 bytes .../data/palettes/level/yoshi_house/snow.mw3 | Bin 0 -> 514 bytes .../palettes/level/yoshi_house/strong_sun.mw3 | Bin 0 -> 514 bytes .../yoshi_house/sunsetish_grass_hills.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/forest/atardecer.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/forest/burnt_forest.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/forest/dark_forest.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/forest/halloween.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/forest/ice_forest.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/forest/lost_woods.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/forest/mono.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/forest/original.mw3 | Bin 0 -> 514 bytes .../palettes/map/forest/original_special.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/forest/sepia.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/forest/snow_day.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/main/atardecer.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/main/brawler.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/main/cake_frosting.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/main/invertido.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/main/mono.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/main/morning.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/main/night.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/main/night_time.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/main/original.mw3 | Bin 0 -> 514 bytes .../palettes/map/main/original_special.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/main/sepia.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/main/snow_day.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/palettes.json | 92 + .../data/palettes/map/special/black_out.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/special/blood_star.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/special/brawler.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/special/green.mw3 | Bin 0 -> 514 bytes .../map/special/light_pollution_map.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/special/original.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/special/purple.mw3 | Bin 0 -> 514 bytes .../palettes/map/special/white_special.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/star/blood_moon.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/star/mono.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/star/mountain_top.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/star/original.mw3 | Bin 0 -> 514 bytes .../palettes/map/star/original_special.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/star/pink_star.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/star/sepia.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/star/yellow_star.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/valley/Tamaulipas.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/valley/bowser.mw3 | Bin 0 -> 514 bytes .../palettes/map/valley/castle_colors.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/valley/dark cave.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/valley/dream_world.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/valley/fire cave.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/valley/invertido.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/valley/mono.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/valley/orange.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/valley/original.mw3 | Bin 0 -> 514 bytes .../palettes/map/valley/original_special.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/valley/purple_blue.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/valley/sepia.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/valley/snow.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/vanilla/DOMO.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/vanilla/aqua_marine.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/vanilla/dark cave.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/vanilla/fire cave.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/vanilla/gold_mine.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/vanilla/invertido.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/vanilla/mono.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/vanilla/original.mw3 | Bin 0 -> 514 bytes .../palettes/map/vanilla/original_special.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/vanilla/purple.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/vanilla/sepia.mw3 | Bin 0 -> 514 bytes .../palettes/map/vanilla/witches_cauldron.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/yoshi/atardecer.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/yoshi/gum.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/yoshi/lava_island.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/yoshi/mono.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/yoshi/original.mw3 | Bin 0 -> 514 bytes .../palettes/map/yoshi/original_special.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/yoshi/sepia.mw3 | Bin 0 -> 514 bytes .../smw/data/palettes/map/yoshi/snow_day.mw3 | Bin 0 -> 514 bytes worlds/smw/data/palettes/map/yoshi/sunset.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/yoshi/tritanopia.mw3 | Bin 0 -> 514 bytes .../data/palettes/map/yoshi/yochis_ailand.mw3 | Bin 0 -> 514 bytes 395 files changed, 8433 insertions(+), 775 deletions(-) create mode 100644 worlds/smw/data/blocksanity.json create mode 100644 worlds/smw/data/graphics/indicators.bin create mode 100644 worlds/smw/data/palettes/level/castle_pillars/agnus_castle.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/cheese.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/chocolate_blue.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/dark_aqua_marine.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/dollhouse.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/gold_caslte.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/keves_castle.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/original_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/original_mustard.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/original_white.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/pink_purple.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/purple_pink.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/sand_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/sand_green.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/shenhe.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_pillars/whatsapp.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/dark_lava.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/dark_purple.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/dollhouse.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/forgotten_temple.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/original_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/original_volcanic.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/original_water.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/sand_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/sand_green.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/shenhe.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/water.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_small_windows/whatsapp.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/cheese.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/dollhouse.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/grand_marshall.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/hot_wall.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/original.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/sand_green.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/shenhe.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_wall/water.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/brawler_pink.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/cheese.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/dark_aqua_marine.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/dollhouse.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/original_brown.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/original_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/original_water.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/red_castle.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/shenhe.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/underwater.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/water.mw3 create mode 100644 worlds/smw/data/palettes/level/castle_windows/whatsapp.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/brawler_dark.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/brawler_purple.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/brawler_red.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/brawler_teal.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/bright_magma.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/dark_red.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/glowing_mushroom.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/green_depths.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/ice.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/magma_cave.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/original_chocolate.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/original_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/original_ice.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/original_mustard.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/original_volcanic.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/snow.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/toxic.mw3 create mode 100644 worlds/smw/data/palettes/level/cave/toxic_moss.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/bocchi_rock_hair_cube_things.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/brawler_volcanic.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/ice.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/layer_2.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/original_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/original_mustard.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/pyra_mythra_ft_pneuma.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/snow.mw3 create mode 100644 worlds/smw/data/palettes/level/cave_rocks/toxic.mw3 create mode 100644 worlds/smw/data/palettes/level/clouds/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/clouds/charcoal.mw3 create mode 100644 worlds/smw/data/palettes/level/clouds/cloudy.mw3 create mode 100644 worlds/smw/data/palettes/level/clouds/cotton_candy.mw3 create mode 100644 worlds/smw/data/palettes/level/clouds/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/clouds/original_orange.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/agnian_queen.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/frozen.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/halloween.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/kevesi_queen.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/original_dark.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/original_fall.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/sakura.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/snow_dark_leaves.mw3 create mode 100644 worlds/smw/data/palettes/level/forest/snow_green_leaves.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/brawler_cyan.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/brawler_orange.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/brawler_purple.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/creepypasta.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/crimson_house.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/golden_house.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/halloween_pallet.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/orange_lights.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/original_aqua.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/original_blue.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/original_dark.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house/original_white.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house_exit/evening_exit.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house_exit/golden_house.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house_exit/original.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house_exit/original_blue_door.mw3 create mode 100644 worlds/smw/data/palettes/level/ghost_house_exit/underwater.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/crimson.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/electro.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/geo.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/miku.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/original_blue.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/pizza.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/sakura.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/shukfr.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/snow_day.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_clouds/volcanic_rock.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/autumn.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/brawler.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/brawler_atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/brawler_green.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/crimson.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/deep_forest.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/electro.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/geo.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/miku.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/myon.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/original_aqua.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/pizza.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/sakura.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/snow_dark_leaves.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/snow_green.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_forest/winter.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/brawler_green.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/crimson.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/electro.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/geo.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/miku.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/mogumogu.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/nocturno.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/original.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/sakura.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/snow.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/sunsetish_grass_hills.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_hills/toothpaste.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/brawler_lifeless.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/classic_sm.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/crimson.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/dry_hills.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/electro.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/geo.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/late_sandish.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/miku.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/original_aqua.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/original_blue.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/original_white.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/recksfr.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/sakura_hills.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_mountains/snow_day.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/crimson.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/dark.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/electro.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/geo.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/ice.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/miku.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/napolitano.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/original_aqua.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/original_choco_volcanic.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/original_ice.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/original_volcanic.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/original_volcanic_green.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/original_white.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/original_white_2.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/recks.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/sakura.mw3 create mode 100644 worlds/smw/data/palettes/level/grass_rocks/thanks_doc.mw3 create mode 100644 worlds/smw/data/palettes/level/logs/brawler.mw3 create mode 100644 worlds/smw/data/palettes/level/logs/evening.mw3 create mode 100644 worlds/smw/data/palettes/level/logs/mahogany.mw3 create mode 100644 worlds/smw/data/palettes/level/logs/not_quite_dawnbreak.mw3 create mode 100644 worlds/smw/data/palettes/level/logs/original.mw3 create mode 100644 worlds/smw/data/palettes/level/logs/riesgo_de_chubascos.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_cave/argent_cave.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_cave/glowing_mushroom.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_cave/green_aqua.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_cave/ice.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_cave/original.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_cave/really_dark.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_cave/toxic.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_clouds/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_clouds/greenshroom.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_clouds/oilshroom.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_clouds/original_aqua.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_clouds/original_blue.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_clouds/original_yellow.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_clouds/riesgo_de_chubascos.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/autumn.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/count_shroomcula.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/cursed_gold.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/dark_green.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/lifeless_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/original.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/snow_dark.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_forest/snow_green.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/atardecer_naranjo.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/atardecer_verde.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/future.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/original.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/riesgo_de_chubascos_azul.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/riesgo_de_chubascos_cafe.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/riesgo_de_chubascos_negro.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_hills/watermelon_skies.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/brightshroom.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/original_ice.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/original_volcanic.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/original_white.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/riesgo_de_chubascos_cafe.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/riesgo_de_chubascos_negro.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_rocks/shuk_ft_reyn.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/cool.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/dark_night.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/halloween.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/light_pollution.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/midas.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/original_night.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/purpleish_night.mw3 create mode 100644 worlds/smw/data/palettes/level/mushroom_stars/riesgo_de_chubascos.mw3 create mode 100644 worlds/smw/data/palettes/level/palettes.json create mode 100644 worlds/smw/data/palettes/level/ship_exterior/blue_purple.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_exterior/doc_ship.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_exterior/grey_ship.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_exterior/original.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_exterior/reddish.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_interior/blue_purple.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_interior/bocchi_hitori.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_interior/bocchi_rock.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_interior/brawler.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_interior/grey_ship.mw3 create mode 100644 worlds/smw/data/palettes/level/ship_interior/original.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/blue_grid.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/brawler_brown.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/cafe_claro.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/color_de_gato.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/color_del_gato_2.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/green_grid.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/gris.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/mario_pants.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/monado.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/morado.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/negro.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/onigiria.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/original.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/original_bonus.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/pink.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/red_grid.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/verde.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/verde_agua.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/yellow_grid.mw3 create mode 100644 worlds/smw/data/palettes/level/switch_palace/youbonus.mw3 create mode 100644 worlds/smw/data/palettes/level/water/dark_water.mw3 create mode 100644 worlds/smw/data/palettes/level/water/deep_aqua.mw3 create mode 100644 worlds/smw/data/palettes/level/water/deep_chocolate.mw3 create mode 100644 worlds/smw/data/palettes/level/water/harmless_magma.mw3 create mode 100644 worlds/smw/data/palettes/level/water/murky.mw3 create mode 100644 worlds/smw/data/palettes/level/water/oil_spill.mw3 create mode 100644 worlds/smw/data/palettes/level/water/original_brown.mw3 create mode 100644 worlds/smw/data/palettes/level/water/original_gray.mw3 create mode 100644 worlds/smw/data/palettes/level/water/original_green.mw3 create mode 100644 worlds/smw/data/palettes/level/water/original_mustard.mw3 create mode 100644 worlds/smw/data/palettes/level/water/original_volcanic.mw3 create mode 100644 worlds/smw/data/palettes/level/water/pickle_juice.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/brawler_green.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/choco.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/crimson.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/miku.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/mogumogu.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/monocromo.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/neon.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/nieve.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/night.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/nocturno.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/original.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/sakura.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/snow.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/strong_sun.mw3 create mode 100644 worlds/smw/data/palettes/level/yoshi_house/sunsetish_grass_hills.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/burnt_forest.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/dark_forest.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/halloween.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/ice_forest.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/lost_woods.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/mono.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/original.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/original_special.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/sepia.mw3 create mode 100644 worlds/smw/data/palettes/map/forest/snow_day.mw3 create mode 100644 worlds/smw/data/palettes/map/main/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/map/main/brawler.mw3 create mode 100644 worlds/smw/data/palettes/map/main/cake_frosting.mw3 create mode 100644 worlds/smw/data/palettes/map/main/invertido.mw3 create mode 100644 worlds/smw/data/palettes/map/main/mono.mw3 create mode 100644 worlds/smw/data/palettes/map/main/morning.mw3 create mode 100644 worlds/smw/data/palettes/map/main/night.mw3 create mode 100644 worlds/smw/data/palettes/map/main/night_time.mw3 create mode 100644 worlds/smw/data/palettes/map/main/original.mw3 create mode 100644 worlds/smw/data/palettes/map/main/original_special.mw3 create mode 100644 worlds/smw/data/palettes/map/main/sepia.mw3 create mode 100644 worlds/smw/data/palettes/map/main/snow_day.mw3 create mode 100644 worlds/smw/data/palettes/map/palettes.json create mode 100644 worlds/smw/data/palettes/map/special/black_out.mw3 create mode 100644 worlds/smw/data/palettes/map/special/blood_star.mw3 create mode 100644 worlds/smw/data/palettes/map/special/brawler.mw3 create mode 100644 worlds/smw/data/palettes/map/special/green.mw3 create mode 100644 worlds/smw/data/palettes/map/special/light_pollution_map.mw3 create mode 100644 worlds/smw/data/palettes/map/special/original.mw3 create mode 100644 worlds/smw/data/palettes/map/special/purple.mw3 create mode 100644 worlds/smw/data/palettes/map/special/white_special.mw3 create mode 100644 worlds/smw/data/palettes/map/star/blood_moon.mw3 create mode 100644 worlds/smw/data/palettes/map/star/mono.mw3 create mode 100644 worlds/smw/data/palettes/map/star/mountain_top.mw3 create mode 100644 worlds/smw/data/palettes/map/star/original.mw3 create mode 100644 worlds/smw/data/palettes/map/star/original_special.mw3 create mode 100644 worlds/smw/data/palettes/map/star/pink_star.mw3 create mode 100644 worlds/smw/data/palettes/map/star/sepia.mw3 create mode 100644 worlds/smw/data/palettes/map/star/yellow_star.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/Tamaulipas.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/bowser.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/castle_colors.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/dark cave.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/dream_world.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/fire cave.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/invertido.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/mono.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/orange.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/original.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/original_special.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/purple_blue.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/sepia.mw3 create mode 100644 worlds/smw/data/palettes/map/valley/snow.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/DOMO.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/aqua_marine.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/dark cave.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/fire cave.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/gold_mine.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/invertido.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/mono.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/original.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/original_special.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/purple.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/sepia.mw3 create mode 100644 worlds/smw/data/palettes/map/vanilla/witches_cauldron.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/atardecer.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/gum.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/lava_island.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/mono.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/original.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/original_special.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/sepia.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/snow_day.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/sunset.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/tritanopia.mw3 create mode 100644 worlds/smw/data/palettes/map/yoshi/yochis_ailand.mw3 diff --git a/worlds/smw/Aesthetics.py b/worlds/smw/Aesthetics.py index 73ca616508..16b2b138f3 100644 --- a/worlds/smw/Aesthetics.py +++ b/worlds/smw/Aesthetics.py @@ -1,3 +1,82 @@ +import json +import pkgutil + +from worlds.AutoWorld import World + +tileset_names = [ + "grass_hills", + "grass_forest", + "grass_rocks", + "grass_clouds", + "grass_mountains", + "cave", + "cave_rocks", + "water", + "mushroom_rocks", + "mushroom_clouds", + "mushroom_forest", + "mushroom_hills", + "mushroom_stars", + "mushroom_cave", + "forest", + "logs", + "clouds", + "castle_pillars", + "castle_windows", + "castle_wall", + "castle_small_windows", + "ghost_house", + "ghost_house_exit", + "ship_exterior", + "ship_interior", + "switch_palace", + "yoshi_house" +] + +map_names = [ + "main", + "yoshi", + "vanilla", + "forest", + "valley", + "special", + "star" +] + +level_palette_index = [ + 0xFF,0x03,0x09,0x01,0x15,0x0A,0x04,0x12,0x19,0x06,0x07,0x12,0x09,0x0F,0x13,0x09, # Levels 000-00F + 0x03,0x07,0xFF,0x15,0x19,0x04,0x04,0xFF,0x17,0xFF,0x14,0x12,0x02,0x05,0xFF,0x11, # Levels 010-01F + 0x12,0x15,0x04,0x02,0x02,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 020-02F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 030-03F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 040-04F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 050-05F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 060-06F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 070-07F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 080-08F + 0xFF,0xFF,0xFF,0x12,0x12,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 090-09F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 0A0-0AF + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x19,0x08,0x09, # Levels 0B0-0BF + 0x02,0x08,0x05,0x04,0x16,0x1A,0x04,0x02,0x0C,0x19,0x19,0x09,0xFF,0x02,0x02,0x02, # Levels 0C0-0CF + 0x04,0x04,0x05,0x12,0x14,0xFF,0x12,0x10,0x05,0xFF,0x19,0x12,0x14,0x0F,0x15,0xFF, # Levels 0D0-0DF + 0x12,0x12,0xFF,0x04,0x15,0xFF,0x19,0x14,0x12,0x05,0x05,0x16,0x15,0x15,0x15,0x12, # Levels 0E0-0EF + 0x16,0x15,0x15,0x09,0x19,0x04,0x04,0x13,0x18,0x15,0x15,0x16,0x15,0x19,0x15,0x04, # Levels 0F0-0FF + 0xFF,0x11,0x08,0x02,0x1A,0x00,0x01,0x15,0xFF,0x05,0x05,0x05,0xFF,0x11,0x12,0x05, # Levels 100-10F + 0x12,0x14,0xFF,0x0D,0x15,0x06,0x05,0x05,0x05,0x0C,0x05,0x19,0x12,0x15,0x0E,0x01, # Levels 110-11F + 0x07,0x19,0x0E,0x0E,0xFF,0x04,0x0E,0x02,0x02,0xFF,0x09,0x04,0x0B,0x02,0xFF,0xFF, # Levels 120-12F + 0x07,0xFF,0x0C,0xFF,0x05,0x0C,0x0C,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 130-13F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 140-14F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 150-15F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 160-16F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 170-17F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 180-18F + 0xFF,0xFF,0xFF,0x12,0x12,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 190-19F + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, # Levels 1A0-1AF + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x19,0x19,0x12,0x02,0x05, # Levels 1B0-1BF + 0x02,0x07,0x05,0x05,0x03,0x03,0x00,0xFF,0x0F,0x10,0x05,0x05,0x12,0x11,0x14,0x14, # Levels 1C0-1CF + 0x11,0x12,0x12,0x12,0x11,0x03,0x03,0x19,0x19,0x15,0x16,0x15,0x15,0x15,0xFF,0x05, # Levels 1D0-1DF + 0x10,0x02,0x06,0x06,0x19,0x05,0x16,0x16,0x15,0x15,0x15,0xFF,0x06,0x05,0x05,0x06, # Levels 1E0-1EF + 0x05,0x05,0x12,0x14,0x12,0x05,0xFF,0x19,0x05,0x16,0x15,0x15,0x11,0x05,0x12,0x09 # Levels 1F0-1FF +] mario_palettes = [ [0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0x1F, 0x39, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0xB6, 0x30, 0xDF, 0x35, 0xFF, 0x03], # Mario @@ -145,36 +224,413 @@ valid_ow_palettes = { 0x2D24: [0x00, 0x02, 0x03], # Star Road } -def generate_shuffled_level_music(world, player): +valid_sfxs = [ + [0x01, 1], # Jump + [0x01, 0], # Hit head + [0x02, 0], # Contact/Spinjump on an enemy + [0x03, 0], # Kick item + [0x04, 0], # Go in pipe, get hurt + [0x05, 0], # Midway point + [0x06, 0], # Yoshi gulp + [0x07, 0], # Dry bones collapse + [0x08, 0], # Kill enemy with a spin jump + [0x09, 0], # Fly with cape + [0x0A, 0], # Get powerup + [0x0B, 0], # ON/OFF switch + [0x0C, 0], # Carry item past the goal + [0x0D, 0], # Get cape + [0x0E, 0], # Swim + [0x0F, 0], # Hurt while flying + [0x10, 0], # Magikoopa shoot magic + [0x13, 0], # Enemy stomp #1 + [0x14, 0], # Enemy stomp #2 + [0x15, 0], # Enemy stomp #3 + [0x16, 0], # Enemy stomp #4 + [0x17, 0], # Enemy stomp #5 + [0x18, 0], # Enemy stomp #6 + [0x19, 0], # Enemy stomp #7 + [0x1C, 0], # Yoshi Coin + [0x1E, 0], # P-Balloon + [0x1F, 0], # Koopaling defeated + [0x20, 0], # Yoshi spit + [0x23, 0], # Lemmy/Wendy falling + [0x25, 0], # Blargg roar + [0x26, 0], # Firework whistle + [0x27, 0], # Firework bang + [0x2A, 0], # Peach pops up from the Clown Car + [0x04, 1], # Grinder + [0x01, 3], # Coin + [0x02, 3], # Hit a ? block + [0x03, 3], # Hit a block with a vine inside + [0x04, 3], # Spin jump + [0x05, 3], # 1up + [0x06, 3], # Shatter block + [0x07, 3], # Shoot fireball + [0x08, 3], # Springboard + [0x09, 3], # Bullet bill + [0x0A, 3], # Egg hatch + [0x0B, 3], # Item going into item box + [0x0C, 3], # Item falls from item box + [0x0E, 3], # L/R scroll + [0x0F, 3], # Door + [0x13, 3], # Lose Yoshi + [0x14, 3], # SMW2: New level available + [0x15, 3], # OW tile reveal + [0x16, 3], # OW castle collapse + [0x17, 3], # Fire spit + [0x18, 3], # Thunder + [0x19, 3], # Clap + [0x1A, 3], # Castle bomb + [0x1C, 3], # OW switch palace block ejection + [0x1E, 3], # Whistle + [0x1F, 3], # Yoshi mount + [0x20, 3], # Lemmy/Wendy going in lava + [0x21, 3], # Yoshi's tongue + [0x22, 3], # Message box hit + [0x23, 3], # Landing in a level tile + [0x24, 3], # P-Switch running out + [0x25, 3], # Yoshi defeats an enemy + [0x26, 3], # Swooper + [0x27, 3], # Podoboo + [0x28, 3], # Enemy hurt + [0x29, 3], # Correct + [0x2A, 3], # Wrong + [0x2B, 3], # Firework whistle + [0x2C, 3] # Firework bang +] + +game_sfx_calls = [ + 0x0565E, # Jump + 0x1BABD, # Spin jump + 0x06D41, # Hit head on ceiling + 0x0B4F2, # Hit head on sprite + 0x07EB5, # Shooting a fireball + 0x0507B, # Cape spin + 0x058A8, # Cape smash + 0x075F3, # Taking damage + 0x075E2, # Taking damage while flying + 0x07919, # Something during a boss fight + 0x05AA9, # Swim + 0x1BC04, # Spin jump off water + 0x05BA5, # Jump off a net + 0x05BB2, # Punching a net + 0x06C10, # Entering a door + 0x05254, # Entering a pipe #1 + 0x07439, # Entering a pipe #2 + 0x052A5, # Shot from a diagonal pipe + 0x072E8, # Hit a midway point + 0x07236, # Hit a wrong block + 0x07B7D, # Spawn a powerup during the goal tape + 0x1C342, # Invisible mushroom spawn + 0x04E3F, # Scrolling the screen with L/R + 0x0AAFD, # Pressing a P-Switch + 0x04557, # P-Switch running out + 0x0BAD7, # Climbing door turning + 0x0C109, # Break goal tape + 0x0C548, # Putting item in item box + 0x10012, # Trigger item box + 0x2B34D, # Collecting a coin + 0x07358, # Collecting a Yoshi Coin + 0x0C57A, # Collecting a powerup (generic) + 0x0C59C, # Collecting a feather + 0x0C309, # Collecting a P-Balloon + 0x0E6A9, # Bouncing off a springboard + 0x1117D, # Bouncing off a note block + 0x14DEC, # Bouncing off a wall springboard + 0x1067F, # Block shattering + 0x1081E, # Activate ON/OFF switch #1 + 0x1118C, # Activate ON/OFF switch #2 + 0x12045, # Fireballs hitting a block/sprite + 0x12124, # Fireballs converting an enemy into a coin + 0x12106, # Fireballs defeating a Chuck + 0x18D7D, # Activating a message box + 0x1C209, # Activating a red question block + 0x0A290, # Baby Yoshi swallowing an item #1 + 0x1C037, # Baby Yoshi swallowing an item #2 + 0x0F756, # Yoshi egg hatching + 0x0A2C5, # Yoshi growing #1 + 0x1C06C, # Yoshi growing #2 + 0x0ED5F, # Mounting Yoshi + 0x0F71D, # Yoshi hurt + 0x12481, # Yoshi hurt (projectiles) + 0x0EF0E, # Yoshi flying + 0x06F90, # Yoshi stomping an enemy + 0x06FB6, # Yoshi ground pound (yellow shell) + 0x07024, # Yoshi bounces off a triangle + 0x11BE9, # Yoshi stomping the ground + 0x0F0D3, # Yoshi swallowing a sprite + 0x0F0FD, # Yoshi eating a green berry + 0x1BA7D, # Yoshi sticking out tongue + 0x0F5A1, # Yoshi unable to eat + 0x0F2DF, # Yoshi spitting out an item + 0x0F28F, # Yoshi spitting out flames + 0x0F3EC, # Collecting Yoshi's wings (eaten) + 0x0F6C8, # Collecting Yoshi's wings (touched) + 0x7FE04, # Defeated sprite combo #1 (using Y index) + 0x7FE0E, # Defeated sprite combo #2 (using Y index) + 0x7FE18, # Defeated sprite combo #3 (using Y index) + 0x7FE22, # Defeated sprite combo #4 (using Y index) + 0x7FE2C, # Defeated sprite combo #5 (using Y index) + 0x7FE36, # Defeated sprite combo #6 (using Y index) + 0x7FE40, # Defeated sprite combo #7 (using Y index) + 0x7FE4B, # Defeated sprite combo #1 (using X index) + 0x7FE55, # Defeated sprite combo #2 (using X index) + 0x7FE5F, # Defeated sprite combo #3 (using X index) + 0x7FE69, # Defeated sprite combo #4 (using X index) + 0x7FE73, # Defeated sprite combo #5 (using X index) + 0x7FE7D, # Defeated sprite combo #6 (using X index) + 0x7FE87, # Defeated sprite combo #7 (using X index) + 0x0A728, # Kicking a carryable item + 0x0B12F, # Kicking a stunned and vulnerable enemy + 0x0A8D8, # Performing a spinjump on a immune enemy + 0x0A93F, # Defeating an enemy via spinjump + 0x0999E, # Thrown sprite hitting the ground from the side + 0x192B8, # Creating/Eating block moving + 0x195EC, # Rex stomped + 0x134A7, # Bullet bill blaster shooting + 0x13088, # Bullet bill generator #1 + 0x130DF, # Bullet bill generator #2 + 0x09631, # Bob-omb explosion + 0x15918, # Popping a bubble + 0x15D64, # Sumo bro stomping the ground + 0x15ECC, # Sumo bro lightning spawning flames + 0x1726B, # Bouncing off wiggler + 0x08390, # Banzai bill spawn + 0x0AF17, # Thwomp hitting the ground + 0x0AFFC, # Thwimp hitting the ground + 0x14707, # Chuck running + 0x14381, # Chuck whistling + 0x144F8, # Chuck clapping + 0x14536, # Chuck jumping + 0x145AE, # Chuck splitting + 0x147D2, # Chuck bounce + 0x147F6, # Chuck hurt + 0x147B8, # Chuck defeated + 0x19D55, # Dino torch shooting fire + 0x19FFA, # Blargg attacking + 0x188FF, # Swooper bat swooping + 0x08584, # Bowser statue flame spawn + 0x18ADA, # Bowser statue shooting a flame + 0x13043, # Bowser statue flame from generator + 0x0BF28, # Magikoopa shooting a magic spell + 0x0BC5F, # Magikoopa's magic spell hitting the ground + 0x0D745, # Line guided sprites' motor + 0x0DB70, # Grinder sound + 0x0E0A1, # Podoboo jumping + 0x0E5F2, # Dry bones/Bony beetle collapsing + 0x15474, # Giant wooden pillar hitting the ground + 0x2C9C1, # Spiked columns hitting the ground + 0x19B03, # Reznor shooting a fireball + 0x19A66, # Reznor: Hitting a platform + 0x1D752, # Reznor: Bridge collapsing + 0x19ABB, # Reznor: Defeated + 0x180E9, # Big Boo: Reappearing + 0x18233, # Big Boo: Hurt + 0x181DE, # Big Boo: Defeated + 0x1CEC1, # Wendy/Lemmy: Hitting a dummy + 0x1CECB, # Wendy/Lemmy: Hurt + 0x1CE33, # Wendy/Lemmy: Hurt (correct) + 0x1CE46, # Wendy/Lemmy: Hurt (incorrect) + 0x1CE24, # Wendy/Lemmy: Defeated + 0x1CE7E, # Wendy/Lemmy: Falling into lava + 0x0CF0A, # Ludwig: Jumping + 0x0D059, # Ludwig: Shooting a fireball + 0x10414, # Morton/Roy: Pillar drop + 0x0D299, # Morton/Roy: Ground smash + 0x0D3AB, # Morton/Roy/Ludwig: Hit by a fireball + 0x0D2FD, # Morton/Roy/Ludwig: Bouncing off + 0x0D31E, # Morton/Roy/Ludwig: Bouncing off (immune) + 0x0D334, # Morton/Roy/Ludwig: Bouncing off (immune, going up a wall) + 0x0CFD0, # Morton/Roy/Ludwig: Defeated + 0x0FCCE, # Iggy/Larry: Being hit + 0x0FD40, # Iggy/Larry: Being hit by a fireball + 0x0FB60, # Iggy/Larry: Falling in lava + 0x1A8B2, # Peach emerging from Clown Car + 0x1A8E3, # Peach throwing an item + 0x1B0B8, # Bumping into Clown Car + 0x1B129, # Bowser: Hurt + 0x1AB8C, # Bowser: Slamming the ground (third phase) + 0x1A5D0, # Bowser: Throwing a Mechakoopa + 0x1A603, # Bowser: Dropping a ball + 0x1A7F6, # Bowser: Spawning a flame + 0x1B1A3, # Bowser's ball slam #1 + 0x1B1B1, # Bowser's ball slam #2 + 0x1E016, # Bowser's arena lightning effect + 0x26CAA, # Map: Level tile reveal + 0x26763, # Map: Terrain reveal + 0x21170, # Map: Using a star + 0x2666F, # Map: Castle destruction + 0x272A4, # Map: Switch palace blocks spawning + 0x203CC, # Map: Earthquake + 0x27A78, # Map: Fish jumping + 0x27736, # Map: Valley of bowser thunder + 0x013C0, # Menu: Nintendo presents + 0x01AE3, # Menu: File menu option select + 0x01AF9, # Menu: File menu option change + 0x01BBB, # Menu: Saving game + 0x273FF, # Menu: Map misc menu appearing + 0x27567, # Menu: Something during the map + 0x1767A, # Cutscene: Castle door opening + 0x17683, # Cutscene: Castle door closing + 0x17765, # Cutscene: Ghost house door opening + 0x1776E, # Cutscene: Ghost house door closing + 0x04720, # Cutscene: Detonator fuse + 0x04732, # Cutscene: Bouncing off something + 0x0475F, # Cutscene: Tossing the castle + 0x04798, # Cutscene: Picking up the castle + 0x047AC, # Cutscene: Huff + 0x047D1, # Cutscene: Hitting a castle + 0x1C830, # Cutscene: Shooting a firework + 0x625AF, # Cutscene: Egg shattering + 0x64F2C, # Cutscene: Hitting a hill + 0x6512A, # Cutscene: Castle crashing + 0x65295, # Cutscene: Explosion + 0x652B2, # Cutscene: Castle sinking + 0x652BD, # Cutscene: Castle flying + 0x652D8, # Cutscene: Fake explosion + 0x653E7, # Cutscene: Castle being hit by a hammer + 0x657D8 # Cutscene: Castle being mopped away +] + +def generate_shuffled_sfx(rom, world: World): + # Adjust "hitting sprites in succession" codes + rom.write_bytes(0x0A60B, bytearray([0x22, 0x00, 0xFE, 0x0F, 0xEA, 0xEA])) # jsl $0FFE00 : nop #2 # Thrown sprites combo #1 + rom.write_bytes(0x0A659, bytearray([0x22, 0x47, 0xFE, 0x0F, 0xEA, 0xEA])) # jsl $0FFE47 : nop #2 # Thrown sprites combo #2 + rom.write_bytes(0x0A865, bytearray([0x22, 0x47, 0xFE, 0x0F, 0xEA, 0xEA])) # jsl $0FFE47 : nop #2 # Star combo + rom.write_bytes(0x0AB57, bytearray([0x22, 0x00, 0xFE, 0x0F, 0xEA, 0xEA])) # jsl $0FFE00 : nop #2 # Bouncing off enemies + rom.write_bytes(0x172C0, bytearray([0x22, 0x00, 0xFE, 0x0F, 0xEA, 0xEA])) # jsl $0FFE00 : nop #2 # Star combo (wigglers) + rom.write_bytes(0x1961D, bytearray([0x22, 0x00, 0xFE, 0x0F, 0xEA, 0xEA])) # jsl $0FFE00 : nop #2 # Star combo (rexes) + rom.write_bytes(0x19639, bytearray([0x22, 0x00, 0xFE, 0x0F, 0xEA, 0xEA])) # jsl $0FFE00 : nop #2 # Bouncing off rexes + + COMBO_SFX_ADDR = 0x7FE00 + rom.write_bytes(COMBO_SFX_ADDR + 0x0000, bytearray([0xC0, 0x01])) # COMBO_Y: CPY #$01 + rom.write_bytes(COMBO_SFX_ADDR + 0x0002, bytearray([0xD0, 0x06])) # BNE label_0FFE0A + rom.write_bytes(COMBO_SFX_ADDR + 0x0004, bytearray([0xA9, 0x13])) # LDA #$13 + rom.write_bytes(COMBO_SFX_ADDR + 0x0006, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0009, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x000A, bytearray([0xC0, 0x02])) # label_0FFE0A: CPY #$02 + rom.write_bytes(COMBO_SFX_ADDR + 0x000C, bytearray([0xD0, 0x06])) # BNE label_0FFE14 + rom.write_bytes(COMBO_SFX_ADDR + 0x000E, bytearray([0xA9, 0x14])) # LDA #$14 + rom.write_bytes(COMBO_SFX_ADDR + 0x0010, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0013, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0014, bytearray([0xC0, 0x03])) # label_0FFE14: CPY #$03 + rom.write_bytes(COMBO_SFX_ADDR + 0x0016, bytearray([0xD0, 0x06])) # BNE label_0FFE1E + rom.write_bytes(COMBO_SFX_ADDR + 0x0018, bytearray([0xA9, 0x15])) # LDA #$15 + rom.write_bytes(COMBO_SFX_ADDR + 0x001A, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x001D, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x001E, bytearray([0xC0, 0x04])) # label_0FFE1E: CPY #$04 + rom.write_bytes(COMBO_SFX_ADDR + 0x0020, bytearray([0xD0, 0x06])) # BNE label_0FFE28 + rom.write_bytes(COMBO_SFX_ADDR + 0x0022, bytearray([0xA9, 0x16])) # LDA #$16 + rom.write_bytes(COMBO_SFX_ADDR + 0x0024, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0027, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0028, bytearray([0xC0, 0x05])) # label_0FFE28: CPY #$05 + rom.write_bytes(COMBO_SFX_ADDR + 0x002A, bytearray([0xD0, 0x06])) # BNE label_0FFE32 + rom.write_bytes(COMBO_SFX_ADDR + 0x002C, bytearray([0xA9, 0x17])) # LDA #$17 + rom.write_bytes(COMBO_SFX_ADDR + 0x002E, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0031, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0032, bytearray([0xC0, 0x06])) # label_0FFE32: CPY #$06 + rom.write_bytes(COMBO_SFX_ADDR + 0x0034, bytearray([0xD0, 0x06])) # BNE label_0FFE3C + rom.write_bytes(COMBO_SFX_ADDR + 0x0036, bytearray([0xA9, 0x18])) # LDA #$18 + rom.write_bytes(COMBO_SFX_ADDR + 0x0038, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x003B, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x003C, bytearray([0xC0, 0x07])) # label_0FFE3C: CPY #$07 + rom.write_bytes(COMBO_SFX_ADDR + 0x003E, bytearray([0xD0, 0x06])) # BNE label_0FFE46 + rom.write_bytes(COMBO_SFX_ADDR + 0x0040, bytearray([0xA9, 0x19])) # LDA #$19 + rom.write_bytes(COMBO_SFX_ADDR + 0x0042, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0045, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0046, bytearray([0x6B])) # label_0FFE46: RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0047, bytearray([0xE0, 0x01])) # COMBO_X: CPX #$01 + rom.write_bytes(COMBO_SFX_ADDR + 0x0049, bytearray([0xD0, 0x06])) # BNE label_0FFE51 + rom.write_bytes(COMBO_SFX_ADDR + 0x004B, bytearray([0xA9, 0x13])) # LDA #$13 + rom.write_bytes(COMBO_SFX_ADDR + 0x004D, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0050, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0051, bytearray([0xE0, 0x02])) # label_0FFE51: CPX #$02 + rom.write_bytes(COMBO_SFX_ADDR + 0x0053, bytearray([0xD0, 0x06])) # BNE label_0FFE5B + rom.write_bytes(COMBO_SFX_ADDR + 0x0055, bytearray([0xA9, 0x14])) # LDA #$14 + rom.write_bytes(COMBO_SFX_ADDR + 0x0057, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x005A, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x005B, bytearray([0xE0, 0x03])) # label_0FFE5B: CPX #$03 + rom.write_bytes(COMBO_SFX_ADDR + 0x005D, bytearray([0xD0, 0x06])) # BNE label_0FFE65 + rom.write_bytes(COMBO_SFX_ADDR + 0x005F, bytearray([0xA9, 0x15])) # LDA #$15 + rom.write_bytes(COMBO_SFX_ADDR + 0x0061, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0064, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0065, bytearray([0xE0, 0x04])) # label_0FFE65: CPX #$04 + rom.write_bytes(COMBO_SFX_ADDR + 0x0067, bytearray([0xD0, 0x06])) # BNE label_0FFE6F + rom.write_bytes(COMBO_SFX_ADDR + 0x0069, bytearray([0xA9, 0x16])) # LDA #$16 + rom.write_bytes(COMBO_SFX_ADDR + 0x006B, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x006E, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x006F, bytearray([0xE0, 0x05])) # label_0FFE6F: CPX #$05 + rom.write_bytes(COMBO_SFX_ADDR + 0x0071, bytearray([0xD0, 0x06])) # BNE label_0FFE79 + rom.write_bytes(COMBO_SFX_ADDR + 0x0073, bytearray([0xA9, 0x17])) # LDA #$17 + rom.write_bytes(COMBO_SFX_ADDR + 0x0075, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0078, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0079, bytearray([0xE0, 0x06])) # label_0FFE79: CPX #$06 + rom.write_bytes(COMBO_SFX_ADDR + 0x007B, bytearray([0xD0, 0x06])) # BNE label_0FFE83 + rom.write_bytes(COMBO_SFX_ADDR + 0x007D, bytearray([0xA9, 0x18])) # LDA #$18 + rom.write_bytes(COMBO_SFX_ADDR + 0x007F, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x0082, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x0083, bytearray([0xE0, 0x07])) # label_0FFE83: CPX #$07 + rom.write_bytes(COMBO_SFX_ADDR + 0x0085, bytearray([0xD0, 0x06])) # BNE label_0FFE8D + rom.write_bytes(COMBO_SFX_ADDR + 0x0087, bytearray([0xA9, 0x19])) # LDA #$19 + rom.write_bytes(COMBO_SFX_ADDR + 0x0089, bytearray([0x8D, 0xF9, 0x1D])) # STA $1DF9 + rom.write_bytes(COMBO_SFX_ADDR + 0x008C, bytearray([0x6B])) # RTL + rom.write_bytes(COMBO_SFX_ADDR + 0x008D, bytearray([0x6B])) # label_0FFE8D: RTL + + # Adjust "Hit head on ceiling" code + rom.write_bytes(0x06D41 + 0x00, bytearray([0xA9, 0x01])) # lda #$01 + rom.write_bytes(0x06D41 + 0x02, bytearray([0x8D, 0xF9, 0x1D])) # sta $1DF9 + rom.write_bytes(0x06D41 + 0x05, bytearray([0xEA, 0xEA, 0xEA, 0xEA])) # nop #4 + + # Manually add "Map: Stepping onto a level tile" random SFX + selected_sfx = world.random.choice(valid_sfxs) + rom.write_byte(0x2169F + 0x01, selected_sfx[0]) + rom.write_byte(0x2169F + 0x04, selected_sfx[1] + 0xF9) + + # Disable panning on Bowser's flames + rom.write_bytes(0x1A83D, bytearray([0xEA, 0xEA, 0xEA])) # nop #3 + + # Randomize SFX calls + for address in game_sfx_calls: + # Get random SFX + if world.options.sfx_shuffle != "singularity": + selected_sfx = world.random.choice(valid_sfxs) + # Write randomized SFX num + rom.write_byte(address + 0x01, selected_sfx[0]) + # Write randomized SFX port + rom.write_byte(address + 0x03, selected_sfx[1] + 0xF9) + +def generate_shuffled_level_music(world: World): shuffled_level_music = level_music_value_data.copy() - if world.music_shuffle[player] == "consistent": - world.per_slot_randoms[player].shuffle(shuffled_level_music) - elif world.music_shuffle[player] == "singularity": - single_song = world.per_slot_randoms[player].choice(shuffled_level_music) + if world.options.music_shuffle == "consistent": + world.random.shuffle(shuffled_level_music) + elif world.options.music_shuffle == "singularity": + single_song = world.random.choice(shuffled_level_music) shuffled_level_music = [single_song for i in range(len(shuffled_level_music))] return shuffled_level_music -def generate_shuffled_ow_music(world, player): +def generate_shuffled_ow_music(world: World): shuffled_ow_music = ow_music_value_data.copy() - if world.music_shuffle[player] == "consistent" or world.music_shuffle[player] == "full": - world.per_slot_randoms[player].shuffle(shuffled_ow_music) - elif world.music_shuffle[player] == "singularity": - single_song = world.per_slot_randoms[player].choice(shuffled_ow_music) + if world.options.music_shuffle == "consistent" or world.options.music_shuffle == "full": + world.random.shuffle(shuffled_ow_music) + elif world.options.music_shuffle == "singularity": + single_song = world.random.choice(shuffled_ow_music) shuffled_ow_music = [single_song for i in range(len(shuffled_ow_music))] return shuffled_ow_music -def generate_shuffled_ow_palettes(rom, world, player): - if world.overworld_palette_shuffle[player]: - for address, valid_palettes in valid_ow_palettes.items(): - chosen_palette = world.per_slot_randoms[player].choice(valid_palettes) - rom.write_byte(address, chosen_palette) +def generate_shuffled_ow_palettes(rom, world: World): + if world.options.overworld_palette_shuffle != "on_legacy": + return -def generate_shuffled_header_data(rom, world, player): - if world.music_shuffle[player] != "full" and not world.foreground_palette_shuffle[player] and not world.background_palette_shuffle[player]: + for address, valid_palettes in valid_ow_palettes.items(): + chosen_palette = world.random.choice(valid_palettes) + rom.write_byte(address, chosen_palette) + +def generate_shuffled_header_data(rom, world: World): + if world.options.music_shuffle != "full" and world.options.level_palette_shuffle != "on_legacy": return for level_id in range(0, 0x200): @@ -194,24 +650,425 @@ def generate_shuffled_header_data(rom, world, player): tileset = level_header[4] & 0x0F - if world.music_shuffle[player] == "full": + if world.options.music_shuffle == "full": level_header[2] &= 0x8F - level_header[2] |= (world.per_slot_randoms[player].randint(0, 7) << 5) + level_header[2] |= (world.random.randint(0, 7) << 5) - if (world.foreground_palette_shuffle[player] and tileset in valid_foreground_palettes): - level_header[3] &= 0xF8 - level_header[3] |= world.per_slot_randoms[player].choice(valid_foreground_palettes[tileset]) + if world.options.level_palette_shuffle == "on_legacy": + if tileset in valid_foreground_palettes: + level_header[3] &= 0xF8 + level_header[3] |= world.random.choice(valid_foreground_palettes[tileset]) - if world.background_palette_shuffle[player]: layer2_ptr_list = list(rom.read_bytes(0x2E600 + level_id * 3, 3)) layer2_ptr = (layer2_ptr_list[2] << 16 | layer2_ptr_list[1] << 8 | layer2_ptr_list[0]) if layer2_ptr in valid_background_palettes: level_header[0] &= 0x1F - level_header[0] |= (world.per_slot_randoms[player].choice(valid_background_palettes[layer2_ptr]) << 5) + level_header[0] |= (world.random.choice(valid_background_palettes[layer2_ptr]) << 5) if layer2_ptr in valid_background_colors: level_header[1] &= 0x1F - level_header[1] |= (world.per_slot_randoms[player].choice(valid_background_colors[layer2_ptr]) << 5) + level_header[1] |= (world.random.choice(valid_background_colors[layer2_ptr]) << 5) rom.write_bytes(layer1_ptr, bytes(level_header)) + +def generate_curated_level_palette_data(rom, world: World): + PALETTE_LEVEL_CODE_ADDR = 0x88000 + PALETTE_INDEX_ADDR = 0x8F000 + PALETTE_LEVEL_TILESET_ADDR = 0x8F200 + PALETTE_LEVEL_PTR_ADDR = 0x92000 + PALETTE_LEVEL_DATA_ADDR = 0xA8000 + + addr = pc_to_snes(PALETTE_LEVEL_PTR_ADDR) + snes_level_palette_pointers_1 = bytearray([0xBF, (addr)&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF]) + snes_level_palette_pointers_2 = bytearray([0xBF, (addr+2)&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF]) + + # Enable curated palette loader + rom.write_bytes(0x02BED, bytearray([0x5C, 0x00, 0x80, 0x11])) # org $00ABED : jml custom_palettes + rom.write_bytes(0x02330, bytearray([0x5C, 0x02, 0x80, 0x11])) # org $00A318 : jml custom_palettes_original + rom.write_bytes(0x013D7, bytearray([0x20, 0x30, 0xA3])) # org $0093D7 : jmp $A330 + rom.write_bytes(0x014DA, bytearray([0x20, 0x30, 0xA3])) # org $0094DA : jmp $A330 + rom.write_bytes(0x015EC, bytearray([0x20, 0x30, 0xA3])) # org $0095EC : jmp $A330 + rom.write_bytes(0x0165B, bytearray([0x20, 0x30, 0xA3])) # org $00965B : jmp $A330 + rom.write_bytes(0x02DD9, bytearray([0x20, 0x30, 0xA3])) # org $00ADD9 : jmp $A330 + rom.write_bytes(0x02E1F, bytearray([0x20, 0x30, 0xA3])) # org $00AE1F : jmp $A330 + + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0000, bytearray([0x80, 0x09])) # bra custom_palettes + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0002, bytearray([0xC2, 0x30])) # .original rep #$30 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0004, bytearray([0xA9, 0xDD, 0x7F])) # lda #$7FDD + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0007, bytearray([0x5C, 0xF2, 0xAB, 0x00])) # jml $00ABF2 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x000B, bytearray([0xC2, 0x30])) # custom_palettes: rep #$30 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x000D, bytearray([0xA9, 0x70, 0xB1])) # lda #$B170 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0010, bytearray([0x85, 0x0A])) # sta !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0012, bytearray([0x64, 0x0C])) # stz !_ptr+$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0014, bytearray([0xA9, 0x10, 0x00])) # lda.w #$0010 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0017, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0019, bytearray([0xA9, 0x07, 0x00])) # lda #$0007 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x001C, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x001E, bytearray([0xA9, 0x01, 0x00])) # lda #$0001 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0021, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0023, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0026, bytearray([0xAE, 0x0B, 0x01])) # .get_index ldx $010B + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0029, bytearray([0xBF, 0x00, 0xF2, 0x11])) # lda.l level_tilesets,x + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x002D, bytearray([0x29, 0xFF, 0x00])) # and #$00FF + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0030, bytearray([0xEB])) # xba + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0031, bytearray([0x85, 0x00])) # sta !_tileset + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0033, bytearray([0xBF, 0x00, 0xF0, 0x11])) # lda.l level_index,x + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0037, bytearray([0x29, 0xFF, 0x00])) # and #$00FF + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x003A, bytearray([0x05, 0x00])) # ora !_tileset + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x003C, bytearray([0x85, 0x0A])) # sta !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x003E, bytearray([0x0A])) # asl + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x003F, bytearray([0x18])) # clc + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0040, bytearray([0x65, 0x0A])) # adc !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0042, bytearray([0x85, 0x0E])) # sta !_num + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0044, bytearray([0xAA])) # tax + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0045, snes_level_palette_pointers_1) # .back_color lda.l palette_pointers,x + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0049, bytearray([0x85, 0x0A])) # sta !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x004B, snes_level_palette_pointers_2) # lda.l palette_pointers+$02,x + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x004F, bytearray([0x85, 0x0C])) # sta !_ptr+$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0051, bytearray([0xA7, 0x0A])) # lda [!_ptr] + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0053, bytearray([0x8D, 0x01, 0x07])) # sta $0701 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0056, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0058, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x005A, bytearray([0xA9, 0x02, 0x00])) # .background lda.w #$0001*$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x005D, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x005F, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0062, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0064, bytearray([0xA9, 0x01, 0x00])) # lda #$0001 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0067, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0069, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x006C, bytearray([0xA9, 0x42, 0x00])) # .foreground lda.w #$0021*$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x006F, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0071, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0074, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0076, bytearray([0xA9, 0x01, 0x00])) # lda #$0001 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0079, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x007B, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x007E, bytearray([0xA9, 0x52, 0x00])) # .berries lda.w #$0029*$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0081, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0083, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0086, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0088, bytearray([0xA9, 0x02, 0x00])) # lda #$0002 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x008B, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x008D, bytearray([0xA5, 0x0A])) # lda !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x008F, bytearray([0x48])) # pha + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0090, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0093, bytearray([0x68])) # pla + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0094, bytearray([0x85, 0x0A])) # sta !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0096, bytearray([0xA9, 0x32, 0x01])) # lda.w #$0099*$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0099, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x009B, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x009E, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00A0, bytearray([0xA9, 0x02, 0x00])) # lda #$0002 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00A3, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00A5, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00A8, bytearray([0xA9, 0x82, 0x00])) # .global lda.w #$0041*$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00AB, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00AD, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00B0, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00B2, bytearray([0xA9, 0x0B, 0x00])) # lda #$000B + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00B5, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00B7, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00BA, bytearray([0xA5, 0x00])) # .sprite_specific lda !_tileset + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00BC, bytearray([0xC9, 0x00, 0x05])) # cmp #$0500 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00BF, bytearray([0xD0, 0x1D])) # bne .end + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00C1, bytearray([0xAD, 0x2E, 0x19])) # lda $192E + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00C4, bytearray([0x29, 0x0F, 0x00])) # and #$000F + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00C7, bytearray([0xC9, 0x02, 0x00])) # cmp #$0002 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00CA, bytearray([0xD0, 0x12])) # bne .end + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00CC, bytearray([0xA9, 0xC2, 0x01])) # lda.w #$00E1*$02 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00CF, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00D1, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00D4, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00D6, bytearray([0xA9, 0x01, 0x00])) # lda #$0001 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00D9, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00DB, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00DE, bytearray([0xE2, 0x30])) # .end sep #$30 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00E0, bytearray([0x5C, 0xEC, 0xAC, 0x00])) # jml $00ACEC + + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00E4, bytearray([0xA6, 0x04])) # load_colors: ldx !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00E6, bytearray([0xA4, 0x06])) # ldy !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00E8, bytearray([0xA7, 0x0A])) # .x_loop lda [!_ptr] + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00EA, bytearray([0x9D, 0x03, 0x07])) # sta $0703,x + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00ED, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00EF, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F1, bytearray([0xE8])) # inx + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F2, bytearray([0xE8])) # inx + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F3, bytearray([0x88])) # dey + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F4, bytearray([0x10, 0xF2])) # bpl .x_loop + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F6, bytearray([0xA5, 0x04])) # lda !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F8, bytearray([0x18])) # clc + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F9, bytearray([0x69, 0x20, 0x00])) # adc #$0020 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00FC, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00FE, bytearray([0xC6, 0x08])) # dec !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0100, bytearray([0x10, 0xE2])) # bpl load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0102, bytearray([0x60])) # rts + + # Load palette paths + data = pkgutil.get_data(__name__, f"data/palettes/level/palettes.json").decode("utf-8") + tilesets = json.loads(data) + + # Writes the level tileset index to ROM + rom.write_bytes(PALETTE_LEVEL_TILESET_ADDR, bytearray(level_palette_index)) + + # Builds the table in ROM that holds the palette index for each level, including sublevels + for level_id in range(0x200): + tileset_num = level_palette_index[level_id] + if tileset_num != 0xFF: + tileset = tileset_names[tileset_num] + else: + tileset = tileset_names[0x19] + palette = world.random.randint(0, len(tilesets[tileset])-1) + rom.write_bytes(PALETTE_INDEX_ADDR + level_id, bytearray([palette])) + + # Writes the actual level palette data and pointer to said data to the ROM + pal_offset = 0x0000 + tileset_num = 0 + bank_palette_count = 0 + for tileset in tilesets.keys(): + for palette in range(len(tilesets[tileset])): + # Handle bank crossing + if bank_palette_count == 110: + pal_offset = (pal_offset & 0xF8000) + 0x8000 + bank_palette_count = 0 + # Write pointer + data_ptr = pc_to_snes(PALETTE_LEVEL_DATA_ADDR + pal_offset) + rom.write_bytes(PALETTE_LEVEL_PTR_ADDR + ((tileset_num*3)<<8) + (palette*3), bytearray([data_ptr & 0xFF, (data_ptr>>8)&0xFF, (data_ptr>>16)&0xFF])) + # Write data + rom.write_bytes(PALETTE_LEVEL_DATA_ADDR + pal_offset, read_palette_file(tileset, tilesets[tileset][palette], "level")) + pal_offset += 0x128 + bank_palette_count += 1 + tileset_num += 1 + + # Fix eaten berry tiles + EATEN_BERRY_ADDR = 0x68248 + rom.write_byte(EATEN_BERRY_ADDR + 0x01, 0x04) + rom.write_byte(EATEN_BERRY_ADDR + 0x03, 0x04) + rom.write_byte(EATEN_BERRY_ADDR + 0x05, 0x04) + rom.write_byte(EATEN_BERRY_ADDR + 0x07, 0x04) + + # Fix title screen changing background colors + rom.write_bytes(0x1D30, bytearray([0xEA, 0xEA, 0xEA])) + + # Skips level intros automatically + rom.write_byte(0x4896, 0x80) + +def generate_curated_map_palette_data(rom, world: World): + PALETTE_MAP_CODE_ADDR = 0x88200 + PALETTE_UPLOADER_EDIT = 0x88400 + PALETTE_MAP_INDEX_ADDR = 0x8F400 + PALETTE_MAP_PTR_ADDR = 0x90000 + PALETTE_MAP_DATA_ADDR = 0x98000 + + addr = pc_to_snes(PALETTE_MAP_PTR_ADDR) + snes_map_palette_pointers_1 = bytearray([0xBF, (addr)&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF]) + snes_map_palette_pointers_2 = bytearray([0xBF, (addr+2)&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF]) + + rom.write_bytes(0x02D25, bytearray([0x5C, 0x09, 0x82, 0x11])) # org $00AD25 : jml map_palettes + + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0000, bytearray([0xC2, 0x30])) # map_og_palettes: rep #$30 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0002, bytearray([0xA0, 0xD8, 0xB3])) # ldy #$B3D8 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0005, bytearray([0x5C, 0x2A, 0xAD, 0x00])) # jml $00AD2A + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0009, bytearray([0xC2, 0x30])) # map_palettes: rep #$30 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x000B, bytearray([0xAD, 0x31, 0x19])) # .prepare_index lda $1931 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x000E, bytearray([0x29, 0x0F, 0x00])) # and #$000F + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0011, bytearray([0x3A])) # dec + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0012, bytearray([0xAA])) # tax + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0013, bytearray([0xEB])) # xba + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0014, bytearray([0x85, 0x0E])) # sta !_num + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0016, bytearray([0xBF, 0x00, 0xF4, 0x11])) # lda.l map_index,x + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x001A, bytearray([0x29, 0xFF, 0x00])) # and #$00FF + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x001D, bytearray([0x05, 0x0E])) # ora !_num + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x001F, bytearray([0x85, 0x0A])) # sta !_ptr + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0021, bytearray([0x0A])) # asl + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0022, bytearray([0x18])) # clc + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0023, bytearray([0x65, 0x0A])) # adc !_ptr + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0025, bytearray([0xAA])) # tax + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0026, snes_map_palette_pointers_1) # lda.l map_palette_pointers,x + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x002A, bytearray([0x85, 0x0A])) # sta !_ptr + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x002C, snes_map_palette_pointers_2) # lda.l map_palette_pointers+$02,x + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0030, bytearray([0x85, 0x0C])) # sta !_ptr+$02 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0032, bytearray([0xA7, 0x0A])) # .load_back_color lda [!_ptr] + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0034, bytearray([0x8D, 0x01, 0x07])) # sta $0701 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0037, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0039, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x003B, bytearray([0xA9, 0x82, 0x00])) # .load_layer_2 lda.w #$0041*$02 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x003E, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0040, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0043, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0045, bytearray([0xA9, 0x03, 0x00])) # lda #$0003 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0048, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x004A, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x004D, bytearray([0xA9, 0x52, 0x00])) # .load_layer_1 lda.w #$0029*$02 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0050, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0052, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0055, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0057, bytearray([0xA9, 0x05, 0x00])) # lda #$0005 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x005A, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x005C, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x005F, bytearray([0xA9, 0x10, 0x00])) # .load_layer_3 lda.w #$0008*$02 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0062, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0064, bytearray([0xA9, 0x07, 0x00])) # lda #$0007 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0067, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0069, bytearray([0xA9, 0x01, 0x00])) # lda #$0001 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x006C, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x006E, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0071, bytearray([0xA9, 0x02, 0x01])) # .load_sprites lda.w #$0081*$02 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0074, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0076, bytearray([0xA9, 0x06, 0x00])) # lda #$0006 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0079, bytearray([0x85, 0x06])) # sta !_x_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x007B, bytearray([0xA9, 0x07, 0x00])) # lda #$0007 + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x007E, bytearray([0x85, 0x08])) # sta !_y_span + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0080, bytearray([0x20, 0xE4, 0x80])) # jsr load_colors + rom.write_bytes(PALETTE_MAP_CODE_ADDR + 0x0083, bytearray([0x5C, 0xA3, 0xAD, 0x00])) # .return jml $00ADA3 + + rom.write_bytes(0x2488, bytearray([0x5C, 0x00, 0x84, 0x11])) # org $00A488 : jml palette_upload + + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0000, bytearray([0xAD, 0x00, 0x01])) # palette_upload: lda $0100 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0003, bytearray([0xC9, 0x0E])) # cmp #$0E + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0005, bytearray([0xF0, 0x0A])) # beq .map + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0007, bytearray([0xAC, 0x80, 0x06])) # .regular ldy $0680 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x000A, bytearray([0xBE, 0x81, 0xA4])) # ldx.w $A47F+2,y + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x000D, bytearray([0x5C, 0x8E, 0xA4, 0x00])) # jml $00A48E + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0011, bytearray([0xAD, 0xD9, 0x13])) # .map lda $13D9 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0014, bytearray([0xC9, 0x0A])) # cmp #$0A + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0016, bytearray([0xD0, 0xEF])) # bne .regular + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0018, bytearray([0xAD, 0xE8, 0x1D])) # lda $1DE8 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x001B, bytearray([0xC9, 0x06])) # cmp #$06 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x001D, bytearray([0xD0, 0xE8])) # bne .regular + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x001F, bytearray([0x9C, 0x03, 0x07])) # stz $0703 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0022, bytearray([0x9C, 0x04, 0x07])) # stz $0704 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0025, bytearray([0x9C, 0x21, 0x21])) # stz $2121 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0028, bytearray([0xA2, 0x06])) # ldx #$06 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x002A, bytearray([0xBD, 0x49, 0x92])) # .loop lda.w $9249,x + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x002D, bytearray([0x9D, 0x20, 0x43])) # sta $4320,x + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0030, bytearray([0xCA])) # dex + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0031, bytearray([0x10, 0xF7])) # bpl .loop + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0033, bytearray([0xA9, 0x04])) # lda #$04 + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0035, bytearray([0x8D, 0x0B, 0x42])) # sta $420B + rom.write_bytes(PALETTE_UPLOADER_EDIT + 0x0038, bytearray([0x5C, 0xCF, 0xA4, 0x00])) # jml $00A4CF + + # Insert this piece of ASM again in case levels are disabled + PALETTE_LEVEL_CODE_ADDR = 0x88000 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00E4, bytearray([0xA6, 0x04])) # load_colors: ldx !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00E6, bytearray([0xA4, 0x06])) # ldy !_x_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00E8, bytearray([0xA7, 0x0A])) # .x_loop lda [!_ptr] + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00EA, bytearray([0x9D, 0x03, 0x07])) # sta $0703,x + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00ED, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00EF, bytearray([0xE6, 0x0A])) # inc !_ptr + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F1, bytearray([0xE8])) # inx + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F2, bytearray([0xE8])) # inx + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F3, bytearray([0x88])) # dey + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F4, bytearray([0x10, 0xF2])) # bpl .x_loop + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F6, bytearray([0xA5, 0x04])) # lda !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F8, bytearray([0x18])) # clc + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00F9, bytearray([0x69, 0x20, 0x00])) # adc #$0020 + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00FC, bytearray([0x85, 0x04])) # sta !_index + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x00FE, bytearray([0xC6, 0x08])) # dec !_y_span + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0100, bytearray([0x10, 0xE2])) # bpl load_colors + rom.write_bytes(PALETTE_LEVEL_CODE_ADDR + 0x0102, bytearray([0x60])) # rts + + # Load palette paths + data = pkgutil.get_data(__name__, f"data/palettes/map/palettes.json").decode("utf-8") + maps = json.loads(data) + + for map_id in range(0x07): + current_map_name = map_names[map_id] + palette = world.random.randint(0, len(maps[current_map_name])-1) + rom.write_bytes(PALETTE_MAP_INDEX_ADDR + map_id, bytearray([palette])) + + # Writes the actual map palette data and pointer to said data to the ROM + pal_offset = 0x0000 + map_num = 0 + bank_palette_count = 0 + for current_map in maps.keys(): + for palette in range(len(maps[current_map])): + # Handle bank crossing + if bank_palette_count == 113: + pal_offset = (pal_offset & 0xF8000) + 0x8000 + bank_palette_count = 0 + # Write pointer + data_ptr = pc_to_snes(PALETTE_MAP_DATA_ADDR + pal_offset) + rom.write_bytes(PALETTE_MAP_PTR_ADDR + ((map_num*3)<<8) + (palette*3), bytearray([data_ptr & 0xFF, (data_ptr>>8)&0xFF, (data_ptr>>16)&0xFF])) + # Write data + rom.write_bytes(PALETTE_MAP_DATA_ADDR + pal_offset, read_palette_file(current_map, maps[current_map][palette], "map")) + # Update map mario palette + chosen_palette = world.options.mario_palette.value + rom.write_bytes(PALETTE_MAP_DATA_ADDR + pal_offset + 206, bytes(ow_mario_palettes[chosen_palette])) + pal_offset += 0x11C + bank_palette_count += 1 + map_num += 1 + + +def pc_to_snes(address): + return ((address << 1) & 0x7F0000) | (address & 0x7FFF) | 0x8000 + +def read_palette_file(tileset, filename, type_): + palette_file = pkgutil.get_data(__name__, f"data/palettes/{type_}/{tileset}/{filename}") + colors = bytearray([]) + + # Copy back colors + colors += bytearray([palette_file[0x200], palette_file[0x201]]) + + if type_ == "level": + # Copy background colors + colors += bytearray([palette_file[(0x01*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x11*2)+(i)] for i in range(14)]) + + # Copy foreground colors + colors += bytearray([palette_file[(0x21*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x31*2)+(i)] for i in range(14)]) + + # Copy berry colors + colors += bytearray([palette_file[(0x29*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x39*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x49*2)+(i)] for i in range(14)]) + + # Copy global colors + colors += bytearray([palette_file[(0x41*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x51*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x61*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x71*2)+(i)] for i in range(14)]) + + # Copy sprite colors + colors += bytearray([palette_file[(0x81*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x91*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xA1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xB1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xC1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xD1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xE1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xF1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xE9*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xF9*2)+(i)] for i in range(14)]) + + elif type_ == "map": + # Copy layer 2 colors + colors += bytearray([palette_file[(0x41*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x51*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x61*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x71*2)+(i)] for i in range(14)]) + + # Copy layer 1 colors + colors += bytearray([palette_file[(0x29*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x39*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x49*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x59*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x69*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x79*2)+(i)] for i in range(14)]) + + # Copy layer 3 colors + colors += bytearray([palette_file[(0x08*2)+(i)] for i in range(16)]) + colors += bytearray([palette_file[(0x18*2)+(i)] for i in range(16)]) + + # Copy sprite colors + colors += bytearray([palette_file[(0x81*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0x91*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xA1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xB1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xC1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xD1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xE1*2)+(i)] for i in range(14)]) + colors += bytearray([palette_file[(0xF1*2)+(i)] for i in range(14)]) + + return colors diff --git a/worlds/smw/Client.py b/worlds/smw/Client.py index 50899abe37..eb9b4ec3d3 100644 --- a/worlds/smw/Client.py +++ b/worlds/smw/Client.py @@ -1,5 +1,4 @@ import logging -import asyncio import time from NetUtils import ClientStatus, color @@ -17,11 +16,19 @@ SRAM_START = 0xE00000 SMW_ROMHASH_START = 0x7FC0 ROMHASH_SIZE = 0x15 -SMW_PROGRESS_DATA = WRAM_START + 0x1F02 -SMW_DRAGON_COINS_DATA = WRAM_START + 0x1F2F -SMW_PATH_DATA = WRAM_START + 0x1EA2 -SMW_EVENT_ROM_DATA = ROM_START + 0x2D608 -SMW_ACTIVE_LEVEL_DATA = ROM_START + 0x37F70 +SMW_PROGRESS_DATA = WRAM_START + 0x1F02 +SMW_DRAGON_COINS_DATA = WRAM_START + 0x1F2F +SMW_PATH_DATA = WRAM_START + 0x1EA2 +SMW_EVENT_ROM_DATA = ROM_START + 0x2D608 +SMW_ACTIVE_LEVEL_DATA = ROM_START + 0x37F70 +SMW_MOON_DATA = WRAM_START + 0x1FEE +SMW_HIDDEN_1UP_DATA = WRAM_START + 0x1F3C +SMW_BONUS_BLOCK_DATA = WRAM_START + 0x1A000 +SMW_BLOCKSANITY_DATA = WRAM_START + 0x1A400 +SMW_BLOCKSANITY_FLAGS = WRAM_START + 0x1A010 +SMW_LEVEL_CLEAR_FLAGS = WRAM_START + 0x1A200 +SMW_SPECIAL_WORLD_CLEAR = WRAM_START + 0x1F1E + SMW_GOAL_DATA = ROM_START + 0x01BFA0 SMW_REQUIRED_BOSSES_DATA = ROM_START + 0x01BFA1 @@ -31,22 +38,32 @@ SMW_RECEIVE_MSG_DATA = ROM_START + 0x01BFA4 SMW_DEATH_LINK_ACTIVE_ADDR = ROM_START + 0x01BFA5 SMW_DRAGON_COINS_ACTIVE_ADDR = ROM_START + 0x01BFA6 SMW_SWAMP_DONUT_GH_ADDR = ROM_START + 0x01BFA7 +SMW_MOON_ACTIVE_ADDR = ROM_START + 0x01BFA8 +SMW_HIDDEN_1UP_ACTIVE_ADDR = ROM_START + 0x01BFA9 +SMW_BONUS_BLOCK_ACTIVE_ADDR = ROM_START + 0x01BFAA +SMW_BLOCKSANITY_ACTIVE_ADDR = ROM_START + 0x01BFAB -SMW_GAME_STATE_ADDR = WRAM_START + 0x100 -SMW_MARIO_STATE_ADDR = WRAM_START + 0x71 -SMW_BOSS_STATE_ADDR = WRAM_START + 0xD9B -SMW_ACTIVE_BOSS_ADDR = WRAM_START + 0x13FC -SMW_CURRENT_LEVEL_ADDR = WRAM_START + 0x13BF -SMW_MESSAGE_BOX_ADDR = WRAM_START + 0x1426 -SMW_BONUS_STAR_ADDR = WRAM_START + 0xF48 -SMW_EGG_COUNT_ADDR = WRAM_START + 0x1F24 -SMW_BOSS_COUNT_ADDR = WRAM_START + 0x1F26 -SMW_NUM_EVENTS_ADDR = WRAM_START + 0x1F2E -SMW_SFX_ADDR = WRAM_START + 0x1DFC -SMW_PAUSE_ADDR = WRAM_START + 0x13D4 -SMW_MESSAGE_QUEUE_ADDR = WRAM_START + 0xC391 -SMW_RECV_PROGRESS_ADDR = WRAM_START + 0x1F2B +SMW_GAME_STATE_ADDR = WRAM_START + 0x100 +SMW_MARIO_STATE_ADDR = WRAM_START + 0x71 +SMW_BOSS_STATE_ADDR = WRAM_START + 0xD9B +SMW_ACTIVE_BOSS_ADDR = WRAM_START + 0x13FC +SMW_CURRENT_LEVEL_ADDR = WRAM_START + 0x13BF +SMW_CURRENT_SUBLEVEL_ADDR = WRAM_START + 0x10B +SMW_MESSAGE_BOX_ADDR = WRAM_START + 0x1426 +SMW_BONUS_STAR_ADDR = WRAM_START + 0xF48 +SMW_EGG_COUNT_ADDR = WRAM_START + 0x1F24 +SMW_BOSS_COUNT_ADDR = WRAM_START + 0x1F26 +SMW_NUM_EVENTS_ADDR = WRAM_START + 0x1F2E +SMW_SFX_ADDR = WRAM_START + 0x1DFC +SMW_PAUSE_ADDR = WRAM_START + 0x13D4 +SMW_MESSAGE_QUEUE_ADDR = WRAM_START + 0xC391 +SMW_ACTIVE_THWIMP_ADDR = WRAM_START + 0x0F3C +SMW_GOAL_ITEM_COUNT = WRAM_START + 0x1A01E + +SMW_RECV_PROGRESS_ADDR = WRAM_START + 0x01F2B + +SMW_BLOCKSANITY_BLOCK_COUNT = 582 SMW_GOAL_LEVELS = [0x28, 0x31, 0x32] SMW_INVALID_MARIO_STATES = [0x05, 0x06, 0x0A, 0x0C, 0x0D] @@ -115,6 +132,9 @@ class SMWSNIClient(SNIClient): if death_link: await ctx.update_death_link(bool(death_link[0] & 0b1)) + if ctx.rom != rom_name: + ctx.current_sublevel_value = 0 + ctx.rom = rom_name return True @@ -176,6 +196,11 @@ class SMWSNIClient(SNIClient): self.trap_queue.append((trap_item, trap_msg)) + def should_show_message(self, ctx, next_item): + return ctx.receive_option == 1 or \ + (ctx.receive_option == 2 and ((next_item.flags & 1) != 0)) or \ + (ctx.receive_option == 3 and ((next_item.flags & 1) != 0 and next_item.item != 0xBC0002)) + async def handle_trap_queue(self, ctx): from SNIClient import snes_buffered_write, snes_flush_writes, snes_read @@ -217,6 +242,13 @@ class SMWSNIClient(SNIClient): self.add_trap_to_queue(next_trap, message) return else: + if next_trap.item == 0xBC001D: + # Special case thwimp trap + # Do not fire if the previous thwimp hasn't reached the player's Y pos + active_thwimp = await snes_read(ctx, SMW_ACTIVE_THWIMP_ADDR, 0x1) + if active_thwimp[0] != 0xFF: + self.add_trap_to_queue(next_trap, message) + return verify_game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1) if verify_game_state[0] == 0x14 and len(trap_rom_data[next_trap.item]) > 2: snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([trap_rom_data[next_trap.item][2]])) @@ -236,13 +268,14 @@ class SMWSNIClient(SNIClient): if active_boss[0] != 0x00: return - if ctx.receive_option == 1 or (ctx.receive_option == 2 and ((next_trap.flags & 1) != 0)): + if self.should_show_message(ctx, next_trap): self.add_message_to_queue(message) async def game_watcher(self, ctx): from SNIClient import snes_buffered_write, snes_flush_writes, snes_read - + + boss_state = await snes_read(ctx, SMW_BOSS_STATE_ADDR, 0x1) game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1) mario_state = await snes_read(ctx, SMW_MARIO_STATE_ADDR, 0x1) if game_state is None: @@ -259,6 +292,7 @@ class SMWSNIClient(SNIClient): elif game_state[0] < 0x0B: # We haven't loaded a save file ctx.message_queue = [] + ctx.current_sublevel_value = 0 return elif mario_state[0] in SMW_INVALID_MARIO_STATES: # Mario can't come to the phone right now @@ -304,8 +338,18 @@ class SMWSNIClient(SNIClient): progress_data = bytearray(await snes_read(ctx, SMW_PROGRESS_DATA, 0x0F)) dragon_coins_data = bytearray(await snes_read(ctx, SMW_DRAGON_COINS_DATA, 0x0C)) dragon_coins_active = await snes_read(ctx, SMW_DRAGON_COINS_ACTIVE_ADDR, 0x1) - from worlds.smw.Rom import item_rom_data, ability_rom_data, trap_rom_data - from worlds.smw.Levels import location_id_to_level_id, level_info_dict + moon_data = bytearray(await snes_read(ctx, SMW_MOON_DATA, 0x0C)) + moon_active = await snes_read(ctx, SMW_MOON_ACTIVE_ADDR, 0x1) + hidden_1up_data = bytearray(await snes_read(ctx, SMW_HIDDEN_1UP_DATA, 0x0C)) + hidden_1up_active = await snes_read(ctx, SMW_HIDDEN_1UP_ACTIVE_ADDR, 0x1) + bonus_block_data = bytearray(await snes_read(ctx, SMW_BONUS_BLOCK_DATA, 0x0C)) + bonus_block_active = await snes_read(ctx, SMW_BONUS_BLOCK_ACTIVE_ADDR, 0x1) + blocksanity_data = bytearray(await snes_read(ctx, SMW_BLOCKSANITY_DATA, SMW_BLOCKSANITY_BLOCK_COUNT)) + blocksanity_flags = bytearray(await snes_read(ctx, SMW_BLOCKSANITY_FLAGS, 0xC)) + blocksanity_active = await snes_read(ctx, SMW_BLOCKSANITY_ACTIVE_ADDR, 0x1) + level_clear_flags = bytearray(await snes_read(ctx, SMW_LEVEL_CLEAR_FLAGS, 0x60)) + from worlds.smw.Rom import item_rom_data, ability_rom_data, trap_rom_data, icon_rom_data + from worlds.smw.Levels import location_id_to_level_id, level_info_dict, level_blocks_data from worlds import AutoWorldRegister for loc_name, level_data in location_id_to_level_id.items(): loc_id = AutoWorldRegister.world_types[ctx.game].location_name_to_id[loc_name] @@ -327,6 +371,54 @@ class SMWSNIClient(SNIClient): if bit_set: new_checks.append(loc_id) + elif level_data[1] == 3: + # Moon Check + if not moon_active or moon_active[0] == 0: + continue + + progress_byte = (level_data[0] // 8) + progress_bit = 7 - (level_data[0] % 8) + + data = moon_data[progress_byte] + masked_data = data & (1 << progress_bit) + bit_set = (masked_data != 0) + + if bit_set: + new_checks.append(loc_id) + elif level_data[1] == 4: + # Hidden 1-Up Check + if not hidden_1up_active or hidden_1up_active[0] == 0: + continue + + progress_byte = (level_data[0] // 8) + progress_bit = 7 - (level_data[0] % 8) + + data = hidden_1up_data[progress_byte] + masked_data = data & (1 << progress_bit) + bit_set = (masked_data != 0) + + if bit_set: + new_checks.append(loc_id) + elif level_data[1] == 5: + # Bonus Block Check + if not bonus_block_active or bonus_block_active[0] == 0: + continue + + progress_byte = (level_data[0] // 8) + progress_bit = 7 - (level_data[0] % 8) + + data = bonus_block_data[progress_byte] + masked_data = data & (1 << progress_bit) + bit_set = (masked_data != 0) + + if bit_set: + new_checks.append(loc_id) + elif level_data[1] >= 100: + if not blocksanity_active or blocksanity_active[0] == 0: + continue + block_index = level_data[1] - 100 + if blocksanity_data[block_index] != 0: + new_checks.append(loc_id) else: event_id_value = event_id + level_data[1] @@ -360,12 +452,48 @@ class SMWSNIClient(SNIClient): f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})') await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) + # Send Current Room for Tracker + current_sublevel_data = await snes_read(ctx, SMW_CURRENT_SUBLEVEL_ADDR, 2) + current_sublevel_value = current_sublevel_data[0] + (current_sublevel_data[1] << 8) + + if game_state[0] != 0x14: + current_sublevel_value = 0 + + if ctx.current_sublevel_value != current_sublevel_value: + ctx.current_sublevel_value = current_sublevel_value + + # Send level id data to tracker + await ctx.send_msgs( + [ + { + "cmd": "Set", + "key": f"smw_curlevelid_{ctx.team}_{ctx.slot}", + "default": 0, + "want_reply": False, + "operations": [ + { + "operation": "replace", + "value": ctx.current_sublevel_value, + } + ], + } + ] + ) + if game_state[0] != 0x14: # Don't receive items or collect locations outside of in-level mode + ctx.current_sublevel_value = 0 + return + + if boss_state[0] in SMW_BOSS_STATES: + # Don't receive items or collect locations inside boss battles return - recv_count = await snes_read(ctx, SMW_RECV_PROGRESS_ADDR, 1) - recv_index = recv_count[0] + recv_count = await snes_read(ctx, SMW_RECV_PROGRESS_ADDR, 2) + if recv_count is None: + # Add a small failsafe in case we get a None. Other SNI games do this... + return + recv_index = recv_count[0] | (recv_count[1] << 8) if recv_index < len(ctx.items_received): item = ctx.items_received[recv_index] @@ -375,7 +503,7 @@ class SMWSNIClient(SNIClient): color(ctx.player_names[item.player], 'yellow'), ctx.location_names[item.location], recv_index, len(ctx.items_received))) - if ctx.receive_option == 1 or (ctx.receive_option == 2 and ((item.flags & 1) != 0)): + if self.should_show_message(ctx, item): if item.item != 0xBC0012 and item.item not in trap_rom_data: # Don't send messages for Boss Tokens item_name = ctx.item_names[item.item] @@ -384,7 +512,7 @@ class SMWSNIClient(SNIClient): receive_message = generate_received_text(item_name, player_name) self.add_message_to_queue(receive_message) - snes_buffered_write(ctx, SMW_RECV_PROGRESS_ADDR, bytes([recv_index])) + snes_buffered_write(ctx, SMW_RECV_PROGRESS_ADDR, bytes([recv_index&0xFF, (recv_index>>8)&0xFF])) if item.item in trap_rom_data: item_name = ctx.item_names[item.item] player_name = ctx.player_names[item.player] @@ -405,6 +533,15 @@ class SMWSNIClient(SNIClient): snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([item_rom_data[item.item][2]])) snes_buffered_write(ctx, WRAM_START + item_rom_data[item.item][0], bytes([new_item_count])) + elif item.item in icon_rom_data: + queue_addr = await snes_read(ctx, WRAM_START + icon_rom_data[item.item][0], 2) + queue_addr = queue_addr[0] + (queue_addr[1] << 8) + queue_addr += 1 + snes_buffered_write(ctx, WRAM_START + icon_rom_data[item.item][0], bytes([queue_addr&0xFF, (queue_addr>>8)&0xFF])) + if (goal[0] == 0 and item.item == 0xBC0012) or (goal[0] == 1 and item.item == 0xBC0002): + goal_item_count = await snes_read(ctx, SMW_GOAL_ITEM_COUNT, 1) + snes_buffered_write(ctx, SMW_GOAL_ITEM_COUNT, bytes([goal_item_count[0] + 1])) + elif item.item in ability_rom_data: # Handle Upgrades for rom_data in ability_rom_data[item.item]: @@ -449,6 +586,12 @@ class SMWSNIClient(SNIClient): path_data = bytearray(await snes_read(ctx, SMW_PATH_DATA, 0x60)) donut_gh_swapped = await snes_read(ctx, SMW_SWAMP_DONUT_GH_ADDR, 0x1) new_dragon_coin = False + new_moon = False + new_hidden_1up = False + new_bonus_block = False + new_blocksanity = False + new_blocksanity_flags = False + for loc_id in ctx.checked_locations: if loc_id not in ctx.locations_checked: ctx.locations_checked.add(loc_id) @@ -470,10 +613,64 @@ class SMWSNIClient(SNIClient): dragon_coins_data[progress_byte] = new_data new_dragon_coin = True + elif level_data[1] == 3: + # Moon Check + + progress_byte = (level_data[0] // 8) + progress_bit = 7 - (level_data[0] % 8) + + data = moon_data[progress_byte] + new_data = data | (1 << progress_bit) + moon_data[progress_byte] = new_data + + new_moon = True + elif level_data[1] == 4: + # Hidden 1-Up Check + progress_byte = (level_data[0] // 8) + progress_bit = 7 - (level_data[0] % 8) + + data = hidden_1up_data[progress_byte] + new_data = data | (1 << progress_bit) + hidden_1up_data[progress_byte] = new_data + + new_hidden_1up = True + elif level_data[1] == 5: + # Bonus block prize Check + + progress_byte = (level_data[0] // 8) + progress_bit = 7 - (level_data[0] % 8) + + data = bonus_block_data[progress_byte] + new_data = data | (1 << progress_bit) + bonus_block_data[progress_byte] = new_data + + new_bonus_block = True + elif level_data[1] >= 100: + # Blocksanity flag Check + block_index = level_data[1] - 100 + blocksanity_data[block_index] = 1 + new_blocksanity = True + + # All blocksanity blocks flag + new_blocksanity_flags = True + for block_id in level_blocks_data[level_data[0]]: + if blocksanity_data[block_id] != 1: + new_blocksanity_flags = False + continue + if new_blocksanity_flags is True: + progress_byte = (level_data[0] // 8) + progress_bit = 7 - (level_data[0] % 8) + data = blocksanity_flags[progress_byte] + new_data = data | (1 << progress_bit) + blocksanity_flags[progress_byte] = new_data else: if level_data[0] in SMW_UNCOLLECTABLE_LEVELS: continue + # Handle map indicators + flag = 1 if level_data[1] == 0 else 2 + level_clear_flags[level_data[0]] |= flag + event_id = event_data[level_data[0]] event_id_value = event_id + level_data[1] @@ -514,7 +711,18 @@ class SMWSNIClient(SNIClient): if new_dragon_coin: snes_buffered_write(ctx, SMW_DRAGON_COINS_DATA, bytes(dragon_coins_data)) + if new_moon: + snes_buffered_write(ctx, SMW_MOON_DATA, bytes(moon_data)) + if new_hidden_1up: + snes_buffered_write(ctx, SMW_HIDDEN_1UP_DATA, bytes(hidden_1up_data)) + if new_bonus_block: + snes_buffered_write(ctx, SMW_BONUS_BLOCK_DATA, bytes(bonus_block_data)) + if new_blocksanity: + snes_buffered_write(ctx, SMW_BLOCKSANITY_DATA, bytes(blocksanity_data)) + if new_blocksanity_flags: + snes_buffered_write(ctx, SMW_BLOCKSANITY_FLAGS, bytes(blocksanity_flags)) if new_events > 0: + snes_buffered_write(ctx, SMW_LEVEL_CLEAR_FLAGS, bytes(level_clear_flags)) snes_buffered_write(ctx, SMW_PROGRESS_DATA, bytes(progress_data)) snes_buffered_write(ctx, SMW_PATH_DATA, bytes(path_data)) old_events = await snes_read(ctx, SMW_NUM_EVENTS_ADDR, 0x1) diff --git a/worlds/smw/Items.py b/worlds/smw/Items.py index 5b6cce5a7f..eaf58b9b8e 100644 --- a/worlds/smw/Items.py +++ b/worlds/smw/Items.py @@ -18,6 +18,10 @@ class SMWItem(Item): # Separate tables for each type of item. junk_table = { + ItemName.one_coin: ItemData(0xBC0017, False), + ItemName.five_coins: ItemData(0xBC0018, False), + ItemName.ten_coins: ItemData(0xBC0019, False), + ItemName.fifty_coins: ItemData(0xBC001A, False), ItemName.one_up_mushroom: ItemData(0xBC0001, False), } @@ -36,6 +40,7 @@ upgrade_table = { ItemName.progressive_powerup: ItemData(0xBC000A, True), ItemName.p_balloon: ItemData(0xBC000B, True), ItemName.super_star_active: ItemData(0xBC000D, True), + ItemName.special_world_clear: ItemData(0xBC001B, True), } switch_palace_table = { @@ -46,10 +51,12 @@ switch_palace_table = { } trap_table = { - ItemName.ice_trap: ItemData(0xBC0013, False, True), - ItemName.stun_trap: ItemData(0xBC0014, False, True), - ItemName.literature_trap: ItemData(0xBC0015, False, True), - ItemName.timer_trap: ItemData(0xBC0016, False, True), + ItemName.ice_trap: ItemData(0xBC0013, False, True), + ItemName.stun_trap: ItemData(0xBC0014, False, True), + ItemName.literature_trap: ItemData(0xBC0015, False, True), + ItemName.timer_trap: ItemData(0xBC0016, False, True), + ItemName.reverse_controls_trap: ItemData(0xBC001C, False, True), + ItemName.thwimp_trap: ItemData(0xBC001D, False, True), } event_table = { diff --git a/worlds/smw/Levels.py b/worlds/smw/Levels.py index 3940a08c7c..7aa9428b91 100644 --- a/worlds/smw/Levels.py +++ b/worlds/smw/Levels.py @@ -1,4 +1,5 @@ +from worlds.AutoWorld import World from .Names import LocationName @@ -75,6 +76,103 @@ ow_boss_rooms = [ ] +level_blocks_data = { + 0x01: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + 0x02: [12, 13], + 0x04: [14, 15, 16, 17, 18, 19], + 0x05: [20, 21, 22, 23, 24, 25], + 0x06: [26, 27, 28, 29], + 0x07: [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], + 0x09: [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], + 0x0A: [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], + 0x0B: [60, 61, 62], + 0x0C: [63, 64, 65, 66, 67, 68], + 0x0D: [69, 70, 71], + 0x0E: [72], + 0x0F: [73, 74, 75, 76], + 0x10: [77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111 + ], + 0x11: [112], + 0x13: [113, 114, 115, 116, 117], + 0x15: [118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140 + ], + 0x18: [141, 142], + 0x1A: [143, 144, 145], + 0x1B: [146, 147, 148, 149, 150], + 0x1C: [151, 152, 153, 154], + 0x1D: [155, 156, 157], + 0x1F: [158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168], + 0x20: [169], + 0x21: [170, 171, 172], + 0x22: [173, 174, 175, 176, 177], + 0x23: [178, 179, 180, 181, 182, 183, 184, 185, 186], + 0x24: [187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202 + ], + 0x25: [203, 204, 205, 206, 207, 208], + 0x26: [209, 210, 211, 212], + 0x27: [213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229 + ], + 0x29: [230, 231, 232, 233], + 0x2A: [234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249 + ], + 0x2B: [250, 251, 252, 253, 254], + 0x2D: [255, 256, 257, 258, 259, 260, 261, 262], + 0x2E: [263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279 + ], + 0x2F: [280, 281, 282, 283, 284], + 0x33: [285, 286, 287, 288, 289, 290], + 0x34: [291, 292, 293], + 0x35: [294, 295], + 0x37: [296, 297], + 0x38: [298, 299, 300, 301], + 0x39: [302, 303, 304, 305], + 0x3A: [306, 307, 308, 309, 310, 311, 312, 313, 314], + 0x3B: [315, 316], + 0x3C: [317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330], + 0x3D: [331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341], + 0x3E: [342, 343, 344, 345, 346, 347, 348, 349, 350, 351], + 0x40: [352, 353, 354, 355, 356], + 0x41: [357, 358, 359, 360, 361], + 0x42: [362, 363, 364, 365, 366], + 0x43: [367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379], + 0x44: [380, 381, 382, 383, 384, 385, 386], + 0x46: [387, 388, 389], + 0x47: [390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416 + ], + 0x49: [417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446 + ], + 0x4A: [447, 448, 449, 450, 451], + 0x4B: [452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, + 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, + 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489 + ], + 0x4C: [490], + 0x4E: [491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 512 + ], + 0x4F: [513, 514, 515, 516, 517, 518, 519, 520, 521, 522], + 0x50: [523, 524, 525], + 0x51: [526, 527], + 0x54: [528], + 0x56: [529], + 0x59: [530, 531, 532, 533, 534, 535, 536, 537, 538], + 0x5A: [539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, + 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, + 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, + 579, 580, 581 + ] +} + class SMWPath(): thisEndDirection: int otherLevelID: int @@ -330,12 +428,15 @@ switch_palace_levels = [ location_id_to_level_id = { LocationName.yoshis_island_1_exit_1: [0x29, 0], LocationName.yoshis_island_1_dragon: [0x29, 2], + LocationName.yoshis_island_1_moon: [0x29, 3], LocationName.yoshis_island_2_exit_1: [0x2A, 0], LocationName.yoshis_island_2_dragon: [0x2A, 2], LocationName.yoshis_island_3_exit_1: [0x27, 0], LocationName.yoshis_island_3_dragon: [0x27, 2], + LocationName.yoshis_island_3_bonus_block: [0x27, 5], LocationName.yoshis_island_4_exit_1: [0x26, 0], LocationName.yoshis_island_4_dragon: [0x26, 2], + LocationName.yoshis_island_4_hidden_1up: [0x26, 4], LocationName.yoshis_island_castle: [0x25, 0], LocationName.yoshis_island_koopaling: [0x25, 0], LocationName.yellow_switch_palace: [0x14, 0], @@ -343,13 +444,17 @@ location_id_to_level_id = { LocationName.donut_plains_1_exit_1: [0x15, 0], LocationName.donut_plains_1_exit_2: [0x15, 1], LocationName.donut_plains_1_dragon: [0x15, 2], + LocationName.donut_plains_1_hidden_1up: [0x15, 4], LocationName.donut_plains_2_exit_1: [0x09, 0], LocationName.donut_plains_2_exit_2: [0x09, 1], LocationName.donut_plains_2_dragon: [0x09, 2], LocationName.donut_plains_3_exit_1: [0x05, 0], LocationName.donut_plains_3_dragon: [0x05, 2], + LocationName.donut_plains_3_bonus_block: [0x05, 5], LocationName.donut_plains_4_exit_1: [0x06, 0], LocationName.donut_plains_4_dragon: [0x06, 2], + LocationName.donut_plains_4_moon: [0x06, 3], + LocationName.donut_plains_4_hidden_1up: [0x06, 4], LocationName.donut_secret_1_exit_1: [0x0A, 0], LocationName.donut_secret_1_exit_2: [0x0A, 1], LocationName.donut_secret_1_dragon: [0x0A, 2], @@ -360,6 +465,7 @@ location_id_to_level_id = { LocationName.donut_secret_house_exit_1: [0x13, 0], LocationName.donut_secret_house_exit_2: [0x13, 1], LocationName.donut_plains_castle: [0x07, 0], + LocationName.donut_plains_castle_hidden_1up: [0x07, 4], LocationName.donut_plains_koopaling: [0x07, 0], LocationName.green_switch_palace: [0x08, 0], @@ -371,8 +477,10 @@ location_id_to_level_id = { LocationName.vanilla_dome_2_dragon: [0x3C, 2], LocationName.vanilla_dome_3_exit_1: [0x2E, 0], LocationName.vanilla_dome_3_dragon: [0x2E, 2], + LocationName.vanilla_dome_3_moon: [0x2E, 3], LocationName.vanilla_dome_4_exit_1: [0x3D, 0], LocationName.vanilla_dome_4_dragon: [0x3D, 2], + LocationName.vanilla_dome_4_hidden_1up: [0x3D, 4], LocationName.vanilla_secret_1_exit_1: [0x2D, 0], LocationName.vanilla_secret_1_exit_2: [0x2D, 1], LocationName.vanilla_secret_1_dragon: [0x2D, 2], @@ -382,7 +490,9 @@ location_id_to_level_id = { LocationName.vanilla_secret_3_dragon: [0x02, 2], LocationName.vanilla_ghost_house_exit_1: [0x2B, 0], LocationName.vanilla_ghost_house_dragon: [0x2B, 2], + LocationName.vanilla_ghost_house_hidden_1up: [0x2B, 4], LocationName.vanilla_fortress: [0x0B, 0], + LocationName.vanilla_fortress_hidden_1up: [0x0B, 4], LocationName.vanilla_reznor: [0x0B, 0], LocationName.vanilla_dome_castle: [0x40, 0], LocationName.vanilla_dome_koopaling: [0x40, 0], @@ -390,13 +500,16 @@ location_id_to_level_id = { LocationName.butter_bridge_1_exit_1: [0x0C, 0], LocationName.butter_bridge_1_dragon: [0x0C, 2], + LocationName.butter_bridge_1_bonus_block: [0x0C, 5], LocationName.butter_bridge_2_exit_1: [0x0D, 0], LocationName.butter_bridge_2_dragon: [0x0D, 2], LocationName.cheese_bridge_exit_1: [0x0F, 0], LocationName.cheese_bridge_exit_2: [0x0F, 1], LocationName.cheese_bridge_dragon: [0x0F, 2], + LocationName.cheese_bridge_moon: [0x0F, 3], LocationName.cookie_mountain_exit_1: [0x10, 0], LocationName.cookie_mountain_dragon: [0x10, 2], + LocationName.cookie_mountain_hidden_1up: [0x10, 4], LocationName.soda_lake_exit_1: [0x11, 0], LocationName.soda_lake_dragon: [0x11, 2], LocationName.twin_bridges_castle: [0x0E, 0], @@ -410,12 +523,14 @@ location_id_to_level_id = { LocationName.forest_of_illusion_3_exit_1: [0x47, 0], LocationName.forest_of_illusion_3_exit_2: [0x47, 1], LocationName.forest_of_illusion_3_dragon: [0x47, 2], + LocationName.forest_of_illusion_3_hidden_1up: [0x47, 4], LocationName.forest_of_illusion_4_exit_1: [0x43, 0], LocationName.forest_of_illusion_4_exit_2: [0x43, 1], LocationName.forest_of_illusion_4_dragon: [0x43, 2], LocationName.forest_ghost_house_exit_1: [0x41, 0], LocationName.forest_ghost_house_exit_2: [0x41, 1], LocationName.forest_ghost_house_dragon: [0x41, 2], + LocationName.forest_ghost_house_moon: [0x41, 3], LocationName.forest_secret_exit_1: [0x46, 0], LocationName.forest_secret_dragon: [0x46, 2], LocationName.forest_fortress: [0x1F, 0], @@ -427,12 +542,15 @@ location_id_to_level_id = { LocationName.chocolate_island_1_exit_1: [0x22, 0], LocationName.chocolate_island_1_dragon: [0x22, 2], + LocationName.chocolate_island_1_moon: [0x22, 3], LocationName.chocolate_island_2_exit_1: [0x24, 0], LocationName.chocolate_island_2_exit_2: [0x24, 1], LocationName.chocolate_island_2_dragon: [0x24, 2], + LocationName.chocolate_island_2_hidden_1up: [0x24, 4], LocationName.chocolate_island_3_exit_1: [0x23, 0], LocationName.chocolate_island_3_exit_2: [0x23, 1], LocationName.chocolate_island_3_dragon: [0x23, 2], + LocationName.chocolate_island_3_bonus_block: [0x23, 5], LocationName.chocolate_island_4_exit_1: [0x1D, 0], LocationName.chocolate_island_4_dragon: [0x1D, 2], LocationName.chocolate_island_5_exit_1: [0x1C, 0], @@ -442,6 +560,7 @@ location_id_to_level_id = { LocationName.chocolate_fortress: [0x1B, 0], LocationName.chocolate_reznor: [0x1B, 0], LocationName.chocolate_castle: [0x1A, 0], + LocationName.chocolate_castle_hidden_1up: [0x1A, 4], LocationName.chocolate_koopaling: [0x1A, 0], LocationName.sunken_ghost_ship: [0x18, 0], @@ -449,9 +568,11 @@ location_id_to_level_id = { LocationName.valley_of_bowser_1_exit_1: [0x3A, 0], LocationName.valley_of_bowser_1_dragon: [0x3A, 2], + LocationName.valley_of_bowser_1_moon: [0x3A, 3], LocationName.valley_of_bowser_2_exit_1: [0x39, 0], LocationName.valley_of_bowser_2_exit_2: [0x39, 1], LocationName.valley_of_bowser_2_dragon: [0x39, 2], + LocationName.valley_of_bowser_2_hidden_1up: [0x39, 4], LocationName.valley_of_bowser_3_exit_1: [0x37, 0], LocationName.valley_of_bowser_3_dragon: [0x37, 2], LocationName.valley_of_bowser_4_exit_1: [0x33, 0], @@ -464,6 +585,7 @@ location_id_to_level_id = { LocationName.valley_castle: [0x34, 0], LocationName.valley_koopaling: [0x34, 0], LocationName.valley_castle_dragon: [0x34, 2], + LocationName.valley_castle_hidden_1up: [0x34, 4], LocationName.star_road_1_exit_1: [0x58, 0], LocationName.star_road_1_exit_2: [0x58, 1], @@ -479,6 +601,7 @@ location_id_to_level_id = { LocationName.special_zone_1_exit_1: [0x4E, 0], LocationName.special_zone_1_dragon: [0x4E, 2], + LocationName.special_zone_1_hidden_1up: [0x4E, 4], LocationName.special_zone_2_exit_1: [0x4F, 0], LocationName.special_zone_2_dragon: [0x4F, 2], LocationName.special_zone_3_exit_1: [0x50, 0], @@ -493,19 +616,602 @@ location_id_to_level_id = { LocationName.special_zone_7_dragon: [0x4A, 2], LocationName.special_zone_8_exit_1: [0x49, 0], LocationName.special_zone_8_dragon: [0x49, 2], + + LocationName.vanilla_secret_2_yoshi_block_1: [0x01, 100], + LocationName.vanilla_secret_2_green_block_1: [0x01, 101], + LocationName.vanilla_secret_2_powerup_block_1: [0x01, 102], + LocationName.vanilla_secret_2_powerup_block_2: [0x01, 103], + LocationName.vanilla_secret_2_multi_coin_block_1: [0x01, 104], + LocationName.vanilla_secret_2_gray_pow_block_1: [0x01, 105], + LocationName.vanilla_secret_2_coin_block_1: [0x01, 106], + LocationName.vanilla_secret_2_coin_block_2: [0x01, 107], + LocationName.vanilla_secret_2_coin_block_3: [0x01, 108], + LocationName.vanilla_secret_2_coin_block_4: [0x01, 109], + LocationName.vanilla_secret_2_coin_block_5: [0x01, 110], + LocationName.vanilla_secret_2_coin_block_6: [0x01, 111], + LocationName.vanilla_secret_3_powerup_block_1: [0x02, 112], + LocationName.vanilla_secret_3_powerup_block_2: [0x02, 113], + LocationName.donut_ghost_house_vine_block_1: [0x04, 114], + LocationName.donut_ghost_house_directional_coin_block_1: [0x04, 115], + LocationName.donut_ghost_house_life_block_1: [0x04, 116], + LocationName.donut_ghost_house_life_block_2: [0x04, 117], + LocationName.donut_ghost_house_life_block_3: [0x04, 118], + LocationName.donut_ghost_house_life_block_4: [0x04, 119], + LocationName.donut_plains_3_green_block_1: [0x05, 120], + LocationName.donut_plains_3_coin_block_1: [0x05, 121], + LocationName.donut_plains_3_coin_block_2: [0x05, 122], + LocationName.donut_plains_3_vine_block_1: [0x05, 123], + LocationName.donut_plains_3_powerup_block_1: [0x05, 124], + LocationName.donut_plains_3_bonus_block_1: [0x05, 125], + LocationName.donut_plains_4_coin_block_1: [0x06, 126], + LocationName.donut_plains_4_powerup_block_1: [0x06, 127], + LocationName.donut_plains_4_coin_block_2: [0x06, 128], + LocationName.donut_plains_4_yoshi_block_1: [0x06, 129], + LocationName.donut_plains_castle_yellow_block_1: [0x07, 130], + LocationName.donut_plains_castle_coin_block_1: [0x07, 131], + LocationName.donut_plains_castle_powerup_block_1: [0x07, 132], + LocationName.donut_plains_castle_coin_block_2: [0x07, 133], + LocationName.donut_plains_castle_vine_block_1: [0x07, 134], + LocationName.donut_plains_castle_invis_life_block_1: [0x07, 135], + LocationName.donut_plains_castle_coin_block_3: [0x07, 136], + LocationName.donut_plains_castle_coin_block_4: [0x07, 137], + LocationName.donut_plains_castle_coin_block_5: [0x07, 138], + LocationName.donut_plains_castle_green_block_1: [0x07, 139], + LocationName.donut_plains_2_coin_block_1: [0x09, 140], + LocationName.donut_plains_2_coin_block_2: [0x09, 141], + LocationName.donut_plains_2_coin_block_3: [0x09, 142], + LocationName.donut_plains_2_yellow_block_1: [0x09, 143], + LocationName.donut_plains_2_powerup_block_1: [0x09, 144], + LocationName.donut_plains_2_multi_coin_block_1: [0x09, 145], + LocationName.donut_plains_2_flying_block_1: [0x09, 146], + LocationName.donut_plains_2_green_block_1: [0x09, 147], + LocationName.donut_plains_2_yellow_block_2: [0x09, 148], + LocationName.donut_plains_2_vine_block_1: [0x09, 149], + LocationName.donut_secret_1_coin_block_1: [0x0A, 150], + LocationName.donut_secret_1_coin_block_2: [0x0A, 151], + LocationName.donut_secret_1_powerup_block_1: [0x0A, 152], + LocationName.donut_secret_1_coin_block_3: [0x0A, 153], + LocationName.donut_secret_1_powerup_block_2: [0x0A, 154], + LocationName.donut_secret_1_powerup_block_3: [0x0A, 155], + LocationName.donut_secret_1_life_block_1: [0x0A, 156], + LocationName.donut_secret_1_powerup_block_4: [0x0A, 157], + LocationName.donut_secret_1_powerup_block_5: [0x0A, 158], + LocationName.donut_secret_1_key_block_1: [0x0A, 159], + LocationName.vanilla_fortress_powerup_block_1: [0x0B, 160], + LocationName.vanilla_fortress_powerup_block_2: [0x0B, 161], + LocationName.vanilla_fortress_yellow_block_1: [0x0B, 162], + LocationName.butter_bridge_1_powerup_block_1: [0x0C, 163], + LocationName.butter_bridge_1_multi_coin_block_1: [0x0C, 164], + LocationName.butter_bridge_1_multi_coin_block_2: [0x0C, 165], + LocationName.butter_bridge_1_multi_coin_block_3: [0x0C, 166], + LocationName.butter_bridge_1_life_block_1: [0x0C, 167], + LocationName.butter_bridge_1_bonus_block_1: [0x0C, 168], + LocationName.butter_bridge_2_powerup_block_1: [0x0D, 169], + LocationName.butter_bridge_2_green_block_1: [0x0D, 170], + LocationName.butter_bridge_2_yoshi_block_1: [0x0D, 171], + LocationName.twin_bridges_castle_powerup_block_1: [0x0E, 172], + LocationName.cheese_bridge_powerup_block_1: [0x0F, 173], + LocationName.cheese_bridge_powerup_block_2: [0x0F, 174], + LocationName.cheese_bridge_wings_block_1: [0x0F, 175], + LocationName.cheese_bridge_powerup_block_3: [0x0F, 176], + LocationName.cookie_mountain_coin_block_1: [0x10, 177], + LocationName.cookie_mountain_coin_block_2: [0x10, 178], + LocationName.cookie_mountain_coin_block_3: [0x10, 179], + LocationName.cookie_mountain_coin_block_4: [0x10, 180], + LocationName.cookie_mountain_coin_block_5: [0x10, 181], + LocationName.cookie_mountain_coin_block_6: [0x10, 182], + LocationName.cookie_mountain_coin_block_7: [0x10, 183], + LocationName.cookie_mountain_coin_block_8: [0x10, 184], + LocationName.cookie_mountain_coin_block_9: [0x10, 185], + LocationName.cookie_mountain_powerup_block_1: [0x10, 186], + LocationName.cookie_mountain_life_block_1: [0x10, 187], + LocationName.cookie_mountain_vine_block_1: [0x10, 188], + LocationName.cookie_mountain_yoshi_block_1: [0x10, 189], + LocationName.cookie_mountain_coin_block_10: [0x10, 190], + LocationName.cookie_mountain_coin_block_11: [0x10, 191], + LocationName.cookie_mountain_powerup_block_2: [0x10, 192], + LocationName.cookie_mountain_coin_block_12: [0x10, 193], + LocationName.cookie_mountain_coin_block_13: [0x10, 194], + LocationName.cookie_mountain_coin_block_14: [0x10, 195], + LocationName.cookie_mountain_coin_block_15: [0x10, 196], + LocationName.cookie_mountain_coin_block_16: [0x10, 197], + LocationName.cookie_mountain_coin_block_17: [0x10, 198], + LocationName.cookie_mountain_coin_block_18: [0x10, 199], + LocationName.cookie_mountain_coin_block_19: [0x10, 200], + LocationName.cookie_mountain_coin_block_20: [0x10, 201], + LocationName.cookie_mountain_coin_block_21: [0x10, 202], + LocationName.cookie_mountain_coin_block_22: [0x10, 203], + LocationName.cookie_mountain_coin_block_23: [0x10, 204], + LocationName.cookie_mountain_coin_block_24: [0x10, 205], + LocationName.cookie_mountain_coin_block_25: [0x10, 206], + LocationName.cookie_mountain_coin_block_26: [0x10, 207], + LocationName.cookie_mountain_coin_block_27: [0x10, 208], + LocationName.cookie_mountain_coin_block_28: [0x10, 209], + LocationName.cookie_mountain_coin_block_29: [0x10, 210], + LocationName.cookie_mountain_coin_block_30: [0x10, 211], + LocationName.soda_lake_powerup_block_1: [0x11, 212], + LocationName.donut_secret_house_powerup_block_1: [0x13, 213], + LocationName.donut_secret_house_multi_coin_block_1: [0x13, 214], + LocationName.donut_secret_house_life_block_1: [0x13, 215], + LocationName.donut_secret_house_vine_block_1: [0x13, 216], + LocationName.donut_secret_house_directional_coin_block_1: [0x13, 217], + LocationName.donut_plains_1_coin_block_1: [0x15, 218], + LocationName.donut_plains_1_coin_block_2: [0x15, 219], + LocationName.donut_plains_1_yoshi_block_1: [0x15, 220], + LocationName.donut_plains_1_vine_block_1: [0x15, 221], + LocationName.donut_plains_1_green_block_1: [0x15, 222], + LocationName.donut_plains_1_green_block_2: [0x15, 223], + LocationName.donut_plains_1_green_block_3: [0x15, 224], + LocationName.donut_plains_1_green_block_4: [0x15, 225], + LocationName.donut_plains_1_green_block_5: [0x15, 226], + LocationName.donut_plains_1_green_block_6: [0x15, 227], + LocationName.donut_plains_1_green_block_7: [0x15, 228], + LocationName.donut_plains_1_green_block_8: [0x15, 229], + LocationName.donut_plains_1_green_block_9: [0x15, 230], + LocationName.donut_plains_1_green_block_10: [0x15, 231], + LocationName.donut_plains_1_green_block_11: [0x15, 232], + LocationName.donut_plains_1_green_block_12: [0x15, 233], + LocationName.donut_plains_1_green_block_13: [0x15, 234], + LocationName.donut_plains_1_green_block_14: [0x15, 235], + LocationName.donut_plains_1_green_block_15: [0x15, 236], + LocationName.donut_plains_1_green_block_16: [0x15, 237], + LocationName.donut_plains_1_yellow_block_1: [0x15, 238], + LocationName.donut_plains_1_yellow_block_2: [0x15, 239], + LocationName.donut_plains_1_yellow_block_3: [0x15, 240], + LocationName.sunken_ghost_ship_powerup_block_1: [0x18, 241], + LocationName.sunken_ghost_ship_star_block_1: [0x18, 242], + LocationName.chocolate_castle_yellow_block_1: [0x1A, 243], + LocationName.chocolate_castle_yellow_block_2: [0x1A, 244], + LocationName.chocolate_castle_green_block_1: [0x1A, 245], + LocationName.chocolate_fortress_powerup_block_1: [0x1B, 246], + LocationName.chocolate_fortress_powerup_block_2: [0x1B, 247], + LocationName.chocolate_fortress_coin_block_1: [0x1B, 248], + LocationName.chocolate_fortress_coin_block_2: [0x1B, 249], + LocationName.chocolate_fortress_green_block_1: [0x1B, 250], + LocationName.chocolate_island_5_yoshi_block_1: [0x1C, 251], + LocationName.chocolate_island_5_powerup_block_1: [0x1C, 252], + LocationName.chocolate_island_5_life_block_1: [0x1C, 253], + LocationName.chocolate_island_5_yellow_block_1: [0x1C, 254], + LocationName.chocolate_island_4_yellow_block_1: [0x1D, 255], + LocationName.chocolate_island_4_blue_pow_block_1: [0x1D, 256], + LocationName.chocolate_island_4_powerup_block_1: [0x1D, 257], + LocationName.forest_fortress_yellow_block_1: [0x1F, 258], + LocationName.forest_fortress_powerup_block_1: [0x1F, 259], + LocationName.forest_fortress_life_block_1: [0x1F, 260], + LocationName.forest_fortress_life_block_2: [0x1F, 261], + LocationName.forest_fortress_life_block_3: [0x1F, 262], + LocationName.forest_fortress_life_block_4: [0x1F, 263], + LocationName.forest_fortress_life_block_5: [0x1F, 264], + LocationName.forest_fortress_life_block_6: [0x1F, 265], + LocationName.forest_fortress_life_block_7: [0x1F, 266], + LocationName.forest_fortress_life_block_8: [0x1F, 267], + LocationName.forest_fortress_life_block_9: [0x1F, 268], + LocationName.forest_castle_green_block_1: [0x20, 269], + LocationName.chocolate_ghost_house_powerup_block_1: [0x21, 270], + LocationName.chocolate_ghost_house_powerup_block_2: [0x21, 271], + LocationName.chocolate_ghost_house_life_block_1: [0x21, 272], + LocationName.chocolate_island_1_flying_block_1: [0x22, 273], + LocationName.chocolate_island_1_flying_block_2: [0x22, 274], + LocationName.chocolate_island_1_yoshi_block_1: [0x22, 275], + LocationName.chocolate_island_1_green_block_1: [0x22, 276], + LocationName.chocolate_island_1_life_block_1: [0x22, 277], + LocationName.chocolate_island_3_powerup_block_1: [0x23, 278], + LocationName.chocolate_island_3_powerup_block_2: [0x23, 279], + LocationName.chocolate_island_3_powerup_block_3: [0x23, 280], + LocationName.chocolate_island_3_green_block_1: [0x23, 281], + LocationName.chocolate_island_3_bonus_block_1: [0x23, 282], + LocationName.chocolate_island_3_vine_block_1: [0x23, 283], + LocationName.chocolate_island_3_life_block_1: [0x23, 284], + LocationName.chocolate_island_3_life_block_2: [0x23, 285], + LocationName.chocolate_island_3_life_block_3: [0x23, 286], + LocationName.chocolate_island_2_multi_coin_block_1: [0x24, 287], + LocationName.chocolate_island_2_invis_coin_block_1: [0x24, 288], + LocationName.chocolate_island_2_yoshi_block_1: [0x24, 289], + LocationName.chocolate_island_2_coin_block_1: [0x24, 290], + LocationName.chocolate_island_2_coin_block_2: [0x24, 291], + LocationName.chocolate_island_2_multi_coin_block_2: [0x24, 292], + LocationName.chocolate_island_2_powerup_block_1: [0x24, 293], + LocationName.chocolate_island_2_blue_pow_block_1: [0x24, 294], + LocationName.chocolate_island_2_yellow_block_1: [0x24, 295], + LocationName.chocolate_island_2_yellow_block_2: [0x24, 296], + LocationName.chocolate_island_2_green_block_1: [0x24, 297], + LocationName.chocolate_island_2_green_block_2: [0x24, 298], + LocationName.chocolate_island_2_green_block_3: [0x24, 299], + LocationName.chocolate_island_2_green_block_4: [0x24, 300], + LocationName.chocolate_island_2_green_block_5: [0x24, 301], + LocationName.chocolate_island_2_green_block_6: [0x24, 302], + LocationName.yoshis_island_castle_coin_block_1: [0x25, 303], + LocationName.yoshis_island_castle_coin_block_2: [0x25, 304], + LocationName.yoshis_island_castle_powerup_block_1: [0x25, 305], + LocationName.yoshis_island_castle_coin_block_3: [0x25, 306], + LocationName.yoshis_island_castle_coin_block_4: [0x25, 307], + LocationName.yoshis_island_castle_flying_block_1: [0x25, 308], + LocationName.yoshis_island_4_yellow_block_1: [0x26, 309], + LocationName.yoshis_island_4_powerup_block_1: [0x26, 310], + LocationName.yoshis_island_4_multi_coin_block_1: [0x26, 311], + LocationName.yoshis_island_4_star_block_1: [0x26, 312], + LocationName.yoshis_island_3_yellow_block_1: [0x27, 313], + LocationName.yoshis_island_3_yellow_block_2: [0x27, 314], + LocationName.yoshis_island_3_yellow_block_3: [0x27, 315], + LocationName.yoshis_island_3_yellow_block_4: [0x27, 316], + LocationName.yoshis_island_3_yellow_block_5: [0x27, 317], + LocationName.yoshis_island_3_yellow_block_6: [0x27, 318], + LocationName.yoshis_island_3_yellow_block_7: [0x27, 319], + LocationName.yoshis_island_3_yellow_block_8: [0x27, 320], + LocationName.yoshis_island_3_yellow_block_9: [0x27, 321], + LocationName.yoshis_island_3_coin_block_1: [0x27, 322], + LocationName.yoshis_island_3_yoshi_block_1: [0x27, 323], + LocationName.yoshis_island_3_coin_block_2: [0x27, 324], + LocationName.yoshis_island_3_powerup_block_1: [0x27, 325], + LocationName.yoshis_island_3_yellow_block_10: [0x27, 326], + LocationName.yoshis_island_3_yellow_block_11: [0x27, 327], + LocationName.yoshis_island_3_yellow_block_12: [0x27, 328], + LocationName.yoshis_island_3_bonus_block_1: [0x27, 329], + LocationName.yoshis_island_1_flying_block_1: [0x29, 330], + LocationName.yoshis_island_1_yellow_block_1: [0x29, 331], + LocationName.yoshis_island_1_life_block_1: [0x29, 332], + LocationName.yoshis_island_1_powerup_block_1: [0x29, 333], + LocationName.yoshis_island_2_flying_block_1: [0x2A, 334], + LocationName.yoshis_island_2_flying_block_2: [0x2A, 335], + LocationName.yoshis_island_2_flying_block_3: [0x2A, 336], + LocationName.yoshis_island_2_flying_block_4: [0x2A, 337], + LocationName.yoshis_island_2_flying_block_5: [0x2A, 338], + LocationName.yoshis_island_2_flying_block_6: [0x2A, 339], + LocationName.yoshis_island_2_coin_block_1: [0x2A, 340], + LocationName.yoshis_island_2_yellow_block_1: [0x2A, 341], + LocationName.yoshis_island_2_coin_block_2: [0x2A, 342], + LocationName.yoshis_island_2_coin_block_3: [0x2A, 343], + LocationName.yoshis_island_2_yoshi_block_1: [0x2A, 344], + LocationName.yoshis_island_2_coin_block_4: [0x2A, 345], + LocationName.yoshis_island_2_yoshi_block_2: [0x2A, 346], + LocationName.yoshis_island_2_coin_block_5: [0x2A, 347], + LocationName.yoshis_island_2_vine_block_1: [0x2A, 348], + LocationName.yoshis_island_2_yellow_block_2: [0x2A, 349], + LocationName.vanilla_ghost_house_powerup_block_1: [0x2B, 350], + LocationName.vanilla_ghost_house_vine_block_1: [0x2B, 351], + LocationName.vanilla_ghost_house_powerup_block_2: [0x2B, 352], + LocationName.vanilla_ghost_house_multi_coin_block_1: [0x2B, 353], + LocationName.vanilla_ghost_house_blue_pow_block_1: [0x2B, 354], + LocationName.vanilla_secret_1_coin_block_1: [0x2D, 355], + LocationName.vanilla_secret_1_powerup_block_1: [0x2D, 356], + LocationName.vanilla_secret_1_multi_coin_block_1: [0x2D, 357], + LocationName.vanilla_secret_1_vine_block_1: [0x2D, 358], + LocationName.vanilla_secret_1_vine_block_2: [0x2D, 359], + LocationName.vanilla_secret_1_coin_block_2: [0x2D, 360], + LocationName.vanilla_secret_1_coin_block_3: [0x2D, 361], + LocationName.vanilla_secret_1_powerup_block_2: [0x2D, 362], + LocationName.vanilla_dome_3_coin_block_1: [0x2E, 363], + LocationName.vanilla_dome_3_flying_block_1: [0x2E, 364], + LocationName.vanilla_dome_3_flying_block_2: [0x2E, 365], + LocationName.vanilla_dome_3_powerup_block_1: [0x2E, 366], + LocationName.vanilla_dome_3_flying_block_3: [0x2E, 367], + LocationName.vanilla_dome_3_invis_coin_block_1: [0x2E, 368], + LocationName.vanilla_dome_3_powerup_block_2: [0x2E, 369], + LocationName.vanilla_dome_3_multi_coin_block_1: [0x2E, 370], + LocationName.vanilla_dome_3_powerup_block_3: [0x2E, 371], + LocationName.vanilla_dome_3_yoshi_block_1: [0x2E, 372], + LocationName.vanilla_dome_3_powerup_block_4: [0x2E, 373], + LocationName.vanilla_dome_3_pswitch_coin_block_1: [0x2E, 374], + LocationName.vanilla_dome_3_pswitch_coin_block_2: [0x2E, 375], + LocationName.vanilla_dome_3_pswitch_coin_block_3: [0x2E, 376], + LocationName.vanilla_dome_3_pswitch_coin_block_4: [0x2E, 377], + LocationName.vanilla_dome_3_pswitch_coin_block_5: [0x2E, 378], + LocationName.vanilla_dome_3_pswitch_coin_block_6: [0x2E, 379], + LocationName.donut_secret_2_directional_coin_block_1: [0x2F, 380], + LocationName.donut_secret_2_vine_block_1: [0x2F, 381], + LocationName.donut_secret_2_star_block_1: [0x2F, 382], + LocationName.donut_secret_2_powerup_block_1: [0x2F, 383], + LocationName.donut_secret_2_star_block_2: [0x2F, 384], + LocationName.valley_of_bowser_4_yellow_block_1: [0x33, 385], + LocationName.valley_of_bowser_4_powerup_block_1: [0x33, 386], + LocationName.valley_of_bowser_4_vine_block_1: [0x33, 387], + LocationName.valley_of_bowser_4_yoshi_block_1: [0x33, 388], + LocationName.valley_of_bowser_4_life_block_1: [0x33, 389], + LocationName.valley_of_bowser_4_powerup_block_2: [0x33, 390], + LocationName.valley_castle_yellow_block_1: [0x34, 391], + LocationName.valley_castle_yellow_block_2: [0x34, 392], + LocationName.valley_castle_green_block_1: [0x34, 393], + LocationName.valley_fortress_green_block_1: [0x35, 394], + LocationName.valley_fortress_yellow_block_1: [0x35, 395], + LocationName.valley_of_bowser_3_powerup_block_1: [0x37, 396], + LocationName.valley_of_bowser_3_powerup_block_2: [0x37, 397], + LocationName.valley_ghost_house_pswitch_coin_block_1: [0x38, 398], + LocationName.valley_ghost_house_multi_coin_block_1: [0x38, 399], + LocationName.valley_ghost_house_powerup_block_1: [0x38, 400], + LocationName.valley_ghost_house_directional_coin_block_1: [0x38, 401], + LocationName.valley_of_bowser_2_powerup_block_1: [0x39, 402], + LocationName.valley_of_bowser_2_yellow_block_1: [0x39, 403], + LocationName.valley_of_bowser_2_powerup_block_2: [0x39, 404], + LocationName.valley_of_bowser_2_wings_block_1: [0x39, 405], + LocationName.valley_of_bowser_1_green_block_1: [0x3A, 406], + LocationName.valley_of_bowser_1_invis_coin_block_1: [0x3A, 407], + LocationName.valley_of_bowser_1_invis_coin_block_2: [0x3A, 408], + LocationName.valley_of_bowser_1_invis_coin_block_3: [0x3A, 409], + LocationName.valley_of_bowser_1_yellow_block_1: [0x3A, 410], + LocationName.valley_of_bowser_1_yellow_block_2: [0x3A, 411], + LocationName.valley_of_bowser_1_yellow_block_3: [0x3A, 412], + LocationName.valley_of_bowser_1_yellow_block_4: [0x3A, 413], + LocationName.valley_of_bowser_1_vine_block_1: [0x3A, 414], + LocationName.chocolate_secret_powerup_block_1: [0x3B, 415], + LocationName.chocolate_secret_powerup_block_2: [0x3B, 416], + LocationName.vanilla_dome_2_coin_block_1: [0x3C, 417], + LocationName.vanilla_dome_2_powerup_block_1: [0x3C, 418], + LocationName.vanilla_dome_2_coin_block_2: [0x3C, 419], + LocationName.vanilla_dome_2_coin_block_3: [0x3C, 420], + LocationName.vanilla_dome_2_vine_block_1: [0x3C, 421], + LocationName.vanilla_dome_2_invis_life_block_1: [0x3C, 422], + LocationName.vanilla_dome_2_coin_block_4: [0x3C, 423], + LocationName.vanilla_dome_2_coin_block_5: [0x3C, 424], + LocationName.vanilla_dome_2_powerup_block_2: [0x3C, 425], + LocationName.vanilla_dome_2_powerup_block_3: [0x3C, 426], + LocationName.vanilla_dome_2_powerup_block_4: [0x3C, 427], + LocationName.vanilla_dome_2_powerup_block_5: [0x3C, 428], + LocationName.vanilla_dome_2_multi_coin_block_1: [0x3C, 429], + LocationName.vanilla_dome_2_multi_coin_block_2: [0x3C, 430], + LocationName.vanilla_dome_4_powerup_block_1: [0x3D, 431], + LocationName.vanilla_dome_4_powerup_block_2: [0x3D, 432], + LocationName.vanilla_dome_4_coin_block_1: [0x3D, 433], + LocationName.vanilla_dome_4_coin_block_2: [0x3D, 434], + LocationName.vanilla_dome_4_coin_block_3: [0x3D, 435], + LocationName.vanilla_dome_4_life_block_1: [0x3D, 436], + LocationName.vanilla_dome_4_coin_block_4: [0x3D, 437], + LocationName.vanilla_dome_4_coin_block_5: [0x3D, 438], + LocationName.vanilla_dome_4_coin_block_6: [0x3D, 439], + LocationName.vanilla_dome_4_coin_block_7: [0x3D, 440], + LocationName.vanilla_dome_4_coin_block_8: [0x3D, 441], + LocationName.vanilla_dome_1_flying_block_1: [0x3E, 442], + LocationName.vanilla_dome_1_powerup_block_1: [0x3E, 443], + LocationName.vanilla_dome_1_powerup_block_2: [0x3E, 444], + LocationName.vanilla_dome_1_coin_block_1: [0x3E, 445], + LocationName.vanilla_dome_1_life_block_1: [0x3E, 446], + LocationName.vanilla_dome_1_powerup_block_3: [0x3E, 447], + LocationName.vanilla_dome_1_vine_block_1: [0x3E, 448], + LocationName.vanilla_dome_1_star_block_1: [0x3E, 449], + LocationName.vanilla_dome_1_powerup_block_4: [0x3E, 450], + LocationName.vanilla_dome_1_coin_block_2: [0x3E, 451], + LocationName.vanilla_dome_castle_life_block_1: [0x40, 452], + LocationName.vanilla_dome_castle_life_block_2: [0x40, 453], + LocationName.vanilla_dome_castle_powerup_block_1: [0x40, 454], + LocationName.vanilla_dome_castle_life_block_3: [0x40, 455], + LocationName.vanilla_dome_castle_green_block_1: [0x40, 456], + LocationName.forest_ghost_house_coin_block_1: [0x41, 457], + LocationName.forest_ghost_house_powerup_block_1: [0x41, 458], + LocationName.forest_ghost_house_flying_block_1: [0x41, 459], + LocationName.forest_ghost_house_powerup_block_2: [0x41, 460], + LocationName.forest_ghost_house_life_block_1: [0x41, 461], + LocationName.forest_of_illusion_1_powerup_block_1: [0x42, 462], + LocationName.forest_of_illusion_1_yoshi_block_1: [0x42, 463], + LocationName.forest_of_illusion_1_powerup_block_2: [0x42, 464], + LocationName.forest_of_illusion_1_key_block_1: [0x42, 465], + LocationName.forest_of_illusion_1_life_block_1: [0x42, 466], + LocationName.forest_of_illusion_4_multi_coin_block_1: [0x43, 467], + LocationName.forest_of_illusion_4_coin_block_1: [0x43, 468], + LocationName.forest_of_illusion_4_coin_block_2: [0x43, 469], + LocationName.forest_of_illusion_4_coin_block_3: [0x43, 470], + LocationName.forest_of_illusion_4_coin_block_4: [0x43, 471], + LocationName.forest_of_illusion_4_powerup_block_1: [0x43, 472], + LocationName.forest_of_illusion_4_coin_block_5: [0x43, 473], + LocationName.forest_of_illusion_4_coin_block_6: [0x43, 474], + LocationName.forest_of_illusion_4_coin_block_7: [0x43, 475], + LocationName.forest_of_illusion_4_powerup_block_2: [0x43, 476], + LocationName.forest_of_illusion_4_coin_block_8: [0x43, 477], + LocationName.forest_of_illusion_4_coin_block_9: [0x43, 478], + LocationName.forest_of_illusion_4_coin_block_10: [0x43, 479], + LocationName.forest_of_illusion_2_green_block_1: [0x44, 480], + LocationName.forest_of_illusion_2_powerup_block_1: [0x44, 481], + LocationName.forest_of_illusion_2_invis_coin_block_1: [0x44, 482], + LocationName.forest_of_illusion_2_invis_coin_block_2: [0x44, 483], + LocationName.forest_of_illusion_2_invis_life_block_1: [0x44, 484], + LocationName.forest_of_illusion_2_invis_coin_block_3: [0x44, 485], + LocationName.forest_of_illusion_2_yellow_block_1: [0x44, 486], + LocationName.forest_secret_powerup_block_1: [0x46, 487], + LocationName.forest_secret_powerup_block_2: [0x46, 488], + LocationName.forest_secret_life_block_1: [0x46, 489], + LocationName.forest_of_illusion_3_yoshi_block_1: [0x47, 490], + LocationName.forest_of_illusion_3_coin_block_1: [0x47, 491], + LocationName.forest_of_illusion_3_multi_coin_block_1: [0x47, 492], + LocationName.forest_of_illusion_3_coin_block_2: [0x47, 493], + LocationName.forest_of_illusion_3_multi_coin_block_2: [0x47, 494], + LocationName.forest_of_illusion_3_coin_block_3: [0x47, 495], + LocationName.forest_of_illusion_3_coin_block_4: [0x47, 496], + LocationName.forest_of_illusion_3_coin_block_5: [0x47, 497], + LocationName.forest_of_illusion_3_coin_block_6: [0x47, 498], + LocationName.forest_of_illusion_3_coin_block_7: [0x47, 499], + LocationName.forest_of_illusion_3_coin_block_8: [0x47, 500], + LocationName.forest_of_illusion_3_coin_block_9: [0x47, 501], + LocationName.forest_of_illusion_3_coin_block_10: [0x47, 502], + LocationName.forest_of_illusion_3_coin_block_11: [0x47, 503], + LocationName.forest_of_illusion_3_coin_block_12: [0x47, 504], + LocationName.forest_of_illusion_3_coin_block_13: [0x47, 505], + LocationName.forest_of_illusion_3_coin_block_14: [0x47, 506], + LocationName.forest_of_illusion_3_coin_block_15: [0x47, 507], + LocationName.forest_of_illusion_3_coin_block_16: [0x47, 508], + LocationName.forest_of_illusion_3_coin_block_17: [0x47, 509], + LocationName.forest_of_illusion_3_coin_block_18: [0x47, 510], + LocationName.forest_of_illusion_3_coin_block_19: [0x47, 511], + LocationName.forest_of_illusion_3_coin_block_20: [0x47, 512], + LocationName.forest_of_illusion_3_coin_block_21: [0x47, 513], + LocationName.forest_of_illusion_3_coin_block_22: [0x47, 514], + LocationName.forest_of_illusion_3_coin_block_23: [0x47, 515], + LocationName.forest_of_illusion_3_coin_block_24: [0x47, 516], + LocationName.special_zone_8_yoshi_block_1: [0x49, 517], + LocationName.special_zone_8_coin_block_1: [0x49, 518], + LocationName.special_zone_8_coin_block_2: [0x49, 519], + LocationName.special_zone_8_coin_block_3: [0x49, 520], + LocationName.special_zone_8_coin_block_4: [0x49, 521], + LocationName.special_zone_8_coin_block_5: [0x49, 522], + LocationName.special_zone_8_blue_pow_block_1: [0x49, 523], + LocationName.special_zone_8_powerup_block_1: [0x49, 524], + LocationName.special_zone_8_star_block_1: [0x49, 525], + LocationName.special_zone_8_coin_block_6: [0x49, 526], + LocationName.special_zone_8_coin_block_7: [0x49, 527], + LocationName.special_zone_8_coin_block_8: [0x49, 528], + LocationName.special_zone_8_coin_block_9: [0x49, 529], + LocationName.special_zone_8_coin_block_10: [0x49, 530], + LocationName.special_zone_8_coin_block_11: [0x49, 531], + LocationName.special_zone_8_coin_block_12: [0x49, 532], + LocationName.special_zone_8_coin_block_13: [0x49, 533], + LocationName.special_zone_8_coin_block_14: [0x49, 534], + LocationName.special_zone_8_coin_block_15: [0x49, 535], + LocationName.special_zone_8_coin_block_16: [0x49, 536], + LocationName.special_zone_8_coin_block_17: [0x49, 537], + LocationName.special_zone_8_coin_block_18: [0x49, 538], + LocationName.special_zone_8_multi_coin_block_1: [0x49, 539], + LocationName.special_zone_8_coin_block_19: [0x49, 540], + LocationName.special_zone_8_coin_block_20: [0x49, 541], + LocationName.special_zone_8_coin_block_21: [0x49, 542], + LocationName.special_zone_8_coin_block_22: [0x49, 543], + LocationName.special_zone_8_coin_block_23: [0x49, 544], + LocationName.special_zone_8_powerup_block_2: [0x49, 545], + LocationName.special_zone_8_flying_block_1: [0x49, 546], + LocationName.special_zone_7_powerup_block_1: [0x4A, 547], + LocationName.special_zone_7_yoshi_block_1: [0x4A, 548], + LocationName.special_zone_7_coin_block_1: [0x4A, 549], + LocationName.special_zone_7_powerup_block_2: [0x4A, 550], + LocationName.special_zone_7_coin_block_2: [0x4A, 551], + LocationName.special_zone_6_powerup_block_1: [0x4B, 552], + LocationName.special_zone_6_coin_block_1: [0x4B, 553], + LocationName.special_zone_6_coin_block_2: [0x4B, 554], + LocationName.special_zone_6_yoshi_block_1: [0x4B, 555], + LocationName.special_zone_6_life_block_1: [0x4B, 556], + LocationName.special_zone_6_multi_coin_block_1: [0x4B, 557], + LocationName.special_zone_6_coin_block_3: [0x4B, 558], + LocationName.special_zone_6_coin_block_4: [0x4B, 559], + LocationName.special_zone_6_coin_block_5: [0x4B, 560], + LocationName.special_zone_6_coin_block_6: [0x4B, 561], + LocationName.special_zone_6_coin_block_7: [0x4B, 562], + LocationName.special_zone_6_coin_block_8: [0x4B, 563], + LocationName.special_zone_6_coin_block_9: [0x4B, 564], + LocationName.special_zone_6_coin_block_10: [0x4B, 565], + LocationName.special_zone_6_coin_block_11: [0x4B, 566], + LocationName.special_zone_6_coin_block_12: [0x4B, 567], + LocationName.special_zone_6_coin_block_13: [0x4B, 568], + LocationName.special_zone_6_coin_block_14: [0x4B, 569], + LocationName.special_zone_6_coin_block_15: [0x4B, 570], + LocationName.special_zone_6_coin_block_16: [0x4B, 571], + LocationName.special_zone_6_coin_block_17: [0x4B, 572], + LocationName.special_zone_6_coin_block_18: [0x4B, 573], + LocationName.special_zone_6_coin_block_19: [0x4B, 574], + LocationName.special_zone_6_coin_block_20: [0x4B, 575], + LocationName.special_zone_6_coin_block_21: [0x4B, 576], + LocationName.special_zone_6_coin_block_22: [0x4B, 577], + LocationName.special_zone_6_coin_block_23: [0x4B, 578], + LocationName.special_zone_6_coin_block_24: [0x4B, 579], + LocationName.special_zone_6_coin_block_25: [0x4B, 580], + LocationName.special_zone_6_coin_block_26: [0x4B, 581], + LocationName.special_zone_6_coin_block_27: [0x4B, 582], + LocationName.special_zone_6_coin_block_28: [0x4B, 583], + LocationName.special_zone_6_powerup_block_2: [0x4B, 584], + LocationName.special_zone_6_coin_block_29: [0x4B, 585], + LocationName.special_zone_6_coin_block_30: [0x4B, 586], + LocationName.special_zone_6_coin_block_31: [0x4B, 587], + LocationName.special_zone_6_coin_block_32: [0x4B, 588], + LocationName.special_zone_6_coin_block_33: [0x4B, 589], + LocationName.special_zone_5_yoshi_block_1: [0x4C, 590], + LocationName.special_zone_1_vine_block_1: [0x4E, 591], + LocationName.special_zone_1_vine_block_2: [0x4E, 592], + LocationName.special_zone_1_vine_block_3: [0x4E, 593], + LocationName.special_zone_1_vine_block_4: [0x4E, 594], + LocationName.special_zone_1_life_block_1: [0x4E, 595], + LocationName.special_zone_1_vine_block_5: [0x4E, 596], + LocationName.special_zone_1_blue_pow_block_1: [0x4E, 597], + LocationName.special_zone_1_vine_block_6: [0x4E, 598], + LocationName.special_zone_1_powerup_block_1: [0x4E, 599], + LocationName.special_zone_1_pswitch_coin_block_1: [0x4E, 600], + LocationName.special_zone_1_pswitch_coin_block_2: [0x4E, 601], + LocationName.special_zone_1_pswitch_coin_block_3: [0x4E, 602], + LocationName.special_zone_1_pswitch_coin_block_4: [0x4E, 603], + LocationName.special_zone_1_pswitch_coin_block_5: [0x4E, 604], + LocationName.special_zone_1_pswitch_coin_block_6: [0x4E, 605], + LocationName.special_zone_1_pswitch_coin_block_7: [0x4E, 606], + LocationName.special_zone_1_pswitch_coin_block_8: [0x4E, 607], + LocationName.special_zone_1_pswitch_coin_block_9: [0x4E, 608], + LocationName.special_zone_1_pswitch_coin_block_10: [0x4E, 609], + LocationName.special_zone_1_pswitch_coin_block_11: [0x4E, 610], + LocationName.special_zone_1_pswitch_coin_block_12: [0x4E, 611], + LocationName.special_zone_1_pswitch_coin_block_13: [0x4E, 612], + LocationName.special_zone_2_powerup_block_1: [0x4F, 613], + LocationName.special_zone_2_coin_block_1: [0x4F, 614], + LocationName.special_zone_2_coin_block_2: [0x4F, 615], + LocationName.special_zone_2_powerup_block_2: [0x4F, 616], + LocationName.special_zone_2_coin_block_3: [0x4F, 617], + LocationName.special_zone_2_coin_block_4: [0x4F, 618], + LocationName.special_zone_2_powerup_block_3: [0x4F, 619], + LocationName.special_zone_2_multi_coin_block_1: [0x4F, 620], + LocationName.special_zone_2_coin_block_5: [0x4F, 621], + LocationName.special_zone_2_coin_block_6: [0x4F, 622], + LocationName.special_zone_3_powerup_block_1: [0x50, 623], + LocationName.special_zone_3_yoshi_block_1: [0x50, 624], + LocationName.special_zone_3_wings_block_1: [0x50, 625], + LocationName.special_zone_4_powerup_block_1: [0x51, 626], + LocationName.special_zone_4_star_block_1: [0x51, 627], + LocationName.star_road_2_star_block_1: [0x54, 628], + LocationName.star_road_3_key_block_1: [0x56, 629], + LocationName.star_road_4_powerup_block_1: [0x59, 630], + LocationName.star_road_4_green_block_1: [0x59, 631], + LocationName.star_road_4_green_block_2: [0x59, 632], + LocationName.star_road_4_green_block_3: [0x59, 633], + LocationName.star_road_4_green_block_4: [0x59, 634], + LocationName.star_road_4_green_block_5: [0x59, 635], + LocationName.star_road_4_green_block_6: [0x59, 636], + LocationName.star_road_4_green_block_7: [0x59, 637], + LocationName.star_road_4_key_block_1: [0x59, 638], + LocationName.star_road_5_directional_coin_block_1: [0x5A, 639], + LocationName.star_road_5_life_block_1: [0x5A, 640], + LocationName.star_road_5_vine_block_1: [0x5A, 641], + LocationName.star_road_5_yellow_block_1: [0x5A, 642], + LocationName.star_road_5_yellow_block_2: [0x5A, 643], + LocationName.star_road_5_yellow_block_3: [0x5A, 644], + LocationName.star_road_5_yellow_block_4: [0x5A, 645], + LocationName.star_road_5_yellow_block_5: [0x5A, 646], + LocationName.star_road_5_yellow_block_6: [0x5A, 647], + LocationName.star_road_5_yellow_block_7: [0x5A, 648], + LocationName.star_road_5_yellow_block_8: [0x5A, 649], + LocationName.star_road_5_yellow_block_9: [0x5A, 650], + LocationName.star_road_5_yellow_block_10: [0x5A, 651], + LocationName.star_road_5_yellow_block_11: [0x5A, 652], + LocationName.star_road_5_yellow_block_12: [0x5A, 653], + LocationName.star_road_5_yellow_block_13: [0x5A, 654], + LocationName.star_road_5_yellow_block_14: [0x5A, 655], + LocationName.star_road_5_yellow_block_15: [0x5A, 656], + LocationName.star_road_5_yellow_block_16: [0x5A, 657], + LocationName.star_road_5_yellow_block_17: [0x5A, 658], + LocationName.star_road_5_yellow_block_18: [0x5A, 659], + LocationName.star_road_5_yellow_block_19: [0x5A, 660], + LocationName.star_road_5_yellow_block_20: [0x5A, 661], + LocationName.star_road_5_green_block_1: [0x5A, 662], + LocationName.star_road_5_green_block_2: [0x5A, 663], + LocationName.star_road_5_green_block_3: [0x5A, 664], + LocationName.star_road_5_green_block_4: [0x5A, 665], + LocationName.star_road_5_green_block_5: [0x5A, 666], + LocationName.star_road_5_green_block_6: [0x5A, 667], + LocationName.star_road_5_green_block_7: [0x5A, 668], + LocationName.star_road_5_green_block_8: [0x5A, 669], + LocationName.star_road_5_green_block_9: [0x5A, 670], + LocationName.star_road_5_green_block_10: [0x5A, 671], + LocationName.star_road_5_green_block_11: [0x5A, 672], + LocationName.star_road_5_green_block_12: [0x5A, 673], + LocationName.star_road_5_green_block_13: [0x5A, 674], + LocationName.star_road_5_green_block_14: [0x5A, 675], + LocationName.star_road_5_green_block_15: [0x5A, 676], + LocationName.star_road_5_green_block_16: [0x5A, 677], + LocationName.star_road_5_green_block_17: [0x5A, 678], + LocationName.star_road_5_green_block_18: [0x5A, 679], + LocationName.star_road_5_green_block_19: [0x5A, 680], + LocationName.star_road_5_green_block_20: [0x5A, 681] } -def generate_level_list(world, player): +def generate_level_list(world: World): - if not world.level_shuffle[player]: + if not world.options.level_shuffle: out_level_list = full_level_list.copy() out_level_list[0x00] = 0x03 out_level_list[0x11] = 0x28 - if world.bowser_castle_doors[player] == "fast": + if world.options.bowser_castle_doors == "fast": out_level_list[0x41] = 0x82 out_level_list[0x42] = 0x32 - elif world.bowser_castle_doors[player] == "slow": + elif world.options.bowser_castle_doors == "slow": out_level_list[0x41] = 0x31 out_level_list[0x42] = 0x81 @@ -552,7 +1258,7 @@ def generate_level_list(world, player): shuffled_level_list.append(0x16) single_levels_copy = (easy_single_levels_copy.copy() + hard_single_levels_copy.copy()) - if not world.exclude_special_zone[player]: + if not world.options.exclude_special_zone: single_levels_copy.extend(special_zone_levels_copy) world.random.shuffle(single_levels_copy) @@ -619,10 +1325,10 @@ def generate_level_list(world, player): shuffled_level_list.append(castle_fortress_levels_copy.pop(0)) # Front/Back Door - if world.bowser_castle_doors[player] == "fast": + if world.options.bowser_castle_doors == "fast": shuffled_level_list.append(0x82) shuffled_level_list.append(0x32) - elif world.bowser_castle_doors[player] == "slow": + elif world.options.bowser_castle_doors == "slow": shuffled_level_list.append(0x31) shuffled_level_list.append(0x81) else: @@ -646,7 +1352,7 @@ def generate_level_list(world, player): # Special Zone shuffled_level_list.append(0x4D) - if not world.exclude_special_zone[player]: + if not world.options.exclude_special_zone: shuffled_level_list.append(single_levels_copy.pop(0)) shuffled_level_list.append(single_levels_copy.pop(0)) shuffled_level_list.append(single_levels_copy.pop(0)) diff --git a/worlds/smw/Locations.py b/worlds/smw/Locations.py index a8b7f7a4ec..47e821fc61 100644 --- a/worlds/smw/Locations.py +++ b/worlds/smw/Locations.py @@ -1,9 +1,9 @@ import typing from BaseClasses import Location +from worlds.AutoWorld import World from .Names import LocationName - class SMWLocation(Location): game: str = "Super Mario World" @@ -197,6 +197,624 @@ dragon_coin_location_table = { LocationName.special_zone_8_dragon: 0xBC0162, } +moon_location_table = { + LocationName.yoshis_island_1_moon: 0xBC0300, + LocationName.donut_plains_4_moon: 0xBC030B, + LocationName.vanilla_dome_3_moon: 0xBC0318, + LocationName.cheese_bridge_moon: 0xBC0325, + LocationName.forest_ghost_house_moon: 0xBC0332, + LocationName.chocolate_island_1_moon: 0xBC0338, + LocationName.valley_of_bowser_1_moon: 0xBC0345 +} + +hidden_1ups_location_table = { + LocationName.yoshis_island_4_hidden_1up: 0xBC0403, + LocationName.donut_plains_1_hidden_1up: 0xBC0406, + LocationName.donut_plains_4_hidden_1up: 0xBC040B, + LocationName.donut_plains_castle_hidden_1up: 0xBC0412, + LocationName.vanilla_dome_4_hidden_1up: 0xBC0419, + LocationName.vanilla_ghost_house_hidden_1up: 0xBC041E, + LocationName.vanilla_fortress_hidden_1up: 0xBC0420, + LocationName.cookie_mountain_hidden_1up: 0xBC0427, + LocationName.forest_of_illusion_3_hidden_1up: 0xBC042E, + LocationName.chocolate_island_2_hidden_1up: 0xBC0439, + LocationName.chocolate_castle_hidden_1up: 0xBC0443, + LocationName.valley_of_bowser_2_hidden_1up: 0xBC0446, + LocationName.valley_castle_hidden_1up: 0xBC044F, + LocationName.special_zone_1_hidden_1up: 0xBC045B +} +bonus_block_location_table = { + LocationName.yoshis_island_3_bonus_block: 0xBC0502, + LocationName.donut_plains_3_bonus_block: 0xBC050A, + LocationName.butter_bridge_1_bonus_block: 0xBC0523, + LocationName.chocolate_island_3_bonus_block: 0xBC053B +} + +blocksanity_location_table = { + LocationName.vanilla_secret_2_yoshi_block_1: 0xBC0600, + LocationName.vanilla_secret_2_green_block_1: 0xBC0601, + LocationName.vanilla_secret_2_powerup_block_1: 0xBC0602, + LocationName.vanilla_secret_2_powerup_block_2: 0xBC0603, + LocationName.vanilla_secret_2_multi_coin_block_1: 0xBC0604, + LocationName.vanilla_secret_2_gray_pow_block_1: 0xBC0605, + LocationName.vanilla_secret_2_coin_block_1: 0xBC0606, + LocationName.vanilla_secret_2_coin_block_2: 0xBC0607, + LocationName.vanilla_secret_2_coin_block_3: 0xBC0608, + LocationName.vanilla_secret_2_coin_block_4: 0xBC0609, + LocationName.vanilla_secret_2_coin_block_5: 0xBC060A, + LocationName.vanilla_secret_2_coin_block_6: 0xBC060B, + LocationName.vanilla_secret_3_powerup_block_1: 0xBC060C, + LocationName.vanilla_secret_3_powerup_block_2: 0xBC060D, + LocationName.donut_ghost_house_vine_block_1: 0xBC060E, + LocationName.donut_ghost_house_directional_coin_block_1: 0xBC060F, + LocationName.donut_ghost_house_life_block_1: 0xBC0610, + LocationName.donut_ghost_house_life_block_2: 0xBC0611, + LocationName.donut_ghost_house_life_block_3: 0xBC0612, + LocationName.donut_ghost_house_life_block_4: 0xBC0613, + LocationName.donut_plains_3_green_block_1: 0xBC0614, + LocationName.donut_plains_3_coin_block_1: 0xBC0615, + LocationName.donut_plains_3_coin_block_2: 0xBC0616, + LocationName.donut_plains_3_vine_block_1: 0xBC0617, + LocationName.donut_plains_3_powerup_block_1: 0xBC0618, + LocationName.donut_plains_3_bonus_block_1: 0xBC0619, + LocationName.donut_plains_4_coin_block_1: 0xBC061A, + LocationName.donut_plains_4_powerup_block_1: 0xBC061B, + LocationName.donut_plains_4_coin_block_2: 0xBC061C, + LocationName.donut_plains_4_yoshi_block_1: 0xBC061D, + LocationName.donut_plains_castle_yellow_block_1: 0xBC061E, + LocationName.donut_plains_castle_coin_block_1: 0xBC061F, + LocationName.donut_plains_castle_powerup_block_1: 0xBC0620, + LocationName.donut_plains_castle_coin_block_2: 0xBC0621, + LocationName.donut_plains_castle_vine_block_1: 0xBC0622, + LocationName.donut_plains_castle_invis_life_block_1: 0xBC0623, + LocationName.donut_plains_castle_coin_block_3: 0xBC0624, + LocationName.donut_plains_castle_coin_block_4: 0xBC0625, + LocationName.donut_plains_castle_coin_block_5: 0xBC0626, + LocationName.donut_plains_castle_green_block_1: 0xBC0627, + LocationName.donut_plains_2_coin_block_1: 0xBC0628, + LocationName.donut_plains_2_coin_block_2: 0xBC0629, + LocationName.donut_plains_2_coin_block_3: 0xBC062A, + LocationName.donut_plains_2_yellow_block_1: 0xBC062B, + LocationName.donut_plains_2_powerup_block_1: 0xBC062C, + LocationName.donut_plains_2_multi_coin_block_1: 0xBC062D, + LocationName.donut_plains_2_flying_block_1: 0xBC062E, + LocationName.donut_plains_2_green_block_1: 0xBC062F, + LocationName.donut_plains_2_yellow_block_2: 0xBC0630, + LocationName.donut_plains_2_vine_block_1: 0xBC0631, + LocationName.donut_secret_1_coin_block_1: 0xBC0632, + LocationName.donut_secret_1_coin_block_2: 0xBC0633, + LocationName.donut_secret_1_powerup_block_1: 0xBC0634, + LocationName.donut_secret_1_coin_block_3: 0xBC0635, + LocationName.donut_secret_1_powerup_block_2: 0xBC0636, + LocationName.donut_secret_1_powerup_block_3: 0xBC0637, + LocationName.donut_secret_1_life_block_1: 0xBC0638, + LocationName.donut_secret_1_powerup_block_4: 0xBC0639, + LocationName.donut_secret_1_powerup_block_5: 0xBC063A, + LocationName.donut_secret_1_key_block_1: 0xBC063B, + LocationName.vanilla_fortress_powerup_block_1: 0xBC063C, + LocationName.vanilla_fortress_powerup_block_2: 0xBC063D, + LocationName.vanilla_fortress_yellow_block_1: 0xBC063E, + LocationName.butter_bridge_1_powerup_block_1: 0xBC063F, + LocationName.butter_bridge_1_multi_coin_block_1: 0xBC0640, + LocationName.butter_bridge_1_multi_coin_block_2: 0xBC0641, + LocationName.butter_bridge_1_multi_coin_block_3: 0xBC0642, + LocationName.butter_bridge_1_life_block_1: 0xBC0643, + LocationName.butter_bridge_1_bonus_block_1: 0xBC0644, + LocationName.butter_bridge_2_powerup_block_1: 0xBC0645, + LocationName.butter_bridge_2_green_block_1: 0xBC0646, + LocationName.butter_bridge_2_yoshi_block_1: 0xBC0647, + LocationName.twin_bridges_castle_powerup_block_1: 0xBC0648, + LocationName.cheese_bridge_powerup_block_1: 0xBC0649, + LocationName.cheese_bridge_powerup_block_2: 0xBC064A, + LocationName.cheese_bridge_wings_block_1: 0xBC064B, + LocationName.cheese_bridge_powerup_block_3: 0xBC064C, + LocationName.cookie_mountain_coin_block_1: 0xBC064D, + LocationName.cookie_mountain_coin_block_2: 0xBC064E, + LocationName.cookie_mountain_coin_block_3: 0xBC064F, + LocationName.cookie_mountain_coin_block_4: 0xBC0650, + LocationName.cookie_mountain_coin_block_5: 0xBC0651, + LocationName.cookie_mountain_coin_block_6: 0xBC0652, + LocationName.cookie_mountain_coin_block_7: 0xBC0653, + LocationName.cookie_mountain_coin_block_8: 0xBC0654, + LocationName.cookie_mountain_coin_block_9: 0xBC0655, + LocationName.cookie_mountain_powerup_block_1: 0xBC0656, + LocationName.cookie_mountain_life_block_1: 0xBC0657, + LocationName.cookie_mountain_vine_block_1: 0xBC0658, + LocationName.cookie_mountain_yoshi_block_1: 0xBC0659, + LocationName.cookie_mountain_coin_block_10: 0xBC065A, + LocationName.cookie_mountain_coin_block_11: 0xBC065B, + LocationName.cookie_mountain_powerup_block_2: 0xBC065C, + LocationName.cookie_mountain_coin_block_12: 0xBC065D, + LocationName.cookie_mountain_coin_block_13: 0xBC065E, + LocationName.cookie_mountain_coin_block_14: 0xBC065F, + LocationName.cookie_mountain_coin_block_15: 0xBC0660, + LocationName.cookie_mountain_coin_block_16: 0xBC0661, + LocationName.cookie_mountain_coin_block_17: 0xBC0662, + LocationName.cookie_mountain_coin_block_18: 0xBC0663, + LocationName.cookie_mountain_coin_block_19: 0xBC0664, + LocationName.cookie_mountain_coin_block_20: 0xBC0665, + LocationName.cookie_mountain_coin_block_21: 0xBC0666, + LocationName.cookie_mountain_coin_block_22: 0xBC0667, + LocationName.cookie_mountain_coin_block_23: 0xBC0668, + LocationName.cookie_mountain_coin_block_24: 0xBC0669, + LocationName.cookie_mountain_coin_block_25: 0xBC066A, + LocationName.cookie_mountain_coin_block_26: 0xBC066B, + LocationName.cookie_mountain_coin_block_27: 0xBC066C, + LocationName.cookie_mountain_coin_block_28: 0xBC066D, + LocationName.cookie_mountain_coin_block_29: 0xBC066E, + LocationName.cookie_mountain_coin_block_30: 0xBC066F, + LocationName.soda_lake_powerup_block_1: 0xBC0670, + LocationName.donut_secret_house_powerup_block_1: 0xBC0671, + LocationName.donut_secret_house_multi_coin_block_1: 0xBC0672, + LocationName.donut_secret_house_life_block_1: 0xBC0673, + LocationName.donut_secret_house_vine_block_1: 0xBC0674, + LocationName.donut_secret_house_directional_coin_block_1: 0xBC0675, + LocationName.donut_plains_1_coin_block_1: 0xBC0676, + LocationName.donut_plains_1_coin_block_2: 0xBC0677, + LocationName.donut_plains_1_yoshi_block_1: 0xBC0678, + LocationName.donut_plains_1_vine_block_1: 0xBC0679, + LocationName.donut_plains_1_green_block_1: 0xBC067A, + LocationName.donut_plains_1_green_block_2: 0xBC067B, + LocationName.donut_plains_1_green_block_3: 0xBC067C, + LocationName.donut_plains_1_green_block_4: 0xBC067D, + LocationName.donut_plains_1_green_block_5: 0xBC067E, + LocationName.donut_plains_1_green_block_6: 0xBC067F, + LocationName.donut_plains_1_green_block_7: 0xBC0680, + LocationName.donut_plains_1_green_block_8: 0xBC0681, + LocationName.donut_plains_1_green_block_9: 0xBC0682, + LocationName.donut_plains_1_green_block_10: 0xBC0683, + LocationName.donut_plains_1_green_block_11: 0xBC0684, + LocationName.donut_plains_1_green_block_12: 0xBC0685, + LocationName.donut_plains_1_green_block_13: 0xBC0686, + LocationName.donut_plains_1_green_block_14: 0xBC0687, + LocationName.donut_plains_1_green_block_15: 0xBC0688, + LocationName.donut_plains_1_green_block_16: 0xBC0689, + LocationName.donut_plains_1_yellow_block_1: 0xBC068A, + LocationName.donut_plains_1_yellow_block_2: 0xBC068B, + LocationName.donut_plains_1_yellow_block_3: 0xBC068C, + LocationName.sunken_ghost_ship_powerup_block_1: 0xBC068D, + LocationName.sunken_ghost_ship_star_block_1: 0xBC068E, + LocationName.chocolate_castle_yellow_block_1: 0xBC068F, + LocationName.chocolate_castle_yellow_block_2: 0xBC0690, + LocationName.chocolate_castle_green_block_1: 0xBC0691, + LocationName.chocolate_fortress_powerup_block_1: 0xBC0692, + LocationName.chocolate_fortress_powerup_block_2: 0xBC0693, + LocationName.chocolate_fortress_coin_block_1: 0xBC0694, + LocationName.chocolate_fortress_coin_block_2: 0xBC0695, + LocationName.chocolate_fortress_green_block_1: 0xBC0696, + LocationName.chocolate_island_5_yoshi_block_1: 0xBC0697, + LocationName.chocolate_island_5_powerup_block_1: 0xBC0698, + LocationName.chocolate_island_5_life_block_1: 0xBC0699, + LocationName.chocolate_island_5_yellow_block_1: 0xBC069A, + LocationName.chocolate_island_4_yellow_block_1: 0xBC069B, + LocationName.chocolate_island_4_blue_pow_block_1: 0xBC069C, + LocationName.chocolate_island_4_powerup_block_1: 0xBC069D, + LocationName.forest_fortress_yellow_block_1: 0xBC069E, + LocationName.forest_fortress_powerup_block_1: 0xBC069F, + LocationName.forest_fortress_life_block_1: 0xBC06A0, + LocationName.forest_fortress_life_block_2: 0xBC06A1, + LocationName.forest_fortress_life_block_3: 0xBC06A2, + LocationName.forest_fortress_life_block_4: 0xBC06A3, + LocationName.forest_fortress_life_block_5: 0xBC06A4, + LocationName.forest_fortress_life_block_6: 0xBC06A5, + LocationName.forest_fortress_life_block_7: 0xBC06A6, + LocationName.forest_fortress_life_block_8: 0xBC06A7, + LocationName.forest_fortress_life_block_9: 0xBC06A8, + LocationName.forest_castle_green_block_1: 0xBC06A9, + LocationName.chocolate_ghost_house_powerup_block_1: 0xBC06AA, + LocationName.chocolate_ghost_house_powerup_block_2: 0xBC06AB, + LocationName.chocolate_ghost_house_life_block_1: 0xBC06AC, + LocationName.chocolate_island_1_flying_block_1: 0xBC06AD, + LocationName.chocolate_island_1_flying_block_2: 0xBC06AE, + LocationName.chocolate_island_1_yoshi_block_1: 0xBC06AF, + LocationName.chocolate_island_1_green_block_1: 0xBC06B0, + LocationName.chocolate_island_1_life_block_1: 0xBC06B1, + LocationName.chocolate_island_3_powerup_block_1: 0xBC06B2, + LocationName.chocolate_island_3_powerup_block_2: 0xBC06B3, + LocationName.chocolate_island_3_powerup_block_3: 0xBC06B4, + LocationName.chocolate_island_3_green_block_1: 0xBC06B5, + LocationName.chocolate_island_3_bonus_block_1: 0xBC06B6, + LocationName.chocolate_island_3_vine_block_1: 0xBC06B7, + LocationName.chocolate_island_3_life_block_1: 0xBC06B8, + LocationName.chocolate_island_3_life_block_2: 0xBC06B9, + LocationName.chocolate_island_3_life_block_3: 0xBC06BA, + LocationName.chocolate_island_2_multi_coin_block_1: 0xBC06BB, + LocationName.chocolate_island_2_invis_coin_block_1: 0xBC06BC, + LocationName.chocolate_island_2_yoshi_block_1: 0xBC06BD, + LocationName.chocolate_island_2_coin_block_1: 0xBC06BE, + LocationName.chocolate_island_2_coin_block_2: 0xBC06BF, + LocationName.chocolate_island_2_multi_coin_block_2: 0xBC06C0, + LocationName.chocolate_island_2_powerup_block_1: 0xBC06C1, + LocationName.chocolate_island_2_blue_pow_block_1: 0xBC06C2, + LocationName.chocolate_island_2_yellow_block_1: 0xBC06C3, + LocationName.chocolate_island_2_yellow_block_2: 0xBC06C4, + LocationName.chocolate_island_2_green_block_1: 0xBC06C5, + LocationName.chocolate_island_2_green_block_2: 0xBC06C6, + LocationName.chocolate_island_2_green_block_3: 0xBC06C7, + LocationName.chocolate_island_2_green_block_4: 0xBC06C8, + LocationName.chocolate_island_2_green_block_5: 0xBC06C9, + LocationName.chocolate_island_2_green_block_6: 0xBC06CA, + LocationName.yoshis_island_castle_coin_block_1: 0xBC06CB, + LocationName.yoshis_island_castle_coin_block_2: 0xBC06CC, + LocationName.yoshis_island_castle_powerup_block_1: 0xBC06CD, + LocationName.yoshis_island_castle_coin_block_3: 0xBC06CE, + LocationName.yoshis_island_castle_coin_block_4: 0xBC06CF, + LocationName.yoshis_island_castle_flying_block_1: 0xBC06D0, + LocationName.yoshis_island_4_yellow_block_1: 0xBC06D1, + LocationName.yoshis_island_4_powerup_block_1: 0xBC06D2, + LocationName.yoshis_island_4_multi_coin_block_1: 0xBC06D3, + LocationName.yoshis_island_4_star_block_1: 0xBC06D4, + LocationName.yoshis_island_3_yellow_block_1: 0xBC06D5, + LocationName.yoshis_island_3_yellow_block_2: 0xBC06D6, + LocationName.yoshis_island_3_yellow_block_3: 0xBC06D7, + LocationName.yoshis_island_3_yellow_block_4: 0xBC06D8, + LocationName.yoshis_island_3_yellow_block_5: 0xBC06D9, + LocationName.yoshis_island_3_yellow_block_6: 0xBC06DA, + LocationName.yoshis_island_3_yellow_block_7: 0xBC06DB, + LocationName.yoshis_island_3_yellow_block_8: 0xBC06DC, + LocationName.yoshis_island_3_yellow_block_9: 0xBC06DD, + LocationName.yoshis_island_3_coin_block_1: 0xBC06DE, + LocationName.yoshis_island_3_yoshi_block_1: 0xBC06DF, + LocationName.yoshis_island_3_coin_block_2: 0xBC06E0, + LocationName.yoshis_island_3_powerup_block_1: 0xBC06E1, + LocationName.yoshis_island_3_yellow_block_10: 0xBC06E2, + LocationName.yoshis_island_3_yellow_block_11: 0xBC06E3, + LocationName.yoshis_island_3_yellow_block_12: 0xBC06E4, + LocationName.yoshis_island_3_bonus_block_1: 0xBC06E5, + LocationName.yoshis_island_1_flying_block_1: 0xBC06E6, + LocationName.yoshis_island_1_yellow_block_1: 0xBC06E7, + LocationName.yoshis_island_1_life_block_1: 0xBC06E8, + LocationName.yoshis_island_1_powerup_block_1: 0xBC06E9, + LocationName.yoshis_island_2_flying_block_1: 0xBC06EA, + LocationName.yoshis_island_2_flying_block_2: 0xBC06EB, + LocationName.yoshis_island_2_flying_block_3: 0xBC06EC, + LocationName.yoshis_island_2_flying_block_4: 0xBC06ED, + LocationName.yoshis_island_2_flying_block_5: 0xBC06EE, + LocationName.yoshis_island_2_flying_block_6: 0xBC06EF, + LocationName.yoshis_island_2_coin_block_1: 0xBC06F0, + LocationName.yoshis_island_2_yellow_block_1: 0xBC06F1, + LocationName.yoshis_island_2_coin_block_2: 0xBC06F2, + LocationName.yoshis_island_2_coin_block_3: 0xBC06F3, + LocationName.yoshis_island_2_yoshi_block_1: 0xBC06F4, + LocationName.yoshis_island_2_coin_block_4: 0xBC06F5, + LocationName.yoshis_island_2_yoshi_block_2: 0xBC06F6, + LocationName.yoshis_island_2_coin_block_5: 0xBC06F7, + LocationName.yoshis_island_2_vine_block_1: 0xBC06F8, + LocationName.yoshis_island_2_yellow_block_2: 0xBC06F9, + LocationName.vanilla_ghost_house_powerup_block_1: 0xBC06FA, + LocationName.vanilla_ghost_house_vine_block_1: 0xBC06FB, + LocationName.vanilla_ghost_house_powerup_block_2: 0xBC06FC, + LocationName.vanilla_ghost_house_multi_coin_block_1: 0xBC06FD, + LocationName.vanilla_ghost_house_blue_pow_block_1: 0xBC06FE, + LocationName.vanilla_secret_1_coin_block_1: 0xBC06FF, + LocationName.vanilla_secret_1_powerup_block_1: 0xBC0700, + LocationName.vanilla_secret_1_multi_coin_block_1: 0xBC0701, + LocationName.vanilla_secret_1_vine_block_1: 0xBC0702, + LocationName.vanilla_secret_1_vine_block_2: 0xBC0703, + LocationName.vanilla_secret_1_coin_block_2: 0xBC0704, + LocationName.vanilla_secret_1_coin_block_3: 0xBC0705, + LocationName.vanilla_secret_1_powerup_block_2: 0xBC0706, + LocationName.vanilla_dome_3_coin_block_1: 0xBC0707, + LocationName.vanilla_dome_3_flying_block_1: 0xBC0708, + LocationName.vanilla_dome_3_flying_block_2: 0xBC0709, + LocationName.vanilla_dome_3_powerup_block_1: 0xBC070A, + LocationName.vanilla_dome_3_flying_block_3: 0xBC070B, + LocationName.vanilla_dome_3_invis_coin_block_1: 0xBC070C, + LocationName.vanilla_dome_3_powerup_block_2: 0xBC070D, + LocationName.vanilla_dome_3_multi_coin_block_1: 0xBC070E, + LocationName.vanilla_dome_3_powerup_block_3: 0xBC070F, + LocationName.vanilla_dome_3_yoshi_block_1: 0xBC0710, + LocationName.vanilla_dome_3_powerup_block_4: 0xBC0711, + LocationName.vanilla_dome_3_pswitch_coin_block_1: 0xBC0712, + LocationName.vanilla_dome_3_pswitch_coin_block_2: 0xBC0713, + LocationName.vanilla_dome_3_pswitch_coin_block_3: 0xBC0714, + LocationName.vanilla_dome_3_pswitch_coin_block_4: 0xBC0715, + LocationName.vanilla_dome_3_pswitch_coin_block_5: 0xBC0716, + LocationName.vanilla_dome_3_pswitch_coin_block_6: 0xBC0717, + LocationName.donut_secret_2_directional_coin_block_1: 0xBC0718, + LocationName.donut_secret_2_vine_block_1: 0xBC0719, + LocationName.donut_secret_2_star_block_1: 0xBC071A, + LocationName.donut_secret_2_powerup_block_1: 0xBC071B, + LocationName.donut_secret_2_star_block_2: 0xBC071C, + LocationName.valley_of_bowser_4_yellow_block_1: 0xBC071D, + LocationName.valley_of_bowser_4_powerup_block_1: 0xBC071E, + LocationName.valley_of_bowser_4_vine_block_1: 0xBC071F, + LocationName.valley_of_bowser_4_yoshi_block_1: 0xBC0720, + LocationName.valley_of_bowser_4_life_block_1: 0xBC0721, + LocationName.valley_of_bowser_4_powerup_block_2: 0xBC0722, + LocationName.valley_castle_yellow_block_1: 0xBC0723, + LocationName.valley_castle_yellow_block_2: 0xBC0724, + LocationName.valley_castle_green_block_1: 0xBC0725, + LocationName.valley_fortress_green_block_1: 0xBC0726, + LocationName.valley_fortress_yellow_block_1: 0xBC0727, + LocationName.valley_of_bowser_3_powerup_block_1: 0xBC0728, + LocationName.valley_of_bowser_3_powerup_block_2: 0xBC0729, + LocationName.valley_ghost_house_pswitch_coin_block_1: 0xBC072A, + LocationName.valley_ghost_house_multi_coin_block_1: 0xBC072B, + LocationName.valley_ghost_house_powerup_block_1: 0xBC072C, + LocationName.valley_ghost_house_directional_coin_block_1: 0xBC072D, + LocationName.valley_of_bowser_2_powerup_block_1: 0xBC072E, + LocationName.valley_of_bowser_2_yellow_block_1: 0xBC072F, + LocationName.valley_of_bowser_2_powerup_block_2: 0xBC0730, + LocationName.valley_of_bowser_2_wings_block_1: 0xBC0731, + LocationName.valley_of_bowser_1_green_block_1: 0xBC0732, + LocationName.valley_of_bowser_1_invis_coin_block_1: 0xBC0733, + LocationName.valley_of_bowser_1_invis_coin_block_2: 0xBC0734, + LocationName.valley_of_bowser_1_invis_coin_block_3: 0xBC0735, + LocationName.valley_of_bowser_1_yellow_block_1: 0xBC0736, + LocationName.valley_of_bowser_1_yellow_block_2: 0xBC0737, + LocationName.valley_of_bowser_1_yellow_block_3: 0xBC0738, + LocationName.valley_of_bowser_1_yellow_block_4: 0xBC0739, + LocationName.valley_of_bowser_1_vine_block_1: 0xBC073A, + LocationName.chocolate_secret_powerup_block_1: 0xBC073B, + LocationName.chocolate_secret_powerup_block_2: 0xBC073C, + LocationName.vanilla_dome_2_coin_block_1: 0xBC073D, + LocationName.vanilla_dome_2_powerup_block_1: 0xBC073E, + LocationName.vanilla_dome_2_coin_block_2: 0xBC073F, + LocationName.vanilla_dome_2_coin_block_3: 0xBC0740, + LocationName.vanilla_dome_2_vine_block_1: 0xBC0741, + LocationName.vanilla_dome_2_invis_life_block_1: 0xBC0742, + LocationName.vanilla_dome_2_coin_block_4: 0xBC0743, + LocationName.vanilla_dome_2_coin_block_5: 0xBC0744, + LocationName.vanilla_dome_2_powerup_block_2: 0xBC0745, + LocationName.vanilla_dome_2_powerup_block_3: 0xBC0746, + LocationName.vanilla_dome_2_powerup_block_4: 0xBC0747, + LocationName.vanilla_dome_2_powerup_block_5: 0xBC0748, + LocationName.vanilla_dome_2_multi_coin_block_1: 0xBC0749, + LocationName.vanilla_dome_2_multi_coin_block_2: 0xBC074A, + LocationName.vanilla_dome_4_powerup_block_1: 0xBC074B, + LocationName.vanilla_dome_4_powerup_block_2: 0xBC074C, + LocationName.vanilla_dome_4_coin_block_1: 0xBC074D, + LocationName.vanilla_dome_4_coin_block_2: 0xBC074E, + LocationName.vanilla_dome_4_coin_block_3: 0xBC074F, + LocationName.vanilla_dome_4_life_block_1: 0xBC0750, + LocationName.vanilla_dome_4_coin_block_4: 0xBC0751, + LocationName.vanilla_dome_4_coin_block_5: 0xBC0752, + LocationName.vanilla_dome_4_coin_block_6: 0xBC0753, + LocationName.vanilla_dome_4_coin_block_7: 0xBC0754, + LocationName.vanilla_dome_4_coin_block_8: 0xBC0755, + LocationName.vanilla_dome_1_flying_block_1: 0xBC0756, + LocationName.vanilla_dome_1_powerup_block_1: 0xBC0757, + LocationName.vanilla_dome_1_powerup_block_2: 0xBC0758, + LocationName.vanilla_dome_1_coin_block_1: 0xBC0759, + LocationName.vanilla_dome_1_life_block_1: 0xBC075A, + LocationName.vanilla_dome_1_powerup_block_3: 0xBC075B, + LocationName.vanilla_dome_1_vine_block_1: 0xBC075C, + LocationName.vanilla_dome_1_star_block_1: 0xBC075D, + LocationName.vanilla_dome_1_powerup_block_4: 0xBC075E, + LocationName.vanilla_dome_1_coin_block_2: 0xBC075F, + LocationName.vanilla_dome_castle_life_block_1: 0xBC0760, + LocationName.vanilla_dome_castle_life_block_2: 0xBC0761, + LocationName.vanilla_dome_castle_powerup_block_1: 0xBC0762, + LocationName.vanilla_dome_castle_life_block_3: 0xBC0763, + LocationName.vanilla_dome_castle_green_block_1: 0xBC0764, + LocationName.forest_ghost_house_coin_block_1: 0xBC0765, + LocationName.forest_ghost_house_powerup_block_1: 0xBC0766, + LocationName.forest_ghost_house_flying_block_1: 0xBC0767, + LocationName.forest_ghost_house_powerup_block_2: 0xBC0768, + LocationName.forest_ghost_house_life_block_1: 0xBC0769, + LocationName.forest_of_illusion_1_powerup_block_1: 0xBC076A, + LocationName.forest_of_illusion_1_yoshi_block_1: 0xBC076B, + LocationName.forest_of_illusion_1_powerup_block_2: 0xBC076C, + LocationName.forest_of_illusion_1_key_block_1: 0xBC076D, + LocationName.forest_of_illusion_1_life_block_1: 0xBC076E, + LocationName.forest_of_illusion_4_multi_coin_block_1: 0xBC076F, + LocationName.forest_of_illusion_4_coin_block_1: 0xBC0770, + LocationName.forest_of_illusion_4_coin_block_2: 0xBC0771, + LocationName.forest_of_illusion_4_coin_block_3: 0xBC0772, + LocationName.forest_of_illusion_4_coin_block_4: 0xBC0773, + LocationName.forest_of_illusion_4_powerup_block_1: 0xBC0774, + LocationName.forest_of_illusion_4_coin_block_5: 0xBC0775, + LocationName.forest_of_illusion_4_coin_block_6: 0xBC0776, + LocationName.forest_of_illusion_4_coin_block_7: 0xBC0777, + LocationName.forest_of_illusion_4_powerup_block_2: 0xBC0778, + LocationName.forest_of_illusion_4_coin_block_8: 0xBC0779, + LocationName.forest_of_illusion_4_coin_block_9: 0xBC077A, + LocationName.forest_of_illusion_4_coin_block_10: 0xBC077B, + LocationName.forest_of_illusion_2_green_block_1: 0xBC077C, + LocationName.forest_of_illusion_2_powerup_block_1: 0xBC077D, + LocationName.forest_of_illusion_2_invis_coin_block_1: 0xBC077E, + LocationName.forest_of_illusion_2_invis_coin_block_2: 0xBC077F, + LocationName.forest_of_illusion_2_invis_life_block_1: 0xBC0780, + LocationName.forest_of_illusion_2_invis_coin_block_3: 0xBC0781, + LocationName.forest_of_illusion_2_yellow_block_1: 0xBC0782, + LocationName.forest_secret_powerup_block_1: 0xBC0783, + LocationName.forest_secret_powerup_block_2: 0xBC0784, + LocationName.forest_secret_life_block_1: 0xBC0785, + LocationName.forest_of_illusion_3_yoshi_block_1: 0xBC0786, + LocationName.forest_of_illusion_3_coin_block_1: 0xBC0787, + LocationName.forest_of_illusion_3_multi_coin_block_1: 0xBC0788, + LocationName.forest_of_illusion_3_coin_block_2: 0xBC0789, + LocationName.forest_of_illusion_3_multi_coin_block_2: 0xBC078A, + LocationName.forest_of_illusion_3_coin_block_3: 0xBC078B, + LocationName.forest_of_illusion_3_coin_block_4: 0xBC078C, + LocationName.forest_of_illusion_3_coin_block_5: 0xBC078D, + LocationName.forest_of_illusion_3_coin_block_6: 0xBC078E, + LocationName.forest_of_illusion_3_coin_block_7: 0xBC078F, + LocationName.forest_of_illusion_3_coin_block_8: 0xBC0790, + LocationName.forest_of_illusion_3_coin_block_9: 0xBC0791, + LocationName.forest_of_illusion_3_coin_block_10: 0xBC0792, + LocationName.forest_of_illusion_3_coin_block_11: 0xBC0793, + LocationName.forest_of_illusion_3_coin_block_12: 0xBC0794, + LocationName.forest_of_illusion_3_coin_block_13: 0xBC0795, + LocationName.forest_of_illusion_3_coin_block_14: 0xBC0796, + LocationName.forest_of_illusion_3_coin_block_15: 0xBC0797, + LocationName.forest_of_illusion_3_coin_block_16: 0xBC0798, + LocationName.forest_of_illusion_3_coin_block_17: 0xBC0799, + LocationName.forest_of_illusion_3_coin_block_18: 0xBC079A, + LocationName.forest_of_illusion_3_coin_block_19: 0xBC079B, + LocationName.forest_of_illusion_3_coin_block_20: 0xBC079C, + LocationName.forest_of_illusion_3_coin_block_21: 0xBC079D, + LocationName.forest_of_illusion_3_coin_block_22: 0xBC079E, + LocationName.forest_of_illusion_3_coin_block_23: 0xBC079F, + LocationName.forest_of_illusion_3_coin_block_24: 0xBC07A0, + LocationName.special_zone_8_yoshi_block_1: 0xBC07A1, + LocationName.special_zone_8_coin_block_1: 0xBC07A2, + LocationName.special_zone_8_coin_block_2: 0xBC07A3, + LocationName.special_zone_8_coin_block_3: 0xBC07A4, + LocationName.special_zone_8_coin_block_4: 0xBC07A5, + LocationName.special_zone_8_coin_block_5: 0xBC07A6, + LocationName.special_zone_8_blue_pow_block_1: 0xBC07A7, + LocationName.special_zone_8_powerup_block_1: 0xBC07A8, + LocationName.special_zone_8_star_block_1: 0xBC07A9, + LocationName.special_zone_8_coin_block_6: 0xBC07AA, + LocationName.special_zone_8_coin_block_7: 0xBC07AB, + LocationName.special_zone_8_coin_block_8: 0xBC07AC, + LocationName.special_zone_8_coin_block_9: 0xBC07AD, + LocationName.special_zone_8_coin_block_10: 0xBC07AE, + LocationName.special_zone_8_coin_block_11: 0xBC07AF, + LocationName.special_zone_8_coin_block_12: 0xBC07B0, + LocationName.special_zone_8_coin_block_13: 0xBC07B1, + LocationName.special_zone_8_coin_block_14: 0xBC07B2, + LocationName.special_zone_8_coin_block_15: 0xBC07B3, + LocationName.special_zone_8_coin_block_16: 0xBC07B4, + LocationName.special_zone_8_coin_block_17: 0xBC07B5, + LocationName.special_zone_8_coin_block_18: 0xBC07B6, + LocationName.special_zone_8_multi_coin_block_1: 0xBC07B7, + LocationName.special_zone_8_coin_block_19: 0xBC07B8, + LocationName.special_zone_8_coin_block_20: 0xBC07B9, + LocationName.special_zone_8_coin_block_21: 0xBC07BA, + LocationName.special_zone_8_coin_block_22: 0xBC07BB, + LocationName.special_zone_8_coin_block_23: 0xBC07BC, + LocationName.special_zone_8_powerup_block_2: 0xBC07BD, + LocationName.special_zone_8_flying_block_1: 0xBC07BE, + LocationName.special_zone_7_powerup_block_1: 0xBC07BF, + LocationName.special_zone_7_yoshi_block_1: 0xBC07C0, + LocationName.special_zone_7_coin_block_1: 0xBC07C1, + LocationName.special_zone_7_powerup_block_2: 0xBC07C2, + LocationName.special_zone_7_coin_block_2: 0xBC07C3, + LocationName.special_zone_6_powerup_block_1: 0xBC07C4, + LocationName.special_zone_6_coin_block_1: 0xBC07C5, + LocationName.special_zone_6_coin_block_2: 0xBC07C6, + LocationName.special_zone_6_yoshi_block_1: 0xBC07C7, + LocationName.special_zone_6_life_block_1: 0xBC07C8, + LocationName.special_zone_6_multi_coin_block_1: 0xBC07C9, + LocationName.special_zone_6_coin_block_3: 0xBC07CA, + LocationName.special_zone_6_coin_block_4: 0xBC07CB, + LocationName.special_zone_6_coin_block_5: 0xBC07CC, + LocationName.special_zone_6_coin_block_6: 0xBC07CD, + LocationName.special_zone_6_coin_block_7: 0xBC07CE, + LocationName.special_zone_6_coin_block_8: 0xBC07CF, + LocationName.special_zone_6_coin_block_9: 0xBC07D0, + LocationName.special_zone_6_coin_block_10: 0xBC07D1, + LocationName.special_zone_6_coin_block_11: 0xBC07D2, + LocationName.special_zone_6_coin_block_12: 0xBC07D3, + LocationName.special_zone_6_coin_block_13: 0xBC07D4, + LocationName.special_zone_6_coin_block_14: 0xBC07D5, + LocationName.special_zone_6_coin_block_15: 0xBC07D6, + LocationName.special_zone_6_coin_block_16: 0xBC07D7, + LocationName.special_zone_6_coin_block_17: 0xBC07D8, + LocationName.special_zone_6_coin_block_18: 0xBC07D9, + LocationName.special_zone_6_coin_block_19: 0xBC07DA, + LocationName.special_zone_6_coin_block_20: 0xBC07DB, + LocationName.special_zone_6_coin_block_21: 0xBC07DC, + LocationName.special_zone_6_coin_block_22: 0xBC07DD, + LocationName.special_zone_6_coin_block_23: 0xBC07DE, + LocationName.special_zone_6_coin_block_24: 0xBC07DF, + LocationName.special_zone_6_coin_block_25: 0xBC07E0, + LocationName.special_zone_6_coin_block_26: 0xBC07E1, + LocationName.special_zone_6_coin_block_27: 0xBC07E2, + LocationName.special_zone_6_coin_block_28: 0xBC07E3, + LocationName.special_zone_6_powerup_block_2: 0xBC07E4, + LocationName.special_zone_6_coin_block_29: 0xBC07E5, + LocationName.special_zone_6_coin_block_30: 0xBC07E6, + LocationName.special_zone_6_coin_block_31: 0xBC07E7, + LocationName.special_zone_6_coin_block_32: 0xBC07E8, + LocationName.special_zone_6_coin_block_33: 0xBC07E9, + LocationName.special_zone_5_yoshi_block_1: 0xBC07EA, + LocationName.special_zone_1_vine_block_1: 0xBC07EB, + LocationName.special_zone_1_vine_block_2: 0xBC07EC, + LocationName.special_zone_1_vine_block_3: 0xBC07ED, + LocationName.special_zone_1_vine_block_4: 0xBC07EE, + LocationName.special_zone_1_life_block_1: 0xBC07EF, + LocationName.special_zone_1_vine_block_5: 0xBC07F0, + LocationName.special_zone_1_blue_pow_block_1: 0xBC07F1, + LocationName.special_zone_1_vine_block_6: 0xBC07F2, + LocationName.special_zone_1_powerup_block_1: 0xBC07F3, + LocationName.special_zone_1_pswitch_coin_block_1: 0xBC07F4, + LocationName.special_zone_1_pswitch_coin_block_2: 0xBC07F5, + LocationName.special_zone_1_pswitch_coin_block_3: 0xBC07F6, + LocationName.special_zone_1_pswitch_coin_block_4: 0xBC07F7, + LocationName.special_zone_1_pswitch_coin_block_5: 0xBC07F8, + LocationName.special_zone_1_pswitch_coin_block_6: 0xBC07F9, + LocationName.special_zone_1_pswitch_coin_block_7: 0xBC07FA, + LocationName.special_zone_1_pswitch_coin_block_8: 0xBC07FB, + LocationName.special_zone_1_pswitch_coin_block_9: 0xBC07FC, + LocationName.special_zone_1_pswitch_coin_block_10: 0xBC07FD, + LocationName.special_zone_1_pswitch_coin_block_11: 0xBC07FE, + LocationName.special_zone_1_pswitch_coin_block_12: 0xBC07FF, + LocationName.special_zone_1_pswitch_coin_block_13: 0xBC0800, + LocationName.special_zone_2_powerup_block_1: 0xBC0801, + LocationName.special_zone_2_coin_block_1: 0xBC0802, + LocationName.special_zone_2_coin_block_2: 0xBC0803, + LocationName.special_zone_2_powerup_block_2: 0xBC0804, + LocationName.special_zone_2_coin_block_3: 0xBC0805, + LocationName.special_zone_2_coin_block_4: 0xBC0806, + LocationName.special_zone_2_powerup_block_3: 0xBC0807, + LocationName.special_zone_2_multi_coin_block_1: 0xBC0808, + LocationName.special_zone_2_coin_block_5: 0xBC0809, + LocationName.special_zone_2_coin_block_6: 0xBC080A, + LocationName.special_zone_3_powerup_block_1: 0xBC080B, + LocationName.special_zone_3_yoshi_block_1: 0xBC080C, + LocationName.special_zone_3_wings_block_1: 0xBC080D, + LocationName.special_zone_4_powerup_block_1: 0xBC080E, + LocationName.special_zone_4_star_block_1: 0xBC080F, + LocationName.star_road_2_star_block_1: 0xBC0810, + LocationName.star_road_3_key_block_1: 0xBC0811, + LocationName.star_road_4_powerup_block_1: 0xBC0812, + LocationName.star_road_4_green_block_1: 0xBC0813, + LocationName.star_road_4_green_block_2: 0xBC0814, + LocationName.star_road_4_green_block_3: 0xBC0815, + LocationName.star_road_4_green_block_4: 0xBC0816, + LocationName.star_road_4_green_block_5: 0xBC0817, + LocationName.star_road_4_green_block_6: 0xBC0818, + LocationName.star_road_4_green_block_7: 0xBC0819, + LocationName.star_road_4_key_block_1: 0xBC081A, + LocationName.star_road_5_directional_coin_block_1: 0xBC081B, + LocationName.star_road_5_life_block_1: 0xBC081C, + LocationName.star_road_5_vine_block_1: 0xBC081D, + LocationName.star_road_5_yellow_block_1: 0xBC081E, + LocationName.star_road_5_yellow_block_2: 0xBC081F, + LocationName.star_road_5_yellow_block_3: 0xBC0820, + LocationName.star_road_5_yellow_block_4: 0xBC0821, + LocationName.star_road_5_yellow_block_5: 0xBC0822, + LocationName.star_road_5_yellow_block_6: 0xBC0823, + LocationName.star_road_5_yellow_block_7: 0xBC0824, + LocationName.star_road_5_yellow_block_8: 0xBC0825, + LocationName.star_road_5_yellow_block_9: 0xBC0826, + LocationName.star_road_5_yellow_block_10: 0xBC0827, + LocationName.star_road_5_yellow_block_11: 0xBC0828, + LocationName.star_road_5_yellow_block_12: 0xBC0829, + LocationName.star_road_5_yellow_block_13: 0xBC082A, + LocationName.star_road_5_yellow_block_14: 0xBC082B, + LocationName.star_road_5_yellow_block_15: 0xBC082C, + LocationName.star_road_5_yellow_block_16: 0xBC082D, + LocationName.star_road_5_yellow_block_17: 0xBC082E, + LocationName.star_road_5_yellow_block_18: 0xBC082F, + LocationName.star_road_5_yellow_block_19: 0xBC0830, + LocationName.star_road_5_yellow_block_20: 0xBC0831, + LocationName.star_road_5_green_block_1: 0xBC0832, + LocationName.star_road_5_green_block_2: 0xBC0833, + LocationName.star_road_5_green_block_3: 0xBC0834, + LocationName.star_road_5_green_block_4: 0xBC0835, + LocationName.star_road_5_green_block_5: 0xBC0836, + LocationName.star_road_5_green_block_6: 0xBC0837, + LocationName.star_road_5_green_block_7: 0xBC0838, + LocationName.star_road_5_green_block_8: 0xBC0839, + LocationName.star_road_5_green_block_9: 0xBC083A, + LocationName.star_road_5_green_block_10: 0xBC083B, + LocationName.star_road_5_green_block_11: 0xBC083C, + LocationName.star_road_5_green_block_12: 0xBC083D, + LocationName.star_road_5_green_block_13: 0xBC083E, + LocationName.star_road_5_green_block_14: 0xBC083F, + LocationName.star_road_5_green_block_15: 0xBC0840, + LocationName.star_road_5_green_block_16: 0xBC0841, + LocationName.star_road_5_green_block_17: 0xBC0842, + LocationName.star_road_5_green_block_18: 0xBC0843, + LocationName.star_road_5_green_block_19: 0xBC0844, + LocationName.star_road_5_green_block_20: 0xBC0845 +} + bowser_location_table = { LocationName.bowser: 0xBC0200, } @@ -208,6 +826,10 @@ yoshi_house_location_table = { all_locations = { **level_location_table, **dragon_coin_location_table, + **moon_location_table, + **hidden_1ups_location_table, + **bonus_block_location_table, + **blocksanity_location_table, **bowser_location_table, **yoshi_house_location_table, } @@ -234,20 +856,149 @@ special_zone_dragon_coin_names = [ LocationName.special_zone_8_dragon, ] +special_zone_hidden_1up_names = [ + LocationName.special_zone_1_hidden_1up +] + +special_zone_blocksanity_names = [ + LocationName.special_zone_8_yoshi_block_1, + LocationName.special_zone_8_coin_block_1, + LocationName.special_zone_8_coin_block_2, + LocationName.special_zone_8_coin_block_3, + LocationName.special_zone_8_coin_block_4, + LocationName.special_zone_8_coin_block_5, + LocationName.special_zone_8_blue_pow_block_1, + LocationName.special_zone_8_powerup_block_1, + LocationName.special_zone_8_star_block_1, + LocationName.special_zone_8_coin_block_6, + LocationName.special_zone_8_coin_block_7, + LocationName.special_zone_8_coin_block_8, + LocationName.special_zone_8_coin_block_9, + LocationName.special_zone_8_coin_block_10, + LocationName.special_zone_8_coin_block_11, + LocationName.special_zone_8_coin_block_12, + LocationName.special_zone_8_coin_block_13, + LocationName.special_zone_8_coin_block_14, + LocationName.special_zone_8_coin_block_15, + LocationName.special_zone_8_coin_block_16, + LocationName.special_zone_8_coin_block_17, + LocationName.special_zone_8_coin_block_18, + LocationName.special_zone_8_multi_coin_block_1, + LocationName.special_zone_8_coin_block_19, + LocationName.special_zone_8_coin_block_20, + LocationName.special_zone_8_coin_block_21, + LocationName.special_zone_8_coin_block_22, + LocationName.special_zone_8_coin_block_23, + LocationName.special_zone_8_powerup_block_2, + LocationName.special_zone_8_flying_block_1, + LocationName.special_zone_7_powerup_block_1, + LocationName.special_zone_7_yoshi_block_1, + LocationName.special_zone_7_coin_block_1, + LocationName.special_zone_7_powerup_block_2, + LocationName.special_zone_7_coin_block_2, + LocationName.special_zone_6_powerup_block_1, + LocationName.special_zone_6_coin_block_1, + LocationName.special_zone_6_coin_block_2, + LocationName.special_zone_6_yoshi_block_1, + LocationName.special_zone_6_life_block_1, + LocationName.special_zone_6_multi_coin_block_1, + LocationName.special_zone_6_coin_block_3, + LocationName.special_zone_6_coin_block_4, + LocationName.special_zone_6_coin_block_5, + LocationName.special_zone_6_coin_block_6, + LocationName.special_zone_6_coin_block_7, + LocationName.special_zone_6_coin_block_8, + LocationName.special_zone_6_coin_block_9, + LocationName.special_zone_6_coin_block_10, + LocationName.special_zone_6_coin_block_11, + LocationName.special_zone_6_coin_block_12, + LocationName.special_zone_6_coin_block_13, + LocationName.special_zone_6_coin_block_14, + LocationName.special_zone_6_coin_block_15, + LocationName.special_zone_6_coin_block_16, + LocationName.special_zone_6_coin_block_17, + LocationName.special_zone_6_coin_block_18, + LocationName.special_zone_6_coin_block_19, + LocationName.special_zone_6_coin_block_20, + LocationName.special_zone_6_coin_block_21, + LocationName.special_zone_6_coin_block_22, + LocationName.special_zone_6_coin_block_23, + LocationName.special_zone_6_coin_block_24, + LocationName.special_zone_6_coin_block_25, + LocationName.special_zone_6_coin_block_26, + LocationName.special_zone_6_coin_block_27, + LocationName.special_zone_6_coin_block_28, + LocationName.special_zone_6_powerup_block_2, + LocationName.special_zone_6_coin_block_29, + LocationName.special_zone_6_coin_block_30, + LocationName.special_zone_6_coin_block_31, + LocationName.special_zone_6_coin_block_32, + LocationName.special_zone_6_coin_block_33, + LocationName.special_zone_5_yoshi_block_1, + LocationName.special_zone_1_vine_block_1, + LocationName.special_zone_1_vine_block_2, + LocationName.special_zone_1_vine_block_3, + LocationName.special_zone_1_vine_block_4, + LocationName.special_zone_1_life_block_1, + LocationName.special_zone_1_vine_block_5, + LocationName.special_zone_1_blue_pow_block_1, + LocationName.special_zone_1_vine_block_6, + LocationName.special_zone_1_powerup_block_1, + LocationName.special_zone_1_pswitch_coin_block_1, + LocationName.special_zone_1_pswitch_coin_block_2, + LocationName.special_zone_1_pswitch_coin_block_3, + LocationName.special_zone_1_pswitch_coin_block_4, + LocationName.special_zone_1_pswitch_coin_block_5, + LocationName.special_zone_1_pswitch_coin_block_6, + LocationName.special_zone_1_pswitch_coin_block_7, + LocationName.special_zone_1_pswitch_coin_block_8, + LocationName.special_zone_1_pswitch_coin_block_9, + LocationName.special_zone_1_pswitch_coin_block_10, + LocationName.special_zone_1_pswitch_coin_block_11, + LocationName.special_zone_1_pswitch_coin_block_12, + LocationName.special_zone_1_pswitch_coin_block_13, + LocationName.special_zone_2_powerup_block_1, + LocationName.special_zone_2_coin_block_1, + LocationName.special_zone_2_coin_block_2, + LocationName.special_zone_2_powerup_block_2, + LocationName.special_zone_2_coin_block_3, + LocationName.special_zone_2_coin_block_4, + LocationName.special_zone_2_powerup_block_3, + LocationName.special_zone_2_multi_coin_block_1, + LocationName.special_zone_2_coin_block_5, + LocationName.special_zone_2_coin_block_6, + LocationName.special_zone_3_powerup_block_1, + LocationName.special_zone_3_yoshi_block_1, + LocationName.special_zone_3_wings_block_1, + LocationName.special_zone_4_powerup_block_1, + LocationName.special_zone_4_star_block_1 +] + location_table = {} -def setup_locations(world, player: int): +def setup_locations(world: World): location_table = {**level_location_table} - # Dragon Coins here - if world.dragon_coin_checks[player].value: - location_table.update({**dragon_coin_location_table}) + if world.options.dragon_coin_checks: + location_table.update(dragon_coin_location_table) - if world.goal[player] == "yoshi_egg_hunt": - location_table.update({**yoshi_house_location_table}) + if world.options.moon_checks: + location_table.update(moon_location_table) + + if world.options.hidden_1up_checks: + location_table.update(hidden_1ups_location_table) + + if world.options.bonus_block_checks: + location_table.update(bonus_block_location_table) + + if world.options.blocksanity: + location_table.update(blocksanity_location_table) + + if world.options.goal == "yoshi_egg_hunt": + location_table.update(yoshi_house_location_table) else: - location_table.update({**bowser_location_table}) + location_table.update(bowser_location_table) return location_table diff --git a/worlds/smw/Names/ItemName.py b/worlds/smw/Names/ItemName.py index fecb18685e..e6eced4100 100644 --- a/worlds/smw/Names/ItemName.py +++ b/worlds/smw/Names/ItemName.py @@ -1,5 +1,9 @@ # Junk Definitions one_up_mushroom = "1-Up Mushroom" +one_coin = "1 coin" +five_coins = "5 coins" +ten_coins = "10 coins" +fifty_coins = "50 coins" # Collectable Definitions yoshi_egg = "Yoshi Egg" @@ -22,11 +26,16 @@ green_switch_palace = "Green Switch Palace" red_switch_palace = "Red Switch Palace" blue_switch_palace = "Blue Switch Palace" +# Special Zone clear flag definition +special_world_clear = "Special Zone Clear" + # Trap Definitions -ice_trap = "Ice Trap" -stun_trap = "Stun Trap" -literature_trap = "Literature Trap" -timer_trap = "Timer Trap" +ice_trap = "Ice Trap" +stun_trap = "Stun Trap" +literature_trap = "Literature Trap" +timer_trap = "Timer Trap" +reverse_controls_trap = "Reverse Trap" +thwimp_trap = "Thwimp Trap" # Other Definitions victory = "The Princess" diff --git a/worlds/smw/Names/LocationName.py b/worlds/smw/Names/LocationName.py index cc01b05ece..847b724f78 100644 --- a/worlds/smw/Names/LocationName.py +++ b/worlds/smw/Names/LocationName.py @@ -4,12 +4,15 @@ yoshis_house_tile = "Yoshi's House - Tile" yoshis_island_1_exit_1 = "Yoshi's Island 1 - Normal Exit" yoshis_island_1_dragon = "Yoshi's Island 1 - Dragon Coins" +yoshis_island_1_moon = "Yoshi's Island 1 - 3-Up Moon" yoshis_island_2_exit_1 = "Yoshi's Island 2 - Normal Exit" yoshis_island_2_dragon = "Yoshi's Island 2 - Dragon Coins" yoshis_island_3_exit_1 = "Yoshi's Island 3 - Normal Exit" yoshis_island_3_dragon = "Yoshi's Island 3 - Dragon Coins" +yoshis_island_3_bonus_block = "Yoshi's Island 3 - 1-Up from Bonus Block" yoshis_island_4_exit_1 = "Yoshi's Island 4 - Normal Exit" yoshis_island_4_dragon = "Yoshi's Island 4 - Dragon Coins" +yoshis_island_4_hidden_1up = "Yoshi's Island 4 - Hidden 1-Up" yoshis_island_castle = "#1 Iggy's Castle - Normal Exit" yoshis_island_koopaling = "#1 Iggy's Castle - Boss" @@ -18,13 +21,17 @@ yellow_switch_palace = "Yellow Switch Palace" donut_plains_1_exit_1 = "Donut Plains 1 - Normal Exit" donut_plains_1_exit_2 = "Donut Plains 1 - Secret Exit" donut_plains_1_dragon = "Donut Plains 1 - Dragon Coins" +donut_plains_1_hidden_1up = "Donut Plains 1 - Hidden 1-Up" donut_plains_2_exit_1 = "Donut Plains 2 - Normal Exit" donut_plains_2_exit_2 = "Donut Plains 2 - Secret Exit" donut_plains_2_dragon = "Donut Plains 2 - Dragon Coins" donut_plains_3_exit_1 = "Donut Plains 3 - Normal Exit" donut_plains_3_dragon = "Donut Plains 3 - Dragon Coins" +donut_plains_3_bonus_block = "Donut Plains 3 - 1-Up from Bonus Block" donut_plains_4_exit_1 = "Donut Plains 4 - Normal Exit" donut_plains_4_dragon = "Donut Plains 4 - Dragon Coins" +donut_plains_4_moon = "Donut Plains 4 - 3-Up Moon" +donut_plains_4_hidden_1up = "Donut Plains 4 - Hidden 1-Up" donut_secret_1_exit_1 = "Donut Secret 1 - Normal Exit" donut_secret_1_exit_2 = "Donut Secret 1 - Secret Exit" donut_secret_1_dragon = "Donut Secret 1 - Dragon Coins" @@ -35,6 +42,7 @@ donut_ghost_house_exit_2 = "Donut Ghost House - Secret Exit" donut_secret_house_exit_1 = "Donut Secret House - Normal Exit" donut_secret_house_exit_2 = "Donut Secret House - Secret Exit" donut_plains_castle = "#2 Morton's Castle - Normal Exit" +donut_plains_castle_hidden_1up = "#2 Morton's Castle - Hidden 1-Up" donut_plains_koopaling = "#2 Morton's Castle - Boss" green_switch_palace = "Green Switch Palace" @@ -47,8 +55,10 @@ vanilla_dome_2_exit_2 = "Vanilla Dome 2 - Secret Exit" vanilla_dome_2_dragon = "Vanilla Dome 2 - Dragon Coins" vanilla_dome_3_exit_1 = "Vanilla Dome 3 - Normal Exit" vanilla_dome_3_dragon = "Vanilla Dome 3 - Dragon Coins" +vanilla_dome_3_moon = "Vanilla Dome 3 - 3-Up Moon" vanilla_dome_4_exit_1 = "Vanilla Dome 4 - Normal Exit" vanilla_dome_4_dragon = "Vanilla Dome 4 - Dragon Coins" +vanilla_dome_4_hidden_1up = "Vanilla Dome 4 - Hidden 1-Up" vanilla_secret_1_exit_1 = "Vanilla Secret 1 - Normal Exit" vanilla_secret_1_exit_2 = "Vanilla Secret 1 - Secret Exit" vanilla_secret_1_dragon = "Vanilla Secret 1 - Dragon Coins" @@ -58,7 +68,9 @@ vanilla_secret_3_exit_1 = "Vanilla Secret 3 - Normal Exit" vanilla_secret_3_dragon = "Vanilla Secret 3 - Dragon Coins" vanilla_ghost_house_exit_1 = "Vanilla Ghost House - Normal Exit" vanilla_ghost_house_dragon = "Vanilla Ghost House - Dragon Coins" +vanilla_ghost_house_hidden_1up = "Vanilla Ghost House - Hidden 1-Up" vanilla_fortress = "Vanilla Fortress - Normal Exit" +vanilla_fortress_hidden_1up = "Vanilla Fortress - Hidden 1-Up" vanilla_reznor = "Vanilla Fortress - Boss" vanilla_dome_castle = "#3 Lemmy's Castle - Normal Exit" vanilla_dome_koopaling = "#3 Lemmy's Castle - Boss" @@ -67,13 +79,16 @@ red_switch_palace = "Red Switch Palace" butter_bridge_1_exit_1 = "Butter Bridge 1 - Normal Exit" butter_bridge_1_dragon = "Butter Bridge 1 - Dragon Coins" +butter_bridge_1_bonus_block = "Butter Bridge 1 - 1-Up from Bonus Block" butter_bridge_2_exit_1 = "Butter Bridge 2 - Normal Exit" butter_bridge_2_dragon = "Butter Bridge 2 - Dragon Coins" cheese_bridge_exit_1 = "Cheese Bridge - Normal Exit" cheese_bridge_exit_2 = "Cheese Bridge - Secret Exit" cheese_bridge_dragon = "Cheese Bridge - Dragon Coins" +cheese_bridge_moon = "Cheese Bridge - 3-Up Moon" cookie_mountain_exit_1 = "Cookie Mountain - Normal Exit" cookie_mountain_dragon = "Cookie Mountain - Dragon Coins" +cookie_mountain_hidden_1up = "Cookie Mountain - Hidden 1-Up" soda_lake_exit_1 = "Soda Lake - Normal Exit" soda_lake_dragon = "Soda Lake - Dragon Coins" twin_bridges_castle = "#4 Ludwig's Castle - Normal Exit" @@ -87,12 +102,14 @@ forest_of_illusion_2_dragon = "Forest of Illusion 2 - Dragon Coins" forest_of_illusion_3_exit_1 = "Forest of Illusion 3 - Normal Exit" forest_of_illusion_3_exit_2 = "Forest of Illusion 3 - Secret Exit" forest_of_illusion_3_dragon = "Forest of Illusion 3 - Dragon Coins" +forest_of_illusion_3_hidden_1up = "Forest of Illusion 3 - Hidden 1-Up" forest_of_illusion_4_exit_1 = "Forest of Illusion 4 - Normal Exit" forest_of_illusion_4_exit_2 = "Forest of Illusion 4 - Secret Exit" forest_of_illusion_4_dragon = "Forest of Illusion 4 - Dragon Coins" forest_ghost_house_exit_1 = "Forest Ghost House - Normal Exit" forest_ghost_house_exit_2 = "Forest Ghost House - Secret Exit" forest_ghost_house_dragon = "Forest Ghost House - Dragon Coins" +forest_ghost_house_moon = "Forest Ghost House - 3-Up Moon" forest_secret_exit_1 = "Forest Secret - Normal Exit" forest_secret_dragon = "Forest Secret - Dragon Coins" forest_fortress = "Forest Fortress - Normal Exit" @@ -105,12 +122,15 @@ blue_switch_palace = "Blue Switch Palace" chocolate_island_1_exit_1 = "Chocolate Island 1 - Normal Exit" chocolate_island_1_dragon = "Chocolate Island 1 - Dragon Coins" +chocolate_island_1_moon = "Chocolate Island 1 - 3-Up Moon" chocolate_island_2_exit_1 = "Chocolate Island 2 - Normal Exit" chocolate_island_2_exit_2 = "Chocolate Island 2 - Secret Exit" chocolate_island_2_dragon = "Chocolate Island 2 - Dragon Coins" +chocolate_island_2_hidden_1up = "Chocolate Island 2 - Hidden 1-Up" chocolate_island_3_exit_1 = "Chocolate Island 3 - Normal Exit" chocolate_island_3_exit_2 = "Chocolate Island 3 - Secret Exit" chocolate_island_3_dragon = "Chocolate Island 3 - Dragon Coins" +chocolate_island_3_bonus_block = "Chocolate Island 3 - 1-Up from Bonus Block" chocolate_island_4_exit_1 = "Chocolate Island 4 - Normal Exit" chocolate_island_4_dragon = "Chocolate Island 4 - Dragon Coins" chocolate_island_5_exit_1 = "Chocolate Island 5 - Normal Exit" @@ -120,6 +140,7 @@ chocolate_secret_exit_1 = "Chocolate Secret - Normal Exit" chocolate_fortress = "Chocolate Fortress - Normal Exit" chocolate_reznor = "Chocolate Fortress - Boss" chocolate_castle = "#6 Wendy's Castle - Normal Exit" +chocolate_castle_hidden_1up = "#6 Wendy's Castle - Hidden 1-Up" chocolate_koopaling = "#6 Wendy's Castle - Boss" sunken_ghost_ship = "Sunken Ghost Ship - Normal Exit" @@ -127,9 +148,11 @@ sunken_ghost_ship_dragon = "Sunken Ghost Ship - Dragon Coins" valley_of_bowser_1_exit_1 = "Valley of Bowser 1 - Normal Exit" valley_of_bowser_1_dragon = "Valley of Bowser 1 - Dragon Coins" +valley_of_bowser_1_moon = "Valley of Bowser 1 - 3-Up Moon" valley_of_bowser_2_exit_1 = "Valley of Bowser 2 - Normal Exit" valley_of_bowser_2_exit_2 = "Valley of Bowser 2 - Secret Exit" valley_of_bowser_2_dragon = "Valley of Bowser 2 - Dragon Coins" +valley_of_bowser_2_hidden_1up = "Valley of Bowser 2 - Hidden 1-Up" valley_of_bowser_3_exit_1 = "Valley of Bowser 3 - Normal Exit" valley_of_bowser_3_dragon = "Valley of Bowser 3 - Dragon Coins" valley_of_bowser_4_exit_1 = "Valley of Bowser 4 - Normal Exit" @@ -141,6 +164,7 @@ valley_fortress = "Valley Fortress - Normal Exit" valley_reznor = "Valley Fortress - Boss" valley_castle = "#7 Larry's Castle - Normal Exit" valley_castle_dragon = "#7 Larry's Castle - Dragon Coins" +valley_castle_hidden_1up = "#7 Larry's Castle - Hidden 1-Up" valley_koopaling = "#7 Larry's Castle - Boss" front_door = "Front Door" @@ -161,6 +185,7 @@ star_road_5_exit_2 = "Star Road 5 - Secret Exit" special_zone_1_exit_1 = "Gnarly - Normal Exit" special_zone_1_dragon = "Gnarly - Dragon Coins" +special_zone_1_hidden_1up = "Gnarly - Hidden 1-Up" special_zone_2_exit_1 = "Tubular - Normal Exit" special_zone_2_dragon = "Tubular - Dragon Coins" special_zone_3_exit_1 = "Way Cool - Normal Exit" @@ -362,3 +387,586 @@ special_zone_7_region = "Outrageous" special_zone_8_tile = "Funky - Tile" special_zone_8_region = "Funky" special_complete = "Special Zone - Star Road - Complete" + +vanilla_secret_2_yoshi_block_1 = "Vanilla Secret 2 - Yoshi Block #1" +vanilla_secret_2_green_block_1 = "Vanilla Secret 2 - Green Switch Palace Block #1" +vanilla_secret_2_powerup_block_1 = "Vanilla Secret 2 - Powerup Block #1" +vanilla_secret_2_powerup_block_2 = "Vanilla Secret 2 - Powerup Block #2" +vanilla_secret_2_multi_coin_block_1 = "Vanilla Secret 2 - Multi Coin Block #1" +vanilla_secret_2_gray_pow_block_1 = "Vanilla Secret 2 - Gray P-Switch Block #1" +vanilla_secret_2_coin_block_1 = "Vanilla Secret 2 - Coin Block #1" +vanilla_secret_2_coin_block_2 = "Vanilla Secret 2 - Coin Block #2" +vanilla_secret_2_coin_block_3 = "Vanilla Secret 2 - Coin Block #3" +vanilla_secret_2_coin_block_4 = "Vanilla Secret 2 - Coin Block #4" +vanilla_secret_2_coin_block_5 = "Vanilla Secret 2 - Coin Block #5" +vanilla_secret_2_coin_block_6 = "Vanilla Secret 2 - Coin Block #6" +vanilla_secret_3_powerup_block_1 = "Vanilla Secret 3 - Powerup Block #1" +vanilla_secret_3_powerup_block_2 = "Vanilla Secret 3 - Powerup Block #2" +donut_ghost_house_vine_block_1 = "Donut Ghost House - Vine|P-Switch Block #1" +donut_ghost_house_directional_coin_block_1 = "Donut Ghost House - Directional Coin Block #1" +donut_ghost_house_life_block_1 = "Donut Ghost House - 1-Up Mushroom Block #1" +donut_ghost_house_life_block_2 = "Donut Ghost House - 1-Up Mushroom Block #2" +donut_ghost_house_life_block_3 = "Donut Ghost House - 1-Up Mushroom Block #3" +donut_ghost_house_life_block_4 = "Donut Ghost House - 1-Up Mushroom Block #4" +donut_plains_3_green_block_1 = "Donut Plains 3 - Green Switch Palace Block #1" +donut_plains_3_coin_block_1 = "Donut Plains 3 - Coin Block #1" +donut_plains_3_coin_block_2 = "Donut Plains 3 - Coin Block #2" +donut_plains_3_vine_block_1 = "Donut Plains 3 - Vine Block #1" +donut_plains_3_powerup_block_1 = "Donut Plains 3 - Powerup Block #1" +donut_plains_3_bonus_block_1 = "Donut Plains 3 - Bonus Block #1" +donut_plains_4_coin_block_1 = "Donut Plains 4 - Coin Block #1" +donut_plains_4_powerup_block_1 = "Donut Plains 4 - Powerup Block #1" +donut_plains_4_coin_block_2 = "Donut Plains 4 - Coin Block #2" +donut_plains_4_yoshi_block_1 = "Donut Plains 4 - Yoshi Block #1" +donut_plains_castle_yellow_block_1 = "#2 Morton's Castle - Yellow Switch Palace Block #1" +donut_plains_castle_coin_block_1 = "#2 Morton's Castle - Coin Block #1" +donut_plains_castle_powerup_block_1 = "#2 Morton's Castle - Powerup Block #1" +donut_plains_castle_coin_block_2 = "#2 Morton's Castle - Coin Block #2" +donut_plains_castle_vine_block_1 = "#2 Morton's Castle - Vine Block #1" +donut_plains_castle_invis_life_block_1 = "#2 Morton's Castle - Invisible 1-Up Mushroom Block #1" +donut_plains_castle_coin_block_3 = "#2 Morton's Castle - Coin Block #3" +donut_plains_castle_coin_block_4 = "#2 Morton's Castle - Coin Block #4" +donut_plains_castle_coin_block_5 = "#2 Morton's Castle - Coin Block #5" +donut_plains_castle_green_block_1 = "#2 Morton's Castle - Green Switch Palace Block #1" +donut_plains_2_coin_block_1 = "Donut Plains 2 - Coin Block #1" +donut_plains_2_coin_block_2 = "Donut Plains 2 - Coin Block #2" +donut_plains_2_coin_block_3 = "Donut Plains 2 - Coin Block #3" +donut_plains_2_yellow_block_1 = "Donut Plains 2 - Yellow Switch Palace Block #1" +donut_plains_2_powerup_block_1 = "Donut Plains 2 - Powerup Block #1" +donut_plains_2_multi_coin_block_1 = "Donut Plains 2 - Multi Coin Block #1" +donut_plains_2_flying_block_1 = "Donut Plains 2 - Flying Question Block #1" +donut_plains_2_green_block_1 = "Donut Plains 2 - Green Switch Palace Block #1" +donut_plains_2_yellow_block_2 = "Donut Plains 2 - Yellow Switch Palace Block #2" +donut_plains_2_vine_block_1 = "Donut Plains 2 - Vine Block #1" +donut_secret_1_coin_block_1 = "Donut Secret 1 - Coin Block #1" +donut_secret_1_coin_block_2 = "Donut Secret 1 - Coin Block #2" +donut_secret_1_powerup_block_1 = "Donut Secret 1 - Powerup Block #1" +donut_secret_1_coin_block_3 = "Donut Secret 1 - Coin Block #3" +donut_secret_1_powerup_block_2 = "Donut Secret 1 - Powerup Block #2" +donut_secret_1_powerup_block_3 = "Donut Secret 1 - Powerup Block #3" +donut_secret_1_life_block_1 = "Donut Secret 1 - 1-Up Mushroom Block #1" +donut_secret_1_powerup_block_4 = "Donut Secret 1 - Powerup Block #4" +donut_secret_1_powerup_block_5 = "Donut Secret 1 - Powerup Block #5" +donut_secret_1_key_block_1 = "Donut Secret 1 - Key Block #1" +vanilla_fortress_powerup_block_1 = "Vanilla Fortress - Powerup Block #1" +vanilla_fortress_powerup_block_2 = "Vanilla Fortress - Powerup Block #2" +vanilla_fortress_yellow_block_1 = "Vanilla Fortress - Yellow Switch Palace Block #1" +butter_bridge_1_powerup_block_1 = "Butter Bridge 1 - Powerup Block #1" +butter_bridge_1_multi_coin_block_1 = "Butter Bridge 1 - Multi Coin Block #1" +butter_bridge_1_multi_coin_block_2 = "Butter Bridge 1 - Multi Coin Block #2" +butter_bridge_1_multi_coin_block_3 = "Butter Bridge 1 - Multi Coin Block #3" +butter_bridge_1_life_block_1 = "Butter Bridge 1 - 1-Up Mushroom Block #1" +butter_bridge_1_bonus_block_1 = "Butter Bridge 1 - Bonus Block #1" +butter_bridge_2_powerup_block_1 = "Butter Bridge 2 - Powerup Block #1" +butter_bridge_2_green_block_1 = "Butter Bridge 2 - Green Switch Palace Block #1" +butter_bridge_2_yoshi_block_1 = "Butter Bridge 2 - Yoshi Block #1" +twin_bridges_castle_powerup_block_1 = "#4 Ludwig Castle - Powerup Block #1" +cheese_bridge_powerup_block_1 = "Cheese Bridge Area - Powerup Block #1" +cheese_bridge_powerup_block_2 = "Cheese Bridge Area - Powerup Block #2" +cheese_bridge_wings_block_1 = "Cheese Bridge Area - Wings Block #1" +cheese_bridge_powerup_block_3 = "Cheese Bridge Area - Powerup Block #3" +cookie_mountain_coin_block_1 = "Cookie Mountain - Coin Block #1" +cookie_mountain_coin_block_2 = "Cookie Mountain - Coin Block #2" +cookie_mountain_coin_block_3 = "Cookie Mountain - Coin Block #3" +cookie_mountain_coin_block_4 = "Cookie Mountain - Coin Block #4" +cookie_mountain_coin_block_5 = "Cookie Mountain - Coin Block #5" +cookie_mountain_coin_block_6 = "Cookie Mountain - Coin Block #6" +cookie_mountain_coin_block_7 = "Cookie Mountain - Coin Block #7" +cookie_mountain_coin_block_8 = "Cookie Mountain - Coin Block #8" +cookie_mountain_coin_block_9 = "Cookie Mountain - Coin Block #9" +cookie_mountain_powerup_block_1 = "Cookie Mountain - Powerup Block #1" +cookie_mountain_life_block_1 = "Cookie Mountain - 1-Up Mushroom Block #1" +cookie_mountain_vine_block_1 = "Cookie Mountain - Vine Block #1" +cookie_mountain_yoshi_block_1 = "Cookie Mountain - Yoshi Block #1" +cookie_mountain_coin_block_10 = "Cookie Mountain - Coin Block #10" +cookie_mountain_coin_block_11 = "Cookie Mountain - Coin Block #11" +cookie_mountain_powerup_block_2 = "Cookie Mountain - Powerup Block #2" +cookie_mountain_coin_block_12 = "Cookie Mountain - Coin Block #12" +cookie_mountain_coin_block_13 = "Cookie Mountain - Coin Block #13" +cookie_mountain_coin_block_14 = "Cookie Mountain - Coin Block #14" +cookie_mountain_coin_block_15 = "Cookie Mountain - Coin Block #15" +cookie_mountain_coin_block_16 = "Cookie Mountain - Coin Block #16" +cookie_mountain_coin_block_17 = "Cookie Mountain - Coin Block #17" +cookie_mountain_coin_block_18 = "Cookie Mountain - Coin Block #18" +cookie_mountain_coin_block_19 = "Cookie Mountain - Coin Block #19" +cookie_mountain_coin_block_20 = "Cookie Mountain - Coin Block #20" +cookie_mountain_coin_block_21 = "Cookie Mountain - Coin Block #21" +cookie_mountain_coin_block_22 = "Cookie Mountain - Coin Block #22" +cookie_mountain_coin_block_23 = "Cookie Mountain - Coin Block #23" +cookie_mountain_coin_block_24 = "Cookie Mountain - Coin Block #24" +cookie_mountain_coin_block_25 = "Cookie Mountain - Coin Block #25" +cookie_mountain_coin_block_26 = "Cookie Mountain - Coin Block #26" +cookie_mountain_coin_block_27 = "Cookie Mountain - Coin Block #27" +cookie_mountain_coin_block_28 = "Cookie Mountain - Coin Block #28" +cookie_mountain_coin_block_29 = "Cookie Mountain - Coin Block #29" +cookie_mountain_coin_block_30 = "Cookie Mountain - Coin Block #30" +soda_lake_powerup_block_1 = "Soda Lake - Powerup Block #1" +donut_secret_house_powerup_block_1 = "Donut Secret House - Powerup Block #1" +donut_secret_house_multi_coin_block_1 = "Donut Secret House - Multi Coin Block #1" +donut_secret_house_life_block_1 = "Donut Secret House - 1-Up Mushroom Block #1" +donut_secret_house_vine_block_1 = "Donut Secret House - Vine Block #1" +donut_secret_house_directional_coin_block_1 = "Donut Secret House - Directional Coin Block #1" +donut_plains_1_coin_block_1 = "Donut Plains 1 - Coin Block #1" +donut_plains_1_coin_block_2 = "Donut Plains 1 - Coin Block #2" +donut_plains_1_yoshi_block_1 = "Donut Plains 1 - Yoshi Block #1" +donut_plains_1_vine_block_1 = "Donut Plains 1 - Vine Block #1" +donut_plains_1_green_block_1 = "Donut Plains 1 - Green Switch Palace Block #1" +donut_plains_1_green_block_2 = "Donut Plains 1 - Green Switch Palace Block #2" +donut_plains_1_green_block_3 = "Donut Plains 1 - Green Switch Palace Block #3" +donut_plains_1_green_block_4 = "Donut Plains 1 - Green Switch Palace Block #4" +donut_plains_1_green_block_5 = "Donut Plains 1 - Green Switch Palace Block #5" +donut_plains_1_green_block_6 = "Donut Plains 1 - Green Switch Palace Block #6" +donut_plains_1_green_block_7 = "Donut Plains 1 - Green Switch Palace Block #7" +donut_plains_1_green_block_8 = "Donut Plains 1 - Green Switch Palace Block #8" +donut_plains_1_green_block_9 = "Donut Plains 1 - Green Switch Palace Block #9" +donut_plains_1_green_block_10 = "Donut Plains 1 - Green Switch Palace Block #10" +donut_plains_1_green_block_11 = "Donut Plains 1 - Green Switch Palace Block #11" +donut_plains_1_green_block_12 = "Donut Plains 1 - Green Switch Palace Block #12" +donut_plains_1_green_block_13 = "Donut Plains 1 - Green Switch Palace Block #13" +donut_plains_1_green_block_14 = "Donut Plains 1 - Green Switch Palace Block #14" +donut_plains_1_green_block_15 = "Donut Plains 1 - Green Switch Palace Block #15" +donut_plains_1_green_block_16 = "Donut Plains 1 - Green Switch Palace Block #16" +donut_plains_1_yellow_block_1 = "Donut Plains 1 - Yellow Switch Palace Block #1" +donut_plains_1_yellow_block_2 = "Donut Plains 1 - Yellow Switch Palace Block #2" +donut_plains_1_yellow_block_3 = "Donut Plains 1 - Yellow Switch Palace Block #3" +sunken_ghost_ship_powerup_block_1 = "Sunken Ghost Ship - Powerup Block #1" +sunken_ghost_ship_star_block_1 = "Sunken Ghost Ship - Star Block #1" +chocolate_castle_yellow_block_1 = "#6 Wendy's Castle - Yellow Switch Palace Block #1" +chocolate_castle_yellow_block_2 = "#6 Wendy's Castle - Yellow Switch Palace Block #2" +chocolate_castle_green_block_1 = "#6 Wendy's Castle - Green Switch Palace Block #1" +chocolate_fortress_powerup_block_1 = "Chocolate Fortress - Powerup Block #1" +chocolate_fortress_powerup_block_2 = "Chocolate Fortress - Powerup Block #2" +chocolate_fortress_coin_block_1 = "Chocolate Fortress - Coin Block #1" +chocolate_fortress_coin_block_2 = "Chocolate Fortress - Coin Block #2" +chocolate_fortress_green_block_1 = "Chocolate Fortress - Green Switch Palace Block #1" +chocolate_island_5_yoshi_block_1 = "Chocolate Island 5 - Yoshi Block #1" +chocolate_island_5_powerup_block_1 = "Chocolate Island 5 - Powerup Block #1" +chocolate_island_5_life_block_1 = "Chocolate Island 5 - 1-Up Mushroom Block #1" +chocolate_island_5_yellow_block_1 = "Chocolate Island 5 - Yellow Switch Palace Block #1" +chocolate_island_4_yellow_block_1 = "Chocolate Island 4 - Yellow Switch Palace Block #1" +chocolate_island_4_blue_pow_block_1 = "Chocolate Island 4 - Blue P-Switch Block #1" +chocolate_island_4_powerup_block_1 = "Chocolate Island 4 - Powerup Block #1" +forest_fortress_yellow_block_1 = "Forest Fortress - Yellow Switch Palace Block #1" +forest_fortress_powerup_block_1 = "Forest Fortress - Powerup Block #1" +forest_fortress_life_block_1 = "Forest Fortress - 1-Up Mushroom Block #1" +forest_fortress_life_block_2 = "Forest Fortress - 1-Up Mushroom Block #2" +forest_fortress_life_block_3 = "Forest Fortress - 1-Up Mushroom Block #3" +forest_fortress_life_block_4 = "Forest Fortress - 1-Up Mushroom Block #4" +forest_fortress_life_block_5 = "Forest Fortress - 1-Up Mushroom Block #5" +forest_fortress_life_block_6 = "Forest Fortress - 1-Up Mushroom Block #6" +forest_fortress_life_block_7 = "Forest Fortress - 1-Up Mushroom Block #7" +forest_fortress_life_block_8 = "Forest Fortress - 1-Up Mushroom Block #8" +forest_fortress_life_block_9 = "Forest Fortress - 1-Up Mushroom Block #9" +forest_castle_green_block_1 = "#5 Roy's Castle - Green Switch Palace Block #1" +chocolate_ghost_house_powerup_block_1 = "Choco Ghost House - Powerup Block #1" +chocolate_ghost_house_powerup_block_2 = "Choco Ghost House - Powerup Block #2" +chocolate_ghost_house_life_block_1 = "Choco Ghost House - 1-Up Mushroom Block #1" +chocolate_island_1_flying_block_1 = "Chocolate Island 1 - Flying Question Block #1" +chocolate_island_1_flying_block_2 = "Chocolate Island 1 - Flying Question Block #2" +chocolate_island_1_yoshi_block_1 = "Chocolate Island 1 - Yoshi Block #1" +chocolate_island_1_green_block_1 = "Chocolate Island 1 - Green|Yellow Switch Palace Block #1" +chocolate_island_1_life_block_1 = "Chocolate Island 1 - 1-Up Mushroom Block #1" +chocolate_island_3_powerup_block_1 = "Chocolate Island 3 - Powerup Block #1" +chocolate_island_3_powerup_block_2 = "Chocolate Island 3 - Powerup Block #2" +chocolate_island_3_powerup_block_3 = "Chocolate Island 3 - Powerup Block #3" +chocolate_island_3_green_block_1 = "Chocolate Island 3 - Green Switch Palace Block #1" +chocolate_island_3_bonus_block_1 = "Chocolate Island 3 - Bonus Block #1" +chocolate_island_3_vine_block_1 = "Chocolate Island 3 - Vine Block #1" +chocolate_island_3_life_block_1 = "Chocolate Island 3 - 1-Up Mushroom Block #1" +chocolate_island_3_life_block_2 = "Chocolate Island 3 - 1-Up Mushroom Block #2" +chocolate_island_3_life_block_3 = "Chocolate Island 3 - 1-Up Mushroom Block #3" +chocolate_island_2_multi_coin_block_1 = "Chocolate Island 2 - Multi Coin Block #1" +chocolate_island_2_invis_coin_block_1 = "Chocolate Island 2 - Invisible Coin Block #1" +chocolate_island_2_yoshi_block_1 = "Chocolate Island 2 - Yoshi Block #1" +chocolate_island_2_coin_block_1 = "Chocolate Island 2 - Coin Block #1" +chocolate_island_2_coin_block_2 = "Chocolate Island 2 - Coin Block #2" +chocolate_island_2_multi_coin_block_2 = "Chocolate Island 2 - Multi Coin Block #2" +chocolate_island_2_powerup_block_1 = "Chocolate Island 2 - Powerup Block #1" +chocolate_island_2_blue_pow_block_1 = "Chocolate Island 2 - Blue P-Switch Block #1" +chocolate_island_2_yellow_block_1 = "Chocolate Island 2 - Yellow Switch Palace Block #1" +chocolate_island_2_yellow_block_2 = "Chocolate Island 2 - Yellow Switch Palace Block #2" +chocolate_island_2_green_block_1 = "Chocolate Island 2 - Green Switch Palace Block #1" +chocolate_island_2_green_block_2 = "Chocolate Island 2 - Green Switch Palace Block #2" +chocolate_island_2_green_block_3 = "Chocolate Island 2 - Green Switch Palace Block #3" +chocolate_island_2_green_block_4 = "Chocolate Island 2 - Green Switch Palace Block #4" +chocolate_island_2_green_block_5 = "Chocolate Island 2 - Green Switch Palace Block #5" +chocolate_island_2_green_block_6 = "Chocolate Island 2 - Green Switch Palace Block #6" +yoshis_island_castle_coin_block_1 = "#1 Iggy's Castle - Coin Block #1" +yoshis_island_castle_coin_block_2 = "#1 Iggy's Castle - Coin Block #2" +yoshis_island_castle_powerup_block_1 = "#1 Iggy's Castle - Powerup Block #1" +yoshis_island_castle_coin_block_3 = "#1 Iggy's Castle - Coin Block #3" +yoshis_island_castle_coin_block_4 = "#1 Iggy's Castle - Coin Block #4" +yoshis_island_castle_flying_block_1 = "#1 Iggy's Castle - Flying Question Block #1" +yoshis_island_4_yellow_block_1 = "Yoshi's Island 4 - Yellow Switch Palace Block #1" +yoshis_island_4_powerup_block_1 = "Yoshi's Island 4 - Powerup Block #1" +yoshis_island_4_multi_coin_block_1 = "Yoshi's Island 4 - Multi Coin Block #1" +yoshis_island_4_star_block_1 = "Yoshi's Island 4 - Star Block #1" +yoshis_island_3_yellow_block_1 = "Yoshi's Island 3 - Yellow Switch Palace Block #1" +yoshis_island_3_yellow_block_2 = "Yoshi's Island 3 - Yellow Switch Palace Block #2" +yoshis_island_3_yellow_block_3 = "Yoshi's Island 3 - Yellow Switch Palace Block #3" +yoshis_island_3_yellow_block_4 = "Yoshi's Island 3 - Yellow Switch Palace Block #4" +yoshis_island_3_yellow_block_5 = "Yoshi's Island 3 - Yellow Switch Palace Block #5" +yoshis_island_3_yellow_block_6 = "Yoshi's Island 3 - Yellow Switch Palace Block #6" +yoshis_island_3_yellow_block_7 = "Yoshi's Island 3 - Yellow Switch Palace Block #7" +yoshis_island_3_yellow_block_8 = "Yoshi's Island 3 - Yellow Switch Palace Block #8" +yoshis_island_3_yellow_block_9 = "Yoshi's Island 3 - Yellow Switch Palace Block #9" +yoshis_island_3_coin_block_1 = "Yoshi's Island 3 - Coin Block #1" +yoshis_island_3_yoshi_block_1 = "Yoshi's Island 3 - Yoshi Block #1" +yoshis_island_3_coin_block_2 = "Yoshi's Island 3 - Coin Block #2" +yoshis_island_3_powerup_block_1 = "Yoshi's Island 3 - Powerup Block #1" +yoshis_island_3_yellow_block_10 = "Yoshi's Island 3 - Yellow Switch Palace Block #10" +yoshis_island_3_yellow_block_11 = "Yoshi's Island 3 - Yellow Switch Palace Block #11" +yoshis_island_3_yellow_block_12 = "Yoshi's Island 3 - Yellow Switch Palace Block #12" +yoshis_island_3_bonus_block_1 = "Yoshi's Island 3 - Bonus Block #1" +yoshis_island_1_flying_block_1 = "Yoshi's Island 1 - Flying Question Block #1" +yoshis_island_1_yellow_block_1 = "Yoshi's Island 1 - Yellow Switch Palace Block #1" +yoshis_island_1_life_block_1 = "Yoshi's Island 1 - 1-Up Mushroom Block #1" +yoshis_island_1_powerup_block_1 = "Yoshi's Island 1 - Powerup Block #1" +yoshis_island_2_flying_block_1 = "Yoshi's Island 2 - Flying Question Block #1" +yoshis_island_2_flying_block_2 = "Yoshi's Island 2 - Flying Question Block #2" +yoshis_island_2_flying_block_3 = "Yoshi's Island 2 - Flying Question Block #3" +yoshis_island_2_flying_block_4 = "Yoshi's Island 2 - Flying Question Block #4" +yoshis_island_2_flying_block_5 = "Yoshi's Island 2 - Flying Question Block #5" +yoshis_island_2_flying_block_6 = "Yoshi's Island 2 - Flying Question Block #6" +yoshis_island_2_coin_block_1 = "Yoshi's Island 2 - Coin Block #1" +yoshis_island_2_yellow_block_1 = "Yoshi's Island 2 - Yellow Switch Palace Block #1" +yoshis_island_2_coin_block_2 = "Yoshi's Island 2 - Coin Block #2" +yoshis_island_2_coin_block_3 = "Yoshi's Island 2 - Coin Block #3" +yoshis_island_2_yoshi_block_1 = "Yoshi's Island 2 - Yoshi Block #1" +yoshis_island_2_coin_block_4 = "Yoshi's Island 2 - Coin Block #4" +yoshis_island_2_yoshi_block_2 = "Yoshi's Island 2 - Yoshi Block #2" +yoshis_island_2_coin_block_5 = "Yoshi's Island 2 - Coin Block #5" +yoshis_island_2_vine_block_1 = "Yoshi's Island 2 - Vine Block #1" +yoshis_island_2_yellow_block_2 = "Yoshi's Island 2 - Yellow Switch Palace Block #2" +vanilla_ghost_house_powerup_block_1 = "Vanilla Ghost House - Powerup Block #1" +vanilla_ghost_house_vine_block_1 = "Vanilla Ghost House - Vine Block #1" +vanilla_ghost_house_powerup_block_2 = "Vanilla Ghost House - Powerup Block #2" +vanilla_ghost_house_multi_coin_block_1 = "Vanilla Ghost House - Multi Coin Block #1" +vanilla_ghost_house_blue_pow_block_1 = "Vanilla Ghost House - Blue P-Switch Block #1" +vanilla_secret_1_coin_block_1 = "Vanilla Secret 1 - Coin Block #1" +vanilla_secret_1_powerup_block_1 = "Vanilla Secret 1 - Powerup Block #1" +vanilla_secret_1_multi_coin_block_1 = "Vanilla Secret 1 - Multi Coin Block #1" +vanilla_secret_1_vine_block_1 = "Vanilla Secret 1 - Vine Block #1" +vanilla_secret_1_vine_block_2 = "Vanilla Secret 1 - Vine Block #2" +vanilla_secret_1_coin_block_2 = "Vanilla Secret 1 - Coin Block #2" +vanilla_secret_1_coin_block_3 = "Vanilla Secret 1 - Coin Block #3" +vanilla_secret_1_powerup_block_2 = "Vanilla Secret 1 - Powerup Block #2" +vanilla_dome_3_coin_block_1 = "Vanilla Dome 3 - Coin Block #1" +vanilla_dome_3_flying_block_1 = "Vanilla Dome 3 - Flying Question Block #1" +vanilla_dome_3_flying_block_2 = "Vanilla Dome 3 - Flying Question Block #2" +vanilla_dome_3_powerup_block_1 = "Vanilla Dome 3 - Powerup Block #1" +vanilla_dome_3_flying_block_3 = "Vanilla Dome 3 - Flying Question Block #3" +vanilla_dome_3_invis_coin_block_1 = "Vanilla Dome 3 - Invisible Coin Block #1" +vanilla_dome_3_powerup_block_2 = "Vanilla Dome 3 - Powerup Block #2" +vanilla_dome_3_multi_coin_block_1 = "Vanilla Dome 3 - Multi Coin Block #1" +vanilla_dome_3_powerup_block_3 = "Vanilla Dome 3 - Powerup Block #3" +vanilla_dome_3_yoshi_block_1 = "Vanilla Dome 3 - Yoshi Block #1" +vanilla_dome_3_powerup_block_4 = "Vanilla Dome 3 - Powerup Block #4" +vanilla_dome_3_pswitch_coin_block_1 = "Vanilla Dome 3 - P-Switch Coin Block #1" +vanilla_dome_3_pswitch_coin_block_2 = "Vanilla Dome 3 - P-Switch Coin Block #2" +vanilla_dome_3_pswitch_coin_block_3 = "Vanilla Dome 3 - P-Switch Coin Block #3" +vanilla_dome_3_pswitch_coin_block_4 = "Vanilla Dome 3 - P-Switch Coin Block #4" +vanilla_dome_3_pswitch_coin_block_5 = "Vanilla Dome 3 - P-Switch Coin Block #5" +vanilla_dome_3_pswitch_coin_block_6 = "Vanilla Dome 3 - P-Switch Coin Block #6" +donut_secret_2_directional_coin_block_1 = "Donut Secret 2 - Directional Coin Block #1" +donut_secret_2_vine_block_1 = "Donut Secret 2 - Vine Block #1" +donut_secret_2_star_block_1 = "Donut Secret 2 - Star Block #1" +donut_secret_2_powerup_block_1 = "Donut Secret 2 - Powerup Block #1" +donut_secret_2_star_block_2 = "Donut Secret 2 - Star Block #2" +valley_of_bowser_4_yellow_block_1 = "Valley of Bowser 4 - Yellow Switch Palace Block #1" +valley_of_bowser_4_powerup_block_1 = "Valley of Bowser 4 - Powerup Block #1" +valley_of_bowser_4_vine_block_1 = "Valley of Bowser 4 - Vine Block #1" +valley_of_bowser_4_yoshi_block_1 = "Valley of Bowser 4 - Yoshi Block #1" +valley_of_bowser_4_life_block_1 = "Valley of Bowser 4 - 1-Up Mushroom Block #1" +valley_of_bowser_4_powerup_block_2 = "Valley of Bowser 4 - Powerup Block #2" +valley_castle_yellow_block_1 = "#7 Larry's Castle - Yellow Switch Palace Block #1" +valley_castle_yellow_block_2 = "#7 Larry's Castle - Yellow Switch Palace Block #2" +valley_castle_green_block_1 = "#7 Larry's Castle - Green Switch Palace Block #1" +valley_fortress_green_block_1 = "Valley Fortress - Green Switch Palace Block #1" +valley_fortress_yellow_block_1 = "Valley Fortress - Yellow Switch Palace Block #1" +valley_of_bowser_3_powerup_block_1 = "Valley of Bowser 3 - Powerup Block #1" +valley_of_bowser_3_powerup_block_2 = "Valley of Bowser 3 - Powerup Block #2" +valley_ghost_house_pswitch_coin_block_1 = "Valley Ghost House - P-Switch Coin Block #1" +valley_ghost_house_multi_coin_block_1 = "Valley Ghost House - Multi Coin Block #1" +valley_ghost_house_powerup_block_1 = "Valley Ghost House - Powerup Block #1" +valley_ghost_house_directional_coin_block_1 = "Valley Ghost House - Directional Coin Block #1" +valley_of_bowser_2_powerup_block_1 = "Valley of Bowser 2 - Powerup Block #1" +valley_of_bowser_2_yellow_block_1 = "Valley of Bowser 2 - Yellow Switch Palace Block #1" +valley_of_bowser_2_powerup_block_2 = "Valley of Bowser 2 - Powerup Block #2" +valley_of_bowser_2_wings_block_1 = "Valley of Bowser 2 - Wings Block #1" +valley_of_bowser_1_green_block_1 = "Valley of Bowser 1 - Green Switch Palace Block #1" +valley_of_bowser_1_invis_coin_block_1 = "Valley of Bowser 1 - Invisible Coin Block #1" +valley_of_bowser_1_invis_coin_block_2 = "Valley of Bowser 1 - Invisible Coin Block #2" +valley_of_bowser_1_invis_coin_block_3 = "Valley of Bowser 1 - Invisible Coin Block #3" +valley_of_bowser_1_yellow_block_1 = "Valley of Bowser 1 - Yellow Switch Palace Block #1" +valley_of_bowser_1_yellow_block_2 = "Valley of Bowser 1 - Yellow Switch Palace Block #2" +valley_of_bowser_1_yellow_block_3 = "Valley of Bowser 1 - Yellow Switch Palace Block #3" +valley_of_bowser_1_yellow_block_4 = "Valley of Bowser 1 - Yellow Switch Palace Block #4" +valley_of_bowser_1_vine_block_1 = "Valley of Bowser 1 - Vine Block #1" +chocolate_secret_powerup_block_1 = "Chocolate Secret - Powerup Block #1" +chocolate_secret_powerup_block_2 = "Chocolate Secret - Powerup Block #2" +vanilla_dome_2_coin_block_1 = "Vanilla Dome 2 - Coin Block #1" +vanilla_dome_2_powerup_block_1 = "Vanilla Dome 2 - Powerup Block #1" +vanilla_dome_2_coin_block_2 = "Vanilla Dome 2 - Coin Block #2" +vanilla_dome_2_coin_block_3 = "Vanilla Dome 2 - Coin Block #3" +vanilla_dome_2_vine_block_1 = "Vanilla Dome 2 - Vine Block #1" +vanilla_dome_2_invis_life_block_1 = "Vanilla Dome 2 - Invisible 1-Up Mushroom Block #1" +vanilla_dome_2_coin_block_4 = "Vanilla Dome 2 - Coin Block #4" +vanilla_dome_2_coin_block_5 = "Vanilla Dome 2 - Coin Block #5" +vanilla_dome_2_powerup_block_2 = "Vanilla Dome 2 - Powerup Block #2" +vanilla_dome_2_powerup_block_3 = "Vanilla Dome 2 - Powerup Block #3" +vanilla_dome_2_powerup_block_4 = "Vanilla Dome 2 - Powerup Block #4" +vanilla_dome_2_powerup_block_5 = "Vanilla Dome 2 - Powerup Block #5" +vanilla_dome_2_multi_coin_block_1 = "Vanilla Dome 2 - Multi Coin Block #1" +vanilla_dome_2_multi_coin_block_2 = "Vanilla Dome 2 - Multi Coin Block #2" +vanilla_dome_4_powerup_block_1 = "Vanilla Dome 4 - Powerup Block #1" +vanilla_dome_4_powerup_block_2 = "Vanilla Dome 4 - Powerup Block #2" +vanilla_dome_4_coin_block_1 = "Vanilla Dome 4 - Coin Block #1" +vanilla_dome_4_coin_block_2 = "Vanilla Dome 4 - Coin Block #2" +vanilla_dome_4_coin_block_3 = "Vanilla Dome 4 - Coin Block #3" +vanilla_dome_4_life_block_1 = "Vanilla Dome 4 - 1-Up Mushroom Block #1" +vanilla_dome_4_coin_block_4 = "Vanilla Dome 4 - Coin Block #4" +vanilla_dome_4_coin_block_5 = "Vanilla Dome 4 - Coin Block #5" +vanilla_dome_4_coin_block_6 = "Vanilla Dome 4 - Coin Block #6" +vanilla_dome_4_coin_block_7 = "Vanilla Dome 4 - Coin Block #7" +vanilla_dome_4_coin_block_8 = "Vanilla Dome 4 - Coin Block #8" +vanilla_dome_1_flying_block_1 = "Vanilla Dome 1 - Flying Question Block #1" +vanilla_dome_1_powerup_block_1 = "Vanilla Dome 1 - Powerup Block #1" +vanilla_dome_1_powerup_block_2 = "Vanilla Dome 1 - Powerup Block #2" +vanilla_dome_1_coin_block_1 = "Vanilla Dome 1 - Coin Block #1" +vanilla_dome_1_life_block_1 = "Vanilla Dome 1 - 1-Up Mushroom Block #1" +vanilla_dome_1_powerup_block_3 = "Vanilla Dome 1 - Powerup Block #3" +vanilla_dome_1_vine_block_1 = "Vanilla Dome 1 - Vine Block #1" +vanilla_dome_1_star_block_1 = "Vanilla Dome 1 - Star Block #1" +vanilla_dome_1_powerup_block_4 = "Vanilla Dome 1 - Powerup Block #4" +vanilla_dome_1_coin_block_2 = "Vanilla Dome 1 - Coin Block #2" +vanilla_dome_castle_life_block_1 = "#3 Lemmy's Castle - 1-Up Mushroom Block #1" +vanilla_dome_castle_life_block_2 = "#3 Lemmy's Castle - 1-Up Mushroom Block #2" +vanilla_dome_castle_powerup_block_1 = "#3 Lemmy's Castle - Powerup Block #1" +vanilla_dome_castle_life_block_3 = "#3 Lemmy's Castle - 1-Up Mushroom Block #3" +vanilla_dome_castle_green_block_1 = "#3 Lemmy's Castle - Green Switch Palace Block #1" +forest_ghost_house_coin_block_1 = "Forest Ghost House - Coin Block #1" +forest_ghost_house_powerup_block_1 = "Forest Ghost House - Powerup Block #1" +forest_ghost_house_flying_block_1 = "Forest Ghost House - Flying Question Block #1" +forest_ghost_house_powerup_block_2 = "Forest Ghost House - Powerup Block #2" +forest_ghost_house_life_block_1 = "Forest Ghost House - 1-Up Mushroom Block #1" +forest_of_illusion_1_powerup_block_1 = "Forest of Illusion 1 - Powerup Block #1" +forest_of_illusion_1_yoshi_block_1 = "Forest of Illusion 1 - Yoshi Block #1" +forest_of_illusion_1_powerup_block_2 = "Forest of Illusion 1 - Powerup Block #2" +forest_of_illusion_1_key_block_1 = "Forest of Illusion 1 - Key Block #1" +forest_of_illusion_1_life_block_1 = "Forest of Illusion 1 - 1-Up Mushroom Block #1" +forest_of_illusion_4_multi_coin_block_1 = "Forest of Illusion 4 - Multi Coin Block #1" +forest_of_illusion_4_coin_block_1 = "Forest of Illusion 4 - Coin Block #1" +forest_of_illusion_4_coin_block_2 = "Forest of Illusion 4 - Coin Block #2" +forest_of_illusion_4_coin_block_3 = "Forest of Illusion 4 - Coin Block #3" +forest_of_illusion_4_coin_block_4 = "Forest of Illusion 4 - Coin Block #4" +forest_of_illusion_4_powerup_block_1 = "Forest of Illusion 4 - Powerup Block #1" +forest_of_illusion_4_coin_block_5 = "Forest of Illusion 4 - Coin Block #5" +forest_of_illusion_4_coin_block_6 = "Forest of Illusion 4 - Coin Block #6" +forest_of_illusion_4_coin_block_7 = "Forest of Illusion 4 - Coin Block #7" +forest_of_illusion_4_powerup_block_2 = "Forest of Illusion 4 - Powerup Block #2" +forest_of_illusion_4_coin_block_8 = "Forest of Illusion 4 - Coin Block #8" +forest_of_illusion_4_coin_block_9 = "Forest of Illusion 4 - Coin Block #9" +forest_of_illusion_4_coin_block_10 = "Forest of Illusion 4 - Coin Block #10" +forest_of_illusion_2_green_block_1 = "Forest of Illusion 2 - Green Switch Palace Block #1" +forest_of_illusion_2_powerup_block_1 = "Forest of Illusion 2 - Powerup Block #1" +forest_of_illusion_2_invis_coin_block_1 = "Forest of Illusion 2 - Invisible Coin Block #1" +forest_of_illusion_2_invis_coin_block_2 = "Forest of Illusion 2 - Invisible Coin Block #2" +forest_of_illusion_2_invis_life_block_1 = "Forest of Illusion 2 - Invisible 1-Up Mushroom Block #1" +forest_of_illusion_2_invis_coin_block_3 = "Forest of Illusion 2 - Invisible Coin Block #3" +forest_of_illusion_2_yellow_block_1 = "Forest of Illusion 2 - Yellow Switch Palace Block #1" +forest_secret_powerup_block_1 = "Forest Secret Area - Powerup Block #1" +forest_secret_powerup_block_2 = "Forest Secret Area - Powerup Block #2" +forest_secret_life_block_1 = "Forest Secret Area - 1-Up Mushroom Block #1" +forest_of_illusion_3_yoshi_block_1 = "Forest of Illusion 3 - Yoshi Block #1" +forest_of_illusion_3_coin_block_1 = "Forest of Illusion 3 - Coin Block #1" +forest_of_illusion_3_multi_coin_block_1 = "Forest of Illusion 3 - Multi Coin Block #1" +forest_of_illusion_3_coin_block_2 = "Forest of Illusion 3 - Coin Block #2" +forest_of_illusion_3_multi_coin_block_2 = "Forest of Illusion 3 - Multi Coin Block #2" +forest_of_illusion_3_coin_block_3 = "Forest of Illusion 3 - Coin Block #3" +forest_of_illusion_3_coin_block_4 = "Forest of Illusion 3 - Coin Block #4" +forest_of_illusion_3_coin_block_5 = "Forest of Illusion 3 - Coin Block #5" +forest_of_illusion_3_coin_block_6 = "Forest of Illusion 3 - Coin Block #6" +forest_of_illusion_3_coin_block_7 = "Forest of Illusion 3 - Coin Block #7" +forest_of_illusion_3_coin_block_8 = "Forest of Illusion 3 - Coin Block #8" +forest_of_illusion_3_coin_block_9 = "Forest of Illusion 3 - Coin Block #9" +forest_of_illusion_3_coin_block_10 = "Forest of Illusion 3 - Coin Block #10" +forest_of_illusion_3_coin_block_11 = "Forest of Illusion 3 - Coin Block #11" +forest_of_illusion_3_coin_block_12 = "Forest of Illusion 3 - Coin Block #12" +forest_of_illusion_3_coin_block_13 = "Forest of Illusion 3 - Coin Block #13" +forest_of_illusion_3_coin_block_14 = "Forest of Illusion 3 - Coin Block #14" +forest_of_illusion_3_coin_block_15 = "Forest of Illusion 3 - Coin Block #15" +forest_of_illusion_3_coin_block_16 = "Forest of Illusion 3 - Coin Block #16" +forest_of_illusion_3_coin_block_17 = "Forest of Illusion 3 - Coin Block #17" +forest_of_illusion_3_coin_block_18 = "Forest of Illusion 3 - Coin Block #18" +forest_of_illusion_3_coin_block_19 = "Forest of Illusion 3 - Coin Block #19" +forest_of_illusion_3_coin_block_20 = "Forest of Illusion 3 - Coin Block #20" +forest_of_illusion_3_coin_block_21 = "Forest of Illusion 3 - Coin Block #21" +forest_of_illusion_3_coin_block_22 = "Forest of Illusion 3 - Coin Block #22" +forest_of_illusion_3_coin_block_23 = "Forest of Illusion 3 - Coin Block #23" +forest_of_illusion_3_coin_block_24 = "Forest of Illusion 3 - Coin Block #24" +special_zone_8_yoshi_block_1 = "Funky - Yoshi Block #1" +special_zone_8_coin_block_1 = "Funky - Coin Block #1" +special_zone_8_coin_block_2 = "Funky - Coin Block #2" +special_zone_8_coin_block_3 = "Funky - Coin Block #3" +special_zone_8_coin_block_4 = "Funky - Coin Block #4" +special_zone_8_coin_block_5 = "Funky - Coin Block #5" +special_zone_8_blue_pow_block_1 = "Funky - Blue P-Switch Block #1" +special_zone_8_powerup_block_1 = "Funky - Powerup Block #1" +special_zone_8_star_block_1 = "Funky - Star Block #1" +special_zone_8_coin_block_6 = "Funky - Coin Block #6" +special_zone_8_coin_block_7 = "Funky - Coin Block #7" +special_zone_8_coin_block_8 = "Funky - Coin Block #8" +special_zone_8_coin_block_9 = "Funky - Coin Block #9" +special_zone_8_coin_block_10 = "Funky - Coin Block #10" +special_zone_8_coin_block_11 = "Funky - Coin Block #11" +special_zone_8_coin_block_12 = "Funky - Coin Block #12" +special_zone_8_coin_block_13 = "Funky - Coin Block #13" +special_zone_8_coin_block_14 = "Funky - Coin Block #14" +special_zone_8_coin_block_15 = "Funky - Coin Block #15" +special_zone_8_coin_block_16 = "Funky - Coin Block #16" +special_zone_8_coin_block_17 = "Funky - Coin Block #17" +special_zone_8_coin_block_18 = "Funky - Coin Block #18" +special_zone_8_multi_coin_block_1 = "Funky - Multi Coin Block #1" +special_zone_8_coin_block_19 = "Funky - Coin Block #19" +special_zone_8_coin_block_20 = "Funky - Coin Block #20" +special_zone_8_coin_block_21 = "Funky - Coin Block #21" +special_zone_8_coin_block_22 = "Funky - Coin Block #22" +special_zone_8_coin_block_23 = "Funky - Coin Block #23" +special_zone_8_powerup_block_2 = "Funky - Powerup Block #2" +special_zone_8_flying_block_1 = "Funky - Flying Question Block #1" +special_zone_7_powerup_block_1 = "Outrageous - Powerup Block #1" +special_zone_7_yoshi_block_1 = "Outrageous - Yoshi Block #1" +special_zone_7_coin_block_1 = "Outrageous - Coin Block #1" +special_zone_7_powerup_block_2 = "Outrageous - Powerup Block #2" +special_zone_7_coin_block_2 = "Outrageous - Coin Block #2" +special_zone_6_powerup_block_1 = "Mondo - Powerup Block #1" +special_zone_6_coin_block_1 = "Mondo - Coin Block #1" +special_zone_6_coin_block_2 = "Mondo - Coin Block #2" +special_zone_6_yoshi_block_1 = "Mondo - Yoshi Block #1" +special_zone_6_life_block_1 = "Mondo - 1-Up Mushroom Block #1" +special_zone_6_multi_coin_block_1 = "Mondo - Multi Coin Block #1" +special_zone_6_coin_block_3 = "Mondo - Coin Block #3" +special_zone_6_coin_block_4 = "Mondo - Coin Block #4" +special_zone_6_coin_block_5 = "Mondo - Coin Block #5" +special_zone_6_coin_block_6 = "Mondo - Coin Block #6" +special_zone_6_coin_block_7 = "Mondo - Coin Block #7" +special_zone_6_coin_block_8 = "Mondo - Coin Block #8" +special_zone_6_coin_block_9 = "Mondo - Coin Block #9" +special_zone_6_coin_block_10 = "Mondo - Coin Block #10" +special_zone_6_coin_block_11 = "Mondo - Coin Block #11" +special_zone_6_coin_block_12 = "Mondo - Coin Block #12" +special_zone_6_coin_block_13 = "Mondo - Coin Block #13" +special_zone_6_coin_block_14 = "Mondo - Coin Block #14" +special_zone_6_coin_block_15 = "Mondo - Coin Block #15" +special_zone_6_coin_block_16 = "Mondo - Coin Block #16" +special_zone_6_coin_block_17 = "Mondo - Coin Block #17" +special_zone_6_coin_block_18 = "Mondo - Coin Block #18" +special_zone_6_coin_block_19 = "Mondo - Coin Block #19" +special_zone_6_coin_block_20 = "Mondo - Coin Block #20" +special_zone_6_coin_block_21 = "Mondo - Coin Block #21" +special_zone_6_coin_block_22 = "Mondo - Coin Block #22" +special_zone_6_coin_block_23 = "Mondo - Coin Block #23" +special_zone_6_coin_block_24 = "Mondo - Coin Block #24" +special_zone_6_coin_block_25 = "Mondo - Coin Block #25" +special_zone_6_coin_block_26 = "Mondo - Coin Block #26" +special_zone_6_coin_block_27 = "Mondo - Coin Block #27" +special_zone_6_coin_block_28 = "Mondo - Coin Block #28" +special_zone_6_powerup_block_2 = "Mondo - Powerup Block #2" +special_zone_6_coin_block_29 = "Mondo - Coin Block #29" +special_zone_6_coin_block_30 = "Mondo - Coin Block #30" +special_zone_6_coin_block_31 = "Mondo - Coin Block #31" +special_zone_6_coin_block_32 = "Mondo - Coin Block #32" +special_zone_6_coin_block_33 = "Mondo - Coin Block #33" +special_zone_5_yoshi_block_1 = "Groovy - Yoshi Block #1" +special_zone_1_vine_block_1 = "Gnarly - Vine Block #1" +special_zone_1_vine_block_2 = "Gnarly - Vine Block #2" +special_zone_1_vine_block_3 = "Gnarly - Vine Block #3" +special_zone_1_vine_block_4 = "Gnarly - Vine Block #4" +special_zone_1_life_block_1 = "Gnarly - 1-Up Mushroom Block #1" +special_zone_1_vine_block_5 = "Gnarly - Vine Block #5" +special_zone_1_blue_pow_block_1 = "Gnarly - Blue P-Switch Block #1" +special_zone_1_vine_block_6 = "Gnarly - Vine Block #6" +special_zone_1_powerup_block_1 = "Gnarly - Powerup Block #1" +special_zone_1_pswitch_coin_block_1 = "Gnarly - P-Switch Coin Block #1" +special_zone_1_pswitch_coin_block_2 = "Gnarly - P-Switch Coin Block #2" +special_zone_1_pswitch_coin_block_3 = "Gnarly - P-Switch Coin Block #3" +special_zone_1_pswitch_coin_block_4 = "Gnarly - P-Switch Coin Block #4" +special_zone_1_pswitch_coin_block_5 = "Gnarly - P-Switch Coin Block #5" +special_zone_1_pswitch_coin_block_6 = "Gnarly - P-Switch Coin Block #6" +special_zone_1_pswitch_coin_block_7 = "Gnarly - P-Switch Coin Block #7" +special_zone_1_pswitch_coin_block_8 = "Gnarly - P-Switch Coin Block #8" +special_zone_1_pswitch_coin_block_9 = "Gnarly - P-Switch Coin Block #9" +special_zone_1_pswitch_coin_block_10 = "Gnarly - P-Switch Coin Block #10" +special_zone_1_pswitch_coin_block_11 = "Gnarly - P-Switch Coin Block #11" +special_zone_1_pswitch_coin_block_12 = "Gnarly - P-Switch Coin Block #12" +special_zone_1_pswitch_coin_block_13 = "Gnarly - P-Switch Coin Block #13" +special_zone_2_powerup_block_1 = "Tubular - Powerup Block #1" +special_zone_2_coin_block_1 = "Tubular - Coin Block #1" +special_zone_2_coin_block_2 = "Tubular - Coin Block #2" +special_zone_2_powerup_block_2 = "Tubular - Powerup Block #2" +special_zone_2_coin_block_3 = "Tubular - Coin Block #3" +special_zone_2_coin_block_4 = "Tubular - Coin Block #4" +special_zone_2_powerup_block_3 = "Tubular - Powerup Block #3" +special_zone_2_multi_coin_block_1 = "Tubular - Multi Coin Block #1" +special_zone_2_coin_block_5 = "Tubular - Coin Block #5" +special_zone_2_coin_block_6 = "Tubular - Coin Block #6" +special_zone_3_powerup_block_1 = "Way Cool - Powerup Block #1" +special_zone_3_yoshi_block_1 = "Way Cool - Yoshi Block #1" +special_zone_3_wings_block_1 = "Way Cool - Wings Block #1" +special_zone_4_powerup_block_1 = "Awesome - Powerup Block #1" +special_zone_4_star_block_1 = "Awesome - Star Block #1" +star_road_2_star_block_1 = "Star Road 2 - Star Block #1" +star_road_3_key_block_1 = "Star Road 3 - Key Block #1" +star_road_4_powerup_block_1 = "Star Road 4 - Powerup Block #1" +star_road_4_green_block_1 = "Star Road 4 - Green Switch Palace Block #1" +star_road_4_green_block_2 = "Star Road 4 - Green Switch Palace Block #2" +star_road_4_green_block_3 = "Star Road 4 - Green Switch Palace Block #3" +star_road_4_green_block_4 = "Star Road 4 - Green Switch Palace Block #4" +star_road_4_green_block_5 = "Star Road 4 - Green Switch Palace Block #5" +star_road_4_green_block_6 = "Star Road 4 - Green Switch Palace Block #6" +star_road_4_green_block_7 = "Star Road 4 - Green Switch Palace Block #7" +star_road_4_key_block_1 = "Star Road 4 - Key Block #1" +star_road_5_directional_coin_block_1 = "Star Road 5 - Directional Coin Block #1" +star_road_5_life_block_1 = "Star Road 5 - 1-Up Mushroom Block #1" +star_road_5_vine_block_1 = "Star Road 5 - Vine Block #1" +star_road_5_yellow_block_1 = "Star Road 5 - Yellow Switch Palace Block #1" +star_road_5_yellow_block_2 = "Star Road 5 - Yellow Switch Palace Block #2" +star_road_5_yellow_block_3 = "Star Road 5 - Yellow Switch Palace Block #3" +star_road_5_yellow_block_4 = "Star Road 5 - Yellow Switch Palace Block #4" +star_road_5_yellow_block_5 = "Star Road 5 - Yellow Switch Palace Block #5" +star_road_5_yellow_block_6 = "Star Road 5 - Yellow Switch Palace Block #6" +star_road_5_yellow_block_7 = "Star Road 5 - Yellow Switch Palace Block #7" +star_road_5_yellow_block_8 = "Star Road 5 - Yellow Switch Palace Block #8" +star_road_5_yellow_block_9 = "Star Road 5 - Yellow Switch Palace Block #9" +star_road_5_yellow_block_10 = "Star Road 5 - Yellow Switch Palace Block #10" +star_road_5_yellow_block_11 = "Star Road 5 - Yellow Switch Palace Block #11" +star_road_5_yellow_block_12 = "Star Road 5 - Yellow Switch Palace Block #12" +star_road_5_yellow_block_13 = "Star Road 5 - Yellow Switch Palace Block #13" +star_road_5_yellow_block_14 = "Star Road 5 - Yellow Switch Palace Block #14" +star_road_5_yellow_block_15 = "Star Road 5 - Yellow Switch Palace Block #15" +star_road_5_yellow_block_16 = "Star Road 5 - Yellow Switch Palace Block #16" +star_road_5_yellow_block_17 = "Star Road 5 - Yellow Switch Palace Block #17" +star_road_5_yellow_block_18 = "Star Road 5 - Yellow Switch Palace Block #18" +star_road_5_yellow_block_19 = "Star Road 5 - Yellow Switch Palace Block #19" +star_road_5_yellow_block_20 = "Star Road 5 - Yellow Switch Palace Block #20" +star_road_5_green_block_1 = "Star Road 5 - Green Switch Palace Block #1" +star_road_5_green_block_2 = "Star Road 5 - Green Switch Palace Block #2" +star_road_5_green_block_3 = "Star Road 5 - Green Switch Palace Block #3" +star_road_5_green_block_4 = "Star Road 5 - Green Switch Palace Block #4" +star_road_5_green_block_5 = "Star Road 5 - Green Switch Palace Block #5" +star_road_5_green_block_6 = "Star Road 5 - Green Switch Palace Block #6" +star_road_5_green_block_7 = "Star Road 5 - Green Switch Palace Block #7" +star_road_5_green_block_8 = "Star Road 5 - Green Switch Palace Block #8" +star_road_5_green_block_9 = "Star Road 5 - Green Switch Palace Block #9" +star_road_5_green_block_10 = "Star Road 5 - Green Switch Palace Block #10" +star_road_5_green_block_11 = "Star Road 5 - Green Switch Palace Block #11" +star_road_5_green_block_12 = "Star Road 5 - Green Switch Palace Block #12" +star_road_5_green_block_13 = "Star Road 5 - Green Switch Palace Block #13" +star_road_5_green_block_14 = "Star Road 5 - Green Switch Palace Block #14" +star_road_5_green_block_15 = "Star Road 5 - Green Switch Palace Block #15" +star_road_5_green_block_16 = "Star Road 5 - Green Switch Palace Block #16" +star_road_5_green_block_17 = "Star Road 5 - Green Switch Palace Block #17" +star_road_5_green_block_18 = "Star Road 5 - Green Switch Palace Block #18" +star_road_5_green_block_19 = "Star Road 5 - Green Switch Palace Block #19" +star_road_5_green_block_20 = "Star Road 5 - Green Switch Palace Block #20" diff --git a/worlds/smw/Names/TextBox.py b/worlds/smw/Names/TextBox.py index cecf088661..2302a5f85f 100644 --- a/worlds/smw/Names/TextBox.py +++ b/worlds/smw/Names/TextBox.py @@ -1,5 +1,5 @@ -from BaseClasses import MultiWorld +from worlds.AutoWorld import World import math @@ -63,21 +63,23 @@ def generate_text_box(input_string): return out_bytes -def generate_goal_text(world: MultiWorld, player: int): +def generate_goal_text(world: World): out_array = bytearray() - if world.goal[player] == "yoshi_egg_hunt": - required_yoshi_eggs = max(math.floor( - world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1) + if world.options.goal == "yoshi_egg_hunt": + required_yoshi_eggs = world.required_egg_count + actual_yoshi_eggs = world.actual_egg_count out_array += bytearray([0x9F, 0x9F]) out_array += string_to_bytes(" You must acquire") out_array[-1] += 0x80 - out_array += string_to_bytes(f' {required_yoshi_eggs:02} Yoshi Eggs,') + out_array += string_to_bytes(f' {required_yoshi_eggs:03} of {actual_yoshi_eggs:03}') + out_array[-1] += 0x80 + out_array += string_to_bytes(f' Yoshi Eggs,') out_array[-1] += 0x80 out_array += string_to_bytes("then return here.") out_array[-1] += 0x80 - out_array += bytearray([0x9F, 0x9F, 0x9F]) + out_array += bytearray([0x9F, 0x9F]) else: - bosses_required = world.bosses_required[player].value + bosses_required = world.options.bosses_required.value out_array += bytearray([0x9F, 0x9F]) out_array += string_to_bytes(" You must defeat") out_array[-1] += 0x80 diff --git a/worlds/smw/Options.py b/worlds/smw/Options.py index 60135896c8..ab7fcccdba 100644 --- a/worlds/smw/Options.py +++ b/worlds/smw/Options.py @@ -1,6 +1,6 @@ -import typing +from dataclasses import dataclass -from Options import Choice, Range, Option, Toggle, DeathLink, DefaultOnToggle, OptionList +from Options import Choice, Range, Toggle, DeathLink, DefaultOnToggle, PerGameCommonOptions class Goal(Choice): @@ -27,11 +27,13 @@ class BossesRequired(Range): class NumberOfYoshiEggs(Range): """ - How many Yoshi Eggs are in the pool for Yoshi Egg Hunt + Maximum possible number of Yoshi Eggs that will be in the item pool + If fewer available locations exist in the pool than this number, the number of available locations will be used instead. + Required Percentage of Yoshi Eggs will be calculated based off of that number. """ - display_name = "Total Number of Yoshi Eggs" + display_name = "Max Number of Yoshi Eggs" range_start = 1 - range_end = 80 + range_end = 255 default = 50 @@ -52,6 +54,40 @@ class DragonCoinChecks(Toggle): display_name = "Dragon Coin Checks" +class MoonChecks(Toggle): + """ + Whether collecting a 3-Up Moon in a level will grant a check + """ + display_name = "3up Moon Checks" + + +class Hidden1UpChecks(Toggle): + """ + Whether collecting a hidden 1-Up mushroom in a level will grant a check + These checks are considered cryptic as there's no actual indicator that they're in their respective places + Enable this option at your own risk + """ + display_name = "Hidden 1-Up Checks" + + +class BonusBlockChecks(Toggle): + """ + Whether collecting a 1-Up mushroom from a Bonus Block in a level will grant a check + """ + display_name = "Bonus Block Checks" + + +class Blocksanity(Toggle): + """ + Whether hitting a block with an item or coin inside will grant a check + Note that some blocks are excluded due to how the option and the game works! + Exclusion list: + * Blocks in Top Secret Area & Front Door/Bowser Castle + * Blocks that are unreachable unless you glitch your way in + """ + display_name = "Blocksanity" + + class BowserCastleDoors(Choice): """ How the doors of Bowser's Castle behave @@ -127,16 +163,6 @@ class SwapDonutGhostHouseExits(Toggle): display_name = "Swap Donut GH Exits" -class DisplaySentItemPopups(Choice): - """ - What messages to display in-game for items sent - """ - display_name = "Display Sent Item Popups" - option_none = 0 - option_all = 1 - default = 1 - - class DisplayReceivedItemPopups(Choice): """ What messages to display in-game for items received @@ -145,7 +171,18 @@ class DisplayReceivedItemPopups(Choice): option_none = 0 option_all = 1 option_progression = 2 - default = 2 + option_progression_minus_yoshi_eggs = 3 + default = 3 + + +class JunkFillPercentage(Range): + """ + Replace a percentage of non-required Yoshi Eggs in the item pool with random junk items (only applicable on Yoshi Egg Hunt goal) + """ + display_name = "Junk Fill Percentage" + range_start = 0 + range_end = 100 + default = 0 class TrapFillPercentage(Range): @@ -197,6 +234,20 @@ class TimerTrapWeight(BaseTrapWeight): display_name = "Timer Trap Weight" +class ReverseTrapWeight(BaseTrapWeight): + """ + Likelihood of a receiving a trap which causes the controls to be reversed in the current level + """ + display_name = "Reverse Trap Weight" + + +class ThwimpTrapWeight(BaseTrapWeight): + """ + Likelihood of a receiving a trap which causes a Thwimp to spawn above the player + """ + display_name = "Thwimp Trap Weight" + + class Autosave(DefaultOnToggle): """ Whether a save prompt will appear after every level @@ -239,6 +290,21 @@ class MusicShuffle(Choice): default = 0 +class SFXShuffle(Choice): + """ + Shuffles almost every instance of sound effect playback + Archipelago elements that play sound effects aren't randomized + None: No SFX are shuffled + Full: Each individual SFX call has a random SFX + Singularity: The entire game uses one SFX for every SFX call + """ + display_name = "Sound Effect Shuffle" + option_none = 0 + option_full = 1 + option_singularity = 2 + default = 0 + + class MarioPalette(Choice): """ Mario palette color @@ -255,25 +321,32 @@ class MarioPalette(Choice): default = 0 -class ForegroundPaletteShuffle(Toggle): +class LevelPaletteShuffle(Choice): """ - Whether to shuffle level foreground palettes + Whether to shuffle level palettes + Off: Do not shuffle palettes + On Legacy: Uses only the palette sets from the original game + On Curated: Uses custom, hand-crafted palette sets """ - display_name = "Foreground Palette Shuffle" + display_name = "Level Palette Shuffle" + option_off = 0 + option_on_legacy = 1 + option_on_curated = 2 + default = 0 -class BackgroundPaletteShuffle(Toggle): - """ - Whether to shuffle level background palettes - """ - display_name = "Background Palette Shuffle" - - -class OverworldPaletteShuffle(Toggle): +class OverworldPaletteShuffle(Choice): """ Whether to shuffle overworld palettes + Off: Do not shuffle palettes + On Legacy: Uses only the palette sets from the original game + On Curated: Uses custom, hand-crafted palette sets """ display_name = "Overworld Palette Shuffle" + option_off = 0 + option_on_legacy = 1 + option_on_curated = 2 + default = 0 class StartingLifeCount(Range): @@ -286,34 +359,39 @@ class StartingLifeCount(Range): default = 5 - -smw_options: typing.Dict[str, type(Option)] = { - "death_link": DeathLink, - "goal": Goal, - "bosses_required": BossesRequired, - "number_of_yoshi_eggs": NumberOfYoshiEggs, - "percentage_of_yoshi_eggs": PercentageOfYoshiEggs, - "dragon_coin_checks": DragonCoinChecks, - "bowser_castle_doors": BowserCastleDoors, - "bowser_castle_rooms": BowserCastleRooms, - "level_shuffle": LevelShuffle, - "exclude_special_zone": ExcludeSpecialZone, - "boss_shuffle": BossShuffle, - "swap_donut_gh_exits": SwapDonutGhostHouseExits, - #"display_sent_item_popups": DisplaySentItemPopups, - "display_received_item_popups": DisplayReceivedItemPopups, - "trap_fill_percentage": TrapFillPercentage, - "ice_trap_weight": IceTrapWeight, - "stun_trap_weight": StunTrapWeight, - "literature_trap_weight": LiteratureTrapWeight, - "timer_trap_weight": TimerTrapWeight, - "autosave": Autosave, - "early_climb": EarlyClimb, - "overworld_speed": OverworldSpeed, - "music_shuffle": MusicShuffle, - "mario_palette": MarioPalette, - "foreground_palette_shuffle": ForegroundPaletteShuffle, - "background_palette_shuffle": BackgroundPaletteShuffle, - "overworld_palette_shuffle": OverworldPaletteShuffle, - "starting_life_count": StartingLifeCount, -} +@dataclass +class SMWOptions(PerGameCommonOptions): + death_link: DeathLink + goal: Goal + bosses_required: BossesRequired + max_yoshi_egg_cap: NumberOfYoshiEggs + percentage_of_yoshi_eggs: PercentageOfYoshiEggs + dragon_coin_checks: DragonCoinChecks + moon_checks: MoonChecks + hidden_1up_checks: Hidden1UpChecks + bonus_block_checks: BonusBlockChecks + blocksanity: Blocksanity + bowser_castle_doors: BowserCastleDoors + bowser_castle_rooms: BowserCastleRooms + level_shuffle: LevelShuffle + exclude_special_zone: ExcludeSpecialZone + boss_shuffle: BossShuffle + swap_donut_gh_exits: SwapDonutGhostHouseExits + display_received_item_popups: DisplayReceivedItemPopups + junk_fill_percentage: JunkFillPercentage + trap_fill_percentage: TrapFillPercentage + ice_trap_weight: IceTrapWeight + stun_trap_weight: StunTrapWeight + literature_trap_weight: LiteratureTrapWeight + timer_trap_weight: TimerTrapWeight + reverse_trap_weight: ReverseTrapWeight + thwimp_trap_weight: ThwimpTrapWeight + autosave: Autosave + early_climb: EarlyClimb + overworld_speed: OverworldSpeed + music_shuffle: MusicShuffle + sfx_shuffle: SFXShuffle + mario_palette: MarioPalette + level_palette_shuffle: LevelPaletteShuffle + overworld_palette_shuffle: OverworldPaletteShuffle + starting_life_count: StartingLifeCount diff --git a/worlds/smw/Regions.py b/worlds/smw/Regions.py index 885f209aa7..2f8a128a56 100644 --- a/worlds/smw/Regions.py +++ b/worlds/smw/Regions.py @@ -1,467 +1,470 @@ import typing -from BaseClasses import MultiWorld, Region, Entrance +from BaseClasses import CollectionState, MultiWorld, Region, Entrance from .Locations import SMWLocation from .Levels import level_info_dict from .Names import LocationName, ItemName from worlds.generic.Rules import add_rule, set_rule +from worlds.AutoWorld import World -def create_regions(world, player: int, active_locations): - menu_region = create_region(world, player, active_locations, 'Menu', None) +def create_regions(world: World, active_locations): + multiworld: MultiWorld = world.multiworld + player: int = world.player - yoshis_island_region = create_region(world, player, active_locations, LocationName.yoshis_island_region, None) + menu_region = create_region(multiworld, player, active_locations, 'Menu', None) + yoshis_island_region = create_region(multiworld, player, active_locations, LocationName.yoshis_island_region, None) - yoshis_house_tile = create_region(world, player, active_locations, LocationName.yoshis_house_tile, None) + yoshis_house_tile = create_region(multiworld, player, active_locations, LocationName.yoshis_house_tile, None) yoshis_house_region_locations = [] - if world.goal[player] == "yoshi_egg_hunt": + if world.options.goal == "yoshi_egg_hunt": yoshis_house_region_locations.append(LocationName.yoshis_house) - yoshis_house_region = create_region(world, player, active_locations, LocationName.yoshis_house, + yoshis_house_region = create_region(multiworld, player, active_locations, LocationName.yoshis_house, yoshis_house_region_locations) - yoshis_island_1_tile = create_region(world, player, active_locations, LocationName.yoshis_island_1_tile, None) - yoshis_island_1_region = create_region(world, player, active_locations, LocationName.yoshis_island_1_region, None) - yoshis_island_1_exit_1 = create_region(world, player, active_locations, LocationName.yoshis_island_1_exit_1, + yoshis_island_1_tile = create_region(multiworld, player, active_locations, LocationName.yoshis_island_1_tile, None) + yoshis_island_1_region = create_region(multiworld, player, active_locations, LocationName.yoshis_island_1_region, None) + yoshis_island_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.yoshis_island_1_exit_1, [LocationName.yoshis_island_1_exit_1]) - yoshis_island_2_tile = create_region(world, player, active_locations, LocationName.yoshis_island_2_tile, None) - yoshis_island_2_region = create_region(world, player, active_locations, LocationName.yoshis_island_2_region, None) - yoshis_island_2_exit_1 = create_region(world, player, active_locations, LocationName.yoshis_island_2_exit_1, + yoshis_island_2_tile = create_region(multiworld, player, active_locations, LocationName.yoshis_island_2_tile, None) + yoshis_island_2_region = create_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, None) + yoshis_island_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.yoshis_island_2_exit_1, [LocationName.yoshis_island_2_exit_1]) - yoshis_island_3_tile = create_region(world, player, active_locations, LocationName.yoshis_island_3_tile, None) - yoshis_island_3_region = create_region(world, player, active_locations, LocationName.yoshis_island_3_region, None) - yoshis_island_3_exit_1 = create_region(world, player, active_locations, LocationName.yoshis_island_3_exit_1, + yoshis_island_3_tile = create_region(multiworld, player, active_locations, LocationName.yoshis_island_3_tile, None) + yoshis_island_3_region = create_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, None) + yoshis_island_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.yoshis_island_3_exit_1, [LocationName.yoshis_island_3_exit_1]) - yoshis_island_4_tile = create_region(world, player, active_locations, LocationName.yoshis_island_4_tile, None) - yoshis_island_4_region = create_region(world, player, active_locations, LocationName.yoshis_island_4_region, None) - yoshis_island_4_exit_1 = create_region(world, player, active_locations, LocationName.yoshis_island_4_exit_1, + yoshis_island_4_tile = create_region(multiworld, player, active_locations, LocationName.yoshis_island_4_tile, None) + yoshis_island_4_region = create_region(multiworld, player, active_locations, LocationName.yoshis_island_4_region, None) + yoshis_island_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.yoshis_island_4_exit_1, [LocationName.yoshis_island_4_exit_1]) - yoshis_island_castle_tile = create_region(world, player, active_locations, LocationName.yoshis_island_castle_tile, None) - yoshis_island_castle_region = create_region(world, player, active_locations, LocationName.yoshis_island_castle_region, None) - yoshis_island_castle = create_region(world, player, active_locations, LocationName.yoshis_island_castle, + yoshis_island_castle_tile = create_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_tile, None) + yoshis_island_castle_region = create_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_region, None) + yoshis_island_castle = create_region(multiworld, player, active_locations, LocationName.yoshis_island_castle, [LocationName.yoshis_island_castle, LocationName.yoshis_island_koopaling]) - yellow_switch_palace_tile = create_region(world, player, active_locations, LocationName.yellow_switch_palace_tile, None) - yellow_switch_palace = create_region(world, player, active_locations, LocationName.yellow_switch_palace, + yellow_switch_palace_tile = create_region(multiworld, player, active_locations, LocationName.yellow_switch_palace_tile, None) + yellow_switch_palace = create_region(multiworld, player, active_locations, LocationName.yellow_switch_palace, [LocationName.yellow_switch_palace]) - donut_plains_1_tile = create_region(world, player, active_locations, LocationName.donut_plains_1_tile, None) - donut_plains_1_region = create_region(world, player, active_locations, LocationName.donut_plains_1_region, None) - donut_plains_1_exit_1 = create_region(world, player, active_locations, LocationName.donut_plains_1_exit_1, + donut_plains_1_tile = create_region(multiworld, player, active_locations, LocationName.donut_plains_1_tile, None) + donut_plains_1_region = create_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, None) + donut_plains_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_plains_1_exit_1, [LocationName.donut_plains_1_exit_1]) - donut_plains_1_exit_2 = create_region(world, player, active_locations, LocationName.donut_plains_1_exit_2, + donut_plains_1_exit_2 = create_region(multiworld, player, active_locations, LocationName.donut_plains_1_exit_2, [LocationName.donut_plains_1_exit_2]) - donut_plains_2_tile = create_region(world, player, active_locations, LocationName.donut_plains_2_tile, None) - donut_plains_2_region = create_region(world, player, active_locations, LocationName.donut_plains_2_region, None) - donut_plains_2_exit_1 = create_region(world, player, active_locations, LocationName.donut_plains_2_exit_1, + donut_plains_2_tile = create_region(multiworld, player, active_locations, LocationName.donut_plains_2_tile, None) + donut_plains_2_region = create_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, None) + donut_plains_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_plains_2_exit_1, [LocationName.donut_plains_2_exit_1]) - donut_plains_2_exit_2 = create_region(world, player, active_locations, LocationName.donut_plains_2_exit_2, + donut_plains_2_exit_2 = create_region(multiworld, player, active_locations, LocationName.donut_plains_2_exit_2, [LocationName.donut_plains_2_exit_2]) - donut_plains_3_tile = create_region(world, player, active_locations, LocationName.donut_plains_3_tile, None) - donut_plains_3_region = create_region(world, player, active_locations, LocationName.donut_plains_3_region, None) - donut_plains_3_exit_1 = create_region(world, player, active_locations, LocationName.donut_plains_3_exit_1, + donut_plains_3_tile = create_region(multiworld, player, active_locations, LocationName.donut_plains_3_tile, None) + donut_plains_3_region = create_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, None) + donut_plains_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_plains_3_exit_1, [LocationName.donut_plains_3_exit_1]) - donut_plains_4_tile = create_region(world, player, active_locations, LocationName.donut_plains_4_tile, None) - donut_plains_4_region = create_region(world, player, active_locations, LocationName.donut_plains_4_region, None) - donut_plains_4_exit_1 = create_region(world, player, active_locations, LocationName.donut_plains_4_exit_1, + donut_plains_4_tile = create_region(multiworld, player, active_locations, LocationName.donut_plains_4_tile, None) + donut_plains_4_region = create_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, None) + donut_plains_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_plains_4_exit_1, [LocationName.donut_plains_4_exit_1]) - donut_secret_1_tile = create_region(world, player, active_locations, LocationName.donut_secret_1_tile, None) - donut_secret_1_region = create_region(world, player, active_locations, LocationName.donut_secret_1_region, None) - donut_secret_1_exit_1 = create_region(world, player, active_locations, LocationName.donut_secret_1_exit_1, + donut_secret_1_tile = create_region(multiworld, player, active_locations, LocationName.donut_secret_1_tile, None) + donut_secret_1_region = create_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, None) + donut_secret_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_secret_1_exit_1, [LocationName.donut_secret_1_exit_1]) - donut_secret_1_exit_2 = create_region(world, player, active_locations, LocationName.donut_secret_1_exit_2, + donut_secret_1_exit_2 = create_region(multiworld, player, active_locations, LocationName.donut_secret_1_exit_2, [LocationName.donut_secret_1_exit_2]) - donut_secret_2_tile = create_region(world, player, active_locations, LocationName.donut_secret_2_tile, None) - donut_secret_2_region = create_region(world, player, active_locations, LocationName.donut_secret_2_region, None) - donut_secret_2_exit_1 = create_region(world, player, active_locations, LocationName.donut_secret_2_exit_1, + donut_secret_2_tile = create_region(multiworld, player, active_locations, LocationName.donut_secret_2_tile, None) + donut_secret_2_region = create_region(multiworld, player, active_locations, LocationName.donut_secret_2_region, None) + donut_secret_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_secret_2_exit_1, [LocationName.donut_secret_2_exit_1]) - donut_ghost_house_tile = create_region(world, player, active_locations, LocationName.donut_ghost_house_tile, None) - donut_ghost_house_region = create_region(world, player, active_locations, LocationName.donut_ghost_house_region, None) - donut_ghost_house_exit_1 = create_region(world, player, active_locations, LocationName.donut_ghost_house_exit_1, + donut_ghost_house_tile = create_region(multiworld, player, active_locations, LocationName.donut_ghost_house_tile, None) + donut_ghost_house_region = create_region(multiworld, player, active_locations, LocationName.donut_ghost_house_region, None) + donut_ghost_house_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_ghost_house_exit_1, [LocationName.donut_ghost_house_exit_1]) - donut_ghost_house_exit_2 = create_region(world, player, active_locations, LocationName.donut_ghost_house_exit_2, + donut_ghost_house_exit_2 = create_region(multiworld, player, active_locations, LocationName.donut_ghost_house_exit_2, [LocationName.donut_ghost_house_exit_2]) - donut_secret_house_tile = create_region(world, player, active_locations, LocationName.donut_secret_house_tile, None) - donut_secret_house_region = create_region(world, player, active_locations, LocationName.donut_secret_house_region, None) - donut_secret_house_exit_1 = create_region(world, player, active_locations, LocationName.donut_secret_house_exit_1, + donut_secret_house_tile = create_region(multiworld, player, active_locations, LocationName.donut_secret_house_tile, None) + donut_secret_house_region = create_region(multiworld, player, active_locations, LocationName.donut_secret_house_region, None) + donut_secret_house_exit_1 = create_region(multiworld, player, active_locations, LocationName.donut_secret_house_exit_1, [LocationName.donut_secret_house_exit_1]) - donut_secret_house_exit_2 = create_region(world, player, active_locations, LocationName.donut_secret_house_exit_2, + donut_secret_house_exit_2 = create_region(multiworld, player, active_locations, LocationName.donut_secret_house_exit_2, [LocationName.donut_secret_house_exit_2]) - donut_plains_castle_tile = create_region(world, player, active_locations, LocationName.donut_plains_castle_tile, None) - donut_plains_castle_region = create_region(world, player, active_locations, LocationName.donut_plains_castle_region, None) - donut_plains_castle = create_region(world, player, active_locations, LocationName.donut_plains_castle, + donut_plains_castle_tile = create_region(multiworld, player, active_locations, LocationName.donut_plains_castle_tile, None) + donut_plains_castle_region = create_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, None) + donut_plains_castle = create_region(multiworld, player, active_locations, LocationName.donut_plains_castle, [LocationName.donut_plains_castle, LocationName.donut_plains_koopaling]) - green_switch_palace_tile = create_region(world, player, active_locations, LocationName.green_switch_palace_tile, None) - green_switch_palace = create_region(world, player, active_locations, LocationName.green_switch_palace, + green_switch_palace_tile = create_region(multiworld, player, active_locations, LocationName.green_switch_palace_tile, None) + green_switch_palace = create_region(multiworld, player, active_locations, LocationName.green_switch_palace, [LocationName.green_switch_palace]) - donut_plains_top_secret_tile = create_region(world, player, active_locations, LocationName.donut_plains_top_secret_tile, None) - donut_plains_top_secret = create_region(world, player, active_locations, LocationName.donut_plains_top_secret, None) + donut_plains_top_secret_tile = create_region(multiworld, player, active_locations, LocationName.donut_plains_top_secret_tile, None) + donut_plains_top_secret = create_region(multiworld, player, active_locations, LocationName.donut_plains_top_secret, None) - vanilla_dome_1_tile = create_region(world, player, active_locations, LocationName.vanilla_dome_1_tile, None) - vanilla_dome_1_region = create_region(world, player, active_locations, LocationName.vanilla_dome_1_region, None) - vanilla_dome_1_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_dome_1_exit_1, + vanilla_dome_1_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_tile, None) + vanilla_dome_1_region = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, None) + vanilla_dome_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_exit_1, [LocationName.vanilla_dome_1_exit_1]) - vanilla_dome_1_exit_2 = create_region(world, player, active_locations, LocationName.vanilla_dome_1_exit_2, + vanilla_dome_1_exit_2 = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_exit_2, [LocationName.vanilla_dome_1_exit_2]) - vanilla_dome_2_tile = create_region(world, player, active_locations, LocationName.vanilla_dome_2_tile, None) - vanilla_dome_2_region = create_region(world, player, active_locations, LocationName.vanilla_dome_2_region, None) - vanilla_dome_2_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_dome_2_exit_1, + vanilla_dome_2_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_tile, None) + vanilla_dome_2_region = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, None) + vanilla_dome_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_exit_1, [LocationName.vanilla_dome_2_exit_1]) - vanilla_dome_2_exit_2 = create_region(world, player, active_locations, LocationName.vanilla_dome_2_exit_2, + vanilla_dome_2_exit_2 = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_exit_2, [LocationName.vanilla_dome_2_exit_2]) - vanilla_dome_3_tile = create_region(world, player, active_locations, LocationName.vanilla_dome_3_tile, None) - vanilla_dome_3_region = create_region(world, player, active_locations, LocationName.vanilla_dome_3_region, None) - vanilla_dome_3_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_dome_3_exit_1, + vanilla_dome_3_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_tile, None) + vanilla_dome_3_region = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, None) + vanilla_dome_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_exit_1, [LocationName.vanilla_dome_3_exit_1]) - vanilla_dome_4_tile = create_region(world, player, active_locations, LocationName.vanilla_dome_4_tile, None) - vanilla_dome_4_region = create_region(world, player, active_locations, LocationName.vanilla_dome_4_region, None) - vanilla_dome_4_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_dome_4_exit_1, + vanilla_dome_4_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_tile, None) + vanilla_dome_4_region = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, None) + vanilla_dome_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_exit_1, [LocationName.vanilla_dome_4_exit_1]) - vanilla_secret_1_tile = create_region(world, player, active_locations, LocationName.vanilla_secret_1_tile, None) - vanilla_secret_1_region = create_region(world, player, active_locations, LocationName.vanilla_secret_1_region, None) - vanilla_secret_1_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_secret_1_exit_1, + vanilla_secret_1_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_tile, None) + vanilla_secret_1_region = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, None) + vanilla_secret_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_exit_1, [LocationName.vanilla_secret_1_exit_1]) - vanilla_secret_1_exit_2 = create_region(world, player, active_locations, LocationName.vanilla_secret_1_exit_2, + vanilla_secret_1_exit_2 = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_exit_2, [LocationName.vanilla_secret_1_exit_2]) - vanilla_secret_2_tile = create_region(world, player, active_locations, LocationName.vanilla_secret_2_tile, None) - vanilla_secret_2_region = create_region(world, player, active_locations, LocationName.vanilla_secret_2_region, None) - vanilla_secret_2_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_secret_2_exit_1, + vanilla_secret_2_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_tile, None) + vanilla_secret_2_region = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, None) + vanilla_secret_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_exit_1, [LocationName.vanilla_secret_2_exit_1]) - vanilla_secret_3_tile = create_region(world, player, active_locations, LocationName.vanilla_secret_3_tile, None) - vanilla_secret_3_region = create_region(world, player, active_locations, LocationName.vanilla_secret_3_region, None) - vanilla_secret_3_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_secret_3_exit_1, + vanilla_secret_3_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_3_tile, None) + vanilla_secret_3_region = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_3_region, None) + vanilla_secret_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_secret_3_exit_1, [LocationName.vanilla_secret_3_exit_1]) - vanilla_ghost_house_tile = create_region(world, player, active_locations, LocationName.vanilla_ghost_house_tile, None) - vanilla_ghost_house_region = create_region(world, player, active_locations, LocationName.vanilla_ghost_house_region, None) - vanilla_ghost_house_exit_1 = create_region(world, player, active_locations, LocationName.vanilla_ghost_house_exit_1, + vanilla_ghost_house_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_tile, None) + vanilla_ghost_house_region = create_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, None) + vanilla_ghost_house_exit_1 = create_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_exit_1, [LocationName.vanilla_ghost_house_exit_1]) - vanilla_fortress_tile = create_region(world, player, active_locations, LocationName.vanilla_fortress_tile, None) - vanilla_fortress_region = create_region(world, player, active_locations, LocationName.vanilla_fortress_region, None) - vanilla_fortress = create_region(world, player, active_locations, LocationName.vanilla_fortress, + vanilla_fortress_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_fortress_tile, None) + vanilla_fortress_region = create_region(multiworld, player, active_locations, LocationName.vanilla_fortress_region, None) + vanilla_fortress = create_region(multiworld, player, active_locations, LocationName.vanilla_fortress, [LocationName.vanilla_fortress, LocationName.vanilla_reznor]) - vanilla_dome_castle_tile = create_region(world, player, active_locations, LocationName.vanilla_dome_castle_tile, None) - vanilla_dome_castle_region = create_region(world, player, active_locations, LocationName.vanilla_dome_castle_region, None) - vanilla_dome_castle = create_region(world, player, active_locations, LocationName.vanilla_dome_castle, + vanilla_dome_castle_tile = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle_tile, None) + vanilla_dome_castle_region = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle_region, None) + vanilla_dome_castle = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle, [LocationName.vanilla_dome_castle, LocationName.vanilla_dome_koopaling]) - red_switch_palace_tile = create_region(world, player, active_locations, LocationName.red_switch_palace_tile, None) - red_switch_palace = create_region(world, player, active_locations, LocationName.red_switch_palace, + red_switch_palace_tile = create_region(multiworld, player, active_locations, LocationName.red_switch_palace_tile, None) + red_switch_palace = create_region(multiworld, player, active_locations, LocationName.red_switch_palace, [LocationName.red_switch_palace]) - butter_bridge_1_tile = create_region(world, player, active_locations, LocationName.butter_bridge_1_tile, None) - butter_bridge_1_region = create_region(world, player, active_locations, LocationName.butter_bridge_1_region, None) - butter_bridge_1_exit_1 = create_region(world, player, active_locations, LocationName.butter_bridge_1_exit_1, + butter_bridge_1_tile = create_region(multiworld, player, active_locations, LocationName.butter_bridge_1_tile, None) + butter_bridge_1_region = create_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, None) + butter_bridge_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.butter_bridge_1_exit_1, [LocationName.butter_bridge_1_exit_1]) - butter_bridge_2_tile = create_region(world, player, active_locations, LocationName.butter_bridge_2_tile, None) - butter_bridge_2_region = create_region(world, player, active_locations, LocationName.butter_bridge_2_region, None) - butter_bridge_2_exit_1 = create_region(world, player, active_locations, LocationName.butter_bridge_2_exit_1, + butter_bridge_2_tile = create_region(multiworld, player, active_locations, LocationName.butter_bridge_2_tile, None) + butter_bridge_2_region = create_region(multiworld, player, active_locations, LocationName.butter_bridge_2_region, None) + butter_bridge_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.butter_bridge_2_exit_1, [LocationName.butter_bridge_2_exit_1]) - cheese_bridge_tile = create_region(world, player, active_locations, LocationName.cheese_bridge_tile, None) - cheese_bridge_region = create_region(world, player, active_locations, LocationName.cheese_bridge_region, None) - cheese_bridge_exit_1 = create_region(world, player, active_locations, LocationName.cheese_bridge_exit_1, + cheese_bridge_tile = create_region(multiworld, player, active_locations, LocationName.cheese_bridge_tile, None) + cheese_bridge_region = create_region(multiworld, player, active_locations, LocationName.cheese_bridge_region, None) + cheese_bridge_exit_1 = create_region(multiworld, player, active_locations, LocationName.cheese_bridge_exit_1, [LocationName.cheese_bridge_exit_1]) - cheese_bridge_exit_2 = create_region(world, player, active_locations, LocationName.cheese_bridge_exit_2, + cheese_bridge_exit_2 = create_region(multiworld, player, active_locations, LocationName.cheese_bridge_exit_2, [LocationName.cheese_bridge_exit_2]) - cookie_mountain_tile = create_region(world, player, active_locations, LocationName.cookie_mountain_tile, None) - cookie_mountain_region = create_region(world, player, active_locations, LocationName.cookie_mountain_region, None) - cookie_mountain_exit_1 = create_region(world, player, active_locations, LocationName.cookie_mountain_exit_1, + cookie_mountain_tile = create_region(multiworld, player, active_locations, LocationName.cookie_mountain_tile, None) + cookie_mountain_region = create_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, None) + cookie_mountain_exit_1 = create_region(multiworld, player, active_locations, LocationName.cookie_mountain_exit_1, [LocationName.cookie_mountain_exit_1]) - soda_lake_tile = create_region(world, player, active_locations, LocationName.soda_lake_tile, None) - soda_lake_region = create_region(world, player, active_locations, LocationName.soda_lake_region, None) - soda_lake_exit_1 = create_region(world, player, active_locations, LocationName.soda_lake_exit_1, + soda_lake_tile = create_region(multiworld, player, active_locations, LocationName.soda_lake_tile, None) + soda_lake_region = create_region(multiworld, player, active_locations, LocationName.soda_lake_region, None) + soda_lake_exit_1 = create_region(multiworld, player, active_locations, LocationName.soda_lake_exit_1, [LocationName.soda_lake_exit_1]) - twin_bridges_castle_tile = create_region(world, player, active_locations, LocationName.twin_bridges_castle_tile, None) - twin_bridges_castle_region = create_region(world, player, active_locations, LocationName.twin_bridges_castle_region, None) - twin_bridges_castle = create_region(world, player, active_locations, LocationName.twin_bridges_castle, + twin_bridges_castle_tile = create_region(multiworld, player, active_locations, LocationName.twin_bridges_castle_tile, None) + twin_bridges_castle_region = create_region(multiworld, player, active_locations, LocationName.twin_bridges_castle_region, None) + twin_bridges_castle = create_region(multiworld, player, active_locations, LocationName.twin_bridges_castle, [LocationName.twin_bridges_castle, LocationName.twin_bridges_koopaling]) - forest_of_illusion_1_tile = create_region(world, player, active_locations, LocationName.forest_of_illusion_1_tile, None) - forest_of_illusion_1_region = create_region(world, player, active_locations, LocationName.forest_of_illusion_1_region, None) - forest_of_illusion_1_exit_1 = create_region(world, player, active_locations, LocationName.forest_of_illusion_1_exit_1, + forest_of_illusion_1_tile = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_tile, None) + forest_of_illusion_1_region = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_region, None) + forest_of_illusion_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_exit_1, [LocationName.forest_of_illusion_1_exit_1]) - forest_of_illusion_1_exit_2 = create_region(world, player, active_locations, LocationName.forest_of_illusion_1_exit_2, + forest_of_illusion_1_exit_2 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_exit_2, [LocationName.forest_of_illusion_1_exit_2]) - forest_of_illusion_2_tile = create_region(world, player, active_locations, LocationName.forest_of_illusion_2_tile, None) - forest_of_illusion_2_region = create_region(world, player, active_locations, LocationName.forest_of_illusion_2_region, None) - forest_of_illusion_2_exit_1 = create_region(world, player, active_locations, LocationName.forest_of_illusion_2_exit_1, + forest_of_illusion_2_tile = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_tile, None) + forest_of_illusion_2_region = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, None) + forest_of_illusion_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_exit_1, [LocationName.forest_of_illusion_2_exit_1]) - forest_of_illusion_2_exit_2 = create_region(world, player, active_locations, LocationName.forest_of_illusion_2_exit_2, + forest_of_illusion_2_exit_2 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_exit_2, [LocationName.forest_of_illusion_2_exit_2]) - forest_of_illusion_3_tile = create_region(world, player, active_locations, LocationName.forest_of_illusion_3_tile, None) - forest_of_illusion_3_region = create_region(world, player, active_locations, LocationName.forest_of_illusion_3_region, None) - forest_of_illusion_3_exit_1 = create_region(world, player, active_locations, LocationName.forest_of_illusion_3_exit_1, + forest_of_illusion_3_tile = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_tile, None) + forest_of_illusion_3_region = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, None) + forest_of_illusion_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_exit_1, [LocationName.forest_of_illusion_3_exit_1]) - forest_of_illusion_3_exit_2 = create_region(world, player, active_locations, LocationName.forest_of_illusion_3_exit_2, + forest_of_illusion_3_exit_2 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_exit_2, [LocationName.forest_of_illusion_3_exit_2]) - forest_of_illusion_4_tile = create_region(world, player, active_locations, LocationName.forest_of_illusion_4_tile, None) - forest_of_illusion_4_region = create_region(world, player, active_locations, LocationName.forest_of_illusion_4_region, None) - forest_of_illusion_4_exit_1 = create_region(world, player, active_locations, LocationName.forest_of_illusion_4_exit_1, + forest_of_illusion_4_tile = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_tile, None) + forest_of_illusion_4_region = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, None) + forest_of_illusion_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_exit_1, [LocationName.forest_of_illusion_4_exit_1]) - forest_of_illusion_4_exit_2 = create_region(world, player, active_locations, LocationName.forest_of_illusion_4_exit_2, + forest_of_illusion_4_exit_2 = create_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_exit_2, [LocationName.forest_of_illusion_4_exit_2]) - forest_ghost_house_tile = create_region(world, player, active_locations, LocationName.forest_ghost_house_tile, None) - forest_ghost_house_region = create_region(world, player, active_locations, LocationName.forest_ghost_house_region, None) - forest_ghost_house_exit_1 = create_region(world, player, active_locations, LocationName.forest_ghost_house_exit_1, + forest_ghost_house_tile = create_region(multiworld, player, active_locations, LocationName.forest_ghost_house_tile, None) + forest_ghost_house_region = create_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, None) + forest_ghost_house_exit_1 = create_region(multiworld, player, active_locations, LocationName.forest_ghost_house_exit_1, [LocationName.forest_ghost_house_exit_1]) - forest_ghost_house_exit_2 = create_region(world, player, active_locations, LocationName.forest_ghost_house_exit_2, + forest_ghost_house_exit_2 = create_region(multiworld, player, active_locations, LocationName.forest_ghost_house_exit_2, [LocationName.forest_ghost_house_exit_2]) - forest_secret_tile = create_region(world, player, active_locations, LocationName.forest_secret_tile, None) - forest_secret_region = create_region(world, player, active_locations, LocationName.forest_secret_region, None) - forest_secret_exit_1 = create_region(world, player, active_locations, LocationName.forest_secret_exit_1, + forest_secret_tile = create_region(multiworld, player, active_locations, LocationName.forest_secret_tile, None) + forest_secret_region = create_region(multiworld, player, active_locations, LocationName.forest_secret_region, None) + forest_secret_exit_1 = create_region(multiworld, player, active_locations, LocationName.forest_secret_exit_1, [LocationName.forest_secret_exit_1]) - forest_fortress_tile = create_region(world, player, active_locations, LocationName.forest_fortress_tile, None) - forest_fortress_region = create_region(world, player, active_locations, LocationName.forest_fortress_region, None) - forest_fortress = create_region(world, player, active_locations, LocationName.forest_fortress, + forest_fortress_tile = create_region(multiworld, player, active_locations, LocationName.forest_fortress_tile, None) + forest_fortress_region = create_region(multiworld, player, active_locations, LocationName.forest_fortress_region, None) + forest_fortress = create_region(multiworld, player, active_locations, LocationName.forest_fortress, [LocationName.forest_fortress, LocationName.forest_reznor]) - forest_castle_tile = create_region(world, player, active_locations, LocationName.forest_castle_tile, None) - forest_castle_region = create_region(world, player, active_locations, LocationName.forest_castle_region, None) - forest_castle = create_region(world, player, active_locations, LocationName.forest_castle, + forest_castle_tile = create_region(multiworld, player, active_locations, LocationName.forest_castle_tile, None) + forest_castle_region = create_region(multiworld, player, active_locations, LocationName.forest_castle_region, None) + forest_castle = create_region(multiworld, player, active_locations, LocationName.forest_castle, [LocationName.forest_castle, LocationName.forest_koopaling]) - blue_switch_palace_tile = create_region(world, player, active_locations, LocationName.blue_switch_palace_tile, None) - blue_switch_palace = create_region(world, player, active_locations, LocationName.blue_switch_palace, + blue_switch_palace_tile = create_region(multiworld, player, active_locations, LocationName.blue_switch_palace_tile, None) + blue_switch_palace = create_region(multiworld, player, active_locations, LocationName.blue_switch_palace, [LocationName.blue_switch_palace]) - chocolate_island_1_tile = create_region(world, player, active_locations, LocationName.chocolate_island_1_tile, None) - chocolate_island_1_region = create_region(world, player, active_locations, LocationName.chocolate_island_1_region, None) - chocolate_island_1_exit_1 = create_region(world, player, active_locations, LocationName.chocolate_island_1_exit_1, + chocolate_island_1_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_island_1_tile, None) + chocolate_island_1_region = create_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, None) + chocolate_island_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.chocolate_island_1_exit_1, [LocationName.chocolate_island_1_exit_1]) - chocolate_island_2_tile = create_region(world, player, active_locations, LocationName.chocolate_island_2_tile, None) - chocolate_island_2_region = create_region(world, player, active_locations, LocationName.chocolate_island_2_region, None) - chocolate_island_2_exit_1 = create_region(world, player, active_locations, LocationName.chocolate_island_2_exit_1, + chocolate_island_2_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_island_2_tile, None) + chocolate_island_2_region = create_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, None) + chocolate_island_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.chocolate_island_2_exit_1, [LocationName.chocolate_island_2_exit_1]) - chocolate_island_2_exit_2 = create_region(world, player, active_locations, LocationName.chocolate_island_2_exit_2, + chocolate_island_2_exit_2 = create_region(multiworld, player, active_locations, LocationName.chocolate_island_2_exit_2, [LocationName.chocolate_island_2_exit_2]) - chocolate_island_3_tile = create_region(world, player, active_locations, LocationName.chocolate_island_3_tile, None) - chocolate_island_3_region = create_region(world, player, active_locations, LocationName.chocolate_island_3_region, None) - chocolate_island_3_exit_1 = create_region(world, player, active_locations, LocationName.chocolate_island_3_exit_1, + chocolate_island_3_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_island_3_tile, None) + chocolate_island_3_region = create_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, None) + chocolate_island_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.chocolate_island_3_exit_1, [LocationName.chocolate_island_3_exit_1]) - chocolate_island_3_exit_2 = create_region(world, player, active_locations, LocationName.chocolate_island_3_exit_2, + chocolate_island_3_exit_2 = create_region(multiworld, player, active_locations, LocationName.chocolate_island_3_exit_2, [LocationName.chocolate_island_3_exit_2]) - chocolate_island_4_tile = create_region(world, player, active_locations, LocationName.chocolate_island_4_tile, None) - chocolate_island_4_region = create_region(world, player, active_locations, LocationName.chocolate_island_4_region, None) - chocolate_island_4_exit_1 = create_region(world, player, active_locations, LocationName.chocolate_island_4_exit_1, + chocolate_island_4_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_island_4_tile, None) + chocolate_island_4_region = create_region(multiworld, player, active_locations, LocationName.chocolate_island_4_region, None) + chocolate_island_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.chocolate_island_4_exit_1, [LocationName.chocolate_island_4_exit_1]) - chocolate_island_5_tile = create_region(world, player, active_locations, LocationName.chocolate_island_5_tile, None) - chocolate_island_5_region = create_region(world, player, active_locations, LocationName.chocolate_island_5_region, None) - chocolate_island_5_exit_1 = create_region(world, player, active_locations, LocationName.chocolate_island_5_exit_1, + chocolate_island_5_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_island_5_tile, None) + chocolate_island_5_region = create_region(multiworld, player, active_locations, LocationName.chocolate_island_5_region, None) + chocolate_island_5_exit_1 = create_region(multiworld, player, active_locations, LocationName.chocolate_island_5_exit_1, [LocationName.chocolate_island_5_exit_1]) - chocolate_ghost_house_tile = create_region(world, player, active_locations, LocationName.chocolate_ghost_house_tile, None) - chocolate_ghost_house_region = create_region(world, player, active_locations, LocationName.chocolate_ghost_house_region, None) - chocolate_ghost_house_exit_1 = create_region(world, player, active_locations, LocationName.chocolate_ghost_house_exit_1, + chocolate_ghost_house_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_ghost_house_tile, None) + chocolate_ghost_house_region = create_region(multiworld, player, active_locations, LocationName.chocolate_ghost_house_region, None) + chocolate_ghost_house_exit_1 = create_region(multiworld, player, active_locations, LocationName.chocolate_ghost_house_exit_1, [LocationName.chocolate_ghost_house_exit_1]) - chocolate_secret_tile = create_region(world, player, active_locations, LocationName.chocolate_secret_tile, None) - chocolate_secret_region = create_region(world, player, active_locations, LocationName.chocolate_secret_region, None) - chocolate_secret_exit_1 = create_region(world, player, active_locations, LocationName.chocolate_secret_exit_1, + chocolate_secret_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_secret_tile, None) + chocolate_secret_region = create_region(multiworld, player, active_locations, LocationName.chocolate_secret_region, None) + chocolate_secret_exit_1 = create_region(multiworld, player, active_locations, LocationName.chocolate_secret_exit_1, [LocationName.chocolate_secret_exit_1]) - chocolate_fortress_tile = create_region(world, player, active_locations, LocationName.chocolate_fortress_tile, None) - chocolate_fortress_region = create_region(world, player, active_locations, LocationName.chocolate_fortress_region, None) - chocolate_fortress = create_region(world, player, active_locations, LocationName.chocolate_fortress, + chocolate_fortress_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_fortress_tile, None) + chocolate_fortress_region = create_region(multiworld, player, active_locations, LocationName.chocolate_fortress_region, None) + chocolate_fortress = create_region(multiworld, player, active_locations, LocationName.chocolate_fortress, [LocationName.chocolate_fortress, LocationName.chocolate_reznor]) - chocolate_castle_tile = create_region(world, player, active_locations, LocationName.chocolate_castle_tile, None) - chocolate_castle_region = create_region(world, player, active_locations, LocationName.chocolate_castle_region, None) - chocolate_castle = create_region(world, player, active_locations, LocationName.chocolate_castle, + chocolate_castle_tile = create_region(multiworld, player, active_locations, LocationName.chocolate_castle_tile, None) + chocolate_castle_region = create_region(multiworld, player, active_locations, LocationName.chocolate_castle_region, None) + chocolate_castle = create_region(multiworld, player, active_locations, LocationName.chocolate_castle, [LocationName.chocolate_castle, LocationName.chocolate_koopaling]) - sunken_ghost_ship_tile = create_region(world, player, active_locations, LocationName.sunken_ghost_ship_tile, None) - sunken_ghost_ship_region = create_region(world, player, active_locations, LocationName.sunken_ghost_ship_region, None) - sunken_ghost_ship = create_region(world, player, active_locations, LocationName.sunken_ghost_ship, + sunken_ghost_ship_tile = create_region(multiworld, player, active_locations, LocationName.sunken_ghost_ship_tile, None) + sunken_ghost_ship_region = create_region(multiworld, player, active_locations, LocationName.sunken_ghost_ship_region, None) + sunken_ghost_ship = create_region(multiworld, player, active_locations, LocationName.sunken_ghost_ship, [LocationName.sunken_ghost_ship]) - valley_of_bowser_1_tile = create_region(world, player, active_locations, LocationName.valley_of_bowser_1_tile, None) - valley_of_bowser_1_region = create_region(world, player, active_locations, LocationName.valley_of_bowser_1_region, None) - valley_of_bowser_1_exit_1 = create_region(world, player, active_locations, LocationName.valley_of_bowser_1_exit_1, + valley_of_bowser_1_tile = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_tile, None) + valley_of_bowser_1_region = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, None) + valley_of_bowser_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_exit_1, [LocationName.valley_of_bowser_1_exit_1]) - valley_of_bowser_2_tile = create_region(world, player, active_locations, LocationName.valley_of_bowser_2_tile, None) - valley_of_bowser_2_region = create_region(world, player, active_locations, LocationName.valley_of_bowser_2_region, None) - valley_of_bowser_2_exit_1 = create_region(world, player, active_locations, LocationName.valley_of_bowser_2_exit_1, + valley_of_bowser_2_tile = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_tile, None) + valley_of_bowser_2_region = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_region, None) + valley_of_bowser_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_exit_1, [LocationName.valley_of_bowser_2_exit_1]) - valley_of_bowser_2_exit_2 = create_region(world, player, active_locations, LocationName.valley_of_bowser_2_exit_2, + valley_of_bowser_2_exit_2 = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_exit_2, [LocationName.valley_of_bowser_2_exit_2]) - valley_of_bowser_3_tile = create_region(world, player, active_locations, LocationName.valley_of_bowser_3_tile, None) - valley_of_bowser_3_region = create_region(world, player, active_locations, LocationName.valley_of_bowser_3_region, None) - valley_of_bowser_3_exit_1 = create_region(world, player, active_locations, LocationName.valley_of_bowser_3_exit_1, + valley_of_bowser_3_tile = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_3_tile, None) + valley_of_bowser_3_region = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_3_region, None) + valley_of_bowser_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_3_exit_1, [LocationName.valley_of_bowser_3_exit_1]) - valley_of_bowser_4_tile = create_region(world, player, active_locations, LocationName.valley_of_bowser_4_tile, None) - valley_of_bowser_4_region = create_region(world, player, active_locations, LocationName.valley_of_bowser_4_region, None) - valley_of_bowser_4_exit_1 = create_region(world, player, active_locations, LocationName.valley_of_bowser_4_exit_1, + valley_of_bowser_4_tile = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_tile, None) + valley_of_bowser_4_region = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_region, None) + valley_of_bowser_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_exit_1, [LocationName.valley_of_bowser_4_exit_1]) - valley_of_bowser_4_exit_2 = create_region(world, player, active_locations, LocationName.valley_of_bowser_4_exit_2, + valley_of_bowser_4_exit_2 = create_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_exit_2, [LocationName.valley_of_bowser_4_exit_2]) - valley_ghost_house_tile = create_region(world, player, active_locations, LocationName.valley_ghost_house_tile, None) - valley_ghost_house_region = create_region(world, player, active_locations, LocationName.valley_ghost_house_region, None) - valley_ghost_house_exit_1 = create_region(world, player, active_locations, LocationName.valley_ghost_house_exit_1, + valley_ghost_house_tile = create_region(multiworld, player, active_locations, LocationName.valley_ghost_house_tile, None) + valley_ghost_house_region = create_region(multiworld, player, active_locations, LocationName.valley_ghost_house_region, None) + valley_ghost_house_exit_1 = create_region(multiworld, player, active_locations, LocationName.valley_ghost_house_exit_1, [LocationName.valley_ghost_house_exit_1]) - valley_ghost_house_exit_2 = create_region(world, player, active_locations, LocationName.valley_ghost_house_exit_2, + valley_ghost_house_exit_2 = create_region(multiworld, player, active_locations, LocationName.valley_ghost_house_exit_2, [LocationName.valley_ghost_house_exit_2]) - valley_fortress_tile = create_region(world, player, active_locations, LocationName.valley_fortress_tile, None) - valley_fortress_region = create_region(world, player, active_locations, LocationName.valley_fortress_region, None) - valley_fortress = create_region(world, player, active_locations, LocationName.valley_fortress, + valley_fortress_tile = create_region(multiworld, player, active_locations, LocationName.valley_fortress_tile, None) + valley_fortress_region = create_region(multiworld, player, active_locations, LocationName.valley_fortress_region, None) + valley_fortress = create_region(multiworld, player, active_locations, LocationName.valley_fortress, [LocationName.valley_fortress, LocationName.valley_reznor]) - valley_castle_tile = create_region(world, player, active_locations, LocationName.valley_castle_tile, None) - valley_castle_region = create_region(world, player, active_locations, LocationName.valley_castle_region, None) - valley_castle = create_region(world, player, active_locations, LocationName.valley_castle, + valley_castle_tile = create_region(multiworld, player, active_locations, LocationName.valley_castle_tile, None) + valley_castle_region = create_region(multiworld, player, active_locations, LocationName.valley_castle_region, None) + valley_castle = create_region(multiworld, player, active_locations, LocationName.valley_castle, [LocationName.valley_castle, LocationName.valley_koopaling]) - front_door_tile = create_region(world, player, active_locations, LocationName.front_door_tile, None) - front_door_region = create_region(world, player, active_locations, LocationName.front_door, None) - back_door_tile = create_region(world, player, active_locations, LocationName.back_door_tile, None) - back_door_region = create_region(world, player, active_locations, LocationName.back_door, None) + front_door_tile = create_region(multiworld, player, active_locations, LocationName.front_door_tile, None) + front_door_region = create_region(multiworld, player, active_locations, LocationName.front_door, None) + back_door_tile = create_region(multiworld, player, active_locations, LocationName.back_door_tile, None) + back_door_region = create_region(multiworld, player, active_locations, LocationName.back_door, None) bowser_region_locations = [] - if world.goal[player] == "bowser": + if world.options.goal == "bowser": bowser_region_locations += [LocationName.bowser] - bowser_region = create_region(world, player, active_locations, LocationName.bowser_region, bowser_region_locations) + bowser_region = create_region(multiworld, player, active_locations, LocationName.bowser_region, bowser_region_locations) - donut_plains_star_road = create_region(world, player, active_locations, LocationName.donut_plains_star_road, None) - vanilla_dome_star_road = create_region(world, player, active_locations, LocationName.vanilla_dome_star_road, None) - twin_bridges_star_road = create_region(world, player, active_locations, LocationName.twin_bridges_star_road, None) - forest_star_road = create_region(world, player, active_locations, LocationName.forest_star_road, None) - valley_star_road = create_region(world, player, active_locations, LocationName.valley_star_road, None) - star_road_donut = create_region(world, player, active_locations, LocationName.star_road_donut, None) - star_road_vanilla = create_region(world, player, active_locations, LocationName.star_road_vanilla, None) - star_road_twin_bridges = create_region(world, player, active_locations, LocationName.star_road_twin_bridges, None) - star_road_forest = create_region(world, player, active_locations, LocationName.star_road_forest, None) - star_road_valley = create_region(world, player, active_locations, LocationName.star_road_valley, None) - star_road_special = create_region(world, player, active_locations, LocationName.star_road_special, None) - special_star_road = create_region(world, player, active_locations, LocationName.special_star_road, None) + donut_plains_star_road = create_region(multiworld, player, active_locations, LocationName.donut_plains_star_road, None) + vanilla_dome_star_road = create_region(multiworld, player, active_locations, LocationName.vanilla_dome_star_road, None) + twin_bridges_star_road = create_region(multiworld, player, active_locations, LocationName.twin_bridges_star_road, None) + forest_star_road = create_region(multiworld, player, active_locations, LocationName.forest_star_road, None) + valley_star_road = create_region(multiworld, player, active_locations, LocationName.valley_star_road, None) + star_road_donut = create_region(multiworld, player, active_locations, LocationName.star_road_donut, None) + star_road_vanilla = create_region(multiworld, player, active_locations, LocationName.star_road_vanilla, None) + star_road_twin_bridges = create_region(multiworld, player, active_locations, LocationName.star_road_twin_bridges, None) + star_road_forest = create_region(multiworld, player, active_locations, LocationName.star_road_forest, None) + star_road_valley = create_region(multiworld, player, active_locations, LocationName.star_road_valley, None) + star_road_special = create_region(multiworld, player, active_locations, LocationName.star_road_special, None) + special_star_road = create_region(multiworld, player, active_locations, LocationName.special_star_road, None) - star_road_1_tile = create_region(world, player, active_locations, LocationName.star_road_1_tile, None) - star_road_1_region = create_region(world, player, active_locations, LocationName.star_road_1_region, None) - star_road_1_exit_1 = create_region(world, player, active_locations, LocationName.star_road_1_exit_1, + star_road_1_tile = create_region(multiworld, player, active_locations, LocationName.star_road_1_tile, None) + star_road_1_region = create_region(multiworld, player, active_locations, LocationName.star_road_1_region, None) + star_road_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.star_road_1_exit_1, [LocationName.star_road_1_exit_1]) - star_road_1_exit_2 = create_region(world, player, active_locations, LocationName.star_road_1_exit_2, + star_road_1_exit_2 = create_region(multiworld, player, active_locations, LocationName.star_road_1_exit_2, [LocationName.star_road_1_exit_2]) - star_road_2_tile = create_region(world, player, active_locations, LocationName.star_road_2_tile, None) - star_road_2_region = create_region(world, player, active_locations, LocationName.star_road_2_region, None) - star_road_2_exit_1 = create_region(world, player, active_locations, LocationName.star_road_2_exit_1, + star_road_2_tile = create_region(multiworld, player, active_locations, LocationName.star_road_2_tile, None) + star_road_2_region = create_region(multiworld, player, active_locations, LocationName.star_road_2_region, None) + star_road_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.star_road_2_exit_1, [LocationName.star_road_2_exit_1]) - star_road_2_exit_2 = create_region(world, player, active_locations, LocationName.star_road_2_exit_2, + star_road_2_exit_2 = create_region(multiworld, player, active_locations, LocationName.star_road_2_exit_2, [LocationName.star_road_2_exit_2]) - star_road_3_tile = create_region(world, player, active_locations, LocationName.star_road_3_tile, None) - star_road_3_region = create_region(world, player, active_locations, LocationName.star_road_3_region, None) - star_road_3_exit_1 = create_region(world, player, active_locations, LocationName.star_road_3_exit_1, + star_road_3_tile = create_region(multiworld, player, active_locations, LocationName.star_road_3_tile, None) + star_road_3_region = create_region(multiworld, player, active_locations, LocationName.star_road_3_region, None) + star_road_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.star_road_3_exit_1, [LocationName.star_road_3_exit_1]) - star_road_3_exit_2 = create_region(world, player, active_locations, LocationName.star_road_3_exit_2, + star_road_3_exit_2 = create_region(multiworld, player, active_locations, LocationName.star_road_3_exit_2, [LocationName.star_road_3_exit_2]) - star_road_4_tile = create_region(world, player, active_locations, LocationName.star_road_4_tile, None) - star_road_4_region = create_region(world, player, active_locations, LocationName.star_road_4_region, None) - star_road_4_exit_1 = create_region(world, player, active_locations, LocationName.star_road_4_exit_1, + star_road_4_tile = create_region(multiworld, player, active_locations, LocationName.star_road_4_tile, None) + star_road_4_region = create_region(multiworld, player, active_locations, LocationName.star_road_4_region, None) + star_road_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.star_road_4_exit_1, [LocationName.star_road_4_exit_1]) - star_road_4_exit_2 = create_region(world, player, active_locations, LocationName.star_road_4_exit_2, + star_road_4_exit_2 = create_region(multiworld, player, active_locations, LocationName.star_road_4_exit_2, [LocationName.star_road_4_exit_2]) - star_road_5_tile = create_region(world, player, active_locations, LocationName.star_road_5_tile, None) - star_road_5_region = create_region(world, player, active_locations, LocationName.star_road_5_region, None) - star_road_5_exit_1 = create_region(world, player, active_locations, LocationName.star_road_5_exit_1, + star_road_5_tile = create_region(multiworld, player, active_locations, LocationName.star_road_5_tile, None) + star_road_5_region = create_region(multiworld, player, active_locations, LocationName.star_road_5_region, None) + star_road_5_exit_1 = create_region(multiworld, player, active_locations, LocationName.star_road_5_exit_1, [LocationName.star_road_5_exit_1]) - star_road_5_exit_2 = create_region(world, player, active_locations, LocationName.star_road_5_exit_2, + star_road_5_exit_2 = create_region(multiworld, player, active_locations, LocationName.star_road_5_exit_2, [LocationName.star_road_5_exit_2]) - special_zone_1_tile = create_region(world, player, active_locations, LocationName.special_zone_1_tile, None) - special_zone_1_region = create_region(world, player, active_locations, LocationName.special_zone_1_region, None) - special_zone_1_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_1_exit_1, + special_zone_1_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_1_tile, None) + special_zone_1_region = create_region(multiworld, player, active_locations, LocationName.special_zone_1_region, None) + special_zone_1_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_1_exit_1, [LocationName.special_zone_1_exit_1]) - special_zone_2_tile = create_region(world, player, active_locations, LocationName.special_zone_2_tile, None) - special_zone_2_region = create_region(world, player, active_locations, LocationName.special_zone_2_region, None) - special_zone_2_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_2_exit_1, + special_zone_2_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_2_tile, None) + special_zone_2_region = create_region(multiworld, player, active_locations, LocationName.special_zone_2_region, None) + special_zone_2_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_2_exit_1, [LocationName.special_zone_2_exit_1]) - special_zone_3_tile = create_region(world, player, active_locations, LocationName.special_zone_3_tile, None) - special_zone_3_region = create_region(world, player, active_locations, LocationName.special_zone_3_region, None) - special_zone_3_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_3_exit_1, + special_zone_3_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_3_tile, None) + special_zone_3_region = create_region(multiworld, player, active_locations, LocationName.special_zone_3_region, None) + special_zone_3_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_3_exit_1, [LocationName.special_zone_3_exit_1]) - special_zone_4_tile = create_region(world, player, active_locations, LocationName.special_zone_4_tile, None) - special_zone_4_region = create_region(world, player, active_locations, LocationName.special_zone_4_region, None) - special_zone_4_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_4_exit_1, + special_zone_4_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_4_tile, None) + special_zone_4_region = create_region(multiworld, player, active_locations, LocationName.special_zone_4_region, None) + special_zone_4_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_4_exit_1, [LocationName.special_zone_4_exit_1]) - special_zone_5_tile = create_region(world, player, active_locations, LocationName.special_zone_5_tile, None) - special_zone_5_region = create_region(world, player, active_locations, LocationName.special_zone_5_region, None) - special_zone_5_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_5_exit_1, + special_zone_5_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_5_tile, None) + special_zone_5_region = create_region(multiworld, player, active_locations, LocationName.special_zone_5_region, None) + special_zone_5_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_5_exit_1, [LocationName.special_zone_5_exit_1]) - special_zone_6_tile = create_region(world, player, active_locations, LocationName.special_zone_6_tile, None) - special_zone_6_region = create_region(world, player, active_locations, LocationName.special_zone_6_region, None) - special_zone_6_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_6_exit_1, + special_zone_6_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_6_tile, None) + special_zone_6_region = create_region(multiworld, player, active_locations, LocationName.special_zone_6_region, None) + special_zone_6_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_6_exit_1, [LocationName.special_zone_6_exit_1]) - special_zone_7_tile = create_region(world, player, active_locations, LocationName.special_zone_7_tile, None) - special_zone_7_region = create_region(world, player, active_locations, LocationName.special_zone_7_region, None) - special_zone_7_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_7_exit_1, + special_zone_7_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_7_tile, None) + special_zone_7_region = create_region(multiworld, player, active_locations, LocationName.special_zone_7_region, None) + special_zone_7_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_7_exit_1, [LocationName.special_zone_7_exit_1]) - special_zone_8_tile = create_region(world, player, active_locations, LocationName.special_zone_8_tile, None) - special_zone_8_region = create_region(world, player, active_locations, LocationName.special_zone_8_region, None) - special_zone_8_exit_1 = create_region(world, player, active_locations, LocationName.special_zone_8_exit_1, + special_zone_8_tile = create_region(multiworld, player, active_locations, LocationName.special_zone_8_tile, None) + special_zone_8_region = create_region(multiworld, player, active_locations, LocationName.special_zone_8_region, None) + special_zone_8_exit_1 = create_region(multiworld, player, active_locations, LocationName.special_zone_8_exit_1, [LocationName.special_zone_8_exit_1]) - special_complete = create_region(world, player, active_locations, LocationName.special_complete, None) + special_complete = create_region(multiworld, player, active_locations, LocationName.special_complete, None) # Set up the regions correctly. - world.regions += [ + multiworld.regions += [ menu_region, yoshis_island_region, yoshis_house_tile, @@ -725,323 +728,1327 @@ def create_regions(world, player: int, active_locations): ] - if world.dragon_coin_checks[player]: - add_location_to_region(world, player, active_locations, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_dragon, + if world.options.dragon_coin_checks: + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_dragon, lambda state: (state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.progressive_powerup, player, 1))) - add_location_to_region(world, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_dragon, lambda state: (state.has(ItemName.yoshi_activate, player) or state.has(ItemName.mario_climb, player))) - add_location_to_region(world, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_dragon, lambda state: state.has(ItemName.p_switch, player)) - add_location_to_region(world, player, active_locations, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_dragon, lambda state: (state.has(ItemName.yoshi_activate, player) or state.has(ItemName.mario_swim, player) or (state.has(ItemName.mario_carry, player) and state.has(ItemName.p_switch, player)))) - add_location_to_region(world, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_dragon, lambda state: (state.has(ItemName.mario_climb, player) or state.has(ItemName.yoshi_activate, player) or (state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.mario_run, player)))) - add_location_to_region(world, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_dragon) - add_location_to_region(world, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_dragon, lambda state: ((state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_climb, player) or state.has(ItemName.yoshi_activate, player) or (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) - add_location_to_region(world, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_dragon) - add_location_to_region(world, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_dragon, lambda state: state.has(ItemName.mario_swim, player)) - add_location_to_region(world, player, active_locations, LocationName.donut_secret_2_region, LocationName.donut_secret_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_2_region, LocationName.donut_secret_2_dragon, lambda state: (state.has(ItemName.mario_climb, player) or state.has(ItemName.yoshi_activate, player))) - add_location_to_region(world, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_dragon, lambda state: (state.has(ItemName.mario_carry, player) and state.has(ItemName.mario_run, player) and (state.has(ItemName.super_star_active, player) or state.has(ItemName.progressive_powerup, player, 1)))) - add_location_to_region(world, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_dragon, lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.p_switch, player) and (state.has(ItemName.mario_climb, player) or state.has(ItemName.yoshi_activate, player)))) - add_location_to_region(world, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_dragon) - add_location_to_region(world, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_dragon) - add_location_to_region(world, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_dragon, lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.mario_carry, player))) - add_location_to_region(world, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_dragon, lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) - add_location_to_region(world, player, active_locations, LocationName.vanilla_secret_3_region, LocationName.vanilla_secret_3_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_3_region, LocationName.vanilla_secret_3_dragon, lambda state: state.has(ItemName.mario_swim, player)) - add_location_to_region(world, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_dragon, lambda state: state.has(ItemName.mario_climb, player)) - add_location_to_region(world, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_dragon) - add_location_to_region(world, player, active_locations, LocationName.butter_bridge_2_region, LocationName.butter_bridge_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_2_region, LocationName.butter_bridge_2_dragon, lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) - add_location_to_region(world, player, active_locations, LocationName.cheese_bridge_region, LocationName.cheese_bridge_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.cheese_bridge_region, LocationName.cheese_bridge_dragon, lambda state: (state.has(ItemName.yoshi_activate, player) or state.has(ItemName.mario_climb, player))) - add_location_to_region(world, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_dragon, lambda state: (state.has(ItemName.yoshi_activate, player) or state.has(ItemName.mario_climb, player))) - add_location_to_region(world, player, active_locations, LocationName.soda_lake_region, LocationName.soda_lake_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.soda_lake_region, LocationName.soda_lake_dragon, lambda state: state.has(ItemName.mario_swim, player)) - add_location_to_region(world, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_dragon, lambda state: state.has(ItemName.mario_swim, player)) - add_location_to_region(world, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_dragon, lambda state: (state.has(ItemName.yoshi_activate, player) or state.has(ItemName.mario_carry, player))) - add_location_to_region(world, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_dragon, lambda state: (state.has(ItemName.yoshi_activate, player) or state.has(ItemName.mario_carry, player) or state.has(ItemName.p_switch, player) or state.has(ItemName.progressive_powerup, player, 2))) - add_location_to_region(world, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_dragon, lambda state: state.has(ItemName.p_switch, player)) - add_location_to_region(world, player, active_locations, LocationName.forest_secret_region, LocationName.forest_secret_dragon) - add_location_to_region(world, player, active_locations, LocationName.forest_castle_region, LocationName.forest_castle_dragon) - add_location_to_region(world, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_dragon, - lambda state: state.has(ItemName.mario_swim, player)) - add_location_to_region(world, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.forest_secret_region, LocationName.forest_secret_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_castle_region, LocationName.forest_castle_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_dragon, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_dragon, lambda state: (state.has(ItemName.blue_switch_palace, player) and (state.has(ItemName.p_switch, player) or state.has(ItemName.green_switch_palace, player) or (state.has(ItemName.yellow_switch_palace, player) or state.has(ItemName.red_switch_palace, player))))) - add_location_to_region(world, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_dragon) - add_location_to_region(world, player, active_locations, LocationName.chocolate_island_4_region, LocationName.chocolate_island_4_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_4_region, LocationName.chocolate_island_4_dragon, lambda state: (state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) - add_location_to_region(world, player, active_locations, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_dragon, - lambda state: (state.has(ItemName.mario_swim, player) or - (state.has(ItemName.mario_carry, player) and state.has(ItemName.p_switch, player)))) - add_location_to_region(world, player, active_locations, LocationName.sunken_ghost_ship_region, LocationName.sunken_ghost_ship_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_dragon, + lambda state: (state.has(ItemName.mario_carry, player) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.sunken_ghost_ship_region, LocationName.sunken_ghost_ship_dragon, lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.super_star_active, player) and state.has(ItemName.progressive_powerup, player, 3))) - add_location_to_region(world, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_dragon) - add_location_to_region(world, player, active_locations, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_dragon, lambda state: state.has(ItemName.yoshi_activate, player)) - add_location_to_region(world, player, active_locations, LocationName.valley_of_bowser_3_region, LocationName.valley_of_bowser_3_dragon) - add_location_to_region(world, player, active_locations, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_3_region, LocationName.valley_of_bowser_3_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_dragon, lambda state: state.has(ItemName.p_switch, player)) - add_location_to_region(world, player, active_locations, LocationName.valley_castle_region, LocationName.valley_castle_dragon) - add_location_to_region(world, player, active_locations, LocationName.star_road_1_region, LocationName.star_road_1_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.valley_castle_region, LocationName.valley_castle_dragon) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_1_region, LocationName.star_road_1_dragon, lambda state: (state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.progressive_powerup, player, 1))) - add_location_to_region(world, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_dragon, lambda state: state.has(ItemName.mario_climb, player)) - add_location_to_region(world, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_dragon, lambda state: state.has(ItemName.p_balloon, player)) - add_location_to_region(world, player, active_locations, LocationName.special_zone_3_region, LocationName.special_zone_3_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_3_region, LocationName.special_zone_3_dragon, lambda state: state.has(ItemName.yoshi_activate, player)) - add_location_to_region(world, player, active_locations, LocationName.special_zone_4_region, LocationName.special_zone_4_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_4_region, LocationName.special_zone_4_dragon, lambda state: state.has(ItemName.progressive_powerup, player, 1)) - add_location_to_region(world, player, active_locations, LocationName.special_zone_5_region, LocationName.special_zone_5_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_5_region, LocationName.special_zone_5_dragon, lambda state: state.has(ItemName.progressive_powerup, player, 1)) - add_location_to_region(world, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_dragon, lambda state: state.has(ItemName.mario_swim, player)) - add_location_to_region(world, player, active_locations, LocationName.special_zone_7_region, LocationName.special_zone_7_dragon, - lambda state: state.has(ItemName.progressive_powerup, player, 1)) - add_location_to_region(world, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_dragon, + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_7_region, LocationName.special_zone_7_dragon, lambda state: state.has(ItemName.progressive_powerup, player, 1)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_dragon, + lambda state: ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player)) or + state.has(ItemName.progressive_powerup, player, 3) or + state.has(ItemName.yoshi_activate, player) or + state.has(ItemName.mario_carry, player))) + if world.options.moon_checks: + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_moon, + lambda state: ((state.has(ItemName.mario_run, player) and + state.has(ItemName.progressive_powerup, player, 3)) or + state.has(ItemName.yoshi_activate, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_moon, + lambda state: (state.has(ItemName.mario_run, player) and + state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_moon, + lambda state: (state.has(ItemName.mario_run, player) and + state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.cheese_bridge_region, LocationName.cheese_bridge_moon, + lambda state: (state.has(ItemName.mario_run, player) and + (state.has(ItemName.progressive_powerup, player, 3) or + state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_moon, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_moon, + lambda state: ((state.has(ItemName.mario_run, player) and + state.has(ItemName.progressive_powerup, player, 3)) or + state.has(ItemName.yoshi_activate, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_moon) + if world.options.hidden_1up_checks: + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_hidden_1up, + lambda state: (state.has(ItemName.yoshi_activate, player) or + (state.has(ItemName.mario_run, player, player) and + state.has(ItemName.progressive_powerup, player, 3)))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_hidden_1up) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_hidden_1up, + lambda state: (state.has(ItemName.mario_run, player) and + state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_hidden_1up) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_hidden_1up) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_hidden_1up) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_fortress_region, LocationName.vanilla_fortress_hidden_1up, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_hidden_1up, + lambda state: (state.has(ItemName.mario_swim, player) or + state.has(ItemName.yoshi_activate, player) or + (state.has(ItemName.mario_run, player, player) and + state.has(ItemName.progressive_powerup, player, 3)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_hidden_1up, + lambda state: (state.has(ItemName.mario_carry, player) or + state.has(ItemName.yoshi_activate, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_hidden_1up) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_castle_region, LocationName.chocolate_castle_hidden_1up, + lambda state: (state.has(ItemName.progressive_powerup, player, 1))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_hidden_1up) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_castle_region, LocationName.valley_castle_hidden_1up) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_hidden_1up, + lambda state: state.has(ItemName.mario_climb, player)) + + if world.options.bonus_block_checks: + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_bonus_block) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_bonus_block) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_bonus_block) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_bonus_block) + + if world.options.blocksanity: + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_green_block_1, + lambda state:( ((state.has(ItemName.green_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_gray_pow_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_coin_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_coin_block_5) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_coin_block_6) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_3_region, LocationName.vanilla_secret_3_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_3_region, LocationName.vanilla_secret_3_powerup_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_directional_coin_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_life_block_1, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_life_block_2, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_life_block_3, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_life_block_4, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_vine_block_1, + lambda state: (state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_3_region, LocationName.donut_plains_3_bonus_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_4_region, LocationName.donut_plains_4_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_invis_life_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_coin_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_coin_block_5) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_flying_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_yellow_block_2, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_2_region, LocationName.donut_plains_2_vine_block_1, + lambda state:( ((state.has(ItemName.mario_climb, player) and state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_coin_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_coin_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_coin_block_3, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_powerup_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_powerup_block_3, + lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.p_balloon, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_life_block_1, + lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.p_balloon, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_powerup_block_4, + lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.p_balloon, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_powerup_block_5, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_1_region, LocationName.donut_secret_1_key_block_1, + lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_fortress_region, LocationName.vanilla_fortress_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_fortress_region, LocationName.vanilla_fortress_powerup_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_fortress_region, LocationName.vanilla_fortress_yellow_block_1, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_swim, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_multi_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_multi_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_life_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_bonus_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_2_region, LocationName.butter_bridge_2_powerup_block_1, + lambda state: state.has(ItemName.mario_carry, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_2_region, LocationName.butter_bridge_2_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.butter_bridge_2_region, LocationName.butter_bridge_2_yoshi_block_1, + lambda state: state.has(ItemName.mario_carry, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.twin_bridges_castle_region, LocationName.twin_bridges_castle_powerup_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.cheese_bridge_region, LocationName.cheese_bridge_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.cheese_bridge_region, LocationName.cheese_bridge_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.cheese_bridge_region, LocationName.cheese_bridge_wings_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.cheese_bridge_region, LocationName.cheese_bridge_powerup_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_5) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_6) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_7) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_8) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_9) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_life_block_1, + lambda state:( (state.has(ItemName.mario_climb, player)) or (state.has(ItemName.mario_swim, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_yoshi_block_1, + lambda state: state.has(ItemName.red_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_10) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_11) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_12) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_13) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_14) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_15) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_16) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_17) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_18) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_19) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_20) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_21) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_22) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_23) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_24) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_25) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_26) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_27) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_28) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_29) + add_location_to_region(multiworld, player, active_locations, LocationName.cookie_mountain_region, LocationName.cookie_mountain_coin_block_30) + add_location_to_region(multiworld, player, active_locations, LocationName.soda_lake_region, LocationName.soda_lake_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_house_region, LocationName.donut_secret_house_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_house_region, LocationName.donut_secret_house_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_house_region, LocationName.donut_secret_house_life_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_house_region, LocationName.donut_secret_house_vine_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_house_region, LocationName.donut_secret_house_directional_coin_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_1, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_2, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_3, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_4, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_5, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_6, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_7, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_8, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_9, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_10, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_11, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_12, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_13, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_14, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_15, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_green_block_16, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_yellow_block_2, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_plains_1_region, LocationName.donut_plains_1_yellow_block_3, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.sunken_ghost_ship_region, LocationName.sunken_ghost_ship_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.sunken_ghost_ship_region, LocationName.sunken_ghost_ship_star_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_castle_region, LocationName.chocolate_castle_yellow_block_1, + lambda state: (state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.yellow_switch_palace, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_castle_region, LocationName.chocolate_castle_yellow_block_2, + lambda state: (state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.yellow_switch_palace, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_castle_region, LocationName.chocolate_castle_green_block_1, + lambda state: (state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.yellow_switch_palace, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_fortress_region, LocationName.chocolate_fortress_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_fortress_region, LocationName.chocolate_fortress_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_fortress_region, LocationName.chocolate_fortress_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_fortress_region, LocationName.chocolate_fortress_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_fortress_region, LocationName.chocolate_fortress_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_life_block_1, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.progressive_powerup, player, 3)))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_yellow_block_1, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_4_region, LocationName.chocolate_island_4_yellow_block_1, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.blue_switch_palace, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_4_region, LocationName.chocolate_island_4_blue_pow_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_4_region, LocationName.chocolate_island_4_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_1, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_2, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_3, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_4, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_5, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_6, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_7, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_8, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_fortress_region, LocationName.forest_fortress_life_block_9, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_castle_region, LocationName.forest_castle_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_ghost_house_region, LocationName.chocolate_ghost_house_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_ghost_house_region, LocationName.chocolate_ghost_house_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_ghost_house_region, LocationName.chocolate_ghost_house_life_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_flying_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_flying_block_2, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_yoshi_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_green_block_1, + lambda state:( ((state.has(ItemName.green_switch_palace, player) and state.has(ItemName.blue_switch_palace, player) and state.has(ItemName.p_switch, player))) or ((state.has(ItemName.green_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.blue_switch_palace, player) and state.has(ItemName.p_switch, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_life_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_powerup_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_bonus_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_life_block_1, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_life_block_2, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_life_block_3, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_invis_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_multi_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_blue_pow_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_yellow_block_2, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_green_block_2, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_green_block_3, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_green_block_4, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_green_block_5, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_green_block_6, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle_coin_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle_coin_block_2, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle_powerup_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle_coin_block_3, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle_coin_block_4, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle_flying_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_star_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_2, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_3, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_4, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_5, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_6, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_7, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_8, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_9, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_10, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_11, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_yellow_block_12, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_bonus_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_flying_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_life_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_flying_block_1, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_flying_block_2, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_flying_block_3, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_flying_block_4, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_flying_block_5, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_flying_block_6, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_coin_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_yoshi_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_coin_block_5) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_yellow_block_2, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_blue_pow_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_vine_block_2, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_coin_block_2, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_coin_block_3, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_powerup_block_2, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_flying_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_flying_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_flying_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_invis_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_powerup_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_yoshi_block_1, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_powerup_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_pswitch_coin_block_1, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_pswitch_coin_block_2, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_pswitch_coin_block_3, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_pswitch_coin_block_4, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_pswitch_coin_block_5, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_pswitch_coin_block_6, + lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3) and state.has(ItemName.p_switch, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_2_region, LocationName.donut_secret_2_directional_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_2_region, LocationName.donut_secret_2_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_2_region, LocationName.donut_secret_2_star_block_1, + lambda state:( (state.has(ItemName.mario_climb, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_2_region, LocationName.donut_secret_2_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.donut_secret_2_region, LocationName.donut_secret_2_star_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_yoshi_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_life_block_1, + lambda state: (state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.mario_climb, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_powerup_block_2, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_climb, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_castle_region, LocationName.valley_castle_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_castle_region, LocationName.valley_castle_yellow_block_2, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_castle_region, LocationName.valley_castle_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_fortress_region, LocationName.valley_fortress_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_fortress_region, LocationName.valley_fortress_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_3_region, LocationName.valley_of_bowser_3_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_3_region, LocationName.valley_of_bowser_3_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_pswitch_coin_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_multi_coin_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_directional_coin_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_yellow_block_1, + lambda state: state.has(ItemName.yellow_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_wings_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_invis_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_invis_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_invis_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_yellow_block_1, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_yellow_block_2, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_yellow_block_3, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_yellow_block_4, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_secret_region, LocationName.chocolate_secret_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.chocolate_secret_region, LocationName.chocolate_secret_powerup_block_2, + lambda state: state.has(ItemName.mario_run, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_coin_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_coin_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_coin_block_3, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_vine_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_invis_life_block_1, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_coin_block_4, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_coin_block_5, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_powerup_block_2, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_powerup_block_3, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_powerup_block_4, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_powerup_block_5, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_multi_coin_block_1, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_multi_coin_block_2, + lambda state:( ((state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_climb, player))) or ((state.has(ItemName.mario_swim, player) and state.has(ItemName.yoshi_activate, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_life_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_5) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_6) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_7) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_coin_block_8, + lambda state: state.has(ItemName.mario_carry, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_flying_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_life_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_powerup_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_vine_block_1, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.red_switch_palace, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_star_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_powerup_block_4, + lambda state:( ((state.has(ItemName.mario_run, player) and state.has(ItemName.super_star_active, player))) or ((state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 1))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_coin_block_2, + lambda state:( ((state.has(ItemName.mario_run, player) and state.has(ItemName.super_star_active, player))) or ((state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 1))))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle_region, LocationName.vanilla_dome_castle_life_block_1, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.progressive_powerup, player, 1)))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle_region, LocationName.vanilla_dome_castle_life_block_2, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.progressive_powerup, player, 1)))) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle_region, LocationName.vanilla_dome_castle_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle_region, LocationName.vanilla_dome_castle_life_block_3, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.vanilla_dome_castle_region, LocationName.vanilla_dome_castle_green_block_1, + lambda state: state.has(ItemName.green_switch_palace, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_flying_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_life_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_key_block_1, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_life_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_5) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_6) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_7) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_8) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_9) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_coin_block_10) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_green_block_1, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_invis_coin_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_invis_coin_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_invis_life_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_invis_coin_block_3, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_yellow_block_1, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.mario_swim, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_secret_region, LocationName.forest_secret_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_secret_region, LocationName.forest_secret_powerup_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_secret_region, LocationName.forest_secret_life_block_1, + lambda state:( (state.has(ItemName.blue_switch_palace, player)) or (state.has(ItemName.mario_carry, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_multi_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_2, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_multi_coin_block_2, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_3, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_4, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_5, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_6, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_7, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_8, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_9, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_10, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_11, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_12, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_13, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_14, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_15, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_16, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_17, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_18, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_19, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_20, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_21, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_22, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_23, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_coin_block_24, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_yoshi_block_1, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_5) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_blue_pow_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_star_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_6, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_7, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_8, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_9, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_10, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_11, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_12, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_13, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_14, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_15, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_16, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_17, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_18, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_multi_coin_block_1, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_19, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_20, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_21, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_22, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_coin_block_23, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_powerup_block_2, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_8_region, LocationName.special_zone_8_flying_block_1, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player))) or (state.has(ItemName.progressive_powerup, player, 3)) or (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.yoshi_activate, player)))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_7_region, LocationName.special_zone_7_powerup_block_1, + lambda state: state.has(ItemName.progressive_powerup, player, 1)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_7_region, LocationName.special_zone_7_yoshi_block_1, + lambda state: state.has(ItemName.progressive_powerup, player, 1)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_7_region, LocationName.special_zone_7_coin_block_1, + lambda state: state.has(ItemName.progressive_powerup, player, 1)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_7_region, LocationName.special_zone_7_powerup_block_2, + lambda state: state.has(ItemName.progressive_powerup, player, 1)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_7_region, LocationName.special_zone_7_coin_block_2, + lambda state: state.has(ItemName.progressive_powerup, player, 1)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_powerup_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_yoshi_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_life_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_multi_coin_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_3, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_4, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_5, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_6, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_7, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_8, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_9, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_10, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_11, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_12, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_13, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_14, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_15, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_16, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_17, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_18, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_19, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_20, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_21, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_22, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_23, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_24, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_25, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_26, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_27, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_28, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_powerup_block_2, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_29, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_30, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_31, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_32, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_6_region, LocationName.special_zone_6_coin_block_33, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_5_region, LocationName.special_zone_5_yoshi_block_1, + lambda state: state.has(ItemName.progressive_powerup, player, 1)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_vine_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_vine_block_2) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_vine_block_3) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_vine_block_4) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_life_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_vine_block_5, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_blue_pow_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_vine_block_6, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_powerup_block_1, + lambda state: state.has(ItemName.mario_climb, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_1, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_2, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_3, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_4, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_5, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_6, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_7, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_8, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_9, + lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_10, + lambda state:( ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) or ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_11, + lambda state:( ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) or ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_12, + lambda state:( ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) or ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_1_region, LocationName.special_zone_1_pswitch_coin_block_13, + lambda state:( ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.progressive_powerup, player, 3))) or ((state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_coin_block_1, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_coin_block_2, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_powerup_block_2, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_coin_block_3, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_coin_block_4, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_powerup_block_3, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_multi_coin_block_1, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_coin_block_5, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_2_region, LocationName.special_zone_2_coin_block_6, + lambda state: state.has(ItemName.p_balloon, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_3_region, LocationName.special_zone_3_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_3_region, LocationName.special_zone_3_yoshi_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_3_region, LocationName.special_zone_3_wings_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_4_region, LocationName.special_zone_4_powerup_block_1, + lambda state: state.has(ItemName.progressive_powerup, player, 2)) + add_location_to_region(multiworld, player, active_locations, LocationName.special_zone_4_region, LocationName.special_zone_4_star_block_1, + lambda state:( ((state.has(ItemName.progressive_powerup, player, 2) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.progressive_powerup, player, 2) and state.has(ItemName.p_switch, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_2_region, LocationName.star_road_2_star_block_1, + lambda state: state.has(ItemName.mario_swim, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_3_region, LocationName.star_road_3_key_block_1, + lambda state:( (state.has(ItemName.mario_carry, player)) or (state.has(ItemName.progressive_powerup, player, 2)))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_powerup_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_green_block_1, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_green_block_2, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_green_block_3, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_green_block_4, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_green_block_5, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_green_block_6, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_green_block_7, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_4_region, LocationName.star_road_4_key_block_1, + lambda state:( ((state.has(ItemName.mario_climb, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.green_switch_palace, player) and state.has(ItemName.red_switch_palace, player) and state.has(ItemName.mario_climb, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_directional_coin_block_1) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_life_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_vine_block_1, + lambda state: state.has(ItemName.p_switch, player)) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_1, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_climb, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_2, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_3, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_4, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_5, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_6, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_7, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_8, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_9, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_10, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_11, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_12, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_13, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_14, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_15, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_16, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_17, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_18, + lambda state: (state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_19, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.green_switch_palace, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_climb, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_yellow_block_20, + lambda state:( ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player))) or ((state.has(ItemName.yellow_switch_palace, player) and state.has(ItemName.green_switch_palace, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_climb, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.progressive_powerup, player, 3))))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_1, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_2, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_3, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_4, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_5, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_6, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_7, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_8, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_9, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_10, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_11, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_12, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_13, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_14, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_15, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_16, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_17, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_18, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_19, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + add_location_to_region(multiworld, player, active_locations, LocationName.star_road_5_region, LocationName.star_road_5_green_block_20, + lambda state: (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.special_world_clear, player))) + +def connect_regions(world: World, level_to_tile_dict): + multiworld: MultiWorld = world.multiworld + player: int = world.player -def connect_regions(world, player, level_to_tile_dict): names: typing.Dict[str, int] = {} - connect(world, player, names, "Menu", LocationName.yoshis_island_region) - connect(world, player, names, LocationName.yoshis_island_region, LocationName.yoshis_house_tile) - connect(world, player, names, LocationName.yoshis_house_tile, LocationName.donut_plains_top_secret) - connect(world, player, names, LocationName.yoshis_island_region, LocationName.yoshis_island_1_tile) - connect(world, player, names, LocationName.yoshis_island_region, LocationName.yoshis_island_2_tile) + connect(world, "Menu", LocationName.yoshis_island_region) + connect(world, LocationName.yoshis_island_region, LocationName.yoshis_house_tile) + connect(world, LocationName.yoshis_island_region, LocationName.yoshis_island_1_tile) + connect(world, LocationName.yoshis_island_region, LocationName.yoshis_island_2_tile) # Connect regions within levels using rules - connect(world, player, names, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_exit_1) - connect(world, player, names, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_exit_1) - connect(world, player, names, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_exit_1) - connect(world, player, names, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_exit_1) - connect(world, player, names, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle, + connect(world, LocationName.yoshis_island_1_region, LocationName.yoshis_island_1_exit_1) + connect(world, LocationName.yoshis_island_2_region, LocationName.yoshis_island_2_exit_1) + connect(world, LocationName.yoshis_island_3_region, LocationName.yoshis_island_3_exit_1) + connect(world, LocationName.yoshis_island_4_region, LocationName.yoshis_island_4_exit_1) + connect(world, LocationName.yoshis_island_castle_region, LocationName.yoshis_island_castle, lambda state: (state.has(ItemName.mario_climb, player))) - connect(world, player, names, LocationName.donut_plains_1_region, LocationName.donut_plains_1_exit_1) - connect(world, player, names, LocationName.donut_plains_1_region, LocationName.donut_plains_1_exit_2, + connect(world, LocationName.donut_plains_1_region, LocationName.donut_plains_1_exit_1) + connect(world, LocationName.donut_plains_1_region, LocationName.donut_plains_1_exit_2, lambda state: (state.has(ItemName.mario_carry, player) and (state.has(ItemName.yoshi_activate, player) or state.has(ItemName.green_switch_palace, player) or (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) - connect(world, player, names, LocationName.donut_plains_2_region, LocationName.donut_plains_2_exit_1) - connect(world, player, names, LocationName.donut_plains_2_region, LocationName.donut_plains_2_exit_2, + connect(world, LocationName.donut_plains_2_region, LocationName.donut_plains_2_exit_1) + connect(world, LocationName.donut_plains_2_region, LocationName.donut_plains_2_exit_2, lambda state: (state.has(ItemName.mario_carry, player) and (state.has(ItemName.yoshi_activate, player) or (state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.mario_climb, player) and state.has(ItemName.progressive_powerup, player, 1))))) - connect(world, player, names, LocationName.donut_secret_1_region, LocationName.donut_secret_1_exit_1, + connect(world, LocationName.donut_secret_1_region, LocationName.donut_secret_1_exit_1, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.donut_secret_1_region, LocationName.donut_secret_1_exit_2, + connect(world, LocationName.donut_secret_1_region, LocationName.donut_secret_1_exit_2, lambda state: (state.has(ItemName.mario_carry, player) and state.has(ItemName.mario_swim, player) and state.has(ItemName.p_switch, player))) - connect(world, player, names, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_exit_1, + connect(world, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_exit_1, lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) - connect(world, player, names, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_exit_2, + connect(world, LocationName.donut_ghost_house_region, LocationName.donut_ghost_house_exit_2, lambda state: (state.has(ItemName.mario_climb, player) or (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3)))) - connect(world, player, names, LocationName.donut_secret_house_region, LocationName.donut_secret_house_exit_1, + connect(world, LocationName.donut_secret_house_region, LocationName.donut_secret_house_exit_1, lambda state: state.has(ItemName.p_switch, player)) - connect(world, player, names, LocationName.donut_secret_house_region, LocationName.donut_secret_house_exit_2, + connect(world, LocationName.donut_secret_house_region, LocationName.donut_secret_house_exit_2, lambda state: (state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player) and (state.has(ItemName.mario_climb, player) or (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) - connect(world, player, names, LocationName.donut_plains_3_region, LocationName.donut_plains_3_exit_1) - connect(world, player, names, LocationName.donut_plains_4_region, LocationName.donut_plains_4_exit_1) - connect(world, player, names, LocationName.donut_secret_2_region, LocationName.donut_secret_2_exit_1) - connect(world, player, names, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle) + connect(world, LocationName.donut_plains_3_region, LocationName.donut_plains_3_exit_1) + connect(world, LocationName.donut_plains_4_region, LocationName.donut_plains_4_exit_1) + connect(world, LocationName.donut_secret_2_region, LocationName.donut_secret_2_exit_1) + connect(world, LocationName.donut_plains_castle_region, LocationName.donut_plains_castle) - connect(world, player, names, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_exit_1, + connect(world, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_exit_1, lambda state: (state.has(ItemName.mario_run, player) and (state.has(ItemName.super_star_active, player) or state.has(ItemName.progressive_powerup, player, 1)))) - connect(world, player, names, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_exit_2, + connect(world, LocationName.vanilla_dome_1_region, LocationName.vanilla_dome_1_exit_2, lambda state: (state.has(ItemName.mario_carry, player) and ((state.has(ItemName.yoshi_activate, player) and state.has(ItemName.mario_climb, player)) or (state.has(ItemName.yoshi_activate, player) and state.has(ItemName.red_switch_palace, player)) or (state.has(ItemName.red_switch_palace, player) and state.has(ItemName.mario_climb, player))))) - connect(world, player, names, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_exit_1, + connect(world, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_exit_1, lambda state: (state.has(ItemName.mario_swim, player) and (state.has(ItemName.mario_climb, player) or state.has(ItemName.yoshi_activate, player)))) - connect(world, player, names, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_exit_2, + connect(world, LocationName.vanilla_dome_2_region, LocationName.vanilla_dome_2_exit_2, lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player) and (state.has(ItemName.mario_climb, player) or state.has(ItemName.yoshi_activate, player)))) - connect(world, player, names, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_exit_1, + connect(world, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_exit_1, lambda state: state.has(ItemName.mario_climb, player)) - connect(world, player, names, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_exit_2, + connect(world, LocationName.vanilla_secret_1_region, LocationName.vanilla_secret_1_exit_2, lambda state: (state.has(ItemName.mario_climb, player) and (state.has(ItemName.mario_carry, player) and state.has(ItemName.blue_switch_palace, player)))) - connect(world, player, names, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_exit_1, + connect(world, LocationName.vanilla_ghost_house_region, LocationName.vanilla_ghost_house_exit_1, lambda state: state.has(ItemName.p_switch, player)) - connect(world, player, names, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_exit_1) - connect(world, player, names, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_exit_1) - connect(world, player, names, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_exit_1) - connect(world, player, names, LocationName.vanilla_secret_3_region, LocationName.vanilla_secret_3_exit_1, + connect(world, LocationName.vanilla_dome_3_region, LocationName.vanilla_dome_3_exit_1) + connect(world, LocationName.vanilla_dome_4_region, LocationName.vanilla_dome_4_exit_1) + connect(world, LocationName.vanilla_secret_2_region, LocationName.vanilla_secret_2_exit_1) + connect(world, LocationName.vanilla_secret_3_region, LocationName.vanilla_secret_3_exit_1, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.vanilla_fortress_region, LocationName.vanilla_fortress, + connect(world, LocationName.vanilla_fortress_region, LocationName.vanilla_fortress, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.vanilla_dome_castle_region, LocationName.vanilla_dome_castle) + connect(world, LocationName.vanilla_dome_castle_region, LocationName.vanilla_dome_castle) - connect(world, player, names, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_exit_1) - connect(world, player, names, LocationName.butter_bridge_2_region, LocationName.butter_bridge_2_exit_1) - connect(world, player, names, LocationName.cheese_bridge_region, LocationName.cheese_bridge_exit_1, + connect(world, LocationName.butter_bridge_1_region, LocationName.butter_bridge_1_exit_1) + connect(world, LocationName.butter_bridge_2_region, LocationName.butter_bridge_2_exit_1) + connect(world, LocationName.cheese_bridge_region, LocationName.cheese_bridge_exit_1, lambda state: state.has(ItemName.mario_climb, player)) - connect(world, player, names, LocationName.cheese_bridge_region, LocationName.cheese_bridge_exit_2, - lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) - connect(world, player, names, LocationName.soda_lake_region, LocationName.soda_lake_exit_1, + connect(world, LocationName.cheese_bridge_region, LocationName.cheese_bridge_exit_2, + lambda state: (state.has(ItemName.mario_run, player) and + (state.has(ItemName.progressive_powerup, player, 3) or + state.has(ItemName.yoshi_activate, player)))) + connect(world, LocationName.soda_lake_region, LocationName.soda_lake_exit_1, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.cookie_mountain_region, LocationName.cookie_mountain_exit_1) - connect(world, player, names, LocationName.twin_bridges_castle_region, LocationName.twin_bridges_castle, + connect(world, LocationName.cookie_mountain_region, LocationName.cookie_mountain_exit_1) + connect(world, LocationName.twin_bridges_castle_region, LocationName.twin_bridges_castle, lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.mario_climb, player))) - connect(world, player, names, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_exit_1) - connect(world, player, names, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_exit_2, + connect(world, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_exit_1) + connect(world, LocationName.forest_of_illusion_1_region, LocationName.forest_of_illusion_1_exit_2, lambda state: (state.has(ItemName.mario_carry, player) and state.has(ItemName.p_balloon, player))) - connect(world, player, names, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_exit_1, + connect(world, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_exit_1, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_exit_2, + connect(world, LocationName.forest_of_illusion_2_region, LocationName.forest_of_illusion_2_exit_2, lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_carry, player))) - connect(world, player, names, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_exit_1, + connect(world, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_exit_1, lambda state: (state.has(ItemName.mario_carry, player) or state.has(ItemName.yoshi_activate, player))) - connect(world, player, names, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_exit_2, + connect(world, LocationName.forest_of_illusion_3_region, LocationName.forest_of_illusion_3_exit_2, lambda state: (state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.progressive_powerup, player, 1))) - connect(world, player, names, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_exit_1) - connect(world, player, names, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_exit_2, + connect(world, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_exit_1) + connect(world, LocationName.forest_of_illusion_4_region, LocationName.forest_of_illusion_4_exit_2, lambda state: state.has(ItemName.mario_carry, player)) - connect(world, player, names, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_exit_1, + connect(world, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_exit_1, lambda state: state.has(ItemName.p_switch, player)) - connect(world, player, names, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_exit_2, + connect(world, LocationName.forest_ghost_house_region, LocationName.forest_ghost_house_exit_2, lambda state: state.has(ItemName.p_switch, player)) - connect(world, player, names, LocationName.forest_secret_region, LocationName.forest_secret_exit_1) - connect(world, player, names, LocationName.forest_fortress_region, LocationName.forest_fortress) - connect(world, player, names, LocationName.forest_castle_region, LocationName.forest_castle) + connect(world, LocationName.forest_secret_region, LocationName.forest_secret_exit_1) + connect(world, LocationName.forest_fortress_region, LocationName.forest_fortress) + connect(world, LocationName.forest_castle_region, LocationName.forest_castle) - connect(world, player, names, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_exit_1, + connect(world, LocationName.chocolate_island_1_region, LocationName.chocolate_island_1_exit_1, lambda state: state.has(ItemName.p_switch, player)) - connect(world, player, names, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_exit_1) - connect(world, player, names, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_exit_2, + connect(world, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_exit_1) + connect(world, LocationName.chocolate_island_2_region, LocationName.chocolate_island_2_exit_2, lambda state: state.has(ItemName.mario_carry, player)) - connect(world, player, names, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_exit_1, + connect(world, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_exit_1, lambda state: (state.has(ItemName.mario_climb, player) or (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3)))) - connect(world, player, names, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_exit_2, + connect(world, LocationName.chocolate_island_3_region, LocationName.chocolate_island_3_exit_2, lambda state: (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))) - connect(world, player, names, LocationName.chocolate_island_4_region, LocationName.chocolate_island_4_exit_1) - connect(world, player, names, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_exit_1) - connect(world, player, names, LocationName.chocolate_ghost_house_region, LocationName.chocolate_ghost_house_exit_1) - connect(world, player, names, LocationName.chocolate_fortress_region, LocationName.chocolate_fortress) - connect(world, player, names, LocationName.chocolate_secret_region, LocationName.chocolate_secret_exit_1, + connect(world, LocationName.chocolate_island_4_region, LocationName.chocolate_island_4_exit_1) + connect(world, LocationName.chocolate_island_5_region, LocationName.chocolate_island_5_exit_1) + connect(world, LocationName.chocolate_ghost_house_region, LocationName.chocolate_ghost_house_exit_1) + connect(world, LocationName.chocolate_fortress_region, LocationName.chocolate_fortress) + connect(world, LocationName.chocolate_secret_region, LocationName.chocolate_secret_exit_1, lambda state: state.has(ItemName.mario_run, player)) - connect(world, player, names, LocationName.chocolate_castle_region, LocationName.chocolate_castle, + connect(world, LocationName.chocolate_castle_region, LocationName.chocolate_castle, lambda state: (state.has(ItemName.progressive_powerup, player, 1))) - connect(world, player, names, LocationName.sunken_ghost_ship_region, LocationName.sunken_ghost_ship, + connect(world, LocationName.sunken_ghost_ship_region, LocationName.sunken_ghost_ship, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_exit_1) - connect(world, player, names, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_exit_1) - connect(world, player, names, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_exit_2, + connect(world, LocationName.valley_of_bowser_1_region, LocationName.valley_of_bowser_1_exit_1) + connect(world, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_exit_1) + connect(world, LocationName.valley_of_bowser_2_region, LocationName.valley_of_bowser_2_exit_2, lambda state: state.has(ItemName.mario_carry, player)) - connect(world, player, names, LocationName.valley_of_bowser_3_region, LocationName.valley_of_bowser_3_exit_1) - connect(world, player, names, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_exit_1, + connect(world, LocationName.valley_of_bowser_3_region, LocationName.valley_of_bowser_3_exit_1) + connect(world, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_exit_1, lambda state: state.has(ItemName.mario_climb, player)) - connect(world, player, names, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_exit_2, + connect(world, LocationName.valley_of_bowser_4_region, LocationName.valley_of_bowser_4_exit_2, lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.yoshi_activate, player))) - connect(world, player, names, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_exit_1, + connect(world, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_exit_1, lambda state: state.has(ItemName.p_switch, player)) - connect(world, player, names, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_exit_2, + connect(world, LocationName.valley_ghost_house_region, LocationName.valley_ghost_house_exit_2, lambda state: (state.has(ItemName.p_switch, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.mario_run, player))) - connect(world, player, names, LocationName.valley_fortress_region, LocationName.valley_fortress, + connect(world, LocationName.valley_fortress_region, LocationName.valley_fortress, lambda state: state.has(ItemName.progressive_powerup, player, 1)) - connect(world, player, names, LocationName.valley_castle_region, LocationName.valley_castle) - connect(world, player, names, LocationName.front_door, LocationName.bowser_region, + connect(world, LocationName.valley_castle_region, LocationName.valley_castle) + connect(world, LocationName.front_door, LocationName.bowser_region, lambda state: (state.has(ItemName.mario_climb, player) and state.has(ItemName.mario_run, player) and state.has(ItemName.mario_swim, player) and state.has(ItemName.progressive_powerup, player, 1) and - state.has(ItemName.koopaling, player, world.bosses_required[player].value))) - connect(world, player, names, LocationName.back_door, LocationName.bowser_region, - lambda state: state.has(ItemName.koopaling, player, world.bosses_required[player].value)) + state.has(ItemName.koopaling, player, world.options.bosses_required.value))) + connect(world, LocationName.back_door, LocationName.bowser_region, + lambda state: state.has(ItemName.koopaling, player, world.options.bosses_required.value)) - connect(world, player, names, LocationName.star_road_1_region, LocationName.star_road_1_exit_1, + connect(world, LocationName.star_road_1_region, LocationName.star_road_1_exit_1, lambda state: (state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.progressive_powerup, player, 1))) - connect(world, player, names, LocationName.star_road_1_region, LocationName.star_road_1_exit_2, + connect(world, LocationName.star_road_1_region, LocationName.star_road_1_exit_2, lambda state: (state.has(ItemName.mario_spin_jump, player) and state.has(ItemName.mario_carry, player) and state.has(ItemName.progressive_powerup, player, 1))) - connect(world, player, names, LocationName.star_road_2_region, LocationName.star_road_2_exit_1, + connect(world, LocationName.star_road_2_region, LocationName.star_road_2_exit_1, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.star_road_2_region, LocationName.star_road_2_exit_2, + connect(world, LocationName.star_road_2_region, LocationName.star_road_2_exit_2, lambda state: (state.has(ItemName.mario_swim, player) and state.has(ItemName.mario_carry, player))) - connect(world, player, names, LocationName.star_road_3_region, LocationName.star_road_3_exit_1) - connect(world, player, names, LocationName.star_road_3_region, LocationName.star_road_3_exit_2, + connect(world, LocationName.star_road_3_region, LocationName.star_road_3_exit_1) + connect(world, LocationName.star_road_3_region, LocationName.star_road_3_exit_2, lambda state: state.has(ItemName.mario_carry, player)) - connect(world, player, names, LocationName.star_road_4_region, LocationName.star_road_4_exit_1) - connect(world, player, names, LocationName.star_road_4_region, LocationName.star_road_4_exit_2, + connect(world, LocationName.star_road_4_region, LocationName.star_road_4_exit_1) + connect(world, LocationName.star_road_4_region, LocationName.star_road_4_exit_2, lambda state: (state.has(ItemName.mario_carry, player) and (state.has(ItemName.yoshi_activate, player) or (state.has(ItemName.green_switch_palace, player) and state.has(ItemName.red_switch_palace, player))))) - connect(world, player, names, LocationName.star_road_5_region, LocationName.star_road_5_exit_1, + connect(world, LocationName.star_road_5_region, LocationName.star_road_5_exit_1, lambda state: state.has(ItemName.p_switch, player)) - connect(world, player, names, LocationName.star_road_5_region, LocationName.star_road_5_exit_2, + connect(world, LocationName.star_road_5_region, LocationName.star_road_5_exit_2, lambda state: (state.has(ItemName.mario_carry, player) and state.has(ItemName.mario_climb, player) and state.has(ItemName.p_switch, player) and @@ -1050,26 +2057,29 @@ def connect_regions(world, player, level_to_tile_dict): state.has(ItemName.red_switch_palace, player) and state.has(ItemName.blue_switch_palace, player))) - connect(world, player, names, LocationName.special_zone_1_region, LocationName.special_zone_1_exit_1, + connect(world, LocationName.special_zone_1_region, LocationName.special_zone_1_exit_1, lambda state: (state.has(ItemName.mario_climb, player) and (state.has(ItemName.p_switch, player) or (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3))))) - connect(world, player, names, LocationName.special_zone_2_region, LocationName.special_zone_2_exit_1, + connect(world, LocationName.special_zone_2_region, LocationName.special_zone_2_exit_1, lambda state: state.has(ItemName.p_balloon, player)) - connect(world, player, names, LocationName.special_zone_3_region, LocationName.special_zone_3_exit_1, + connect(world, LocationName.special_zone_3_region, LocationName.special_zone_3_exit_1, lambda state: (state.has(ItemName.mario_climb, player) or - state.has(ItemName.p_switch, player) or - (state.has(ItemName.mario_run, player) and state.has(ItemName.progressive_powerup, player, 3)))) - connect(world, player, names, LocationName.special_zone_4_region, LocationName.special_zone_4_exit_1, + state.has(ItemName.yoshi_activate, player))) + connect(world, LocationName.special_zone_4_region, LocationName.special_zone_4_exit_1, + lambda state: (state.has(ItemName.progressive_powerup, player, 2) or + state.has(ItemName.super_star_active, player))) + connect(world, LocationName.special_zone_5_region, LocationName.special_zone_5_exit_1, lambda state: state.has(ItemName.progressive_powerup, player, 1)) - connect(world, player, names, LocationName.special_zone_5_region, LocationName.special_zone_5_exit_1, - lambda state: state.has(ItemName.progressive_powerup, player, 1)) - connect(world, player, names, LocationName.special_zone_6_region, LocationName.special_zone_6_exit_1, + connect(world, LocationName.special_zone_6_region, LocationName.special_zone_6_exit_1, lambda state: state.has(ItemName.mario_swim, player)) - connect(world, player, names, LocationName.special_zone_7_region, LocationName.special_zone_7_exit_1, - lambda state: state.has(ItemName.progressive_powerup, player, 1)) - connect(world, player, names, LocationName.special_zone_8_region, LocationName.special_zone_8_exit_1, + connect(world, LocationName.special_zone_7_region, LocationName.special_zone_7_exit_1, lambda state: state.has(ItemName.progressive_powerup, player, 1)) + connect(world, LocationName.special_zone_8_region, LocationName.special_zone_8_exit_1, + lambda state: ((state.has(ItemName.progressive_powerup, player, 1) and state.has(ItemName.mario_spin_jump, player)) or + state.has(ItemName.progressive_powerup, player, 3) or + state.has(ItemName.yoshi_activate, player) or + state.has(ItemName.mario_carry, player))) @@ -1085,52 +2095,52 @@ def connect_regions(world, player, level_to_tile_dict): current_tile_name = current_tile_data.levelName if ("Star Road - " not in current_tile_name) and (" - Star Road" not in current_tile_name): current_tile_name += " - Tile" - connect(world, player, names, current_tile_name, current_level_data.levelName) + connect(world, current_tile_name, current_level_data.levelName) # Connect Exit regions to next tile regions if current_tile_data.exit1Path: next_tile_id = current_tile_data.exit1Path.otherLevelID - if world.swap_donut_gh_exits[player] and current_tile_id == 0x04: + if world.options.swap_donut_gh_exits and current_tile_id == 0x04: next_tile_id = current_tile_data.exit2Path.otherLevelID next_tile_name = level_info_dict[next_tile_id].levelName if ("Star Road - " not in next_tile_name) and (" - Star Road" not in next_tile_name): next_tile_name += " - Tile" current_exit_name = (current_level_data.levelName + " - Normal Exit") - connect(world, player, names, current_exit_name, next_tile_name) + connect(world, current_exit_name, next_tile_name) if current_tile_data.exit2Path: next_tile_id = current_tile_data.exit2Path.otherLevelID - if world.swap_donut_gh_exits[player] and current_tile_id == 0x04: + if world.options.swap_donut_gh_exits and current_tile_id == 0x04: next_tile_id = current_tile_data.exit1Path.otherLevelID next_tile_name = level_info_dict[next_tile_id].levelName if ("Star Road - " not in next_tile_name) and (" - Star Road" not in next_tile_name): next_tile_name += " - Tile" current_exit_name = (current_level_data.levelName + " - Secret Exit") - connect(world, player, names, current_exit_name, next_tile_name) + connect(world, current_exit_name, next_tile_name) - connect(world, player, names, LocationName.donut_plains_star_road, LocationName.star_road_donut) - connect(world, player, names, LocationName.star_road_donut, LocationName.donut_plains_star_road) - connect(world, player, names, LocationName.star_road_donut, LocationName.star_road_1_tile) - connect(world, player, names, LocationName.vanilla_dome_star_road, LocationName.star_road_vanilla) - connect(world, player, names, LocationName.star_road_vanilla, LocationName.vanilla_dome_star_road) - connect(world, player, names, LocationName.star_road_vanilla, LocationName.star_road_2_tile) - connect(world, player, names, LocationName.twin_bridges_star_road, LocationName.star_road_twin_bridges) - connect(world, player, names, LocationName.star_road_twin_bridges, LocationName.twin_bridges_star_road) - connect(world, player, names, LocationName.star_road_twin_bridges, LocationName.star_road_3_tile) - connect(world, player, names, LocationName.forest_star_road, LocationName.star_road_forest) - connect(world, player, names, LocationName.star_road_forest, LocationName.forest_star_road) - connect(world, player, names, LocationName.star_road_forest, LocationName.star_road_4_tile) - connect(world, player, names, LocationName.valley_star_road, LocationName.star_road_valley) - connect(world, player, names, LocationName.star_road_valley, LocationName.valley_star_road) - connect(world, player, names, LocationName.star_road_valley, LocationName.star_road_5_tile) - connect(world, player, names, LocationName.star_road_special, LocationName.special_star_road) - connect(world, player, names, LocationName.special_star_road, LocationName.star_road_special) - connect(world, player, names, LocationName.special_star_road, LocationName.special_zone_1_tile) + connect(world, LocationName.donut_plains_star_road, LocationName.star_road_donut) + connect(world, LocationName.star_road_donut, LocationName.donut_plains_star_road) + connect(world, LocationName.star_road_donut, LocationName.star_road_1_tile) + connect(world, LocationName.vanilla_dome_star_road, LocationName.star_road_vanilla) + connect(world, LocationName.star_road_vanilla, LocationName.vanilla_dome_star_road) + connect(world, LocationName.star_road_vanilla, LocationName.star_road_2_tile) + connect(world, LocationName.twin_bridges_star_road, LocationName.star_road_twin_bridges) + connect(world, LocationName.star_road_twin_bridges, LocationName.twin_bridges_star_road) + connect(world, LocationName.star_road_twin_bridges, LocationName.star_road_3_tile) + connect(world, LocationName.forest_star_road, LocationName.star_road_forest) + connect(world, LocationName.star_road_forest, LocationName.forest_star_road) + connect(world, LocationName.star_road_forest, LocationName.star_road_4_tile) + connect(world, LocationName.valley_star_road, LocationName.star_road_valley) + connect(world, LocationName.star_road_valley, LocationName.valley_star_road) + connect(world, LocationName.star_road_valley, LocationName.star_road_5_tile) + connect(world, LocationName.star_road_special, LocationName.special_star_road) + connect(world, LocationName.special_star_road, LocationName.star_road_special) + connect(world, LocationName.special_star_road, LocationName.special_zone_1_tile) - connect(world, player, names, LocationName.star_road_valley, LocationName.front_door_tile) + connect(world, LocationName.star_road_valley, LocationName.front_door_tile) -def create_region(world: MultiWorld, player: int, active_locations, name: str, locations=None): - ret = Region(name, player, world) +def create_region(multiworld: MultiWorld, player: int, active_locations, name: str, locations=None): + ret = Region(name, player, multiworld) if locations: for locationName in locations: loc_id = active_locations.get(locationName, 0) @@ -1140,9 +2150,9 @@ def create_region(world: MultiWorld, player: int, active_locations, name: str, l return ret -def add_location_to_region(world: MultiWorld, player: int, active_locations, region_name: str, location_name: str, +def add_location_to_region(multiworld: MultiWorld, player: int, active_locations, region_name: str, location_name: str, rule: typing.Optional[typing.Callable] = None): - region = world.get_region(region_name, player) + region = multiworld.get_region(region_name, player) loc_id = active_locations.get(location_name, 0) if loc_id: location = SMWLocation(player, location_name, loc_id, region) @@ -1151,23 +2161,8 @@ def add_location_to_region(world: MultiWorld, player: int, active_locations, reg add_rule(location, rule) - -def connect(world: MultiWorld, player: int, used_names: typing.Dict[str, int], source: str, target: str, +def connect(world: World, source: str, target: str, rule: typing.Optional[typing.Callable] = None): - source_region = world.get_region(source, player) - target_region = world.get_region(target, player) - - if target not in used_names: - used_names[target] = 1 - name = target - else: - used_names[target] += 1 - name = target + (' ' * used_names[target]) - - connection = Entrance(player, name, source_region) - - if rule: - connection.access_rule = rule - - source_region.exits.append(connection) - connection.connect(target_region) + source_region: Region = world.get_region(source) + target_region: Region = world.get_region(target) + source_region.connect(target_region, rule=rule) diff --git a/worlds/smw/Rom.py b/worlds/smw/Rom.py index 0f5ec7e4f0..66226d5036 100644 --- a/worlds/smw/Rom.py +++ b/worlds/smw/Rom.py @@ -1,6 +1,7 @@ import Utils +from worlds.AutoWorld import World from worlds.Files import APDeltaPatch -from .Aesthetics import generate_shuffled_header_data, generate_shuffled_ow_palettes +from .Aesthetics import generate_shuffled_header_data, generate_shuffled_ow_palettes, generate_curated_level_palette_data, generate_curated_map_palette_data, generate_shuffled_sfx from .Levels import level_info_dict, full_bowser_rooms, standard_bowser_rooms, submap_boss_rooms, ow_boss_rooms from .Names.TextBox import generate_goal_text, title_text_mapping, generate_text_box @@ -10,38 +11,48 @@ ROM_PLAYER_LIMIT = 65535 import hashlib import os import math +import pkgutil ability_rom_data = { - 0xBC0003: [[0x1F2C, 0x7]], # Run 0x80 - 0xBC0004: [[0x1F2C, 0x6]], # Carry 0x40 - 0xBC0005: [[0x1F2C, 0x2]], # Swim 0x04 - 0xBC0006: [[0x1F2C, 0x3]], # Spin Jump 0x08 - 0xBC0007: [[0x1F2C, 0x5]], # Climb 0x20 - 0xBC0008: [[0x1F2C, 0x1]], # Yoshi 0x02 - 0xBC0009: [[0x1F2C, 0x4]], # P-Switch 0x10 + 0xBC0003: [[0x1F1C, 0x7]], # Run 0x80 + 0xBC0004: [[0x1F1C, 0x6]], # Carry 0x40 + 0xBC0005: [[0x1F1C, 0x2]], # Swim 0x04 + 0xBC0006: [[0x1F1C, 0x3]], # Spin Jump 0x08 + 0xBC0007: [[0x1F1C, 0x5]], # Climb 0x20 + 0xBC0008: [[0x1F1C, 0x1]], # Yoshi 0x02 + 0xBC0009: [[0x1F1C, 0x4]], # P-Switch 0x10 #0xBC000A: [[]] 0xBC000B: [[0x1F2D, 0x3]], # P-Balloon 0x08 - 0xBC000D: [[0x1F2D, 0x4]], # Super Star 0x10 + 0xBC000D: [[0x1F2D, 0x4]] # Super Star 0x10 } +icon_rom_data = { + 0xBC0002: [0x1B00C], # Yoshi Egg + 0xBC0012: [0x1B00E], # Boss Token + 0xBC0017: [0x1B004], # 1 coin + 0xBC0018: [0x1B006], # 5 coins + 0xBC0019: [0x1B008], # 10 coins + 0xBC001A: [0x1B00A], # 50 coins + + 0xBC0001: [0x1B010] # 1-Up Mushroom +} + item_rom_data = { - 0xBC0001: [0x18E4, 0x1], # 1-Up Mushroom - - 0xBC0002: [0x1F24, 0x1, 0x1F], # Yoshi Egg - 0xBC0012: [0x1F26, 0x1, 0x09], # Boss Token - - 0xBC000E: [0x1F28, 0x1, 0x1C], # Yellow Switch Palace - 0xBC000F: [0x1F27, 0x1, 0x1C], # Green Switch Palace - 0xBC0010: [0x1F2A, 0x1, 0x1C], # Red Switch Palace - 0xBC0011: [0x1F29, 0x1, 0x1C], # Blue Switch Palace + 0xBC000E: [0x1F28, 0x1, 0x1C], # Yellow Switch Palace + 0xBC000F: [0x1F27, 0x1, 0x1C], # Green Switch Palace + 0xBC0010: [0x1F2A, 0x1, 0x1C], # Red Switch Palace + 0xBC0011: [0x1F29, 0x1, 0x1C], # Blue Switch Palace + 0xBC001B: [0x1F1E, 0x80, 0x39] # Special Zone Clear } trap_rom_data = { - 0xBC0013: [0x0086, 0x1, 0x0E], # Ice Trap + 0xBC0013: [0x0086, 0x1, 0x0E], # Ice Trap 0xBC0014: [0x18BD, 0x7F, 0x18], # Stun Trap - 0xBC0016: [0x0F31, 0x1], # Timer Trap + 0xBC0016: [0x0F31, 0x1], # Timer Trap + 0xBC001C: [0x18B4, 0x1, 0x44], # Reverse controls trap + 0xBC001D: [0x18B7, 0x1], # Thwimp Trap } @@ -109,7 +120,7 @@ def handle_ability_code(rom): rom.write_bytes(RUN_SUB_ADDR + 0x04, bytearray([0xC8])) # INY rom.write_bytes(RUN_SUB_ADDR + 0x05, bytearray([0xA9, 0x70])) # LDA #70 rom.write_bytes(RUN_SUB_ADDR + 0x07, bytearray([0xAA])) # TAX - rom.write_bytes(RUN_SUB_ADDR + 0x08, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(RUN_SUB_ADDR + 0x08, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(RUN_SUB_ADDR + 0x0B, bytearray([0x89, 0x80])) # BIT #80 rom.write_bytes(RUN_SUB_ADDR + 0x0D, bytearray([0xF0, 0x04])) # BEQ +0x04 rom.write_bytes(RUN_SUB_ADDR + 0x0F, bytearray([0x8A])) # TXA @@ -126,7 +137,7 @@ def handle_ability_code(rom): PURPLE_BLOCK_CARRY_SUB_ADDR = 0x01BA28 rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x04, bytearray([0x89, 0x40])) # BIT #40 rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09 rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x08, bytearray([0x28])) # PLP @@ -145,7 +156,7 @@ def handle_ability_code(rom): SPRINGBOARD_CARRY_SUB_ADDR = 0x01BA40 rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x00, bytearray([0x48])) # PHA rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x01, bytearray([0x08])) # PHP - rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x02, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x05, bytearray([0x89, 0x40])) # BIT #40 rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x07, bytearray([0xF0, 0x08])) # BEQ +0x08 rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x09, bytearray([0xA9, 0x0B])) # LDA #0B @@ -157,7 +168,7 @@ def handle_ability_code(rom): # End Springboard Carry # Shell Carry - rom.write_bytes(0xAA66, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(0xAA66, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(0xAA69, bytearray([0x89, 0x40])) # BIT #40 rom.write_bytes(0xAA6B, bytearray([0xF0, 0x07])) # BEQ +0x07 rom.write_bytes(0xAA6D, bytearray([0x22, 0x60, 0xBA, 0x03])) # JSL $03BA60 @@ -180,7 +191,7 @@ def handle_ability_code(rom): YOSHI_CARRY_SUB_ADDR = 0x01BA70 rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x04, bytearray([0x89, 0x40])) # BIT #40 rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x06, bytearray([0xF0, 0x0A])) # BEQ +0x0A rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x08, bytearray([0xA9, 0x12])) # LDA #12 @@ -197,7 +208,7 @@ def handle_ability_code(rom): CLIMB_SUB_ADDR = 0x01BA88 rom.write_bytes(CLIMB_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(CLIMB_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(CLIMB_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(CLIMB_SUB_ADDR + 0x04, bytearray([0x89, 0x20])) # BIT #20 rom.write_bytes(CLIMB_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09 rom.write_bytes(CLIMB_SUB_ADDR + 0x08, bytearray([0xA5, 0x8B])) # LDA $8B @@ -213,7 +224,7 @@ def handle_ability_code(rom): CLIMB_ROPE_SUB_ADDR = 0x01BC70 rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x04, bytearray([0x89, 0x20])) # BIT #20 rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07 rom.write_bytes(CLIMB_ROPE_SUB_ADDR + 0x08, bytearray([0x28])) # PLP @@ -230,7 +241,7 @@ def handle_ability_code(rom): P_SWITCH_SUB_ADDR = 0x01BAA0 rom.write_bytes(P_SWITCH_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(P_SWITCH_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(P_SWITCH_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(P_SWITCH_SUB_ADDR + 0x04, bytearray([0x89, 0x10])) # BIT #10 rom.write_bytes(P_SWITCH_SUB_ADDR + 0x06, bytearray([0xF0, 0x04])) # BEQ +0x04 rom.write_bytes(P_SWITCH_SUB_ADDR + 0x08, bytearray([0xA9, 0xB0])) # LDA #B0 @@ -242,7 +253,7 @@ def handle_ability_code(rom): # End P-Switch # Spin Jump - rom.write_bytes(0x5645, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(0x5645, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(0x5648, bytearray([0x89, 0x08])) # BIT #08 rom.write_bytes(0x564A, bytearray([0xF0, 0x12])) # BEQ +0x12 rom.write_bytes(0x564C, bytearray([0x22, 0xB8, 0xBA, 0x03])) # JSL $03BAB8 @@ -264,7 +275,7 @@ def handle_ability_code(rom): SPIN_JUMP_WATER_SUB_ADDR = 0x01BBF8 rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08 rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09 rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x08, bytearray([0x1A])) # INC @@ -281,7 +292,7 @@ def handle_ability_code(rom): SPIN_JUMP_SPRING_SUB_ADDR = 0x01BC0C rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08 rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x06, bytearray([0xF0, 0x05])) # BEQ +0x05 rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x08, bytearray([0xA9, 0x01])) # LDA #01 @@ -297,7 +308,7 @@ def handle_ability_code(rom): SWIM_SUB_ADDR = 0x01BAC8 rom.write_bytes(SWIM_SUB_ADDR + 0x00, bytearray([0x48])) # PHA rom.write_bytes(SWIM_SUB_ADDR + 0x01, bytearray([0x08])) # PHP - rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(SWIM_SUB_ADDR + 0x05, bytearray([0x89, 0x04])) # BIT #04 rom.write_bytes(SWIM_SUB_ADDR + 0x07, bytearray([0xF0, 0x0C])) # BEQ +0x0C rom.write_bytes(SWIM_SUB_ADDR + 0x09, bytearray([0x28])) # PLP @@ -321,7 +332,7 @@ def handle_ability_code(rom): SWIM_SUB_ADDR = 0x01BAE8 rom.write_bytes(SWIM_SUB_ADDR + 0x00, bytearray([0x48])) # PHA rom.write_bytes(SWIM_SUB_ADDR + 0x01, bytearray([0x08])) # PHP - rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(SWIM_SUB_ADDR + 0x05, bytearray([0x89, 0x04])) # BIT #04 rom.write_bytes(SWIM_SUB_ADDR + 0x07, bytearray([0xF0, 0x0A])) # BEQ +0x0A rom.write_bytes(SWIM_SUB_ADDR + 0x09, bytearray([0x28])) # PLP @@ -344,7 +355,7 @@ def handle_ability_code(rom): YOSHI_SUB_ADDR = 0x01BB08 rom.write_bytes(YOSHI_SUB_ADDR + 0x00, bytearray([0x08])) # PHP - rom.write_bytes(YOSHI_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(YOSHI_SUB_ADDR + 0x01, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(YOSHI_SUB_ADDR + 0x04, bytearray([0x89, 0x02])) # BIT #02 rom.write_bytes(YOSHI_SUB_ADDR + 0x06, bytearray([0xF0, 0x06])) # BEQ +0x06 rom.write_bytes(YOSHI_SUB_ADDR + 0x08, bytearray([0x28])) # PLP @@ -366,7 +377,7 @@ def handle_ability_code(rom): YOSHI_SUB_ADDR = 0x01BB20 rom.write_bytes(YOSHI_SUB_ADDR + 0x00, bytearray([0x08])) # PHP rom.write_bytes(YOSHI_SUB_ADDR + 0x01, bytearray([0x9C, 0x1E, 0x14])) # STZ $141E - rom.write_bytes(YOSHI_SUB_ADDR + 0x04, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C + rom.write_bytes(YOSHI_SUB_ADDR + 0x04, bytearray([0xAD, 0x1C, 0x1F])) # LDA $1F1C rom.write_bytes(YOSHI_SUB_ADDR + 0x07, bytearray([0x89, 0x02])) # BIT #02 rom.write_bytes(YOSHI_SUB_ADDR + 0x09, bytearray([0xF0, 0x05])) # BEQ +0x05 rom.write_bytes(YOSHI_SUB_ADDR + 0x0B, bytearray([0x28])) # PLP @@ -654,6 +665,7 @@ def handle_level_shuffle(rom, active_level_dict): for level_id, tile_id in active_level_dict.items(): rom.write_byte(0x37F70 + level_id, tile_id) + rom.write_byte(0x37F00 + tile_id, level_id) def handle_collected_paths(rom): @@ -673,38 +685,2139 @@ def handle_collected_paths(rom): def handle_vertical_scroll(rom): - rom.write_bytes(0x285BA, bytearray([0x22, 0x90, 0xBC, 0x03])) # JSL $03BC90 + rom.write_bytes(0x285BA, bytearray([0x22, 0x80, 0xF4, 0x0F])) # JSL $0FF480 - VERTICAL_SCROLL_SUB_ADDR = 0x01BC90 - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x00, bytearray([0x4A])) # LSR - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x01, bytearray([0x4A])) # LSR - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x02, bytearray([0x4A])) # LSR - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x03, bytearray([0x4A])) # LSR - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x04, bytearray([0x08])) # PHP - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x05, bytearray([0xC9, 0x02])) # CMP #02 - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x07, bytearray([0xD0, 0x02])) # BNE +0x02 - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x09, bytearray([0xA9, 0x01])) # LDA #01 - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0B, bytearray([0x28])) # PLP - rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0C, bytearray([0x6B])) # RTL + VERTICAL_SCROLL_SUB_ADDR = 0x7F480 + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0000, bytearray([0x4A])) # vertical_scroll: lsr + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0001, bytearray([0x4A])) # lsr + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0002, bytearray([0x4A])) # lsr + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0003, bytearray([0x4A])) # lsr + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0004, bytearray([0x08])) # php + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0005, bytearray([0xC9, 0x02])) # cmp #$02 + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0007, bytearray([0xD0, 0x0B])) # bne + + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0009, bytearray([0xC2, 0x10])) # rep #$10 + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x000B, bytearray([0xDA])) # phx + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x000C, bytearray([0xAE, 0x0B, 0x01])) # ldx $010B + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x000F, bytearray([0xBF, 0x00, 0xF5, 0x0F])) # lda.l vertical_scroll_levels,x + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0013, bytearray([0xFA])) # plx + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0014, bytearray([0x28])) # + plp + rom.write_bytes(VERTICAL_SCROLL_SUB_ADDR + 0x0015, bytearray([0x6B])) # rtl + + vertical_scroll_table = [ + 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, # Levels 000-00F + 0x01, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, # Levels 010-01F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 020-02F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 030-03F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 040-04F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 050-05F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 060-06F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 070-07F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 080-08F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 090-09F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 0A0-0AF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 0B0-0BF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 0C0-0CF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, # Levels 0D0-0DF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, # Levels 0E0-0EF + 0x02, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, # Levels 0F0-0FF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, # Levels 100-10F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 110-11F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 120-12F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 130-13F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 140-14F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 150-15F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 160-16F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 170-17F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 180-18F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 190-19F + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 1A0-1AF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 1B0-1BF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 1C0-1CF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 1D0-1DF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # Levels 1E0-1EF + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02] # Levels 1F0-1FF + + rom.write_bytes(0x7F500, bytes(vertical_scroll_table)) -def handle_music_shuffle(rom, world, player): +def handle_bonus_block(rom): + rom.write_bytes(0x71A5, bytearray([0x5C, 0x19, 0x8E, 0x05])) # JML $058E19 + + BONUS_BLOCK_ADDR = 0x28E19 + rom.write_bytes(BONUS_BLOCK_ADDR + 0x00, bytearray([0xA9, 0x06])) # LDA #$06 + rom.write_bytes(BONUS_BLOCK_ADDR + 0x02, bytearray([0xAC, 0xC0, 0x0D])) # LDY $0DC0 + rom.write_bytes(BONUS_BLOCK_ADDR + 0x05, bytearray([0xD0, 0x1E])) # BNE IGNORE + rom.write_bytes(BONUS_BLOCK_ADDR + 0x07, bytearray([0xDA])) # PHX + rom.write_bytes(BONUS_BLOCK_ADDR + 0x08, bytearray([0xAD, 0xBF, 0x13])) # LDA $13BF + rom.write_bytes(BONUS_BLOCK_ADDR + 0x0B, bytearray([0x4A])) # LSR + rom.write_bytes(BONUS_BLOCK_ADDR + 0x0C, bytearray([0x4A])) # LSR + rom.write_bytes(BONUS_BLOCK_ADDR + 0x0D, bytearray([0x4A])) # LSR + rom.write_bytes(BONUS_BLOCK_ADDR + 0x0E, bytearray([0x48])) # PHA + rom.write_bytes(BONUS_BLOCK_ADDR + 0x0F, bytearray([0xAD, 0xBF, 0x13])) # LDA $13BF + rom.write_bytes(BONUS_BLOCK_ADDR + 0x12, bytearray([0x29, 0x07])) # AND #$07 + rom.write_bytes(BONUS_BLOCK_ADDR + 0x14, bytearray([0xAA])) # TAX + rom.write_bytes(BONUS_BLOCK_ADDR + 0x15, bytearray([0xBF, 0x5B, 0xB3, 0x05])) # LDA $05B35B,x + rom.write_bytes(BONUS_BLOCK_ADDR + 0x19, bytearray([0xFA])) # PLX + rom.write_bytes(BONUS_BLOCK_ADDR + 0x1A, bytearray([0x1F, 0x00, 0xA0, 0x7F])) # ORA $7FA000,x + rom.write_bytes(BONUS_BLOCK_ADDR + 0x1E, bytearray([0x9F, 0x00, 0xA0, 0x7F])) # STA $7FA000,x + rom.write_bytes(BONUS_BLOCK_ADDR + 0x22, bytearray([0xFA])) # PLX + rom.write_bytes(BONUS_BLOCK_ADDR + 0x23, bytearray([0xA9, 0x05])) # LDA #$05 + rom.write_bytes(BONUS_BLOCK_ADDR + 0x25, bytearray([0x5C, 0xD0, 0xF1, 0x00])) # IGNORE: JML $00F1D0 + + +def handle_blocksanity(rom): + import json + blocksanity_data = pkgutil.get_data(__name__, f"data/blocksanity.json").decode("utf-8") + blocksanity_data = json.loads(blocksanity_data) + blocksanity_coords = bytearray([]) + blocksanity_bytes = bytearray([]) + + block_count = 0 + entries = 0 + for level_name, level_data in blocksanity_data.items(): + # Calculate blocksanity pointer + if level_data == []: + # Skip if the level doesn't have any data + blocksanity_bytes += bytearray([0xFF, 0xFF]) + continue + level_ptr = 0x80C0 + entries + blocksanity_bytes += bytearray([level_ptr & 0xFF, (level_ptr >> 8) & 0xFF]) + + # Get block data + block_coords = bytearray([]) + for x in range(len(level_data)): + block_coords += bytearray([ + int(level_data[x][1], 16) & 0xFF, (int(level_data[x][1], 16) >> 8) & 0xFF, + int(level_data[x][2], 16) & 0xFF, (int(level_data[x][2], 16) >> 8) & 0xFF, + block_count & 0xFF, (block_count >> 8) & 0xFF]) + entries += 6 + block_count += 1 + block_coords += bytearray([0xFF, 0xFF]) + entries += 2 + + blocksanity_coords += block_coords + + blocksanity_bytes += blocksanity_coords + + rom.write_bytes(0x80000, blocksanity_bytes) + rom.write_bytes(0x071D0, bytearray([0x5C, 0x00, 0xF7, 0x0F])) # org $00F1D0 : jml blocksanity_main + rom.write_bytes(0x0AD59, bytearray([0x5C, 0x15, 0xF7, 0x0F])) # org $01AD5C : jml blocksanity_flying_init + rom.write_bytes(0x0AE16, bytearray([0x22, 0x39, 0xF7, 0x0F])) # org $01AE16 : jsl blocksanity_flying_main + + BLOCKSANITY_ADDR = 0x7F700 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0000, bytearray([0x85, 0x05])) # blocksanity_main: sta $05 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0002, bytearray([0x8B])) # phb + rom.write_bytes(BLOCKSANITY_ADDR + 0x0003, bytearray([0xA9, 0x10])) # lda.b #blocksanity_pointers>>16 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0005, bytearray([0x48])) # pha + rom.write_bytes(BLOCKSANITY_ADDR + 0x0006, bytearray([0xAB])) # plb + rom.write_bytes(BLOCKSANITY_ADDR + 0x0007, bytearray([0x5A])) # phy + rom.write_bytes(BLOCKSANITY_ADDR + 0x0008, bytearray([0x20, 0x63, 0xF7])) # jsr process_block + rom.write_bytes(BLOCKSANITY_ADDR + 0x000B, bytearray([0x7A])) # ply + rom.write_bytes(BLOCKSANITY_ADDR + 0x000C, bytearray([0xAB])) # plb + rom.write_bytes(BLOCKSANITY_ADDR + 0x000D, bytearray([0xA5, 0x05])) # lda $05 + rom.write_bytes(BLOCKSANITY_ADDR + 0x000F, bytearray([0xC9, 0x05])) # cmp #$05 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0011, bytearray([0x5C, 0xD4, 0xF1, 0x00])) # jml $00F1D4 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0015, bytearray([0xB5, 0xD8])) # blocksanity_flying_init: lda $D8,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0017, bytearray([0x29, 0xF0])) # and #$F0 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0019, bytearray([0x9F, 0x20, 0xB8, 0x7F])) # sta !sprite_blocksanity_y_lo,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x001D, bytearray([0xBD, 0xD4, 0x14])) # lda $14D4,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0020, bytearray([0x9F, 0x30, 0xB8, 0x7F])) # sta !sprite_blocksanity_y_hi,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0024, bytearray([0xBD, 0xE0, 0x14])) # lda $14E0,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0027, bytearray([0x9F, 0x10, 0xB8, 0x7F])) # sta !sprite_blocksanity_x_hi,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x002B, bytearray([0xB5, 0xE4])) # lda $E4,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x002D, bytearray([0x29, 0xF0])) # and #$F0 + rom.write_bytes(BLOCKSANITY_ADDR + 0x002F, bytearray([0x9F, 0x00, 0xB8, 0x7F])) # sta !sprite_blocksanity_x_lo,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0033, bytearray([0x4A])) # lsr + rom.write_bytes(BLOCKSANITY_ADDR + 0x0034, bytearray([0x4A])) # lsr + rom.write_bytes(BLOCKSANITY_ADDR + 0x0035, bytearray([0x5C, 0x5D, 0xAD, 0x01])) # jml $01AD5D + rom.write_bytes(BLOCKSANITY_ADDR + 0x0039, bytearray([0xBF, 0x20, 0xB8, 0x7F])) # blocksanity_flying_main: lda !sprite_blocksanity_y_lo,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x003D, bytearray([0x85, 0x98])) # sta $98 + rom.write_bytes(BLOCKSANITY_ADDR + 0x003F, bytearray([0xBF, 0x30, 0xB8, 0x7F])) # lda !sprite_blocksanity_y_hi,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0043, bytearray([0x85, 0x99])) # sta $99 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0045, bytearray([0xBF, 0x00, 0xB8, 0x7F])) # lda !sprite_blocksanity_x_lo,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0049, bytearray([0x85, 0x9A])) # sta $9A + rom.write_bytes(BLOCKSANITY_ADDR + 0x004B, bytearray([0xBF, 0x10, 0xB8, 0x7F])) # lda !sprite_blocksanity_x_hi,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x004F, bytearray([0x85, 0x9B])) # sta $9B + rom.write_bytes(BLOCKSANITY_ADDR + 0x0051, bytearray([0x8B])) # phb + rom.write_bytes(BLOCKSANITY_ADDR + 0x0052, bytearray([0xA9, 0x10])) # lda.b #blocksanity_pointers>>16 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0054, bytearray([0x48])) # pha + rom.write_bytes(BLOCKSANITY_ADDR + 0x0055, bytearray([0xAB])) # plb + rom.write_bytes(BLOCKSANITY_ADDR + 0x0056, bytearray([0x5A])) # phy + rom.write_bytes(BLOCKSANITY_ADDR + 0x0057, bytearray([0xDA])) # phx + rom.write_bytes(BLOCKSANITY_ADDR + 0x0058, bytearray([0x20, 0x63, 0xF7])) # jsr process_block + rom.write_bytes(BLOCKSANITY_ADDR + 0x005B, bytearray([0xFA])) # plx + rom.write_bytes(BLOCKSANITY_ADDR + 0x005C, bytearray([0x7A])) # ply + rom.write_bytes(BLOCKSANITY_ADDR + 0x005D, bytearray([0xAB])) # plb + rom.write_bytes(BLOCKSANITY_ADDR + 0x005E, bytearray([0xB5, 0xE4])) # lda $E4,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0060, bytearray([0x85, 0x9A])) # sta $9A + rom.write_bytes(BLOCKSANITY_ADDR + 0x0062, bytearray([0x6B])) # rtl + rom.write_bytes(BLOCKSANITY_ADDR + 0x0063, bytearray([0xA9, 0x0F])) # process_block: lda #$0F + rom.write_bytes(BLOCKSANITY_ADDR + 0x0065, bytearray([0x14, 0x98])) # trb $98 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0067, bytearray([0x14, 0x9A])) # trb $9A + rom.write_bytes(BLOCKSANITY_ADDR + 0x0069, bytearray([0xC2, 0x30])) # rep #$30 + rom.write_bytes(BLOCKSANITY_ADDR + 0x006B, bytearray([0xA5, 0x60])) # lda $60 + rom.write_bytes(BLOCKSANITY_ADDR + 0x006D, bytearray([0x29, 0xFF, 0x00])) # and #$00FF + rom.write_bytes(BLOCKSANITY_ADDR + 0x0070, bytearray([0x0A])) # asl + rom.write_bytes(BLOCKSANITY_ADDR + 0x0071, bytearray([0x18])) # clc + rom.write_bytes(BLOCKSANITY_ADDR + 0x0072, bytearray([0x69, 0x00, 0x80])) # adc.w #blocksanity_pointers + rom.write_bytes(BLOCKSANITY_ADDR + 0x0075, bytearray([0x48])) # pha + rom.write_bytes(BLOCKSANITY_ADDR + 0x0076, bytearray([0xA0, 0x00, 0x00])) # ldy #$0000 + rom.write_bytes(BLOCKSANITY_ADDR + 0x0079, bytearray([0xB3, 0x01])) # lda ($01,s),y + rom.write_bytes(BLOCKSANITY_ADDR + 0x007B, bytearray([0x48])) # pha + rom.write_bytes(BLOCKSANITY_ADDR + 0x007C, bytearray([0xB3, 0x01])) # .loop lda ($01,s),y + rom.write_bytes(BLOCKSANITY_ADDR + 0x007E, bytearray([0xC9, 0xFF, 0xFF])) # cmp #$FFFF + rom.write_bytes(BLOCKSANITY_ADDR + 0x0081, bytearray([0xF0, 0x16])) # beq .return + rom.write_bytes(BLOCKSANITY_ADDR + 0x0083, bytearray([0xC5, 0x9A])) # cmp $9A + rom.write_bytes(BLOCKSANITY_ADDR + 0x0085, bytearray([0xD0, 0x0A])) # bne .next_block_x + rom.write_bytes(BLOCKSANITY_ADDR + 0x0087, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0088, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0089, bytearray([0xB3, 0x01])) # lda ($01,s),y + rom.write_bytes(BLOCKSANITY_ADDR + 0x008B, bytearray([0xC5, 0x98])) # cmp $98 + rom.write_bytes(BLOCKSANITY_ADDR + 0x008D, bytearray([0xF0, 0x0F])) # beq .valid_block + rom.write_bytes(BLOCKSANITY_ADDR + 0x008F, bytearray([0x80, 0x02])) # bra .next_block_y + rom.write_bytes(BLOCKSANITY_ADDR + 0x0091, bytearray([0xC8])) # .next_block_x iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0092, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0093, bytearray([0xC8])) # .next_block_y iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0094, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0095, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0096, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x0097, bytearray([0x80, 0xE3])) # bra .loop + rom.write_bytes(BLOCKSANITY_ADDR + 0x0099, bytearray([0x68])) # .return pla + rom.write_bytes(BLOCKSANITY_ADDR + 0x009A, bytearray([0x68])) # pla + rom.write_bytes(BLOCKSANITY_ADDR + 0x009B, bytearray([0xE2, 0x30])) # sep #$30 + rom.write_bytes(BLOCKSANITY_ADDR + 0x009D, bytearray([0x60])) # rts + rom.write_bytes(BLOCKSANITY_ADDR + 0x009E, bytearray([0xC8])) # .valid_block iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x009F, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x00A0, bytearray([0xB3, 0x01])) # lda ($01,s),y + rom.write_bytes(BLOCKSANITY_ADDR + 0x00A2, bytearray([0xAA])) # tax + rom.write_bytes(BLOCKSANITY_ADDR + 0x00A3, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00A5, bytearray([0xDA])) # phx + rom.write_bytes(BLOCKSANITY_ADDR + 0x00A6, bytearray([0xBF, 0x00, 0xA4, 0x7F])) # lda !blocksanity_data_flags,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x00AA, bytearray([0xD0, 0x08])) # bne .processed + rom.write_bytes(BLOCKSANITY_ADDR + 0x00AC, bytearray([0x1A])) # inc + rom.write_bytes(BLOCKSANITY_ADDR + 0x00AD, bytearray([0x9F, 0x00, 0xA4, 0x7F])) # sta !blocksanity_data_flags,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x00B1, bytearray([0x20, 0xBA, 0xF7])) # jsr blocksanity_check_flags + rom.write_bytes(BLOCKSANITY_ADDR + 0x00B4, bytearray([0xFA])) # .processed plx + rom.write_bytes(BLOCKSANITY_ADDR + 0x00B5, bytearray([0xFA])) # plx + rom.write_bytes(BLOCKSANITY_ADDR + 0x00B6, bytearray([0xFA])) # plx + rom.write_bytes(BLOCKSANITY_ADDR + 0x00B7, bytearray([0xE2, 0x10])) # sep #$10 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00B9, bytearray([0x60])) # rts + rom.write_bytes(BLOCKSANITY_ADDR + 0x00BA, bytearray([0xC2, 0x20])) # blocksanity_check_flags: rep #$20 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00BC, bytearray([0xA0, 0x00, 0x00])) # ldy #$0000 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00BF, bytearray([0xB3, 0x05])) # .loop lda ($05,s),y + rom.write_bytes(BLOCKSANITY_ADDR + 0x00C1, bytearray([0xC9, 0xFF, 0xFF])) # cmp #$FFFF + rom.write_bytes(BLOCKSANITY_ADDR + 0x00C4, bytearray([0xF0, 0x14])) # beq .check + rom.write_bytes(BLOCKSANITY_ADDR + 0x00C6, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x00C7, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x00C8, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x00C9, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x00CA, bytearray([0xB3, 0x05])) # lda ($05,s),y + rom.write_bytes(BLOCKSANITY_ADDR + 0x00CC, bytearray([0xAA])) # tax + rom.write_bytes(BLOCKSANITY_ADDR + 0x00CD, bytearray([0xBF, 0x00, 0xA4, 0x7F])) # lda !blocksanity_data_flags,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x00D1, bytearray([0x29, 0xFF, 0x00])) # and #$00FF + rom.write_bytes(BLOCKSANITY_ADDR + 0x00D4, bytearray([0xF0, 0x22])) # beq .invalid + rom.write_bytes(BLOCKSANITY_ADDR + 0x00D6, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x00D7, bytearray([0xC8])) # iny + rom.write_bytes(BLOCKSANITY_ADDR + 0x00D8, bytearray([0x80, 0xE5])) # bra .loop + rom.write_bytes(BLOCKSANITY_ADDR + 0x00DA, bytearray([0xE2, 0x20])) # .check sep #$20 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00DC, bytearray([0xA9, 0x00])) # lda #$00 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00DE, bytearray([0xEB])) # xba + rom.write_bytes(BLOCKSANITY_ADDR + 0x00DF, bytearray([0xA5, 0x60])) # lda $60 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00E1, bytearray([0x4A])) # lsr + rom.write_bytes(BLOCKSANITY_ADDR + 0x00E2, bytearray([0x4A])) # lsr + rom.write_bytes(BLOCKSANITY_ADDR + 0x00E3, bytearray([0x4A])) # lsr + rom.write_bytes(BLOCKSANITY_ADDR + 0x00E4, bytearray([0xA8])) # tay + rom.write_bytes(BLOCKSANITY_ADDR + 0x00E5, bytearray([0xA5, 0x60])) # lda $60 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00E7, bytearray([0x29, 0x07])) # and #$07 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00E9, bytearray([0xAA])) # tax + rom.write_bytes(BLOCKSANITY_ADDR + 0x00EA, bytearray([0xBF, 0x5B, 0xB3, 0x05])) # lda.l $05B35B,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x00EE, bytearray([0xBB])) # tyx + rom.write_bytes(BLOCKSANITY_ADDR + 0x00EF, bytearray([0x1F, 0x10, 0xA0, 0x7F])) # ora !blocksanity_flags,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x00F3, bytearray([0x9F, 0x10, 0xA0, 0x7F])) # sta !blocksanity_flags,x + rom.write_bytes(BLOCKSANITY_ADDR + 0x00F7, bytearray([0x60])) # rts + rom.write_bytes(BLOCKSANITY_ADDR + 0x00F8, bytearray([0xE2, 0x20])) # .invalid sep #$20 + rom.write_bytes(BLOCKSANITY_ADDR + 0x00FA, bytearray([0x60])) # rts + +def handle_ram(rom): + rom.write_byte(0x07FD8, 0x02) # Expand SRAM + rom.write_bytes(0x01CF5, bytearray([0x5C, 0x00, 0xF2, 0x0F])) # org $009CF5 : jml init_sram + rom.write_bytes(0x01C0F, bytearray([0x5C, 0x00, 0xF3, 0x0F])) # org $009C0F : jml save_sram + rom.write_bytes(0x013BB, bytearray([0x5C, 0xA0, 0xF0, 0x0F])) # org $0093BB : jml init_ram + + INIT_SRAM_ADDR = 0x7F200 + rom.write_bytes(INIT_SRAM_ADDR + 0x0000, bytearray([0xD0, 0x74])) # init_sram: bne .clear + rom.write_bytes(INIT_SRAM_ADDR + 0x0002, bytearray([0x9C, 0x09, 0x01])) # stz $0109 + rom.write_bytes(INIT_SRAM_ADDR + 0x0005, bytearray([0xDA])) # phx + rom.write_bytes(INIT_SRAM_ADDR + 0x0006, bytearray([0x08])) # php + rom.write_bytes(INIT_SRAM_ADDR + 0x0007, bytearray([0xE2, 0x10])) # sep #$10 + rom.write_bytes(INIT_SRAM_ADDR + 0x0009, bytearray([0xA2, 0x5F])) # ldx.b #$5F + rom.write_bytes(INIT_SRAM_ADDR + 0x000B, bytearray([0xBF, 0x00, 0x08, 0x70])) # - lda !level_clears_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x000F, bytearray([0x9F, 0x00, 0xA2, 0x7F])) # sta !level_clears,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0013, bytearray([0xCA])) # dex + rom.write_bytes(INIT_SRAM_ADDR + 0x0014, bytearray([0x10, 0xF5])) # bpl - + rom.write_bytes(INIT_SRAM_ADDR + 0x0016, bytearray([0xA2, 0x0B])) # ldx #$0B + rom.write_bytes(INIT_SRAM_ADDR + 0x0018, bytearray([0xBF, 0x40, 0x09, 0x70])) # - lda !blocksanity_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x001C, bytearray([0x9F, 0x10, 0xA0, 0x7F])) # sta !blocksanity_flags,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0020, bytearray([0xBF, 0x10, 0x09, 0x70])) # lda !moons_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0024, bytearray([0x9D, 0xEE, 0x1F])) # sta !moons_flags,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0027, bytearray([0xBF, 0x00, 0x09, 0x70])) # lda !yoshi_coins_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x002B, bytearray([0x9D, 0x2F, 0x1F])) # sta !yoshi_coins_flags,x + rom.write_bytes(INIT_SRAM_ADDR + 0x002E, bytearray([0xBF, 0x30, 0x09, 0x70])) # lda !bonus_block_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0032, bytearray([0x9F, 0x00, 0xA0, 0x7F])) # sta !bonus_block_flags,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0036, bytearray([0xBF, 0x20, 0x09, 0x70])) # lda !checkpoints_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x003A, bytearray([0x9D, 0x3C, 0x1F])) # sta !checkpoints_flags,x + rom.write_bytes(INIT_SRAM_ADDR + 0x003D, bytearray([0xCA])) # dex + rom.write_bytes(INIT_SRAM_ADDR + 0x003E, bytearray([0x10, 0xD8])) # bpl - + rom.write_bytes(INIT_SRAM_ADDR + 0x0040, bytearray([0xC2, 0x10])) # rep #$10 + rom.write_bytes(INIT_SRAM_ADDR + 0x0042, bytearray([0xA2, 0x45, 0x02])) # ldx.w #!blocksanity_locs-1 + rom.write_bytes(INIT_SRAM_ADDR + 0x0045, bytearray([0xBF, 0x00, 0x0A, 0x70])) # - lda !blocksanity_data_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0049, bytearray([0x9F, 0x00, 0xA4, 0x7F])) # sta !blocksanity_data_flags,x + rom.write_bytes(INIT_SRAM_ADDR + 0x004D, bytearray([0xCA])) # dex + rom.write_bytes(INIT_SRAM_ADDR + 0x004E, bytearray([0x10, 0xF5])) # bpl - + rom.write_bytes(INIT_SRAM_ADDR + 0x0050, bytearray([0xE2, 0x10])) # sep #$10 + #rom.write_bytes(INIT_SRAM_ADDR + 0x0052, bytearray([0xAF, 0x50, 0x09, 0x70])) # lda !received_items_count_sram+$00 + #rom.write_bytes(INIT_SRAM_ADDR + 0x0056, bytearray([0x8F, 0x0E, 0xA0, 0x7F])) # sta !received_items_count+$00 + #rom.write_bytes(INIT_SRAM_ADDR + 0x005A, bytearray([0xAF, 0x51, 0x09, 0x70])) # lda !received_items_count_sram+$01 + #rom.write_bytes(INIT_SRAM_ADDR + 0x005E, bytearray([0x8F, 0x0F, 0xA0, 0x7F])) # sta !received_items_count+$01 + rom.write_bytes(INIT_SRAM_ADDR + 0x0052, bytearray([0xEA] * 0x17)) # Ugly, will apply be better when we port everything to a Base Patch + #rom.write_bytes(INIT_SRAM_ADDR + 0x0062, bytearray([0xAF, 0x52, 0x09, 0x70])) # lda !special_world_clear_sram + #rom.write_bytes(INIT_SRAM_ADDR + 0x0066, bytearray([0x8D, 0xFF, 0x1F])) # sta !special_world_clear_flag + rom.write_bytes(INIT_SRAM_ADDR + 0x0069, bytearray([0xAF, 0x54, 0x09, 0x70])) # lda !goal_item_count_sram + rom.write_bytes(INIT_SRAM_ADDR + 0x006D, bytearray([0x8F, 0x1E, 0xA0, 0x7F])) # sta !goal_item_count + rom.write_bytes(INIT_SRAM_ADDR + 0x0071, bytearray([0x28])) # plp + rom.write_bytes(INIT_SRAM_ADDR + 0x0072, bytearray([0x5C, 0xFB, 0x9C, 0x00])) # jml $009CFB + rom.write_bytes(INIT_SRAM_ADDR + 0x0076, bytearray([0xDA])) # .clear phx + rom.write_bytes(INIT_SRAM_ADDR + 0x0077, bytearray([0xA2, 0x5F, 0x00])) # ldx.w #$005F + rom.write_bytes(INIT_SRAM_ADDR + 0x007A, bytearray([0xA9, 0x00])) # lda #$00 + rom.write_bytes(INIT_SRAM_ADDR + 0x007C, bytearray([0x9F, 0x00, 0x08, 0x70])) # - sta !level_clears_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0080, bytearray([0xCA])) # dex + rom.write_bytes(INIT_SRAM_ADDR + 0x0081, bytearray([0x10, 0xF9])) # bpl - + rom.write_bytes(INIT_SRAM_ADDR + 0x0083, bytearray([0xA2, 0x0B, 0x00])) # ldx.w #$000B + rom.write_bytes(INIT_SRAM_ADDR + 0x0086, bytearray([0x9F, 0x40, 0x09, 0x70])) # - sta !blocksanity_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x008A, bytearray([0x9F, 0x00, 0x09, 0x70])) # sta !yoshi_coins_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x008E, bytearray([0x9F, 0x30, 0x09, 0x70])) # sta !bonus_block_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0092, bytearray([0x9F, 0x10, 0x09, 0x70])) # sta !moons_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x0096, bytearray([0x9F, 0x20, 0x09, 0x70])) # sta !checkpoints_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x009A, bytearray([0xCA])) # dex + rom.write_bytes(INIT_SRAM_ADDR + 0x009B, bytearray([0x10, 0xE9])) # bpl - + rom.write_bytes(INIT_SRAM_ADDR + 0x009D, bytearray([0xA2, 0x45, 0x02])) # ldx.w #!blocksanity_locs-1 + rom.write_bytes(INIT_SRAM_ADDR + 0x00A0, bytearray([0x9F, 0x00, 0x0A, 0x70])) # - sta !blocksanity_data_sram,x + rom.write_bytes(INIT_SRAM_ADDR + 0x00A4, bytearray([0xCA])) # dex + rom.write_bytes(INIT_SRAM_ADDR + 0x00A5, bytearray([0x10, 0xF9])) # bpl - + rom.write_bytes(INIT_SRAM_ADDR + 0x00A7, bytearray([0x8F, 0x52, 0x09, 0x70])) # sta !special_world_clear_sram + rom.write_bytes(INIT_SRAM_ADDR + 0x00AB, bytearray([0x8F, 0x50, 0x09, 0x70])) # sta !received_items_count_sram+$00 + rom.write_bytes(INIT_SRAM_ADDR + 0x00AF, bytearray([0x8F, 0x51, 0x09, 0x70])) # sta !received_items_count_sram+$01 + rom.write_bytes(INIT_SRAM_ADDR + 0x00B3, bytearray([0x8F, 0x54, 0x09, 0x70])) # sta !goal_item_count_sram + rom.write_bytes(INIT_SRAM_ADDR + 0x00B7, bytearray([0xFA])) # plx + rom.write_bytes(INIT_SRAM_ADDR + 0x00B8, bytearray([0x5C, 0x22, 0x9D, 0x00])) # jml $009D22 + + SAVE_SRAM_ADDR = 0x7F300 + rom.write_bytes(SAVE_SRAM_ADDR + 0x0000, bytearray([0xE2, 0x30])) # save_sram: sep #$30 + rom.write_bytes(SAVE_SRAM_ADDR + 0x0002, bytearray([0xAB])) # plb + rom.write_bytes(SAVE_SRAM_ADDR + 0x0003, bytearray([0xA2, 0x5F])) # ldx.b #$5F + rom.write_bytes(SAVE_SRAM_ADDR + 0x0005, bytearray([0xBF, 0x00, 0xA2, 0x7F])) # - lda !level_clears,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0009, bytearray([0x9F, 0x00, 0x08, 0x70])) # sta !level_clears_sram,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x000D, bytearray([0xCA])) # dex + rom.write_bytes(SAVE_SRAM_ADDR + 0x000E, bytearray([0x10, 0xF5])) # bpl - + rom.write_bytes(SAVE_SRAM_ADDR + 0x0010, bytearray([0xA2, 0x0B])) # ldx #$0B + rom.write_bytes(SAVE_SRAM_ADDR + 0x0012, bytearray([0xBF, 0x10, 0xA0, 0x7F])) # - lda !blocksanity_flags,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0016, bytearray([0x9F, 0x40, 0x09, 0x70])) # sta !blocksanity_sram,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x001A, bytearray([0xBD, 0x2F, 0x1F])) # lda !yoshi_coins_flags,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x001D, bytearray([0x9F, 0x00, 0x09, 0x70])) # sta !yoshi_coins_sram,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0021, bytearray([0xBD, 0xEE, 0x1F])) # lda !moons_flags,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0024, bytearray([0x9F, 0x10, 0x09, 0x70])) # sta !moons_sram,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0028, bytearray([0xBF, 0x00, 0xA0, 0x7F])) # lda !bonus_block_flags,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x002C, bytearray([0x9F, 0x30, 0x09, 0x70])) # sta !bonus_block_sram,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0030, bytearray([0xBD, 0x3C, 0x1F])) # lda !checkpoints_flags,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0033, bytearray([0x9F, 0x20, 0x09, 0x70])) # sta !checkpoints_sram,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0037, bytearray([0xCA])) # dex + rom.write_bytes(SAVE_SRAM_ADDR + 0x0038, bytearray([0x10, 0xD8])) # bpl - + rom.write_bytes(SAVE_SRAM_ADDR + 0x003A, bytearray([0xC2, 0x10])) # rep #$10 + rom.write_bytes(SAVE_SRAM_ADDR + 0x003C, bytearray([0xA2, 0x45, 0x02])) # ldx.w #!blocksanity_locs-1 + rom.write_bytes(SAVE_SRAM_ADDR + 0x003F, bytearray([0xBF, 0x00, 0xA4, 0x7F])) # - lda !blocksanity_data_flags,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0043, bytearray([0x9F, 0x00, 0x0A, 0x70])) # sta !blocksanity_data_sram,x + rom.write_bytes(SAVE_SRAM_ADDR + 0x0047, bytearray([0xCA])) # dex + rom.write_bytes(SAVE_SRAM_ADDR + 0x0048, bytearray([0x10, 0xF5])) # bpl - + rom.write_bytes(SAVE_SRAM_ADDR + 0x004A, bytearray([0xE2, 0x10])) # sep #$10 + #rom.write_bytes(SAVE_SRAM_ADDR + 0x004C, bytearray([0xAD, 0xFF, 0x1F])) # lda !special_world_clear_flag + #rom.write_bytes(SAVE_SRAM_ADDR + 0x004F, bytearray([0x8F, 0x52, 0x09, 0x70])) # sta !special_world_clear_sram + #rom.write_bytes(SAVE_SRAM_ADDR + 0x0053, bytearray([0xAF, 0x0E, 0xA0, 0x7F])) # lda !received_items_count+$00 + #rom.write_bytes(SAVE_SRAM_ADDR + 0x0057, bytearray([0x8F, 0x50, 0x09, 0x70])) # sta !received_items_count_sram+$00 + #rom.write_bytes(SAVE_SRAM_ADDR + 0x005B, bytearray([0xAF, 0x0F, 0xA0, 0x7F])) # lda !received_items_count+$01 + #rom.write_bytes(SAVE_SRAM_ADDR + 0x005F, bytearray([0x8F, 0x51, 0x09, 0x70])) # sta !received_items_count_sram+$01 + rom.write_bytes(SAVE_SRAM_ADDR + 0x004C, bytearray([0xEA] * 0x17)) # Ugly, will apply be better when we port everything to a Base Patch + rom.write_bytes(SAVE_SRAM_ADDR + 0x0063, bytearray([0xAF, 0x0F, 0xA0, 0x7F])) # lda !goal_item_count + rom.write_bytes(SAVE_SRAM_ADDR + 0x0067, bytearray([0x8F, 0x51, 0x09, 0x70])) # sta !goal_item_count_sram + rom.write_bytes(SAVE_SRAM_ADDR + 0x006B, bytearray([0x6B])) # rtl + + INIT_RAM_ADDR = 0x7F0A0 + rom.write_bytes(INIT_RAM_ADDR + 0x0000, bytearray([0xA9, 0xAA])) # init_ram: lda #$AA + rom.write_bytes(INIT_RAM_ADDR + 0x0002, bytearray([0x8D, 0x00, 0x04])) # sta $0400 + rom.write_bytes(INIT_RAM_ADDR + 0x0005, bytearray([0xA9, 0x00])) # clear_level_data: lda #$00 + rom.write_bytes(INIT_RAM_ADDR + 0x0007, bytearray([0xA2, 0x5F])) # ldx #$5F + rom.write_bytes(INIT_RAM_ADDR + 0x0009, bytearray([0x9F, 0x00, 0xA2, 0x7F])) # .loop sta !level_clears,x + rom.write_bytes(INIT_RAM_ADDR + 0x000D, bytearray([0xCA])) # dex + rom.write_bytes(INIT_RAM_ADDR + 0x000E, bytearray([0x10, 0xF9])) # bpl .loop + rom.write_bytes(INIT_RAM_ADDR + 0x0010, bytearray([0xC2, 0x10])) # rep #$10 + rom.write_bytes(INIT_RAM_ADDR + 0x0012, bytearray([0xA2, 0x0B, 0x00])) # ldx.w #$000B + rom.write_bytes(INIT_RAM_ADDR + 0x0015, bytearray([0x9F, 0x10, 0xA0, 0x7F])) # - sta !blocksanity_flags,x + rom.write_bytes(INIT_RAM_ADDR + 0x0019, bytearray([0x9D, 0x2F, 0x1F])) # sta !yoshi_coins_flags,x + rom.write_bytes(INIT_RAM_ADDR + 0x001C, bytearray([0x9D, 0xEE, 0x1F])) # sta !moons_flags,x + rom.write_bytes(INIT_RAM_ADDR + 0x001F, bytearray([0x9F, 0x00, 0xA0, 0x7F])) # sta !bonus_block_flags,x + rom.write_bytes(INIT_RAM_ADDR + 0x0023, bytearray([0x9D, 0x3C, 0x1F])) # sta !checkpoints_flags,x + rom.write_bytes(INIT_RAM_ADDR + 0x0026, bytearray([0xCA])) # dex + rom.write_bytes(INIT_RAM_ADDR + 0x0027, bytearray([0x10, 0xEC])) # bpl - + rom.write_bytes(INIT_RAM_ADDR + 0x0029, bytearray([0xA2, 0x45, 0x02])) # ldx.w #!blocksanity_locs-1 + rom.write_bytes(INIT_RAM_ADDR + 0x002C, bytearray([0x9F, 0x00, 0xA4, 0x7F])) # - sta !blocksanity_data_flags,x + rom.write_bytes(INIT_RAM_ADDR + 0x0030, bytearray([0xCA])) # dex + rom.write_bytes(INIT_RAM_ADDR + 0x0031, bytearray([0x10, 0xF9])) # bpl - + rom.write_bytes(INIT_RAM_ADDR + 0x0033, bytearray([0xA2, 0x22, 0x04])) # ldx #$0422 + rom.write_bytes(INIT_RAM_ADDR + 0x0036, bytearray([0x9F, 0x00, 0xB0, 0x7F])) # - sta !score_sprite_count,x + rom.write_bytes(INIT_RAM_ADDR + 0x003A, bytearray([0xCA])) # dex + rom.write_bytes(INIT_RAM_ADDR + 0x003B, bytearray([0x10, 0xF9])) # bpl - + #rom.write_bytes(INIT_RAM_ADDR + 0x003D, bytearray([0x8D, 0xFF, 0x1F])) # sta !special_world_clear_flag + rom.write_bytes(INIT_RAM_ADDR + 0x003D, bytearray([0xEA, 0xEA, 0xEA])) # sta !special_world_clear_flag + rom.write_bytes(INIT_RAM_ADDR + 0x0040, bytearray([0x8F, 0x0E, 0xA0, 0x7F])) # sta !received_items_count+$00 + rom.write_bytes(INIT_RAM_ADDR + 0x0044, bytearray([0x8F, 0x0F, 0xA0, 0x7F])) # sta !received_items_count+$01 + rom.write_bytes(INIT_RAM_ADDR + 0x0048, bytearray([0x8F, 0x1E, 0xA0, 0x7F])) # sta !goal_item_count + rom.write_bytes(INIT_RAM_ADDR + 0x004C, bytearray([0xA9, 0xFF])) # lda #$FF + rom.write_bytes(INIT_RAM_ADDR + 0x004E, bytearray([0x8D, 0x3C, 0x0F])) # sta !thwimp_index + rom.write_bytes(INIT_RAM_ADDR + 0x0051, bytearray([0xE2, 0x10])) # sep #$10 + rom.write_bytes(INIT_RAM_ADDR + 0x0053, bytearray([0x22, 0x20, 0xF1, 0x0F])) # jsl clear_tilemap + rom.write_bytes(INIT_RAM_ADDR + 0x0057, bytearray([0x5C, 0xC0, 0x93, 0x00])) # jml $0093C0 + +def handle_map_indicators(rom): + rom.write_bytes(0x265EE, bytearray([0x4C, 0x00, 0xA3])) # org $04E5EE : jmp check_events + + GET_MAP_LEVEL_NUM_ADDR = 0x22340 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0000, bytearray([0xC2, 0x30])) # get_translevel_num: rep #$30 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0002, bytearray([0xAE, 0xD6, 0x0D])) # ldx $0DD6 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0005, bytearray([0xBD, 0x1F, 0x1F])) # lda $1F1F,x + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0008, bytearray([0x85, 0x00])) # sta $00 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x000A, bytearray([0xBD, 0x21, 0x1F])) # lda $1F21,x + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x000D, bytearray([0x85, 0x02])) # sta $02 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x000F, bytearray([0x8A])) # txa + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0010, bytearray([0x4A])) # lsr + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0011, bytearray([0x4A])) # lsr + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0012, bytearray([0xAA])) # tax + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0013, bytearray([0x20, 0x85, 0x98])) # jsr $9885 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0016, bytearray([0xA6, 0x04])) # ldx $04 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0018, bytearray([0xBF, 0x00, 0xD0, 0x7E])) # lda $7ED000,x + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x001C, bytearray([0xE2, 0x30])) # sep #$30 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x001E, bytearray([0x85, 0x60])) # sta $60 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0020, bytearray([0xAA])) # tax + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0021, bytearray([0xBF, 0x00, 0xFF, 0x06])) # lda $06FF00,x + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0025, bytearray([0xC9, 0xFF])) # cmp #$FF + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0027, bytearray([0xF0, 0x02])) # beq + + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x0029, bytearray([0x85, 0x60])) # sta $60 + rom.write_bytes(GET_MAP_LEVEL_NUM_ADDR + 0x002B, bytearray([0x60])) # + rts + + GET_MAP_LEVEL_BIT_ADDR = 0x22380 + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x0000, bytearray([0xA5, 0x60])) # get_translevel_bit: lda $60 + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x0002, bytearray([0x4A])) # lsr + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x0003, bytearray([0x4A])) # lsr + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x0004, bytearray([0x4A])) # lsr + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x0005, bytearray([0xA8])) # tay + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x0006, bytearray([0xA5, 0x60])) # lda $60 + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x0008, bytearray([0x29, 0x07])) # and #$07 + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x000A, bytearray([0xAA])) # tax + rom.write_bytes(GET_MAP_LEVEL_BIT_ADDR + 0x000B, bytearray([0x60])) # rts + + UPDATE_MAP_PTRS_ADDR = 0x223C0 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x0000, bytearray([0xE6, 0x00])) # update_flag_pointers: inc $00 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x0002, bytearray([0xE6, 0x00])) # inc $00 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x0004, bytearray([0xE6, 0x03])) # inc $03 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x0006, bytearray([0xE6, 0x03])) # inc $03 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x0008, bytearray([0xE6, 0x06])) # inc $06 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x000A, bytearray([0xE6, 0x06])) # inc $06 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x000C, bytearray([0xE6, 0x62])) # inc $62 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x000E, bytearray([0xE6, 0x62])) # inc $62 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x0010, bytearray([0xE6, 0x63])) # inc $63 + rom.write_bytes(UPDATE_MAP_PTRS_ADDR + 0x0012, bytearray([0x60])) # rts + + CLEAR_TILEMAP_ADDR = 0x7F120 + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0000, bytearray([0xC2, 0x20])) # clear_tilemap: rep #$20 + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0002, bytearray([0xA9, 0x1F, 0x39])) # lda.w #$3900+!icon_disabled + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0005, bytearray([0xA2, 0x1E])) # ldx #$1E + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0007, bytearray([0x9F, 0x20, 0xA1, 0x7F])) # .loop sta !ow_tilemap_switches,x + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x000B, bytearray([0x9F, 0x00, 0xA1, 0x7F])) # sta !ow_tilemap_abilities,x + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x000F, bytearray([0x9F, 0x40, 0xA1, 0x7F])) # sta !ow_tilemap_flags_top,x + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0013, bytearray([0x9F, 0x60, 0xA1, 0x7F])) # sta !ow_tilemap_flags_mid,x + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0017, bytearray([0x9F, 0x80, 0xA1, 0x7F])) # sta !ow_tilemap_flags_bot,x + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x001B, bytearray([0xCA])) # dex + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x001C, bytearray([0xCA])) # dex + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x001D, bytearray([0x10, 0xE8])) # bpl .loop + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x001F, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0021, bytearray([0xA9, 0x07])) # lda #$07 + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0023, bytearray([0x85, 0x63])) # sta $63 + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0025, bytearray([0x0A])) # asl + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0026, bytearray([0x85, 0x62])) # sta $62 + rom.write_bytes(CLEAR_TILEMAP_ADDR + 0x0028, bytearray([0x6B])) # rtl + + CLEAR_TILEMAP_FLAGS_ADDR = 0x7F180 + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0000, bytearray([0xC2, 0x20])) # clear_tilemap_flags: rep #$20 + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0002, bytearray([0xA9, 0x1F, 0x39])) # lda.w #$3900+!icon_disabled + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0005, bytearray([0xA2, 0x0C])) # ldx.b #($07*2)-2 + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0007, bytearray([0x9F, 0x40, 0xA1, 0x7F])) # .loop sta !ow_tilemap_flags_top,x + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x000B, bytearray([0x9F, 0x60, 0xA1, 0x7F])) # sta !ow_tilemap_flags_mid,x + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x000F, bytearray([0x9F, 0x80, 0xA1, 0x7F])) # sta !ow_tilemap_flags_bot,x + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0013, bytearray([0xCA])) # dex + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0014, bytearray([0xCA])) # dex + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0015, bytearray([0x10, 0xF0])) # bpl .loop + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0017, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0019, bytearray([0xA9, 0x06])) # lda #$06 + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x001B, bytearray([0x85, 0x63])) # sta $63 + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x001D, bytearray([0x0A])) # asl + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x001E, bytearray([0x85, 0x62])) # sta $62 + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0020, bytearray([0xA9, 0xFF])) # lda #$FF + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0022, bytearray([0x8D, 0x3C, 0x0F])) # sta !thwimp_index + rom.write_bytes(CLEAR_TILEMAP_FLAGS_ADDR + 0x0025, bytearray([0x6B])) # rtl + + CHECK_EVENTS_ADDR = 0x22300 + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0000, bytearray([0xDA])) # check_events: phx + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0001, bytearray([0x20, 0x40, 0xA3])) # jsr get_translevel_num + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0004, bytearray([0xAD, 0xD5, 0x0D])) # lda $0DD5 + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0007, bytearray([0xF0, 0x17])) # beq .dont_sync + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0009, bytearray([0x30, 0x15])) # bmi .dont_sync + rom.write_bytes(CHECK_EVENTS_ADDR + 0x000B, bytearray([0xC9, 0x05])) # cmp #$05 + rom.write_bytes(CHECK_EVENTS_ADDR + 0x000D, bytearray([0xB0, 0x11])) # bcs .dont_sync + rom.write_bytes(CHECK_EVENTS_ADDR + 0x000F, bytearray([0x29, 0x07])) # and #$07 + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0011, bytearray([0xAA])) # tax + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0012, bytearray([0xBF, 0x7D, 0x9E, 0x00])) # lda.l $009E7D,x + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0016, bytearray([0xA6, 0x60])) # ldx $60 + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0018, bytearray([0x1F, 0x00, 0xA2, 0x7F])) # ora !level_clears,x + rom.write_bytes(CHECK_EVENTS_ADDR + 0x001C, bytearray([0x9F, 0x00, 0xA2, 0x7F])) # sta !level_clears,x + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0020, bytearray([0xFA])) # .dont_sync plx + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0021, bytearray([0xAD, 0xD5, 0x0D])) # lda $0DD5 + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0024, bytearray([0xC9, 0x02])) # cmp #$02 + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0026, bytearray([0xD0, 0x03])) # bne .no_secret + rom.write_bytes(CHECK_EVENTS_ADDR + 0x0028, bytearray([0xEE, 0xEA, 0x1D])) # inc $1DEA + rom.write_bytes(CHECK_EVENTS_ADDR + 0x002B, bytearray([0x4C, 0xF8, 0xE5])) # .no_secret jmp $E5F8 + + DRAW_MAP_TILEMAP_ADDR = 0x221B6 + rom.write_bytes(0x00222, bytearray([0x5C, 0xB6, 0xA1, 0x04])) # org $008222 : jml draw_ow_tilemap + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0000, bytearray([0xAD, 0xD9, 0x13])) # draw_ow_tilemap: lda $13D9 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0003, bytearray([0xC9, 0x0A])) # cmp #$0A + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0005, bytearray([0xD0, 0x04])) # bne write_tilemap + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0007, bytearray([0x5C, 0x29, 0x82, 0x00])) # jml $008229 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x000B, bytearray([0xC2, 0x20])) # write_tilemap: rep #$20 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x000D, bytearray([0xA0, 0x80])) # ldy #$80 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x000F, bytearray([0x8C, 0x15, 0x21])) # sty $2115 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0012, bytearray([0xA9, 0x27, 0x50])) # write_abilities: lda #!vram_abilities_top + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0015, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0018, bytearray([0xA2, 0x00])) # ldx.b #$00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x001A, bytearray([0xBF, 0xA2, 0xA2, 0x04])) # ..loop lda.l abilities_top,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x001E, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0021, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0022, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0023, bytearray([0xE0, 0x14])) # cpx.b #$0A*2 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0025, bytearray([0x90, 0xF3])) # bcc ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0027, bytearray([0xA9, 0x47, 0x50])) # .mid lda #!vram_abilities_mid + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x002A, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x002D, bytearray([0xA2, 0x00])) # ldx.b #$00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x002F, bytearray([0xBF, 0xB6, 0xA2, 0x04])) # ..loop lda.l abilities_bottom,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0033, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0036, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0037, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0038, bytearray([0xE0, 0x14])) # cpx.b #$0A*2 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x003A, bytearray([0x90, 0xF3])) # bcc ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x003C, bytearray([0xA9, 0x67, 0x50])) # .bot lda #!vram_abilities_bot + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x003F, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0042, bytearray([0xA2, 0x00])) # ldx.b #$00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0044, bytearray([0xBF, 0x00, 0xA1, 0x7F])) # ..loop lda !ow_tilemap_abilities,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0048, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x004B, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x004C, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x004D, bytearray([0xE0, 0x14])) # cpx.b #$0A*2 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x004F, bytearray([0x90, 0xF3])) # bcc ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0051, bytearray([0xA9, 0x32, 0x50])) # write_switches: lda #!vram_switches_top + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0054, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0057, bytearray([0xA2, 0x00])) # ldx.b #$00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0059, bytearray([0xBF, 0xCA, 0xA2, 0x04])) # ..loop lda.l switches_top,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x005D, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0060, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0061, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0062, bytearray([0xE0, 0x0A])) # cpx.b #$05*2 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0064, bytearray([0x90, 0xF3])) # bcc ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0066, bytearray([0xA9, 0x52, 0x50])) # .mid lda #!vram_switches_mid + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0069, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x006C, bytearray([0xA2, 0x00])) # ldx.b #$00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x006E, bytearray([0xBF, 0xD4, 0xA2, 0x04])) # ..loop lda.l switches_bottom,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0072, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0075, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0076, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0077, bytearray([0xE0, 0x0A])) # cpx.b #$05*2 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0079, bytearray([0x90, 0xF3])) # bcc ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x007B, bytearray([0xA9, 0x72, 0x50])) # .bot lda #!vram_switches_bot + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x007E, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0081, bytearray([0xA2, 0x00])) # ldx.b #$00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0083, bytearray([0xBF, 0x20, 0xA1, 0x7F])) # ..loop lda !ow_tilemap_switches,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0087, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x008A, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x008B, bytearray([0xE8])) # inx + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x008C, bytearray([0xE0, 0x0A])) # cpx.b #$05*2 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x008E, bytearray([0x90, 0xF3])) # bcc ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0090, bytearray([0xD4, 0x00])) # write_level_data: pei ($00) + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0092, bytearray([0xA5, 0x63])) # lda $63 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0094, bytearray([0x29, 0xFF, 0x00])) # and #$00FF + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0097, bytearray([0x85, 0x00])) # sta $00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0099, bytearray([0xF0, 0x48])) # beq .skip_flags + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x009B, bytearray([0xA9, 0x3E, 0x50])) # .top lda.w #!vram_level_data_top+$01 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x009E, bytearray([0x38])) # sec + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x009F, bytearray([0xE5, 0x00])) # sbc $00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00A1, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00A4, bytearray([0xA6, 0x62])) # ldx.b $62 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00A6, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00A7, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00A8, bytearray([0xBF, 0x40, 0xA1, 0x7F])) # ..loop lda.l !ow_tilemap_flags_top,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00AC, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00AF, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00B0, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00B1, bytearray([0x10, 0xF5])) # bpl ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00B3, bytearray([0xA9, 0x5E, 0x50])) # .mid lda.w #!vram_level_data_mid+$01 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00B6, bytearray([0x38])) # sec + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00B7, bytearray([0xE5, 0x00])) # sbc $00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00B9, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00BC, bytearray([0xA6, 0x62])) # ldx.b $62 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00BE, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00BF, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00C0, bytearray([0xBF, 0x60, 0xA1, 0x7F])) # ..loop lda.l !ow_tilemap_flags_mid,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00C4, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00C7, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00C8, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00C9, bytearray([0x10, 0xF5])) # bpl ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00CB, bytearray([0xA9, 0x7E, 0x50])) # .bot lda.w #!vram_level_data_bot+$01 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00CE, bytearray([0x38])) # sec + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00CF, bytearray([0xE5, 0x00])) # sbc $00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00D1, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00D4, bytearray([0xA6, 0x62])) # ldx.b $62 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00D6, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00D7, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00D8, bytearray([0xBF, 0x80, 0xA1, 0x7F])) # ..loop lda.l !ow_tilemap_flags_bot,x + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00DC, bytearray([0x8D, 0x18, 0x21])) # sta $2118 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00DF, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00E0, bytearray([0xCA])) # dex + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00E1, bytearray([0x10, 0xF5])) # bpl ..loop + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00E3, bytearray([0x68])) # .skip_flags pla + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00E4, bytearray([0x85, 0x00])) # sta $00 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00E6, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00E8, bytearray([0x5C, 0x37, 0x82, 0x00])) # jml $008237 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00EC, bytearray([0x0F, 0x39, 0x12, 0x39])) # abilities_top: dw $390F,$3912 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00F0, bytearray([0x11, 0x39, 0x02, 0x39])) # dw $3911,$3902 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00F4, bytearray([0x12, 0x39, 0x02, 0x39])) # dw $3912,$3902 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00F8, bytearray([0x18, 0x39, 0x0F, 0x39])) # dw $3918,$390F + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x00FC, bytearray([0x0F, 0x39, 0x12, 0x39])) # dw $390F,$3912 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0100, bytearray([0x4E, 0x39, 0x4F, 0x39])) # abilities_bottom: dw $394E,$394F + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0104, bytearray([0x54, 0x39, 0x40, 0x39])) # dw $3954,$3940 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0108, bytearray([0x56, 0x39, 0x4B, 0x39])) # dw $3956,$394B + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x010C, bytearray([0x4E, 0x39, 0x52, 0x39])) # dw $394E,$3952 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0110, bytearray([0x41, 0x39, 0x53, 0x39])) # dw $3941,$3953 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0114, bytearray([0x18, 0x39, 0x06, 0x39])) # switches_top: dw $3918,$3906 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0118, bytearray([0x11, 0x39, 0x01, 0x39])) # dw $3911,$3901 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x011C, bytearray([0x12, 0x39])) # dw $3912 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x011E, bytearray([0x12, 0x39, 0x12, 0x39])) # switches_bottom: dw $3912,$3912 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0122, bytearray([0x12, 0x39, 0x12, 0x39])) # dw $3912,$3912 + rom.write_bytes(DRAW_MAP_TILEMAP_ADDR + 0x0126, bytearray([0x4F, 0x39])) # dw $394F + + BUILD_TILEMAP_ADDR = 0x26F3E + rom.write_bytes(0x021C7, bytearray([0x22, 0x3E, 0xEF, 0x04])) # org $00A1C7 : jsl prepare_dynamic_tilemap + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0000, bytearray([0x22, 0x41, 0x82, 0x04])) # prepare_dynamic_tilemap: jsl $048241 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0004, bytearray([0xA0, 0x22])) # .handle_powerup: ldy #$22 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0006, bytearray([0xAD, 0x2D, 0x1F])) # lda $1F2D + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0009, bytearray([0x4A])) # lsr + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x000A, bytearray([0x90, 0x01])) # bcc $01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x000C, bytearray([0xC8])) # iny + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x000D, bytearray([0x4A])) # lsr + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x000E, bytearray([0x90, 0x01])) # bcc $01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0010, bytearray([0xC8])) # iny + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0011, bytearray([0x4A])) # lsr + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0012, bytearray([0x90, 0x01])) # bcc $01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0014, bytearray([0xC8])) # iny + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0015, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0016, bytearray([0x8F, 0x00, 0xA1, 0x7F])) # sta !ow_tilemap_abilities ; Progressive powerup + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x001A, bytearray([0xA0, 0x5E])) # .handle_spinjump: ldy #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x001C, bytearray([0xAD, 0x1C, 0x1F])) # lda $1F1C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x001F, bytearray([0x29, 0x08])) # and #$08 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0021, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0023, bytearray([0xA0, 0x3F])) # ldy #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0025, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0026, bytearray([0x8F, 0x02, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$02 ; Spin jump + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x002A, bytearray([0xA0, 0x5E])) # .handle_run: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x002C, bytearray([0xAD, 0x1C, 0x1F])) # lda $1F1C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x002F, bytearray([0x29, 0x80])) # and #$80 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0031, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0033, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0035, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0036, bytearray([0x8F, 0x04, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$04 ; Run + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x003A, bytearray([0xA0, 0x5E])) # .handle_carry: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x003C, bytearray([0xAD, 0x1C, 0x1F])) # lda $1F1C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x003F, bytearray([0x29, 0x40])) # and #$40 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0041, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0043, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0045, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0046, bytearray([0x8F, 0x06, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$06 ; Carry + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x004A, bytearray([0xA0, 0x5E])) # .handle_swim: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x004C, bytearray([0xAD, 0x1C, 0x1F])) # lda $1F1C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x004F, bytearray([0x29, 0x04])) # and #$04 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0051, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0053, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0055, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0056, bytearray([0x8F, 0x08, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$08 ; Swim + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x005A, bytearray([0xA0, 0x5E])) # .handle_climb: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x005C, bytearray([0xAD, 0x1C, 0x1F])) # lda $1F1C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x005F, bytearray([0x29, 0x20])) # and #$20 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0061, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0063, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0065, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0066, bytearray([0x8F, 0x0A, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$0A ; Climb + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x006A, bytearray([0xA0, 0x5E])) # .handle_yoshi: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x006C, bytearray([0xAD, 0x1C, 0x1F])) # lda $1F1C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x006F, bytearray([0x29, 0x02])) # and #$02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0071, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0073, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0075, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0076, bytearray([0x8F, 0x0C, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$0C ; Yoshi + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x007A, bytearray([0xA0, 0x5E])) # .handle_pswitch: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x007C, bytearray([0xAD, 0x1C, 0x1F])) # lda $1F1C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x007F, bytearray([0x29, 0x10])) # and #$10 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0081, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0083, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0085, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0086, bytearray([0x8F, 0x0E, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$0E ; P-Switch + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x008A, bytearray([0xA0, 0x5E])) # .handle_pballoon: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x008C, bytearray([0xAD, 0x2D, 0x1F])) # lda $1F2D + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x008F, bytearray([0x29, 0x08])) # and #$08 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0091, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0093, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0095, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0096, bytearray([0x8F, 0x10, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$10 ; P-Balloon + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x009A, bytearray([0xA0, 0x5E])) # .handle_star: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x009C, bytearray([0xAD, 0x2D, 0x1F])) # lda $1F2D + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x009F, bytearray([0x29, 0x10])) # and #$10 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00A1, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00A3, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00A5, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00A6, bytearray([0x8F, 0x12, 0xA1, 0x7F])) # sta !ow_tilemap_abilities+$12 ; Star + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00AA, bytearray([0xA0, 0x5E])) # .handle_yellow_switch: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00AC, bytearray([0xAD, 0x28, 0x1F])) # lda $1F28 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00AF, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00B1, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00B3, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00B4, bytearray([0x8F, 0x20, 0xA1, 0x7F])) # sta !ow_tilemap_switches+$00 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00B8, bytearray([0xA0, 0x5E])) # .handle_green_switch: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00BA, bytearray([0xAD, 0x27, 0x1F])) # lda $1F27 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00BD, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00BF, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00C1, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00C2, bytearray([0x8F, 0x22, 0xA1, 0x7F])) # sta !ow_tilemap_switches+$02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00C6, bytearray([0xA0, 0x5E])) # .handle_red_switch: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00C8, bytearray([0xAD, 0x2A, 0x1F])) # lda $1F2A + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00CB, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00CD, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00CF, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00D0, bytearray([0x8F, 0x24, 0xA1, 0x7F])) # sta !ow_tilemap_switches+$04 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00D4, bytearray([0xA0, 0x5E])) # .handle_blue_switch: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00D6, bytearray([0xAD, 0x29, 0x1F])) # lda $1F29 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00D9, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00DB, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00DD, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00DE, bytearray([0x8F, 0x26, 0xA1, 0x7F])) # sta !ow_tilemap_switches+$06 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00E2, bytearray([0xA0, 0x5E])) # .handle_special_world_clear: ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00E4, bytearray([0xAD, 0x1E, 0x1F])) # lda !special_world_clear_flag + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00E7, bytearray([0xF0, 0x02])) # beq $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00E9, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00EB, bytearray([0x98])) # tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00EC, bytearray([0x8F, 0x28, 0xA1, 0x7F])) # sta !ow_tilemap_switches+$08 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00F0, bytearray([0x22, 0x80, 0xF1, 0x0F])) # jsl clear_tilemap_flags + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00F4, bytearray([0xAD, 0xD9, 0x13])) # lda $13D9 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00F7, bytearray([0xC9, 0x01])) # cmp #$01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00F9, bytearray([0xF0, 0x05])) # beq process_level + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00FB, bytearray([0xC9, 0x03])) # cmp #$03 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00FD, bytearray([0xF0, 0x01])) # beq process_level + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x00FF, bytearray([0x6B])) # rtl + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0100, bytearray([0x20, 0x40, 0xA3])) # process_level: jsr get_translevel_num + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0103, bytearray([0xA6, 0x60])) # ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0105, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0109, bytearray([0x10, 0x01])) # bpl .handle_data + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x010B, bytearray([0x6B])) # rtl + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x010C, bytearray([0x64, 0x62])) # .handle_data stz $62 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x010E, bytearray([0x64, 0x63])) # stz $63 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0110, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0112, bytearray([0xA9, 0x40, 0xA1])) # lda.w #!ow_tilemap_flags_top + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0115, bytearray([0x85, 0x00])) # sta $00 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0117, bytearray([0xA9, 0x60, 0xA1])) # lda.w #!ow_tilemap_flags_mid + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x011A, bytearray([0x85, 0x03])) # sta $03 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x011C, bytearray([0xA9, 0x80, 0xA1])) # lda.w #!ow_tilemap_flags_bot + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x011F, bytearray([0x85, 0x06])) # sta $06 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0121, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0123, bytearray([0xA9, 0x7F])) # lda.b #!ow_tilemap_flags_top>>16 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0125, bytearray([0x85, 0x02])) # sta $02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0127, bytearray([0x85, 0x05])) # sta $05 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0129, bytearray([0x85, 0x08])) # sta $08 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x012B, bytearray([0xAF, 0xAB, 0xBF, 0x03])) # handle_blocksanity: lda.l blocksanity_enabled_flag + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x012F, bytearray([0xF0, 0x30])) # beq handle_bonus_blocks + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0131, bytearray([0xA6, 0x60])) # ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0133, bytearray([0xA0, 0x1F])) # ldy.b #!icon_disabled + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0135, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0139, bytearray([0x29, 0x40])) # and #$40 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x013B, bytearray([0xF0, 0x24])) # beq handle_bonus_blocks + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x013D, bytearray([0xA0, 0x5E])) # ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x013F, bytearray([0x5A])) # phy + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0140, bytearray([0x20, 0x80, 0xA3])) # jsr get_translevel_bit + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0143, bytearray([0xDA])) # phx + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0144, bytearray([0xBB])) # tyx + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0145, bytearray([0xBF, 0x10, 0xA0, 0x7F])) # lda.l !blocksanity_flags,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0149, bytearray([0xFA])) # plx + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x014A, bytearray([0x7A])) # ply + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x014B, bytearray([0x3F, 0xA6, 0xA8, 0x0D])) # and.l $0DA8A6,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x014F, bytearray([0xF0, 0x02])) # beq .write + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0151, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0153, bytearray([0x98])) # .write tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0154, bytearray([0x87, 0x06])) # sta [$06] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0156, bytearray([0xA9, 0x01])) # lda #$01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0158, bytearray([0x87, 0x00])) # sta [$00] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x015A, bytearray([0xA9, 0x12])) # lda #$12 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x015C, bytearray([0x87, 0x03])) # sta [$03] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x015E, bytearray([0x20, 0xC0, 0xA3])) # jsr update_flag_pointers + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0161, bytearray([0xAF, 0xAA, 0xBF, 0x03])) # handle_bonus_blocks: lda.l bonus_block_enabled_flag + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0165, bytearray([0xF0, 0x30])) # beq handle_checkpoints + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0167, bytearray([0xA6, 0x60])) # ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0169, bytearray([0xA0, 0x1F])) # ldy.b #!icon_disabled + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x016B, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x016F, bytearray([0x29, 0x20])) # and #$20 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0171, bytearray([0xF0, 0x24])) # beq handle_checkpoints + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0173, bytearray([0xA0, 0x5E])) # ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0175, bytearray([0x5A])) # phy + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0176, bytearray([0x20, 0x80, 0xA3])) # jsr get_translevel_bit + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0179, bytearray([0xDA])) # phx + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x017A, bytearray([0xBB])) # tyx + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x017B, bytearray([0xBF, 0x00, 0xA0, 0x7F])) # lda !bonus_block_flags,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x017F, bytearray([0xFA])) # plx + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0180, bytearray([0x7A])) # ply + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0181, bytearray([0x3F, 0xA6, 0xA8, 0x0D])) # and.l $0DA8A6,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0185, bytearray([0xF0, 0x02])) # beq .write + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0187, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0189, bytearray([0x98])) # .write tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x018A, bytearray([0x87, 0x06])) # sta [$06] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x018C, bytearray([0xA9, 0x01])) # lda #$01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x018E, bytearray([0x87, 0x00])) # sta [$00] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0190, bytearray([0xA9, 0x4E])) # lda #$4E + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0192, bytearray([0x87, 0x03])) # sta [$03] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0194, bytearray([0x20, 0xC0, 0xA3])) # jsr update_flag_pointers + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0197, bytearray([0xAF, 0xA9, 0xBF, 0x03])) # handle_checkpoints: lda.l checkpoints_enabled_flag + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x019B, bytearray([0xF0, 0x2A])) # beq handle_moons + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x019D, bytearray([0xA6, 0x60])) # ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x019F, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01A3, bytearray([0x29, 0x10])) # and #$10 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01A5, bytearray([0xF0, 0x20])) # beq handle_moons + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01A7, bytearray([0xA0, 0x5E])) # ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01A9, bytearray([0x5A])) # phy + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01AA, bytearray([0x20, 0x80, 0xA3])) # jsr get_translevel_bit + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01AD, bytearray([0xB9, 0x3C, 0x1F])) # lda !checkpoints_flags,y + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01B0, bytearray([0x7A])) # ply + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01B1, bytearray([0x3F, 0xA6, 0xA8, 0x0D])) # and.l $0DA8A6,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01B5, bytearray([0xF0, 0x02])) # beq .write + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01B7, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01B9, bytearray([0x98])) # .write tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01BA, bytearray([0x87, 0x06])) # sta [$06] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01BC, bytearray([0xA9, 0x07])) # lda #$07 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01BE, bytearray([0x87, 0x00])) # sta [$00] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01C0, bytearray([0xA9, 0x48])) # lda #$48 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01C2, bytearray([0x87, 0x03])) # sta [$03] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01C4, bytearray([0x20, 0xC0, 0xA3])) # jsr update_flag_pointers + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01C7, bytearray([0xAF, 0xA8, 0xBF, 0x03])) # handle_moons: lda.l moon_enabled_flag + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01CB, bytearray([0xF0, 0x2A])) # beq handle_dragon_coins + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01CD, bytearray([0xA6, 0x60])) # ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01CF, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01D3, bytearray([0x29, 0x08])) # and #$08 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01D5, bytearray([0xF0, 0x20])) # beq handle_dragon_coins + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01D7, bytearray([0xA0, 0x5E])) # ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01D9, bytearray([0x5A])) # phy + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01DA, bytearray([0x20, 0x80, 0xA3])) # jsr get_translevel_bit + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01DD, bytearray([0xB9, 0xEE, 0x1F])) # lda !moons_flags,y + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01E0, bytearray([0x7A])) # ply + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01E1, bytearray([0x3F, 0xA6, 0xA8, 0x0D])) # and.l $0DA8A6,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01E5, bytearray([0xF0, 0x02])) # beq .write + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01E7, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01E9, bytearray([0x98])) # .write tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01EA, bytearray([0x87, 0x06])) # sta [$06] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01EC, bytearray([0xA9, 0x0C])) # lda #$0C + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01EE, bytearray([0x87, 0x00])) # sta [$00] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01F0, bytearray([0xA9, 0x4E])) # lda #$4E + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01F2, bytearray([0x87, 0x03])) # sta [$03] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01F4, bytearray([0x20, 0xC0, 0xA3])) # jsr update_flag_pointers + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01F7, bytearray([0xAF, 0xA6, 0xBF, 0x03])) # handle_dragon_coins: lda.l dragon_coin_enabled_flag + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01FB, bytearray([0xF0, 0x2A])) # beq handle_exit_2 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01FD, bytearray([0xA6, 0x60])) # ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x01FF, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0203, bytearray([0x29, 0x04])) # and #$04 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0205, bytearray([0xF0, 0x20])) # beq handle_exit_2 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0207, bytearray([0xA0, 0x5E])) # ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0209, bytearray([0x5A])) # phy + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x020A, bytearray([0x20, 0x80, 0xA3])) # jsr get_translevel_bit + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x020D, bytearray([0xB9, 0x2F, 0x1F])) # lda !yoshi_coins_flags,y + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0210, bytearray([0x7A])) # ply + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0211, bytearray([0x3F, 0xA6, 0xA8, 0x0D])) # and.l $0DA8A6,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0215, bytearray([0xF0, 0x02])) # beq .write + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0217, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0219, bytearray([0x98])) # .write tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x021A, bytearray([0x87, 0x06])) # sta [$06] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x021C, bytearray([0xA9, 0x03])) # lda #$03 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x021E, bytearray([0x87, 0x00])) # sta [$00] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0220, bytearray([0xA9, 0x02])) # lda #$02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0222, bytearray([0x87, 0x03])) # sta [$03] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0224, bytearray([0x20, 0xC0, 0xA3])) # jsr update_flag_pointers + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0227, bytearray([0xA6, 0x60])) # handle_exit_2: ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0229, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x022D, bytearray([0x29, 0x02])) # and #$02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x022F, bytearray([0xF0, 0x1A])) # beq handle_exit_1 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0231, bytearray([0xA0, 0x5E])) # ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0233, bytearray([0xBF, 0x00, 0xA2, 0x7F])) # lda !level_clears,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0237, bytearray([0x29, 0x02])) # and #$02 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0239, bytearray([0xF0, 0x02])) # beq .write + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x023B, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x023D, bytearray([0x98])) # .write tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x023E, bytearray([0x87, 0x06])) # sta [$06] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0240, bytearray([0xA9, 0x04])) # lda #$04 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0242, bytearray([0x87, 0x00])) # sta [$00] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0244, bytearray([0xA9, 0x24])) # lda #$24 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0246, bytearray([0x87, 0x03])) # sta [$03] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0248, bytearray([0x20, 0xC0, 0xA3])) # jsr update_flag_pointers + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x024B, bytearray([0xA6, 0x60])) # handle_exit_1: ldx $60 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x024D, bytearray([0xBF, 0x00, 0xF4, 0x0F])) # lda.l level_data,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0251, bytearray([0x29, 0x01])) # and #$01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0253, bytearray([0xF0, 0x1A])) # beq .dont_draw + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0255, bytearray([0xA0, 0x5E])) # ldy.b #!icon_not_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0257, bytearray([0xBF, 0x00, 0xA2, 0x7F])) # lda !level_clears,x + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x025B, bytearray([0x29, 0x01])) # and #$01 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x025D, bytearray([0xF0, 0x02])) # beq .write + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x025F, bytearray([0xA0, 0x3F])) # ldy.b #!icon_obtained + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0261, bytearray([0x98])) # .write tya + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0262, bytearray([0x87, 0x06])) # sta [$06] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0264, bytearray([0xA9, 0x04])) # lda #$04 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0266, bytearray([0x87, 0x00])) # sta [$00] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x0268, bytearray([0xA9, 0x23])) # lda #$23 + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x026A, bytearray([0x87, 0x03])) # sta [$03] + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x026C, bytearray([0x20, 0xC0, 0xA3])) # jsr update_flag_pointers + rom.write_bytes(BUILD_TILEMAP_ADDR + 0x026F, bytearray([0x6B])) # .dont_draw rtl + + LEVEL_INDICATOR_DATA_ADDR = 0x7F400 + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0000, bytearray([0x80,0x45,0x45,0x80,0x43,0x65,0x5D,0x51])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0008, bytearray([0x01,0x47,0x47,0x51,0x65,0x45,0x41,0x4F])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0010, bytearray([0x55,0x45,0x80,0x43,0x01,0x57,0x80,0x80])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0018, bytearray([0x45,0x80,0x51,0x41,0x45,0x45,0x80,0x41])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0020, bytearray([0x45,0x41,0x4D,0x67,0x57,0x41,0x55,0x65])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0028, bytearray([0x80,0x4D,0x45,0x55,0x80,0x47,0x4D,0x45])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0030, bytearray([0x80,0x80,0x80,0x43,0x55,0x41,0x80,0x45])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0038, bytearray([0x47,0x57,0x4D,0x41,0x47,0x55,0x47,0x01])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0040, bytearray([0x41,0x4F,0x43,0x47,0x47,0x01,0x45,0x57])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0048, bytearray([0x80,0x45,0x45,0x45,0x45,0x80,0x55,0x45])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0050, bytearray([0x45,0x45,0x80,0x80,0x43,0x80,0x43,0x80])) + rom.write_bytes(LEVEL_INDICATOR_DATA_ADDR + 0x0058, bytearray([0x07,0x43,0x43,0x80,0x80,0x80,0x80,0x80])) + + +def handle_indicators(rom): + INDICATOR_QUEUE_CODE = 0x86000 + rom.write_bytes(0x022E6, bytearray([0x22, 0x00, 0xE0, 0x10])) # org $00A2E6 : jsl gm14_hijack + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0000, bytearray([0xAD, 0x00, 0x01])) # gm14_hijack: lda $0100 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0003, bytearray([0xC9, 0x14])) # cmp #$14 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0005, bytearray([0xD0, 0x04])) # bne .invalid + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0007, bytearray([0xA5, 0x71])) # lda $71 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0009, bytearray([0xF0, 0x04])) # beq .valid + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x000B, bytearray([0x5C, 0xB1, 0x8A, 0x02])) # .invalid jml $028AB1 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x000F, bytearray([0xC2, 0x30])) # .valid rep #$30 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0011, bytearray([0xAF, 0x04, 0xB0, 0x7F])) # lda !score_sprite_add_1_coin + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0015, bytearray([0xF0, 0x03])) # beq .no_1_coin + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0017, bytearray([0x20, 0xC1, 0xE0])) # jsr add_1_coin + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x001A, bytearray([0xAF, 0x06, 0xB0, 0x7F])) # .no_1_coin lda !score_sprite_add_5_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x001E, bytearray([0xF0, 0x03])) # beq .no_5_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0020, bytearray([0x20, 0xDF, 0xE0])) # jsr add_5_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0023, bytearray([0xAF, 0x08, 0xB0, 0x7F])) # .no_5_coins lda !score_sprite_add_10_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0027, bytearray([0xF0, 0x03])) # beq .no_10_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0029, bytearray([0x20, 0xFD, 0xE0])) # jsr add_10_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x002C, bytearray([0xAF, 0x0A, 0xB0, 0x7F])) # .no_10_coins lda !score_sprite_add_15_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0030, bytearray([0xF0, 0x03])) # beq .no_15_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0032, bytearray([0x20, 0x1B, 0xE1])) # jsr add_15_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0035, bytearray([0xAF, 0x10, 0xB0, 0x7F])) # .no_15_coins lda !score_sprite_add_1up + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0039, bytearray([0xF0, 0x03])) # beq .no_1up + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x003B, bytearray([0x20, 0x39, 0xE1])) # jsr add_1up + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x003E, bytearray([0xAF, 0x0C, 0xB0, 0x7F])) # .no_1up lda !score_sprite_add_yoshi_egg + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0042, bytearray([0xF0, 0x03])) # beq .no_yoshi_egg + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0044, bytearray([0x20, 0x57, 0xE1])) # jsr add_yoshi_egg + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0047, bytearray([0xAF, 0x0E, 0xB0, 0x7F])) # .no_yoshi_egg lda !score_sprite_add_boss_token + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x004B, bytearray([0xF0, 0x03])) # beq .no_boss_token + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x004D, bytearray([0x20, 0xCF, 0xE1])) # jsr add_boss_token + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0050, bytearray([0xE2, 0x30])) # .no_boss_token sep #$30 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0052, bytearray([0x20, 0xED, 0xE1])) # jsr goal_sanity_check + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0055, bytearray([0x20, 0x5C, 0xE0])) # jsr score_sprite_queue + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0058, bytearray([0x5C, 0xB1, 0x8A, 0x02])) # jml $028AB1 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x005C, bytearray([0xAF, 0x20, 0xB0, 0x7F])) # score_sprite_queue: lda !score_sprite_queue_delay + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0060, bytearray([0xF0, 0x06])) # beq .spawn + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0062, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0063, bytearray([0x8F, 0x20, 0xB0, 0x7F])) # sta !score_sprite_queue_delay + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0067, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0068, bytearray([0xA9, 0x08])) # .spawn lda #$08 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x006A, bytearray([0x8F, 0x20, 0xB0, 0x7F])) # sta !score_sprite_queue_delay + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x006E, bytearray([0xC2, 0x30])) # rep #$30 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0070, bytearray([0xAF, 0x02, 0xB0, 0x7F])) # lda !score_sprite_index + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0074, bytearray([0xCF, 0x00, 0xB0, 0x7F])) # cmp !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0078, bytearray([0xD0, 0x03])) # bne .check_slots + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x007A, bytearray([0xE2, 0x30])) # sep #$30 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x007C, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x007D, bytearray([0xA0, 0x05, 0x00])) # .check_slots ldy #$0005 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0080, bytearray([0xB9, 0xE1, 0x16])) # ..loop lda !score_sprite_num,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0083, bytearray([0x29, 0xFF, 0x00])) # and #$00FF + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0086, bytearray([0xF0, 0x06])) # beq .found_free + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0088, bytearray([0x88])) # dey + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0089, bytearray([0x10, 0xF5])) # bpl ..loop + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x008B, bytearray([0xE2, 0x30])) # sep #$30 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x008D, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x008E, bytearray([0xAF, 0x02, 0xB0, 0x7F])) # .found_free lda !score_sprite_index + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0092, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0093, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0094, bytearray([0x8F, 0x02, 0xB0, 0x7F])) # sta !score_sprite_index + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0098, bytearray([0xBF, 0x22, 0xB0, 0x7F])) # lda !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x009C, bytearray([0xE2, 0x30])) # sep #$30 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x009E, bytearray([0x99, 0xE1, 0x16])) # sta !score_sprite_num,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00A1, bytearray([0xA5, 0x94])) # lda $94 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00A3, bytearray([0x99, 0xED, 0x16])) # sta !score_sprite_x_lo,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00A6, bytearray([0xA5, 0x95])) # lda $95 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00A8, bytearray([0x99, 0xF3, 0x16])) # sta !score_sprite_x_hi,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00AB, bytearray([0xA5, 0x96])) # lda $96 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00AD, bytearray([0x99, 0xE7, 0x16])) # sta !score_sprite_y_lo,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00B0, bytearray([0xA5, 0x97])) # lda $97 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00B2, bytearray([0x99, 0xF9, 0x16])) # sta !score_sprite_y_hi,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00B5, bytearray([0xA9, 0x30])) # lda #$30 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00B7, bytearray([0x99, 0xFF, 0x16])) # sta !score_sprite_timer,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00BA, bytearray([0xAD, 0xF9, 0x13])) # lda $13F9 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00BD, bytearray([0x99, 0x05, 0x17])) # sta !score_sprite_layer,y + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00C0, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00C1, bytearray([0xAF, 0x04, 0xB0, 0x7F])) # add_1_coin: lda !score_sprite_add_1_coin + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00C5, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00C6, bytearray([0x8F, 0x04, 0xB0, 0x7F])) # sta !score_sprite_add_1_coin + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00CA, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00CE, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00CF, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00D3, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00D4, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00D6, bytearray([0xA9, 0x11])) # lda #$11 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00D8, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00DC, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00DE, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00DF, bytearray([0xAF, 0x06, 0xB0, 0x7F])) # add_5_coins: lda !score_sprite_add_5_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00E3, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00E4, bytearray([0x8F, 0x06, 0xB0, 0x7F])) # sta !score_sprite_add_5_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00E8, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00EC, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00ED, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00F1, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00F2, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00F4, bytearray([0xA9, 0x12])) # lda #$12 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00F6, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00FA, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00FC, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x00FD, bytearray([0xAF, 0x08, 0xB0, 0x7F])) # add_10_coins: lda !score_sprite_add_10_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0101, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0102, bytearray([0x8F, 0x08, 0xB0, 0x7F])) # sta !score_sprite_add_10_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0106, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x010A, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x010B, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x010F, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0110, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0112, bytearray([0xA9, 0x13])) # lda #$13 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0114, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0118, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x011A, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x011B, bytearray([0xAF, 0x0A, 0xB0, 0x7F])) # add_15_coins: lda !score_sprite_add_15_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x011F, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0120, bytearray([0x8F, 0x0A, 0xB0, 0x7F])) # sta !score_sprite_add_15_coins + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0124, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0128, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0129, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x012D, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x012E, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0130, bytearray([0xA9, 0x14])) # lda #$14 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0132, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0136, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0138, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0139, bytearray([0xAF, 0x10, 0xB0, 0x7F])) # add_1up: lda !score_sprite_add_1up + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x013D, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x013E, bytearray([0x8F, 0x10, 0xB0, 0x7F])) # sta !score_sprite_add_1up + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0142, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0146, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0147, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x014B, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x014C, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x014E, bytearray([0xA9, 0x16])) # lda #$16 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0150, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0154, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0156, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0157, bytearray([0xAF, 0x0C, 0xB0, 0x7F])) # add_yoshi_egg: lda !score_sprite_add_yoshi_egg + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x015B, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x015C, bytearray([0x8F, 0x0C, 0xB0, 0x7F])) # sta !score_sprite_add_yoshi_egg + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0160, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0164, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0165, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0169, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x016A, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x016C, bytearray([0xA9, 0x15])) # lda #$15 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x016E, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0172, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0174, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0175, bytearray([0xAF, 0x12, 0xB0, 0x7F])) # add_mushroom: lda !score_sprite_add_mushroom + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0179, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x017A, bytearray([0x8F, 0x12, 0xB0, 0x7F])) # sta !score_sprite_add_mushroom + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x017E, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0182, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0183, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0187, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0188, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x018A, bytearray([0xA9, 0x17])) # lda #$17 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x018C, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0190, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0192, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0193, bytearray([0xAF, 0x14, 0xB0, 0x7F])) # add_flower: lda !score_sprite_add_flower + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0197, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0198, bytearray([0x8F, 0x14, 0xB0, 0x7F])) # sta !score_sprite_add_flower + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x019C, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01A0, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01A1, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01A5, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01A6, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01A8, bytearray([0xA9, 0x18])) # lda #$18 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01AA, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01AE, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01B0, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01B1, bytearray([0xAF, 0x16, 0xB0, 0x7F])) # add_feather: lda !score_sprite_add_feather + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01B5, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01B6, bytearray([0x8F, 0x16, 0xB0, 0x7F])) # sta !score_sprite_add_feather + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01BA, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01BE, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01BF, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01C3, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01C4, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01C6, bytearray([0xA9, 0x19])) # lda #$19 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01C8, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01CC, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01CE, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01CF, bytearray([0xAF, 0x0E, 0xB0, 0x7F])) # add_boss_token: lda !score_sprite_add_boss_token + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01D3, bytearray([0x3A])) # dec + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01D4, bytearray([0x8F, 0x0E, 0xB0, 0x7F])) # sta !score_sprite_add_boss_token + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01D8, bytearray([0xAF, 0x00, 0xB0, 0x7F])) # lda !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01DC, bytearray([0x1A])) # inc + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01DD, bytearray([0x8F, 0x00, 0xB0, 0x7F])) # sta !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01E1, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01E2, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01E4, bytearray([0xA9, 0x1A])) # lda #$1A + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01E6, bytearray([0x9F, 0x22, 0xB0, 0x7F])) # sta !score_sprite_queue,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01EA, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01EC, bytearray([0x60])) # rts + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01ED, bytearray([0xAF, 0xA0, 0xBF, 0x03])) # goal_sanity_check: lda $03BFA0 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01F1, bytearray([0x29, 0x01])) # and #$01 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01F3, bytearray([0x49, 0x01])) # eor #$01 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01F5, bytearray([0x0A])) # asl + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01F6, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01F8, bytearray([0xBF, 0x0C, 0xB0, 0x7F])) # lda !score_sprite_add_yoshi_egg,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01FC, bytearray([0xD0, 0x18])) # bne .return + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x01FE, bytearray([0xAF, 0x02, 0xB0, 0x7F])) # .check_queue lda !score_sprite_index + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0202, bytearray([0xCF, 0x00, 0xB0, 0x7F])) # cmp !score_sprite_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0206, bytearray([0xD0, 0x0E])) # bne .return + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0208, bytearray([0xE2, 0x20])) # .check_count sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x020A, bytearray([0xAF, 0x1E, 0xA0, 0x7F])) # lda !goal_item_count + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x020E, bytearray([0xDD, 0x24, 0x1F])) # cmp $1F24,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0211, bytearray([0xF0, 0x03])) # beq .return + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0213, bytearray([0x9D, 0x24, 0x1F])) # sta $1F24,x + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0216, bytearray([0xE2, 0x20])) # .return sep #$20 + rom.write_bytes(INDICATOR_QUEUE_CODE + 0x0218, bytearray([0x60])) # rts + + # Add code for indicators when receiving items during levels + INDICATOR_CODE = 0x84000 + rom.write_bytes(0x12DBA, bytearray([0x5C, 0x00, 0xC0, 0x10])) # org $02ADBA : jsl score_sprites + rom.write_bytes(INDICATOR_CODE + 0x0000, bytearray([0xBD, 0xE1, 0x16])) # score_sprites: lda !score_sprite_num,x + rom.write_bytes(INDICATOR_CODE + 0x0003, bytearray([0xF0, 0x2D])) # beq .return + rom.write_bytes(INDICATOR_CODE + 0x0005, bytearray([0x8E, 0xE9, 0x15])) # stx $15E9 + rom.write_bytes(INDICATOR_CODE + 0x0008, bytearray([0xC2, 0x30])) # rep #$30 + rom.write_bytes(INDICATOR_CODE + 0x000A, bytearray([0x29, 0x1F, 0x00])) # and #$001F + rom.write_bytes(INDICATOR_CODE + 0x000D, bytearray([0x85, 0x00])) # sta $00 + rom.write_bytes(INDICATOR_CODE + 0x000F, bytearray([0x0A])) # asl + rom.write_bytes(INDICATOR_CODE + 0x0010, bytearray([0x18])) # clc + rom.write_bytes(INDICATOR_CODE + 0x0011, bytearray([0x65, 0x00])) # adc $00 + rom.write_bytes(INDICATOR_CODE + 0x0013, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_CODE + 0x0014, bytearray([0xBF, 0x37, 0xC0, 0x10])) # lda.l .pointers-3,x + rom.write_bytes(INDICATOR_CODE + 0x0018, bytearray([0x85, 0x00])) # sta $00 + rom.write_bytes(INDICATOR_CODE + 0x001A, bytearray([0xE2, 0x30])) # sep #$30 + rom.write_bytes(INDICATOR_CODE + 0x001C, bytearray([0xBF, 0x39, 0xC0, 0x10])) # lda.l .pointers-3+2,x + rom.write_bytes(INDICATOR_CODE + 0x0020, bytearray([0x85, 0x02])) # sta $02 + rom.write_bytes(INDICATOR_CODE + 0x0022, bytearray([0xE2, 0x10])) # sep #$10 + rom.write_bytes(INDICATOR_CODE + 0x0024, bytearray([0xAE, 0xE9, 0x15])) # ldx $15E9 + rom.write_bytes(INDICATOR_CODE + 0x0027, bytearray([0x8B])) # phb + rom.write_bytes(INDICATOR_CODE + 0x0028, bytearray([0x48])) # pha + rom.write_bytes(INDICATOR_CODE + 0x0029, bytearray([0xAB])) # plb + rom.write_bytes(INDICATOR_CODE + 0x002A, bytearray([0x4B])) # phk + rom.write_bytes(INDICATOR_CODE + 0x002B, bytearray([0xF4, 0x30, 0xC0])) # pea.w .return_code-1 + rom.write_bytes(INDICATOR_CODE + 0x002E, bytearray([0xDC, 0x00, 0x00])) # jml [$0000] + rom.write_bytes(INDICATOR_CODE + 0x0031, bytearray([0xAB])) # .return_code plb + rom.write_bytes(INDICATOR_CODE + 0x0032, bytearray([0x5C, 0xC5, 0xAD, 0x02])) # .return jml $02ADC5 + rom.write_bytes(INDICATOR_CODE + 0x0036, bytearray([0x9E, 0xE1, 0x16])) # .kill stz !score_sprite_num,x + rom.write_bytes(INDICATOR_CODE + 0x0039, bytearray([0x6B])) # rtl + rom.write_bytes(INDICATOR_CODE + 0x003A, bytearray([0x97, 0xC0, 0x10])) # .pointers dl original_score_sprites ; 01 - 10 points + rom.write_bytes(INDICATOR_CODE + 0x003D, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 02 - 20 points + rom.write_bytes(INDICATOR_CODE + 0x0040, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 03 - 40 points + rom.write_bytes(INDICATOR_CODE + 0x0043, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 04 - 80 points + rom.write_bytes(INDICATOR_CODE + 0x0046, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 05 - 100 points + rom.write_bytes(INDICATOR_CODE + 0x0049, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 06 - 200 points + rom.write_bytes(INDICATOR_CODE + 0x004C, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 07 - 400 points + rom.write_bytes(INDICATOR_CODE + 0x004F, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 08 - 800 points + rom.write_bytes(INDICATOR_CODE + 0x0052, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 09 - 1000 points + rom.write_bytes(INDICATOR_CODE + 0x0055, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 0A - 2000 points + rom.write_bytes(INDICATOR_CODE + 0x0058, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 0B - 4000 points + rom.write_bytes(INDICATOR_CODE + 0x005B, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 0C - 8000 points + rom.write_bytes(INDICATOR_CODE + 0x005E, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 0D - 1-up + rom.write_bytes(INDICATOR_CODE + 0x0061, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 0E - 2-up + rom.write_bytes(INDICATOR_CODE + 0x0064, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 0F - 3-up + rom.write_bytes(INDICATOR_CODE + 0x0067, bytearray([0x97, 0xC0, 0x10])) # dl original_score_sprites ; 10 - 5-up + rom.write_bytes(INDICATOR_CODE + 0x006A, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 11 - 1 coin + rom.write_bytes(INDICATOR_CODE + 0x006D, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 12 - 5 coins + rom.write_bytes(INDICATOR_CODE + 0x0070, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 13 - 10 coins + rom.write_bytes(INDICATOR_CODE + 0x0073, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 14 - 15 coins + rom.write_bytes(INDICATOR_CODE + 0x0076, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 15 - Yoshi Egg + rom.write_bytes(INDICATOR_CODE + 0x0079, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 16 - 1up Mushroom + rom.write_bytes(INDICATOR_CODE + 0x007C, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 17 - Mushroom + rom.write_bytes(INDICATOR_CODE + 0x007F, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 18 - Flower + rom.write_bytes(INDICATOR_CODE + 0x0082, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 19 - Feather + rom.write_bytes(INDICATOR_CODE + 0x0085, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 1A - Boss token + rom.write_bytes(INDICATOR_CODE + 0x0088, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 1B - + rom.write_bytes(INDICATOR_CODE + 0x008B, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 1C - + rom.write_bytes(INDICATOR_CODE + 0x008E, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 1D - + rom.write_bytes(INDICATOR_CODE + 0x0091, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 1E - + rom.write_bytes(INDICATOR_CODE + 0x0094, bytearray([0xA7, 0xC0, 0x10])) # dl icon_score ; 1F - + rom.write_bytes(INDICATOR_CODE + 0x0097, bytearray([0xA9, 0x02])) # original_score_sprites: lda #$02 + rom.write_bytes(INDICATOR_CODE + 0x0099, bytearray([0x48])) # pha + rom.write_bytes(INDICATOR_CODE + 0x009A, bytearray([0xAB])) # plb + rom.write_bytes(INDICATOR_CODE + 0x009B, bytearray([0x4B])) # phk + rom.write_bytes(INDICATOR_CODE + 0x009C, bytearray([0xF4, 0xA5, 0xC0])) # pea.w .jslrtsreturn-1 + rom.write_bytes(INDICATOR_CODE + 0x009F, bytearray([0xF4, 0x88, 0xB8])) # pea.w $B889-1 + rom.write_bytes(INDICATOR_CODE + 0x00A2, bytearray([0x5C, 0xC9, 0xAD, 0x02])) # jml $02ADC9 + rom.write_bytes(INDICATOR_CODE + 0x00A6, bytearray([0x6B])) # .jslrtsreturn rtl + rom.write_bytes(INDICATOR_CODE + 0x00A7, bytearray([0xBD, 0xFF, 0x16])) # icon_score: lda !score_sprite_timer,x + rom.write_bytes(INDICATOR_CODE + 0x00AA, bytearray([0xD0, 0x04])) # bne .active + rom.write_bytes(INDICATOR_CODE + 0x00AC, bytearray([0x9E, 0xE1, 0x16])) # stz !score_sprite_num,x + rom.write_bytes(INDICATOR_CODE + 0x00AF, bytearray([0x6B])) # rtl + rom.write_bytes(INDICATOR_CODE + 0x00B0, bytearray([0xDE, 0xFF, 0x16])) # .active dec !score_sprite_timer,x + rom.write_bytes(INDICATOR_CODE + 0x00B3, bytearray([0xC9, 0x30])) # cmp #$30 + rom.write_bytes(INDICATOR_CODE + 0x00B5, bytearray([0xD0, 0x14])) # bne .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x00B7, bytearray([0xBD, 0xE1, 0x16])) # lda !score_sprite_num,x + rom.write_bytes(INDICATOR_CODE + 0x00BA, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x00BB, bytearray([0xE9, 0x11])) # sbc #$11 + rom.write_bytes(INDICATOR_CODE + 0x00BD, bytearray([0x0A])) # asl + rom.write_bytes(INDICATOR_CODE + 0x00BE, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x00BF, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_CODE + 0x00C1, bytearray([0xB9, 0x4B, 0xC2])) # lda .reward_ptrs,y + rom.write_bytes(INDICATOR_CODE + 0x00C4, bytearray([0x85, 0x00])) # sta $00 + rom.write_bytes(INDICATOR_CODE + 0x00C6, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_CODE + 0x00C8, bytearray([0x6C, 0x00, 0x00])) # jmp ($0000) + rom.write_bytes(INDICATOR_CODE + 0x00CB, bytearray([0xBD, 0xFF, 0x16])) # .handle_movement lda !score_sprite_timer,x + rom.write_bytes(INDICATOR_CODE + 0x00CE, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x00CF, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x00D0, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x00D1, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x00D2, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x00D3, bytearray([0xA5, 0x13])) # lda $13 + rom.write_bytes(INDICATOR_CODE + 0x00D5, bytearray([0x39, 0xF0, 0xC0])) # and .speed,y + rom.write_bytes(INDICATOR_CODE + 0x00D8, bytearray([0xD0, 0x14])) # bne ..skip_update + rom.write_bytes(INDICATOR_CODE + 0x00DA, bytearray([0xBD, 0xE7, 0x16])) # lda !score_sprite_y_lo,x + rom.write_bytes(INDICATOR_CODE + 0x00DD, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x00DE, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x00DF, bytearray([0xE5, 0x1C])) # sbc $1C + rom.write_bytes(INDICATOR_CODE + 0x00E1, bytearray([0xC9, 0x04])) # cmp #$04 + rom.write_bytes(INDICATOR_CODE + 0x00E3, bytearray([0x90, 0x09])) # bcc ..skip_update + rom.write_bytes(INDICATOR_CODE + 0x00E5, bytearray([0xDE, 0xE7, 0x16])) # dec !score_sprite_y_lo,x + rom.write_bytes(INDICATOR_CODE + 0x00E8, bytearray([0x98])) # tya + rom.write_bytes(INDICATOR_CODE + 0x00E9, bytearray([0xD0, 0x03])) # bne ..skip_update + rom.write_bytes(INDICATOR_CODE + 0x00EB, bytearray([0xDE, 0xF9, 0x16])) # dec !score_sprite_y_hi,x + rom.write_bytes(INDICATOR_CODE + 0x00EE, bytearray([0x80, 0x05])) # ..skip_update bra .gfx + rom.write_bytes(INDICATOR_CODE + 0x00F0, bytearray([0x03, 0x01, 0x00, 0x00])) # .speed db $03,$01,$00,$00 + rom.write_bytes(INDICATOR_CODE + 0x00F4, bytearray([0x6B])) # .return rtl + rom.write_bytes(INDICATOR_CODE + 0x00F5, bytearray([0xBD, 0x05, 0x17])) # .gfx lda !score_sprite_layer,x + rom.write_bytes(INDICATOR_CODE + 0x00F8, bytearray([0x0A])) # asl + rom.write_bytes(INDICATOR_CODE + 0x00F9, bytearray([0x0A])) # asl + rom.write_bytes(INDICATOR_CODE + 0x00FA, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x00FB, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_CODE + 0x00FD, bytearray([0xB9, 0x1C, 0x00])) # lda $001C,y + rom.write_bytes(INDICATOR_CODE + 0x0100, bytearray([0x85, 0x02])) # sta $02 + rom.write_bytes(INDICATOR_CODE + 0x0102, bytearray([0xB9, 0x1A, 0x00])) # lda $001A,y + rom.write_bytes(INDICATOR_CODE + 0x0105, bytearray([0x85, 0x04])) # sta $04 + rom.write_bytes(INDICATOR_CODE + 0x0107, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_CODE + 0x0109, bytearray([0xBD, 0xF3, 0x16])) # lda !score_sprite_x_hi,x + rom.write_bytes(INDICATOR_CODE + 0x010C, bytearray([0xEB])) # xba + rom.write_bytes(INDICATOR_CODE + 0x010D, bytearray([0xBD, 0xED, 0x16])) # lda !score_sprite_x_lo,x + rom.write_bytes(INDICATOR_CODE + 0x0110, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(INDICATOR_CODE + 0x0112, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x0113, bytearray([0xE5, 0x04])) # sbc $04 + rom.write_bytes(INDICATOR_CODE + 0x0115, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x0116, bytearray([0xE9, 0x06, 0x00])) # sbc #$0006 + rom.write_bytes(INDICATOR_CODE + 0x0119, bytearray([0xC9, 0xEA, 0x00])) # cmp #$00EA + rom.write_bytes(INDICATOR_CODE + 0x011C, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(INDICATOR_CODE + 0x011E, bytearray([0xB0, 0xD4])) # bcs .return + rom.write_bytes(INDICATOR_CODE + 0x0120, bytearray([0xBD, 0xE7, 0x16])) # lda !score_sprite_y_lo,x + rom.write_bytes(INDICATOR_CODE + 0x0123, bytearray([0xC5, 0x02])) # cmp $02 + rom.write_bytes(INDICATOR_CODE + 0x0125, bytearray([0xBD, 0xF9, 0x16])) # lda !score_sprite_y_hi,x + rom.write_bytes(INDICATOR_CODE + 0x0128, bytearray([0xE5, 0x03])) # sbc $03 + rom.write_bytes(INDICATOR_CODE + 0x012A, bytearray([0xD0, 0xC8])) # bne .return + rom.write_bytes(INDICATOR_CODE + 0x012C, bytearray([0xBF, 0x9E, 0xAD, 0x02])) # lda $02AD9E,x + rom.write_bytes(INDICATOR_CODE + 0x0130, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x0131, bytearray([0xBD, 0xE7, 0x16])) # lda !score_sprite_y_lo,x + rom.write_bytes(INDICATOR_CODE + 0x0134, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x0135, bytearray([0xE5, 0x02])) # sbc $02 + rom.write_bytes(INDICATOR_CODE + 0x0137, bytearray([0x99, 0x01, 0x02])) # sta $0201,y + rom.write_bytes(INDICATOR_CODE + 0x013A, bytearray([0x99, 0x05, 0x02])) # sta $0205,y + rom.write_bytes(INDICATOR_CODE + 0x013D, bytearray([0xBD, 0xED, 0x16])) # lda !score_sprite_x_lo,x + rom.write_bytes(INDICATOR_CODE + 0x0140, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x0141, bytearray([0xE5, 0x04])) # sbc $04 + rom.write_bytes(INDICATOR_CODE + 0x0143, bytearray([0x18])) # clc + rom.write_bytes(INDICATOR_CODE + 0x0144, bytearray([0x69, 0x09])) # adc #$09 + rom.write_bytes(INDICATOR_CODE + 0x0146, bytearray([0x99, 0x00, 0x02])) # sta $0200,y + rom.write_bytes(INDICATOR_CODE + 0x0149, bytearray([0x18])) # clc + rom.write_bytes(INDICATOR_CODE + 0x014A, bytearray([0x69, 0x05])) # adc #$05 + rom.write_bytes(INDICATOR_CODE + 0x014C, bytearray([0x99, 0x04, 0x02])) # sta $0204,y + rom.write_bytes(INDICATOR_CODE + 0x014F, bytearray([0xDA])) # phx + rom.write_bytes(INDICATOR_CODE + 0x0150, bytearray([0xBD, 0xE1, 0x16])) # lda !score_sprite_num,x + rom.write_bytes(INDICATOR_CODE + 0x0153, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x0154, bytearray([0xE9, 0x11])) # sbc #$11 + rom.write_bytes(INDICATOR_CODE + 0x0156, bytearray([0x0A])) # asl + rom.write_bytes(INDICATOR_CODE + 0x0157, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_CODE + 0x0158, bytearray([0xBD, 0x09, 0xC2])) # lda ..num_tile+$00,x + rom.write_bytes(INDICATOR_CODE + 0x015B, bytearray([0x99, 0x02, 0x02])) # sta $0202,y + rom.write_bytes(INDICATOR_CODE + 0x015E, bytearray([0xBD, 0x0A, 0xC2])) # lda ..num_tile+$01,x + rom.write_bytes(INDICATOR_CODE + 0x0161, bytearray([0x99, 0x06, 0x02])) # sta $0206,y + rom.write_bytes(INDICATOR_CODE + 0x0164, bytearray([0xBD, 0x27, 0xC2])) # lda ..num_props+$00,x + rom.write_bytes(INDICATOR_CODE + 0x0167, bytearray([0x99, 0x03, 0x02])) # sta $0203,y + rom.write_bytes(INDICATOR_CODE + 0x016A, bytearray([0xBD, 0x28, 0xC2])) # lda ..num_props+$01,x + rom.write_bytes(INDICATOR_CODE + 0x016D, bytearray([0x99, 0x07, 0x02])) # sta $0207,y + rom.write_bytes(INDICATOR_CODE + 0x0170, bytearray([0xFA])) # plx + rom.write_bytes(INDICATOR_CODE + 0x0171, bytearray([0x98])) # tya + rom.write_bytes(INDICATOR_CODE + 0x0172, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x0173, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x0174, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x0175, bytearray([0xA9, 0x00])) # lda #$00 + rom.write_bytes(INDICATOR_CODE + 0x0177, bytearray([0x99, 0x20, 0x04])) # sta $0420,y + rom.write_bytes(INDICATOR_CODE + 0x017A, bytearray([0x99, 0x21, 0x04])) # sta $0421,y + rom.write_bytes(INDICATOR_CODE + 0x017D, bytearray([0xBF, 0x45, 0xC2, 0x10])) # lda.l ..oam_2,x + rom.write_bytes(INDICATOR_CODE + 0x0181, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x0182, bytearray([0xBD, 0xE7, 0x16])) # lda !score_sprite_y_lo,x + rom.write_bytes(INDICATOR_CODE + 0x0185, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x0186, bytearray([0xE5, 0x02])) # sbc $02 + rom.write_bytes(INDICATOR_CODE + 0x0188, bytearray([0x99, 0x01, 0x02])) # sta $0201,y + rom.write_bytes(INDICATOR_CODE + 0x018B, bytearray([0x99, 0x05, 0x02])) # sta $0205,y + rom.write_bytes(INDICATOR_CODE + 0x018E, bytearray([0xBD, 0xED, 0x16])) # lda !score_sprite_x_lo,x + rom.write_bytes(INDICATOR_CODE + 0x0191, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x0192, bytearray([0xE5, 0x04])) # sbc $04 + rom.write_bytes(INDICATOR_CODE + 0x0194, bytearray([0xE9, 0x07])) # sbc #$07 + rom.write_bytes(INDICATOR_CODE + 0x0196, bytearray([0x99, 0x00, 0x02])) # sta $0200,y + rom.write_bytes(INDICATOR_CODE + 0x0199, bytearray([0x18])) # clc + rom.write_bytes(INDICATOR_CODE + 0x019A, bytearray([0x69, 0x08])) # adc #$08 + rom.write_bytes(INDICATOR_CODE + 0x019C, bytearray([0x99, 0x04, 0x02])) # sta $0204,y + rom.write_bytes(INDICATOR_CODE + 0x019F, bytearray([0xDA])) # phx + rom.write_bytes(INDICATOR_CODE + 0x01A0, bytearray([0xBD, 0xE1, 0x16])) # lda !score_sprite_num,x + rom.write_bytes(INDICATOR_CODE + 0x01A3, bytearray([0x38])) # sec + rom.write_bytes(INDICATOR_CODE + 0x01A4, bytearray([0xE9, 0x11])) # sbc #$11 + rom.write_bytes(INDICATOR_CODE + 0x01A6, bytearray([0xAA])) # tax + rom.write_bytes(INDICATOR_CODE + 0x01A7, bytearray([0xBD, 0xCD, 0xC1])) # lda ..icon_tile,x + rom.write_bytes(INDICATOR_CODE + 0x01AA, bytearray([0x99, 0x02, 0x02])) # sta $0202,y + rom.write_bytes(INDICATOR_CODE + 0x01AD, bytearray([0xBD, 0xDC, 0xC1])) # lda ..icon_props,x + rom.write_bytes(INDICATOR_CODE + 0x01B0, bytearray([0x99, 0x03, 0x02])) # sta $0203,y + rom.write_bytes(INDICATOR_CODE + 0x01B3, bytearray([0xBD, 0xFA, 0xC1])) # lda ..plus_props,x + rom.write_bytes(INDICATOR_CODE + 0x01B6, bytearray([0x99, 0x07, 0x02])) # sta $0207,y + rom.write_bytes(INDICATOR_CODE + 0x01B9, bytearray([0xBD, 0xEB, 0xC1])) # lda ..plus_tile,x + rom.write_bytes(INDICATOR_CODE + 0x01BC, bytearray([0x99, 0x06, 0x02])) # sta $0206,y + rom.write_bytes(INDICATOR_CODE + 0x01BF, bytearray([0xFA])) # plx + rom.write_bytes(INDICATOR_CODE + 0x01C0, bytearray([0x98])) # tya + rom.write_bytes(INDICATOR_CODE + 0x01C1, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x01C2, bytearray([0x4A])) # lsr + rom.write_bytes(INDICATOR_CODE + 0x01C3, bytearray([0xA8])) # tay + rom.write_bytes(INDICATOR_CODE + 0x01C4, bytearray([0xA9, 0x00])) # lda #$00 + rom.write_bytes(INDICATOR_CODE + 0x01C6, bytearray([0x99, 0x20, 0x04])) # sta $0420,y + rom.write_bytes(INDICATOR_CODE + 0x01C9, bytearray([0x99, 0x21, 0x04])) # sta $0421,y + rom.write_bytes(INDICATOR_CODE + 0x01CC, bytearray([0x6B])) # rtl + rom.write_bytes(INDICATOR_CODE + 0x01CD, bytearray([0x1B])) # ..icon_tile db $1B ; 1 coin + rom.write_bytes(INDICATOR_CODE + 0x01CE, bytearray([0x1B])) # db $1B ; 5 coins + rom.write_bytes(INDICATOR_CODE + 0x01CF, bytearray([0x1B])) # db $1B ; 10 coins + rom.write_bytes(INDICATOR_CODE + 0x01D0, bytearray([0x1B])) # db $1B ; 15 coins + rom.write_bytes(INDICATOR_CODE + 0x01D1, bytearray([0x0A])) # db $0A ; yoshi egg + rom.write_bytes(INDICATOR_CODE + 0x01D2, bytearray([0x0B])) # db $0B ; 1up mushroom + rom.write_bytes(INDICATOR_CODE + 0x01D3, bytearray([0x0B])) # db $0B ; mushroom + rom.write_bytes(INDICATOR_CODE + 0x01D4, bytearray([0x7E])) # db $7E ; flower + rom.write_bytes(INDICATOR_CODE + 0x01D5, bytearray([0x7F])) # db $7F ; feather + rom.write_bytes(INDICATOR_CODE + 0x01D6, bytearray([0x38])) # db $38 ; boss token + rom.write_bytes(INDICATOR_CODE + 0x01D7, bytearray([0x5A])) # db $5A ; + rom.write_bytes(INDICATOR_CODE + 0x01D8, bytearray([0x5A])) # db $5A ; + rom.write_bytes(INDICATOR_CODE + 0x01D9, bytearray([0x5A])) # db $5A ; + rom.write_bytes(INDICATOR_CODE + 0x01DA, bytearray([0x5A])) # db $5A ; + rom.write_bytes(INDICATOR_CODE + 0x01DB, bytearray([0x0B])) # db $0B ; + rom.write_bytes(INDICATOR_CODE + 0x01DC, bytearray([0x34])) # ..icon_props db $34 ; coin + rom.write_bytes(INDICATOR_CODE + 0x01DD, bytearray([0x34])) # db $34 ; coin + rom.write_bytes(INDICATOR_CODE + 0x01DE, bytearray([0x34])) # db $34 ; coin + rom.write_bytes(INDICATOR_CODE + 0x01DF, bytearray([0x34])) # db $34 ; coin + rom.write_bytes(INDICATOR_CODE + 0x01E0, bytearray([0x3A])) # db $3A ; yoshi egg + rom.write_bytes(INDICATOR_CODE + 0x01E1, bytearray([0x3A])) # db $3A ; 1up mushroom + rom.write_bytes(INDICATOR_CODE + 0x01E2, bytearray([0x38])) # db $38 ; mushroom + rom.write_bytes(INDICATOR_CODE + 0x01E3, bytearray([0x3A])) # db $3A ; flower + rom.write_bytes(INDICATOR_CODE + 0x01E4, bytearray([0x34])) # db $34 ; feather + rom.write_bytes(INDICATOR_CODE + 0x01E5, bytearray([0x34])) # db $34 ; boss token + rom.write_bytes(INDICATOR_CODE + 0x01E6, bytearray([0x34])) # db $34 ; + rom.write_bytes(INDICATOR_CODE + 0x01E7, bytearray([0x3A])) # db $3A ; + rom.write_bytes(INDICATOR_CODE + 0x01E8, bytearray([0x38])) # db $38 ; + rom.write_bytes(INDICATOR_CODE + 0x01E9, bytearray([0x36])) # db $36 ; + rom.write_bytes(INDICATOR_CODE + 0x01EA, bytearray([0x36])) # db $36 ; + rom.write_bytes(INDICATOR_CODE + 0x01EB, bytearray([0x1A])) # ..plus_tile db $1A ; 1 coin + rom.write_bytes(INDICATOR_CODE + 0x01EC, bytearray([0x1A])) # db $1A ; 3 coins + rom.write_bytes(INDICATOR_CODE + 0x01ED, bytearray([0x1A])) # db $1A ; 5 coins + rom.write_bytes(INDICATOR_CODE + 0x01EE, bytearray([0x1A])) # db $1A ; 10 coins + rom.write_bytes(INDICATOR_CODE + 0x01EF, bytearray([0x1A])) # db $1A ; yoshi egg + rom.write_bytes(INDICATOR_CODE + 0x01F0, bytearray([0x1A])) # db $1A ; 1up mushroom + rom.write_bytes(INDICATOR_CODE + 0x01F1, bytearray([0x1A])) # db $1A ; mushroom + rom.write_bytes(INDICATOR_CODE + 0x01F2, bytearray([0x1A])) # db $1A ; flower + rom.write_bytes(INDICATOR_CODE + 0x01F3, bytearray([0x1A])) # db $1A ; feather + rom.write_bytes(INDICATOR_CODE + 0x01F4, bytearray([0x1A])) # db $1A ; boss token + rom.write_bytes(INDICATOR_CODE + 0x01F5, bytearray([0x1A])) # db $1A ; + rom.write_bytes(INDICATOR_CODE + 0x01F6, bytearray([0x1A])) # db $1A ; + rom.write_bytes(INDICATOR_CODE + 0x01F7, bytearray([0x1A])) # db $1A ; + rom.write_bytes(INDICATOR_CODE + 0x01F8, bytearray([0x1A])) # db $1A ; + rom.write_bytes(INDICATOR_CODE + 0x01F9, bytearray([0x1A])) # db $1A ; + rom.write_bytes(INDICATOR_CODE + 0x01FA, bytearray([0x32])) # ..plus_props db $32 ; 1 coin + rom.write_bytes(INDICATOR_CODE + 0x01FB, bytearray([0x32])) # db $32 ; 5 coins + rom.write_bytes(INDICATOR_CODE + 0x01FC, bytearray([0x32])) # db $32 ; 10 coins + rom.write_bytes(INDICATOR_CODE + 0x01FD, bytearray([0x32])) # db $32 ; 50 coins + rom.write_bytes(INDICATOR_CODE + 0x01FE, bytearray([0x32])) # db $32 ; yoshi egg + rom.write_bytes(INDICATOR_CODE + 0x01FF, bytearray([0x32])) # db $32 ; 1up mushroom + rom.write_bytes(INDICATOR_CODE + 0x0200, bytearray([0x32])) # db $32 ; mushroom + rom.write_bytes(INDICATOR_CODE + 0x0201, bytearray([0x32])) # db $32 ; flower + rom.write_bytes(INDICATOR_CODE + 0x0202, bytearray([0x32])) # db $32 ; feather + rom.write_bytes(INDICATOR_CODE + 0x0203, bytearray([0x32])) # db $32 ; boss token + rom.write_bytes(INDICATOR_CODE + 0x0204, bytearray([0x32])) # db $32 ; + rom.write_bytes(INDICATOR_CODE + 0x0205, bytearray([0x32])) # db $32 ; + rom.write_bytes(INDICATOR_CODE + 0x0206, bytearray([0x32])) # db $32 ; + rom.write_bytes(INDICATOR_CODE + 0x0207, bytearray([0x32])) # db $32 ; + rom.write_bytes(INDICATOR_CODE + 0x0208, bytearray([0x32])) # db $32 ; + rom.write_bytes(INDICATOR_CODE + 0x0209, bytearray([0x4B, 0x69])) # ..num_tile db $4B,$69 ; 1 coin + rom.write_bytes(INDICATOR_CODE + 0x020B, bytearray([0x5B, 0x69])) # db $5B,$69 ; 5 coins + rom.write_bytes(INDICATOR_CODE + 0x020D, bytearray([0x4B, 0x4A])) # db $4B,$4A ; 10 coins + rom.write_bytes(INDICATOR_CODE + 0x020F, bytearray([0x5B, 0x4A])) # db $4B,$5B ; 50 coins + rom.write_bytes(INDICATOR_CODE + 0x0211, bytearray([0x4B, 0x69])) # db $4B,$69 ; yoshi egg + rom.write_bytes(INDICATOR_CODE + 0x0213, bytearray([0x4B, 0x69])) # db $4B,$69 ; 1up mushroom + rom.write_bytes(INDICATOR_CODE + 0x0215, bytearray([0x4B, 0x69])) # db $4B,$69 ; mushroom + rom.write_bytes(INDICATOR_CODE + 0x0217, bytearray([0x4B, 0x69])) # db $4B,$69 ; flower + rom.write_bytes(INDICATOR_CODE + 0x0219, bytearray([0x4B, 0x69])) # db $4B,$69 ; feather + rom.write_bytes(INDICATOR_CODE + 0x021B, bytearray([0x4B, 0x69])) # db $4B,$69 ; boss token + rom.write_bytes(INDICATOR_CODE + 0x021D, bytearray([0x69, 0x69])) # db $69,$69 ; + rom.write_bytes(INDICATOR_CODE + 0x021F, bytearray([0x69, 0x69])) # db $69,$69 ; + rom.write_bytes(INDICATOR_CODE + 0x0221, bytearray([0x69, 0x69])) # db $69,$69 ; + rom.write_bytes(INDICATOR_CODE + 0x0223, bytearray([0x69, 0x69])) # db $69,$69 ; + rom.write_bytes(INDICATOR_CODE + 0x0225, bytearray([0x69, 0x69])) # db $69,$69 ; + rom.write_bytes(INDICATOR_CODE + 0x0227, bytearray([0x34, 0x34])) # ..num_props db $34,$34 ; 1 coin + rom.write_bytes(INDICATOR_CODE + 0x0229, bytearray([0x34, 0x34])) # db $34,$34 ; 5 coins + rom.write_bytes(INDICATOR_CODE + 0x022B, bytearray([0x34, 0x34])) # db $34,$34 ; 10 coins + rom.write_bytes(INDICATOR_CODE + 0x022D, bytearray([0x34, 0x34])) # db $34,$34 ; 50 coins + rom.write_bytes(INDICATOR_CODE + 0x022F, bytearray([0x34, 0x34])) # db $34,$34 ; yoshi egg + rom.write_bytes(INDICATOR_CODE + 0x0231, bytearray([0x34, 0x34])) # db $34,$34 ; 1up mushroom + rom.write_bytes(INDICATOR_CODE + 0x0233, bytearray([0x34, 0x34])) # db $34,$34 ; mushroom + rom.write_bytes(INDICATOR_CODE + 0x0235, bytearray([0x34, 0x34])) # db $34,$34 ; flower + rom.write_bytes(INDICATOR_CODE + 0x0237, bytearray([0x34, 0x34])) # db $34,$34 ; feather + rom.write_bytes(INDICATOR_CODE + 0x0239, bytearray([0x34, 0x34])) # db $34,$34 ; boss token + rom.write_bytes(INDICATOR_CODE + 0x023B, bytearray([0x34, 0x34])) # db $34,$34 ; + rom.write_bytes(INDICATOR_CODE + 0x023D, bytearray([0x34, 0x34])) # db $34,$34 ; + rom.write_bytes(INDICATOR_CODE + 0x023F, bytearray([0x34, 0x34])) # db $34,$34 ; + rom.write_bytes(INDICATOR_CODE + 0x0241, bytearray([0x34, 0x34])) # db $34,$34 ; + rom.write_bytes(INDICATOR_CODE + 0x0243, bytearray([0x34, 0x34])) # db $34,$34 ; + rom.write_bytes(INDICATOR_CODE + 0x0245, bytearray([0x50, 0x58, 0x60, 0x68, 0x70, 0x78]))# ..oam_2 db $50,$58,$60,$68,$70,$78 + rom.write_bytes(INDICATOR_CODE + 0x024B, bytearray([0x69, 0xC2])) # .reward_ptrs dw .one_coin + rom.write_bytes(INDICATOR_CODE + 0x024D, bytearray([0x6D, 0xC2])) # dw .five_coins + rom.write_bytes(INDICATOR_CODE + 0x024F, bytearray([0x71, 0xC2])) # dw .ten_coins + rom.write_bytes(INDICATOR_CODE + 0x0251, bytearray([0x75, 0xC2])) # dw .fifty_coins + rom.write_bytes(INDICATOR_CODE + 0x0253, bytearray([0x8A, 0xC2])) # dw .yoshi_egg + rom.write_bytes(INDICATOR_CODE + 0x0255, bytearray([0xA7, 0xC2])) # dw .green_mushroom + rom.write_bytes(INDICATOR_CODE + 0x0257, bytearray([0xAD, 0xC2])) # dw .mushroom + rom.write_bytes(INDICATOR_CODE + 0x0259, bytearray([0xAF, 0xC2])) # dw .flower + rom.write_bytes(INDICATOR_CODE + 0x025B, bytearray([0xB1, 0xC2])) # dw .shared_item + rom.write_bytes(INDICATOR_CODE + 0x025D, bytearray([0x9C, 0xC2])) # dw .boss_token + rom.write_bytes(INDICATOR_CODE + 0x025F, bytearray([0xCB, 0xC0])) # dw .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x0261, bytearray([0xCB, 0xC0])) # dw .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x0263, bytearray([0xCB, 0xC0])) # dw .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x0265, bytearray([0xCB, 0xC0])) # dw .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x0267, bytearray([0xCB, 0xC0])) # dw .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x0269, bytearray([0xA9, 0x01])) # .one_coin lda #$01 + rom.write_bytes(INDICATOR_CODE + 0x026B, bytearray([0x80, 0x0A])) # bra .shared_coins + rom.write_bytes(INDICATOR_CODE + 0x026D, bytearray([0xA9, 0x05])) # .five_coins lda #$05 + rom.write_bytes(INDICATOR_CODE + 0x026F, bytearray([0x80, 0x06])) # bra .shared_coins + rom.write_bytes(INDICATOR_CODE + 0x0271, bytearray([0xA9, 0x0A])) # .ten_coins lda #$0A + rom.write_bytes(INDICATOR_CODE + 0x0273, bytearray([0x80, 0x02])) # bra .shared_coins + rom.write_bytes(INDICATOR_CODE + 0x0275, bytearray([0xA9, 0x32])) # .fifty_coins lda #$32 + rom.write_bytes(INDICATOR_CODE + 0x0277, bytearray([0x18])) # .shared_coins clc + rom.write_bytes(INDICATOR_CODE + 0x0278, bytearray([0x6D, 0xCC, 0x13])) # adc $13CC + rom.write_bytes(INDICATOR_CODE + 0x027B, bytearray([0x90, 0x02])) # bcc + + rom.write_bytes(INDICATOR_CODE + 0x027D, bytearray([0xA9, 0xFF])) # lda #$FF + rom.write_bytes(INDICATOR_CODE + 0x027F, bytearray([0x8D, 0xCC, 0x13])) # + sta $13CC + rom.write_bytes(INDICATOR_CODE + 0x0282, bytearray([0xA9, 0x01])) # lda #$01 + rom.write_bytes(INDICATOR_CODE + 0x0284, bytearray([0x8D, 0xFC, 0x1D])) # sta $1DFC + rom.write_bytes(INDICATOR_CODE + 0x0287, bytearray([0x4C, 0xCB, 0xC0])) # jmp .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x028A, bytearray([0xAD, 0x24, 0x1F])) # .yoshi_egg lda $1F24 + rom.write_bytes(INDICATOR_CODE + 0x028D, bytearray([0xC9, 0xFF])) # cmp #$FF + rom.write_bytes(INDICATOR_CODE + 0x028F, bytearray([0xF0, 0x03])) # beq ..nope + rom.write_bytes(INDICATOR_CODE + 0x0291, bytearray([0xEE, 0x24, 0x1F])) # inc $1F24 + rom.write_bytes(INDICATOR_CODE + 0x0294, bytearray([0xA9, 0x1F])) # ..nope lda #$1F + rom.write_bytes(INDICATOR_CODE + 0x0296, bytearray([0x8D, 0xFC, 0x1D])) # sta $1DFC + rom.write_bytes(INDICATOR_CODE + 0x0299, bytearray([0x4C, 0xCB, 0xC0])) # jmp .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x029C, bytearray([0xEE, 0x26, 0x1F])) # .boss_token inc $1F26 + rom.write_bytes(INDICATOR_CODE + 0x029F, bytearray([0xA9, 0x09])) # lda #$09 + rom.write_bytes(INDICATOR_CODE + 0x02A1, bytearray([0x8D, 0xFC, 0x1D])) # sta $1DFC + rom.write_bytes(INDICATOR_CODE + 0x02A4, bytearray([0x4C, 0xCB, 0xC0])) # jmp .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x02A7, bytearray([0xEE, 0xE4, 0x18])) # .green_mushroom inc $18E4 + rom.write_bytes(INDICATOR_CODE + 0x02AA, bytearray([0x4C, 0xCB, 0xC0])) # jmp .handle_movement + rom.write_bytes(INDICATOR_CODE + 0x02AD, bytearray([0x80, 0x02])) # .mushroom bra .shared_item + rom.write_bytes(INDICATOR_CODE + 0x02AF, bytearray([0x80, 0x00])) # .flower bra .shared_item + rom.write_bytes(INDICATOR_CODE + 0x02B1, bytearray([0xA9, 0x0B])) # .shared_item lda #$0B + rom.write_bytes(INDICATOR_CODE + 0x02B3, bytearray([0x8D, 0xFC, 0x1D])) # sta $1DFC + rom.write_bytes(INDICATOR_CODE + 0x02B6, bytearray([0x4C, 0xCB, 0xC0])) # jmp .handle_movement + +def handle_traps(rom): + TRAPS_CODE = 0x86C00 + rom.write_bytes(0x022D8, bytearray([0x22, 0x00, 0xEC, 0x10])) # org $00A2D8 : jsl score_sprites + rom.write_bytes(TRAPS_CODE + 0x0000, bytearray([0xAD, 0x00, 0x01])) # handle_traps: lda $0100 + rom.write_bytes(TRAPS_CODE + 0x0003, bytearray([0xC9, 0x14])) # cmp #$14 + rom.write_bytes(TRAPS_CODE + 0x0005, bytearray([0xD0, 0x04])) # bne .invalid + rom.write_bytes(TRAPS_CODE + 0x0007, bytearray([0xA5, 0x71])) # lda $71 + rom.write_bytes(TRAPS_CODE + 0x0009, bytearray([0xF0, 0x09])) # beq .valid + rom.write_bytes(TRAPS_CODE + 0x000B, bytearray([0xA9, 0xFF])) # .invalid lda #$FF + rom.write_bytes(TRAPS_CODE + 0x000D, bytearray([0x8D, 0x3C, 0x0F])) # sta !thwimp_index + rom.write_bytes(TRAPS_CODE + 0x0010, bytearray([0x5C, 0xBD, 0xE2, 0x00])) # jml $00E2BD + rom.write_bytes(TRAPS_CODE + 0x0014, bytearray([0xAD, 0xB4, 0x18])) # .valid lda !reverse_controls_trap + rom.write_bytes(TRAPS_CODE + 0x0017, bytearray([0xF0, 0x03])) # beq .no_reverse_controls + rom.write_bytes(TRAPS_CODE + 0x0019, bytearray([0x20, 0x2B, 0xEC])) # jsr reverse_controls_trap + rom.write_bytes(TRAPS_CODE + 0x001C, bytearray([0xAD, 0xB7, 0x18])) # .no_reverse_controls lda !thwimp_trap + rom.write_bytes(TRAPS_CODE + 0x001F, bytearray([0xF0, 0x03])) # beq .no_thwimp + rom.write_bytes(TRAPS_CODE + 0x0021, bytearray([0x20, 0x86, 0xEC])) # jsr spawn_thwimp + rom.write_bytes(TRAPS_CODE + 0x0024, bytearray([0x20, 0xCB, 0xEC])) # .no_thwimp jsr handle_thwimp + rom.write_bytes(TRAPS_CODE + 0x0027, bytearray([0x5C, 0xBD, 0xE2, 0x00])) # jml $00E2BD + rom.write_bytes(TRAPS_CODE + 0x002B, bytearray([0xA5, 0x15])) # reverse_controls_trap: lda $15 + rom.write_bytes(TRAPS_CODE + 0x002D, bytearray([0x89, 0x03])) # bit #$03 + rom.write_bytes(TRAPS_CODE + 0x002F, bytearray([0xF0, 0x04])) # beq ..no_swap_hold + rom.write_bytes(TRAPS_CODE + 0x0031, bytearray([0x49, 0x03])) # eor #$03 + rom.write_bytes(TRAPS_CODE + 0x0033, bytearray([0x85, 0x15])) # sta $15 + rom.write_bytes(TRAPS_CODE + 0x0035, bytearray([0xA5, 0x16])) # ..no_swap_hold lda $16 + rom.write_bytes(TRAPS_CODE + 0x0037, bytearray([0x89, 0x03])) # bit #$03 + rom.write_bytes(TRAPS_CODE + 0x0039, bytearray([0xF0, 0x04])) # beq ..no_swap_press + rom.write_bytes(TRAPS_CODE + 0x003B, bytearray([0x49, 0x03])) # eor #$03 + rom.write_bytes(TRAPS_CODE + 0x003D, bytearray([0x85, 0x16])) # sta $16 + rom.write_bytes(TRAPS_CODE + 0x003F, bytearray([0xA5, 0x15])) # .swap_up_and_down lda $15 + rom.write_bytes(TRAPS_CODE + 0x0041, bytearray([0x89, 0x0C])) # bit #$0C + rom.write_bytes(TRAPS_CODE + 0x0043, bytearray([0xF0, 0x04])) # beq .no_swap_hold + rom.write_bytes(TRAPS_CODE + 0x0045, bytearray([0x49, 0x0C])) # eor #$0C + rom.write_bytes(TRAPS_CODE + 0x0047, bytearray([0x85, 0x15])) # sta $15 + rom.write_bytes(TRAPS_CODE + 0x0049, bytearray([0xA5, 0x16])) # .no_swap_hold lda $16 + rom.write_bytes(TRAPS_CODE + 0x004B, bytearray([0x89, 0x0C])) # bit #$0C + rom.write_bytes(TRAPS_CODE + 0x004D, bytearray([0xF0, 0x04])) # beq ..no_swap_press + rom.write_bytes(TRAPS_CODE + 0x004F, bytearray([0x49, 0x0C])) # eor #$0C + rom.write_bytes(TRAPS_CODE + 0x0051, bytearray([0x85, 0x16])) # sta $16 + rom.write_bytes(TRAPS_CODE + 0x0053, bytearray([0xA5, 0x16])) # .swap_a_and_b lda $16 + rom.write_bytes(TRAPS_CODE + 0x0055, bytearray([0x10, 0x0C])) # bpl ..no_swap_b + rom.write_bytes(TRAPS_CODE + 0x0057, bytearray([0x49, 0x80])) # eor #$80 + rom.write_bytes(TRAPS_CODE + 0x0059, bytearray([0x85, 0x16])) # sta $16 + rom.write_bytes(TRAPS_CODE + 0x005B, bytearray([0xA5, 0x18])) # lda $18 + rom.write_bytes(TRAPS_CODE + 0x005D, bytearray([0x49, 0x80])) # eor #$80 + rom.write_bytes(TRAPS_CODE + 0x005F, bytearray([0x85, 0x18])) # sta $18 + rom.write_bytes(TRAPS_CODE + 0x0061, bytearray([0x80, 0x0E])) # bra .swap_l_and_r + rom.write_bytes(TRAPS_CODE + 0x0063, bytearray([0xA5, 0x18])) # ..no_swap_b lda $18 + rom.write_bytes(TRAPS_CODE + 0x0065, bytearray([0x10, 0x0A])) # bpl .swap_l_and_r + rom.write_bytes(TRAPS_CODE + 0x0067, bytearray([0x49, 0x80])) # eor #$80 + rom.write_bytes(TRAPS_CODE + 0x0069, bytearray([0x85, 0x18])) # sta $18 + rom.write_bytes(TRAPS_CODE + 0x006B, bytearray([0xA5, 0x16])) # lda $16 + rom.write_bytes(TRAPS_CODE + 0x006D, bytearray([0x49, 0x80])) # eor #$80 + rom.write_bytes(TRAPS_CODE + 0x006F, bytearray([0x85, 0x16])) # sta $16 + rom.write_bytes(TRAPS_CODE + 0x0071, bytearray([0xA5, 0x17])) # .swap_l_and_r lda $17 + rom.write_bytes(TRAPS_CODE + 0x0073, bytearray([0x89, 0x30])) # bit #$30 + rom.write_bytes(TRAPS_CODE + 0x0075, bytearray([0xF0, 0x04])) # beq ..no_swap_hold + rom.write_bytes(TRAPS_CODE + 0x0077, bytearray([0x49, 0x30])) # eor #$30 + rom.write_bytes(TRAPS_CODE + 0x0079, bytearray([0x85, 0x17])) # sta $17 + rom.write_bytes(TRAPS_CODE + 0x007B, bytearray([0xA5, 0x18])) # ..no_swap_hold lda $18 + rom.write_bytes(TRAPS_CODE + 0x007D, bytearray([0x89, 0x30])) # bit #$30 + rom.write_bytes(TRAPS_CODE + 0x007F, bytearray([0xF0, 0x04])) # beq ..no_swap_press + rom.write_bytes(TRAPS_CODE + 0x0081, bytearray([0x49, 0x30])) # eor #$30 + rom.write_bytes(TRAPS_CODE + 0x0083, bytearray([0x85, 0x18])) # sta $18 + rom.write_bytes(TRAPS_CODE + 0x0085, bytearray([0x60])) # ..no_swap_press rts + rom.write_bytes(TRAPS_CODE + 0x0086, bytearray([0xAE, 0x3C, 0x0F])) # spawn_thwimp: ldx !thwimp_index + rom.write_bytes(TRAPS_CODE + 0x0089, bytearray([0x10, 0x06])) # bpl .return + rom.write_bytes(TRAPS_CODE + 0x008B, bytearray([0x22, 0xE4, 0xA9, 0x02])) # jsl $02A9E4 + rom.write_bytes(TRAPS_CODE + 0x008F, bytearray([0x10, 0x01])) # bpl .found + rom.write_bytes(TRAPS_CODE + 0x0091, bytearray([0x60])) # .return rts + rom.write_bytes(TRAPS_CODE + 0x0092, bytearray([0xBB])) # .found tyx + rom.write_bytes(TRAPS_CODE + 0x0093, bytearray([0x9C, 0xB7, 0x18])) # stz !thwimp_trap + rom.write_bytes(TRAPS_CODE + 0x0096, bytearray([0xA9, 0x10])) # lda #$10 + rom.write_bytes(TRAPS_CODE + 0x0098, bytearray([0x8D, 0xF9, 0x1D])) # sta $1DF9 + rom.write_bytes(TRAPS_CODE + 0x009B, bytearray([0xA9, 0x27])) # lda #$27 + rom.write_bytes(TRAPS_CODE + 0x009D, bytearray([0x95, 0x9E])) # sta $9E,x + rom.write_bytes(TRAPS_CODE + 0x009F, bytearray([0xA9, 0x08])) # lda #$08 + rom.write_bytes(TRAPS_CODE + 0x00A1, bytearray([0x9D, 0xC8, 0x14])) # sta $14C8,x + rom.write_bytes(TRAPS_CODE + 0x00A4, bytearray([0x22, 0xD2, 0xF7, 0x07])) # jsl $07F7D2 + rom.write_bytes(TRAPS_CODE + 0x00A8, bytearray([0xA5, 0x94])) # lda $94 + rom.write_bytes(TRAPS_CODE + 0x00AA, bytearray([0x95, 0xE4])) # sta $E4,x + rom.write_bytes(TRAPS_CODE + 0x00AC, bytearray([0xA5, 0x95])) # lda $95 + rom.write_bytes(TRAPS_CODE + 0x00AE, bytearray([0x9D, 0xE0, 0x14])) # sta $14E0,x + rom.write_bytes(TRAPS_CODE + 0x00B1, bytearray([0xA5, 0x1C])) # lda $1C + rom.write_bytes(TRAPS_CODE + 0x00B3, bytearray([0x38])) # sec + rom.write_bytes(TRAPS_CODE + 0x00B4, bytearray([0xE9, 0x0F])) # sbc #$0F + rom.write_bytes(TRAPS_CODE + 0x00B6, bytearray([0x95, 0xD8])) # sta $D8,x + rom.write_bytes(TRAPS_CODE + 0x00B8, bytearray([0xA5, 0x1D])) # lda $1D + rom.write_bytes(TRAPS_CODE + 0x00BA, bytearray([0xE9, 0x00])) # sbc #$00 + rom.write_bytes(TRAPS_CODE + 0x00BC, bytearray([0x9D, 0xD4, 0x14])) # sta $14D4,x + rom.write_bytes(TRAPS_CODE + 0x00BF, bytearray([0xBD, 0x86, 0x16])) # lda $1686,x + rom.write_bytes(TRAPS_CODE + 0x00C2, bytearray([0x09, 0x80])) # ora #$80 + rom.write_bytes(TRAPS_CODE + 0x00C4, bytearray([0x9D, 0x86, 0x16])) # sta $1686,x + rom.write_bytes(TRAPS_CODE + 0x00C7, bytearray([0x8E, 0x3C, 0x0F])) # stx !thwimp_index + rom.write_bytes(TRAPS_CODE + 0x00CA, bytearray([0x60])) # rts + rom.write_bytes(TRAPS_CODE + 0x00CB, bytearray([0xAE, 0x3C, 0x0F])) # handle_thwimp: ldx !thwimp_index + rom.write_bytes(TRAPS_CODE + 0x00CE, bytearray([0x30, 0x1C])) # bmi .return + rom.write_bytes(TRAPS_CODE + 0x00D0, bytearray([0xBD, 0xD4, 0x14])) # lda $14D4,x + rom.write_bytes(TRAPS_CODE + 0x00D3, bytearray([0xEB])) # xba + rom.write_bytes(TRAPS_CODE + 0x00D4, bytearray([0xB5, 0xD8])) # lda $D8,x + rom.write_bytes(TRAPS_CODE + 0x00D6, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(TRAPS_CODE + 0x00D8, bytearray([0x38])) # sec + rom.write_bytes(TRAPS_CODE + 0x00D9, bytearray([0xE5, 0x96])) # sbc $96 + rom.write_bytes(TRAPS_CODE + 0x00DB, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(TRAPS_CODE + 0x00DD, bytearray([0x30, 0x0D])) # bmi .return + rom.write_bytes(TRAPS_CODE + 0x00DF, bytearray([0xA9, 0xFF])) # lda #$FF + rom.write_bytes(TRAPS_CODE + 0x00E1, bytearray([0x8D, 0x3C, 0x0F])) # sta !thwimp_index + rom.write_bytes(TRAPS_CODE + 0x00E4, bytearray([0xBD, 0x86, 0x16])) # lda $1686,x + rom.write_bytes(TRAPS_CODE + 0x00E7, bytearray([0x29, 0x7F])) # and #$7F + rom.write_bytes(TRAPS_CODE + 0x00E9, bytearray([0x9D, 0x86, 0x16])) # sta $1686,x + rom.write_bytes(TRAPS_CODE + 0x00EC, bytearray([0x60])) # .return rts + + + +def read_graphics_file(filename): + return pkgutil.get_data(__name__, f"data/graphics/{filename}") + +def handle_uncompressed_player_gfx(rom): + # Decompresses and moves into a expanded region the player, yoshi and animated graphics + # This should make swapping the graphics a lot easier. + # Maybe I should look into making a 32x32 version at some point... + # It also moves some 8x8 tiles in GFX00, thus making some free space for indicators and other stuff + # in VRAM during gameplay, will come super handy later. + # + # FOR FUTURE REFERENCE + # Player graphics are now located at 0xE0000 + # Player auxiliary tiles are now located at 0xE6000 + # Yoshi graphics are now located at 0xE8800 + SMW_COMPRESSED_PLAYER_GFX = 0x40000 + SMW_COMPRESSED_ANIMATED_GFX = 0x43FC0 + SMW_COMPRESSED_GFX_00 = 0x459F9 + SMW_COMPRESSED_GFX_10 = 0x4EF1E + SMW_COMPRESSED_GFX_28 = 0x5C06C + compressed_player_gfx = rom.read_bytes(SMW_COMPRESSED_PLAYER_GFX, 0x3FC0) + compressed_animated_gfx = rom.read_bytes(SMW_COMPRESSED_ANIMATED_GFX, 0x1A39) + compressed_gfx_00 = rom.read_bytes(SMW_COMPRESSED_GFX_00, 0x0838) + compressed_gfx_10 = rom.read_bytes(SMW_COMPRESSED_GFX_10, 0x0891) + compressed_gfx_28 = rom.read_bytes(SMW_COMPRESSED_GFX_28, 0x0637) + decompressed_player_gfx = decompress_gfx(compressed_player_gfx) + decompressed_animated_gfx = convert_3bpp(decompress_gfx(compressed_animated_gfx)) + decompressed_gfx_00 = convert_3bpp(decompress_gfx(compressed_gfx_00)) + decompressed_gfx_10 = convert_3bpp(decompress_gfx(compressed_gfx_10)) + decompressed_gfx_28 = decompress_gfx(compressed_gfx_28) + + # Copy berry tiles + order = [0x26C, 0x26D, 0x26E, 0x26F, + 0x27C, 0x27D, 0x27E, 0x27F, + 0x2E0, 0x2E1, 0x2E2, 0x2E3, + 0x2E4, 0x2E5, 0x2E6, 0x2E7] + decompressed_animated_gfx += copy_gfx_tiles(decompressed_player_gfx, order, [5, 32]) + + # Copy Mario's auxiliary tiles + order = [0x80, 0x91, 0x81, 0x90, 0x82, 0x83] + decompressed_gfx_00 += copy_gfx_tiles(decompressed_player_gfx, order, [5, 32]) + order = [0x69, 0x69, 0x0C, 0x69, 0x1A, 0x1B, 0x0D, 0x69, 0x22, 0x23, 0x32, 0x33, 0x0A, 0x0B, 0x20, 0x21, + 0x30, 0x31, 0x7E, 0x69, 0x80, 0x4A, 0x81, 0x5B, 0x82, 0x4B, 0x83, 0x5A, 0x84, 0x69, 0x85, 0x85] + player_small_tiles = copy_gfx_tiles(decompressed_gfx_00, order, [5, 32]) + + # Copy OW mario tiles + order = [0x06, 0x07, 0x16, 0x17, + 0x08, 0x09, 0x18, 0x19, + 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, + 0x0E, 0x0F, 0x1E, 0x1F, + 0x20, 0x21, 0x30, 0x31, + 0x24, 0x25, 0x34, 0x35, + 0x46, 0x47, 0x56, 0x57, + 0x64, 0x65, 0x74, 0x75, + 0x66, 0x67, 0x76, 0x77, + 0x2E, 0x2F, 0x3E, 0x3F, + 0x40, 0x41, 0x50, 0x51, + 0x42, 0x43, 0x52, 0x53] + player_map_tiles = copy_gfx_tiles(decompressed_gfx_10, order, [5, 32]) + + # Copy HUD mario tiles + order = [0x30, 0x31, 0x32, 0x33, 0x34] + player_name_tiles = copy_gfx_tiles(decompressed_gfx_28, order, [4, 16]) + + rom.write_bytes(0xE0000, decompressed_player_gfx) + rom.write_bytes(0xE8000, decompressed_animated_gfx) + rom.write_bytes(0xE6000, player_small_tiles) + rom.write_bytes(0xE6400, player_map_tiles) + rom.write_bytes(0xE6C00, player_name_tiles) + + # Skip Player & Animated tile decompression + rom.write_bytes(0x03888, bytearray([0x60])) # RTS + + # Edit Mario DMA routine + MARIO_GFX_DMA_ADDR = 0x02300 + rom.write_bytes(MARIO_GFX_DMA_ADDR + 0x0000, bytearray([0xA2, 0x04])) # LDX #$04 + rom.write_bytes(MARIO_GFX_DMA_ADDR + 0x0002, bytearray([0x22, 0x00, 0xF0, 0x10])) # JSL $10F000 ; upload_score_sprite_gfx + rom.write_bytes(MARIO_GFX_DMA_ADDR + 0x0006, bytearray([0x22, 0x00, 0xF8, 0x0F])) # JSL $0FF800 ; player_code + rom.write_bytes(MARIO_GFX_DMA_ADDR + 0x000A, bytearray([0x60])) # RTS + + PLAYER_UPLOAD_ADDR = 0x7F800 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0000, bytearray([0xC2, 0x20])) # player_code: rep #$20 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0002, bytearray([0xAC, 0x84, 0x0D])) # ldy $0D84 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0005, bytearray([0xD0, 0x03])) # bne .upload_player_palette + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0007, bytearray([0x4C, 0xD2, 0xF8])) # jmp .skip_everything + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x000A, bytearray([0xA0, 0x86])) # .upload_player_palette ldy #$86 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x000C, bytearray([0x8C, 0x21, 0x21])) # sty $2121 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x000F, bytearray([0xA9, 0x00, 0x22])) # lda #$2200 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0012, bytearray([0x8D, 0x20, 0x43])) # sta $4320 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0015, bytearray([0xA8])) # tay + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0016, bytearray([0xAD, 0x82, 0x0D])) # lda $0D82 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0019, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x001C, bytearray([0x8C, 0x24, 0x43])) # sty $4324 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x001F, bytearray([0xA9, 0x14, 0x00])) # lda #$0014 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0022, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0025, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0028, bytearray([0xA0, 0x80])) # ldy #$80 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x002A, bytearray([0x8C, 0x15, 0x21])) # sty $2115 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x002D, bytearray([0xA9, 0x01, 0x18])) # lda #$1801 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0030, bytearray([0x8D, 0x20, 0x43])) # sta $4320 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0033, bytearray([0xA0, 0x1C])) # ldy.b #player_gfx>>16 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0035, bytearray([0x8C, 0x24, 0x43])) # sty $4324 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0038, bytearray([0xA9, 0x00, 0x60])) # .upload_player_top lda #$6000 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x003B, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x003E, bytearray([0xA8])) # tay + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x003F, bytearray([0xB9, 0x85, 0x0D])) # - lda $0D85,y + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0042, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0045, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0048, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x004B, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x004E, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x004F, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0050, bytearray([0xC0, 0x06])) # cpy #$06 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0052, bytearray([0xD0, 0xEB])) # bne - + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0054, bytearray([0xA9, 0x00, 0x61])) # .upload_player_bottom lda #$6100 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0057, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x005A, bytearray([0xA8])) # tay + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x005B, bytearray([0xB9, 0x8F, 0x0D])) # - lda $0D8F,y + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x005E, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0061, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0064, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0067, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x006A, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x006B, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x006C, bytearray([0xC0, 0x06])) # cpy #$06 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x006E, bytearray([0xD0, 0xEB])) # bne - + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0070, bytearray([0xAC, 0x9B, 0x0D])) # .upload_player_extended ldy $0D9B + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0073, bytearray([0xC0, 0x02])) # cpy #$02 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0075, bytearray([0xF0, 0x5B])) # beq .skip_everything + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0077, bytearray([0xA9, 0xC0, 0x60])) # lda #$60C0 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x007A, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x007D, bytearray([0xAD, 0x99, 0x0D])) # lda $0D99 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0080, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0083, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0086, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0089, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x008C, bytearray([0xA0, 0x1D])) # .upload_misc_tiles ldy.b #animated_tiles>>16 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x008E, bytearray([0x8C, 0x24, 0x43])) # sty $4324 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0091, bytearray([0xA9, 0x60, 0x60])) # lda #$6060 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0094, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0097, bytearray([0xA0, 0x06])) # ldy #$06 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x0099, bytearray([0xCC, 0x84, 0x0D])) # cpy $0D84 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x009C, bytearray([0xB0, 0x34])) # bcs .skip_everything + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x009E, bytearray([0xB9, 0x85, 0x0D])) # - lda $0D85,y + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00A1, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00A4, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00A7, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00AA, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00AD, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00AE, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00AF, bytearray([0xCC, 0x84, 0x0D])) # cpy $0D84 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00B2, bytearray([0x90, 0xEA])) # bcc - + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00B4, bytearray([0xA9, 0x60, 0x61])) # lda #$6160 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00B7, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00BA, bytearray([0xA0, 0x06])) # ldy #$06 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00BC, bytearray([0xB9, 0x8F, 0x0D])) # - lda $0D8F,y + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00BF, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00C2, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00C5, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00C8, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00CB, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00CC, bytearray([0xC8])) # iny + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00CD, bytearray([0xCC, 0x84, 0x0D])) # cpy $0D84 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00D0, bytearray([0x90, 0xEA])) # bcc - + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00D2, bytearray([0xE2, 0x20])) # .skip_everything sep #$20 + rom.write_bytes(PLAYER_UPLOAD_ADDR + 0x00D4, bytearray([0x6B])) # rtl + + # Obtain data for new 8x8 tile + CHAR_TILE_CODE_ADDR = 0x05FE2 + rom.write_bytes(0x063B1, bytearray([0x20, 0xE2, 0xDF])) # jsr $DFE2 + rom.write_bytes(CHAR_TILE_CODE_ADDR + 0x0000, bytearray([0xB9, 0x1A, 0xDF])) # lda $DF1A,y + rom.write_bytes(CHAR_TILE_CODE_ADDR + 0x0003, bytearray([0x10, 0x06])) # bpl $06 + rom.write_bytes(CHAR_TILE_CODE_ADDR + 0x0005, bytearray([0x29, 0x7F])) # and #$7F + rom.write_bytes(CHAR_TILE_CODE_ADDR + 0x0007, bytearray([0x85, 0x0D])) # sta $0D + rom.write_bytes(CHAR_TILE_CODE_ADDR + 0x0009, bytearray([0xA9, 0x04])) # lda #$04 + rom.write_bytes(CHAR_TILE_CODE_ADDR + 0x000B, bytearray([0x60])) # rts + + rom.write_bytes(0x0640D, bytearray([0x20, 0xEE, 0xDF])) # jsr $DFEE + CAPE_TILE_CODE_ADDR = 0x05FEE + rom.write_bytes(CAPE_TILE_CODE_ADDR + 0x0000, bytearray([0xA5, 0x0D])) # lda $0D + rom.write_bytes(CAPE_TILE_CODE_ADDR + 0x0002, bytearray([0xE0, 0x2B])) # cpx #$2B + rom.write_bytes(CAPE_TILE_CODE_ADDR + 0x0004, bytearray([0x90, 0x07])) # bcc $07 + rom.write_bytes(CAPE_TILE_CODE_ADDR + 0x0006, bytearray([0xE0, 0x40])) # cpx #$40 + rom.write_bytes(CAPE_TILE_CODE_ADDR + 0x0008, bytearray([0xB0, 0x03])) # bcs $03 + rom.write_bytes(CAPE_TILE_CODE_ADDR + 0x000A, bytearray([0xBD, 0xD7, 0xE1])) # lda $E1D7,x + rom.write_bytes(CAPE_TILE_CODE_ADDR + 0x000D, bytearray([0x60])) # rts + + # Edit Mario's 8x8 tile data + MARIO_AUX_TILE_DATA_ADDR = 0x05F1A + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0000, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0008, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0010, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0018, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0020, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0028, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0030, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0038, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0040, bytearray([0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0048, bytearray([0x00,0x00,0x82,0x82,0x82,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0050, bytearray([0x00,0x00,0x84,0x00,0x00,0x00,0x00,0x86])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0058, bytearray([0x86,0x86,0x00,0x00,0x88,0x88,0x8A,0x8A])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0060, bytearray([0x8C,0x8C,0x00,0x00,0x90,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0068, bytearray([0x00,0x8E,0x00,0x00,0x00,0x00,0x92,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0070, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0078, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0080, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x82])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0088, bytearray([0x82,0x82,0x00,0x00,0x00,0x00,0x00,0x84])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0090, bytearray([0x00,0x00,0x00,0x00,0x86,0x86,0x86,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x0098, bytearray([0x00,0x88,0x88,0x8A,0x8A,0x8C,0x8C,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x00A0, bytearray([0x00,0x90,0x00,0x00,0x00,0x00,0x8E,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x00A8, bytearray([0x00,0x00,0x00,0x92,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x00B0, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + rom.write_bytes(MARIO_AUX_TILE_DATA_ADDR + 0x00B8, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])) + + MARIO_AUX_TILE_OFFSETS_ADDR = 0x05FDA # ends at $00E00C + rom.write_bytes(MARIO_AUX_TILE_OFFSETS_ADDR + 0x0000, bytearray([0x00,0x02,0x80,0x80,0x00,0x02,0x0C,0x0D])) + rom.write_bytes(MARIO_AUX_TILE_OFFSETS_ADDR + 0x0022, bytearray([0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x02])) + rom.write_bytes(MARIO_AUX_TILE_OFFSETS_ADDR + 0x002A, bytearray([0x02,0x80,0x04,0x0C,0x0D,0xFF,0xFF,0xFF])) + + MARIO_AUX_CAPE_TILE_DATA_ADDR = 0x061FF + rom.write_bytes(MARIO_AUX_CAPE_TILE_DATA_ADDR + 0x0000, bytearray([0x00,0x8C,0x14,0x14,0x2E])) + rom.write_bytes(MARIO_AUX_CAPE_TILE_DATA_ADDR + 0x0005, bytearray([0x00,0xCA,0x16,0x16,0x2E])) + rom.write_bytes(MARIO_AUX_CAPE_TILE_DATA_ADDR + 0x000A, bytearray([0x00,0x8E,0x18,0x18,0x2E])) + rom.write_bytes(MARIO_AUX_CAPE_TILE_DATA_ADDR + 0x000F, bytearray([0x00,0xEB,0x1A,0x1A,0x2E])) + rom.write_bytes(MARIO_AUX_CAPE_TILE_DATA_ADDR + 0x0014, bytearray([0x04,0xED,0x1C,0x1C])) + + # Edit player data offsets + rom.write_bytes(0x07649, bytearray([0x69, 0x00, 0x80])) # adc #$8000 + rom.write_bytes(0x07667, bytearray([0x69, 0x00, 0x80])) # adc #$8000 + rom.write_bytes(0x0767C, bytearray([0x69, 0x00, 0x80])) # adc #$8000 + rom.write_bytes(0x07691, bytearray([0x69, 0x00, 0xE0])) # adc #$E000 + + # Fix berries + FIX_BERRIES_ADDR = 0x7FFE0 + rom.write_bytes(FIX_BERRIES_ADDR + 0x0000, bytearray([0xA0, 0x1D])) # fix_berries: ldy.b #animated_tiles>>16 + rom.write_bytes(FIX_BERRIES_ADDR + 0x0002, bytearray([0x8C, 0x24, 0x43])) # sty $4324 + rom.write_bytes(FIX_BERRIES_ADDR + 0x0005, bytearray([0xAD, 0x76, 0x0D])) # lda $0D76 + rom.write_bytes(FIX_BERRIES_ADDR + 0x0008, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(FIX_BERRIES_ADDR + 0x000B, bytearray([0x6B])) # rtl + + # Fix animated graphics + rom.write_bytes(0x018D1, bytearray([0x1D])) # db $1D + rom.write_bytes(0x0239E, bytearray([0x1D])) # db $1D + + rom.write_bytes(0x023F0, bytearray([0x22, 0xE0, 0xFF, 0x0F])) # jsl $0FFFE0 + rom.write_bytes(0x023F4, bytearray([0xEA])) # nop + rom.write_bytes(0x023F5, bytearray([0xEA])) # nop + + rom.write_bytes(0x0E1A8, bytearray([0x69, 0x00, 0x88])) # adc #$8800 + rom.write_bytes(0x0EEB4, bytearray([0x69, 0x00, 0x88])) # adc #$8800 + rom.write_bytes(0x0EEC9, bytearray([0x69, 0x00, 0x88])) # adc #$8800 + rom.write_bytes(0x16A3E, bytearray([0x69, 0x00, 0x88])) # adc #$8800 + + ANIMATED_TILE_DATA_ADDR = 0x2B999 + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0000, bytearray([0x00,0x98,0x00,0x9A,0x00,0x9C,0x00,0x9E])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0008, bytearray([0x80,0x98,0x80,0x9A,0x80,0x9C,0x80,0x9E])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0010, bytearray([0x00,0x99,0x00,0x99,0x00,0x99,0x00,0x99])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0018, bytearray([0x80,0xA0,0x80,0xA2,0x80,0xA4,0x80,0xA6])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0020, bytearray([0x00,0x99,0x00,0x9B,0x00,0x9D,0x00,0x9F])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0028, bytearray([0x00,0xB0,0x80,0xB0,0x00,0xB1,0x80,0xB1])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0030, bytearray([0x20,0xAF,0x20,0xAF,0x20,0xAF,0x20,0xAF])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0038, bytearray([0x20,0xAF,0x20,0xAF,0x20,0xAF,0x20,0xAF])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0040, bytearray([0x80,0x96,0x80,0x96,0x80,0x96,0x80,0x96])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0048, bytearray([0x00,0xA7,0x80,0xA7,0x00,0xA7,0x80,0xA7])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0050, bytearray([0x20,0xAF,0x20,0xAF,0x20,0xAF,0x20,0xAF])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0058, bytearray([0x00,0xAF,0x00,0xAF,0x00,0xAF,0x00,0xAF])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0060, bytearray([0x00,0x94,0x00,0x94,0x00,0x94,0x00,0x94])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0068, bytearray([0x80,0x99,0x80,0x9B,0x80,0x9D,0x80,0x9F])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0070, bytearray([0x00,0xA0,0x00,0xA2,0x00,0xA4,0x00,0xA6])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0078, bytearray([0x80,0x91,0x80,0x93,0x80,0x95,0x80,0x97])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0080, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0088, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0090, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0098, bytearray([0x00,0xA0,0x00,0xA2,0x00,0xA4,0x00,0xA6])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00A0, bytearray([0x80,0x91,0x80,0x93,0x80,0x95,0x80,0x97])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00A8, bytearray([0x00,0x80,0x00,0x82,0x00,0x84,0x00,0x86])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00B0, bytearray([0x00,0x86,0x00,0x84,0x00,0x82,0x00,0x80])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00B8, bytearray([0x00,0xA1,0x00,0xA3,0x00,0xA5,0x00,0xA3])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00C0, bytearray([0x00,0xA0,0x00,0xA2,0x00,0xA4,0x00,0xA6])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00C8, bytearray([0x00,0xA8,0x00,0xAA,0x00,0xAC,0x00,0xAE])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00D0, bytearray([0x80,0xA8,0x80,0xAA,0x80,0xAC,0x80,0xAE])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00D8, bytearray([0x80,0xAE,0x80,0xAC,0x80,0xAA,0x80,0xA8])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00E0, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00E8, bytearray([0x80,0xA1,0x80,0xA3,0x80,0xA5,0x80,0xA3])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00F0, bytearray([0x80,0x80,0x80,0x82,0x80,0x84,0x80,0x86])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x00F8, bytearray([0x00,0x81,0x00,0x83,0x00,0x85,0x00,0x87])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0100, bytearray([0x80,0x81,0x80,0x83,0x80,0x85,0x80,0x87])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0108, bytearray([0x80,0x86,0x80,0x84,0x80,0x82,0x80,0x80])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0110, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0118, bytearray([0x80,0xA9,0x80,0xAB,0x80,0xAD,0x80,0xAB])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0120, bytearray([0x00,0x91,0x00,0x93,0x00,0x95,0x00,0x97])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0128, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0130, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0138, bytearray([0x80,0xA1,0x80,0xA3,0x80,0xA5,0x80,0xA3])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0140, bytearray([0x00,0xA9,0x00,0xAB,0x00,0xAD,0x00,0xAB])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0148, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0150, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0158, bytearray([0x00,0x98,0x00,0x98,0x00,0x98,0x00,0x98])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0160, bytearray([0x80,0x94,0x80,0x94,0x80,0x94,0x80,0x94])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0168, bytearray([0x80,0x99,0x80,0x9B,0x80,0x9D,0x80,0x9F])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0170, bytearray([0x80,0x99,0x80,0x9B,0x80,0x9D,0x80,0x9F])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0178, bytearray([0x80,0x99,0x80,0x9B,0x80,0x9D,0x80,0x9F])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0180, bytearray([0x00,0x98,0x00,0x9A,0x00,0x9C,0x00,0x9E])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0188, bytearray([0x80,0xAF,0x80,0xAF,0x80,0xAF,0x80,0xAF])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0190, bytearray([0x00,0x96,0x00,0x96,0x00,0x96,0x00,0x96])) + rom.write_bytes(ANIMATED_TILE_DATA_ADDR + 0x0198, bytearray([0x80,0x96,0x80,0x96,0x80,0x96,0x80,0x96])) + + # Insert hand drawn graphics for in level indicators + rom.write_bytes(0xE7000, read_graphics_file("indicators.bin")) + # Upload indicator GFX + UPLOAD_INDICATOR_GFX = 0x87000 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0000, bytearray([0xAD, 0x00, 0x01])) # upload_score_sprite_gfx: lda $0100 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0003, bytearray([0xC9, 0x13])) # cmp #$13 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0005, bytearray([0xF0, 0x03])) # beq .check_level + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0007, bytearray([0x4C, 0x9D, 0xF0])) # jmp .check_map + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x000A, bytearray([0xA5, 0x7C])) # .check_level lda $7C + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x000C, bytearray([0xF0, 0x03])) # beq ..perform + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x000E, bytearray([0x4C, 0x9C, 0xF0])) # jmp .skip + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0011, bytearray([0xE6, 0x7C])) # ..perform inc $7C + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0013, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0015, bytearray([0xA0, 0x80])) # ldy #$80 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0017, bytearray([0x8C, 0x15, 0x21])) # sty $2115 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x001A, bytearray([0xA9, 0x01, 0x18])) # lda #$1801 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x001D, bytearray([0x8D, 0x20, 0x43])) # sta $4320 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0020, bytearray([0xA0, 0x1C])) # ldy.b #$1C + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0022, bytearray([0x8C, 0x24, 0x43])) # sty $4324 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0025, bytearray([0xA9, 0x00, 0xF0])) # lda.w #$F000 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0028, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x002B, bytearray([0xA9, 0xA0, 0x64])) # .nums_01 lda #$64A0 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x002E, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0031, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0034, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0037, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x003A, bytearray([0xA9, 0xA0, 0x65])) # .nums_35 lda #$65A0 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x003D, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0040, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0043, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0046, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0049, bytearray([0xA9, 0xA0, 0x61])) # .plus_coin lda #$61A0 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x004C, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x004F, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0052, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0055, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0058, bytearray([0xA9, 0xA0, 0x60])) # .egg_mushroom lda #$60A0 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x005B, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x005E, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0061, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0064, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0067, bytearray([0xA9, 0xE0, 0x67])) # .thwimp lda #$67E0 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x006A, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x006D, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0070, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0073, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0076, bytearray([0xA9, 0x80, 0x63])) # .token lda #$6380 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0079, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x007C, bytearray([0xA9, 0x20, 0x00])) # lda #$0020 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x007F, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0082, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0085, bytearray([0xA9, 0x00, 0xEC])) # .layer_3 lda #$EC00 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0088, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x008B, bytearray([0xA9, 0x80, 0x41])) # lda #$4180 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x008E, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0091, bytearray([0xA9, 0x50, 0x00])) # lda #$0050 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0094, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0097, bytearray([0x8E, 0x0B, 0x42])) # stx $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x009A, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x009C, bytearray([0x6B])) # .skip rtl + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x009D, bytearray([0xC9, 0x0E])) # .check_map cmp #$0E + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x009F, bytearray([0xF0, 0x51])) # beq .map_pal + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00A1, bytearray([0xC9, 0x0D])) # cmp #$0D + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00A3, bytearray([0xD0, 0xF7])) # bne .skip + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00A5, bytearray([0xA5, 0x7C])) # lda $7C + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00A7, bytearray([0xD0, 0xF3])) # bne .skip + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00A9, bytearray([0xE6, 0x7C])) # inc $7C + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00AB, bytearray([0xC2, 0x20])) # rep #$20 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00AD, bytearray([0xA0, 0x80])) # ldy #$80 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00AF, bytearray([0x8C, 0x15, 0x21])) # sty $2115 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00B2, bytearray([0xA9, 0x01, 0x18])) # lda #$1801 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00B5, bytearray([0x8D, 0x20, 0x43])) # sta $4320 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00B8, bytearray([0xA0, 0x1C])) # ldy.b #$1C + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00BA, bytearray([0x8C, 0x24, 0x43])) # sty $4324 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00BD, bytearray([0xA9, 0x00, 0xE4])) # lda.w #$E400 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00C0, bytearray([0x8D, 0x22, 0x43])) # sta $4322 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00C3, bytearray([0xDA])) # phx + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00C4, bytearray([0x9B])) # txy + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00C5, bytearray([0xA2, 0x18])) # ldx.b #(.map_targets_end-.map_targets-1)*2 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00C7, bytearray([0xA9, 0x40, 0x00])) # ..loop lda #$0040 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00CA, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00CD, bytearray([0xBF, 0x80, 0xFF, 0x10])) # lda.l .map_targets,x + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00D1, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00D4, bytearray([0x8C, 0x0B, 0x42])) # sty $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00D7, bytearray([0xBF, 0x80, 0xFF, 0x10])) # lda.l .map_targets,x + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00DB, bytearray([0x18])) # clc + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00DC, bytearray([0x69, 0x00, 0x01])) # adc #$0100 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00DF, bytearray([0x8D, 0x16, 0x21])) # sta $2116 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00E2, bytearray([0xA9, 0x40, 0x00])) # lda #$0040 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00E5, bytearray([0x8D, 0x25, 0x43])) # sta $4325 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00E8, bytearray([0x8C, 0x0B, 0x42])) # sty $420B + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00EB, bytearray([0xCA])) # dex + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00EC, bytearray([0xCA])) # dex + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00ED, bytearray([0x10, 0xD8])) # bpl .loop + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00EF, bytearray([0xFA])) # plx + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00F0, bytearray([0xE2, 0x20])) # sep #$20 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00F2, bytearray([0xA9, 0xA3])) # .map_pal lda #$A3 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00F4, bytearray([0x8D, 0x21, 0x21])) # sta $2121 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00F7, bytearray([0xAF, 0x9C, 0xB5, 0x00])) # lda $00B59C + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00FB, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x00FE, bytearray([0xAF, 0x9D, 0xB5, 0x00])) # lda $00B59D + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0102, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0105, bytearray([0xAF, 0x9E, 0xB5, 0x00])) # lda $00B59E + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0109, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x010C, bytearray([0xAF, 0x9F, 0xB5, 0x00])) # lda $00B59F + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0110, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0113, bytearray([0xAF, 0xA0, 0xB5, 0x00])) # lda $00B5A0 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0117, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x011A, bytearray([0xAF, 0xA1, 0xB5, 0x00])) # lda $00B5A1 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x011E, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0121, bytearray([0xAF, 0xA2, 0xB5, 0x00])) # lda $00B5A2 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0125, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0128, bytearray([0xAF, 0xA3, 0xB5, 0x00])) # lda $00B5A3 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x012C, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x012F, bytearray([0xAF, 0xA4, 0xB5, 0x00])) # lda $00B5A4 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0133, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x0136, bytearray([0xAF, 0xA5, 0xB5, 0x00])) # lda $00B5A5 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x013A, bytearray([0x8D, 0x22, 0x21])) # sta $2122 + rom.write_bytes(UPLOAD_INDICATOR_GFX + 0x013D, bytearray([0x6B])) # rtl + + vram_targets = bytearray([ + 0x20,0x64, 0x00,0x64, 0xE0,0x62, + 0x60,0x66, 0x40,0x66, + 0x60,0x64, + 0x40,0x62, 0x00,0x62, + 0xE0,0x60, 0xC0,0x60, 0xA0,0x60, 0x80,0x60, 0x60,0x60 + ]) + rom.write_bytes(0x87F80, vram_targets) + +def decompress_gfx(compressed_graphics): + # This code decompresses graphics in LC_LZ2 format in order to be able to swap player and yoshi's graphics with ease. + decompressed_gfx = bytearray([]) + i = 0 + while True: + cmd = compressed_graphics[i] + i += 1 + if cmd == 0xFF: + break + else: + if (cmd >> 5) == 0x07: + size = ((cmd & 0x03) << 8) + compressed_graphics[i] + 1 + cmd = (cmd & 0x1C) >> 2 + i += 1 + else: + size = (cmd & 0x1F) + 1 + cmd = cmd >> 5 + if cmd == 0x00: + decompressed_gfx += bytearray([compressed_graphics[i+j] for j in range(size)]) + i += size + elif cmd == 0x01: + byte_fill = compressed_graphics[i] + i += 1 + decompressed_gfx += bytearray([byte_fill for j in range(size)]) + elif cmd == 0x02: + byte_fill_1 = compressed_graphics[i] + i += 1 + byte_fill_2 = compressed_graphics[i] + i += 1 + for j in range(size): + if (j & 0x1) == 0x00: + decompressed_gfx += bytearray([byte_fill_1]) + else: + decompressed_gfx += bytearray([byte_fill_2]) + elif cmd == 0x03: + byte_read = compressed_graphics[i] + i += 1 + decompressed_gfx += bytearray([(byte_read + j) for j in range(size)]) + elif cmd == 0x04: + position = (compressed_graphics[i] << 8) + compressed_graphics[i+1] + i += 2 + for j in range(size): + copy_byte = decompressed_gfx[position+j] + decompressed_gfx += bytearray([copy_byte]) + return decompressed_gfx + + +def convert_3bpp(decompressed_gfx): + i = 0 + converted_gfx = bytearray([]) + while i < len(decompressed_gfx): + converted_gfx += bytearray([decompressed_gfx[i+j] for j in range(16)]) + i += 16 + for j in range(8): + converted_gfx += bytearray([decompressed_gfx[i]]) + converted_gfx += bytearray([0x00]) + i += 1 + return converted_gfx + + +def copy_gfx_tiles(original, order, size): + result = bytearray([]) + for x in range(len(order)): + z = order[x] << size[0] + result += bytearray([original[z+y] for y in range(size[1])]) + return result + + +def file_to_bytes(filename): + return open(os.path.dirname(__file__)+filename, "rb").read() + + +def handle_music_shuffle(rom, world: World): from .Aesthetics import generate_shuffled_level_music, generate_shuffled_ow_music, level_music_address_data, ow_music_address_data - shuffled_level_music = generate_shuffled_level_music(world, player) + shuffled_level_music = generate_shuffled_level_music(world) for i in range(len(shuffled_level_music)): rom.write_byte(level_music_address_data[i], shuffled_level_music[i]) - shuffled_ow_music = generate_shuffled_ow_music(world, player) + shuffled_ow_music = generate_shuffled_ow_music(world) for i in range(len(shuffled_ow_music)): for addr in ow_music_address_data[i]: rom.write_byte(addr, shuffled_ow_music[i]) -def handle_mario_palette(rom, world, player): +def handle_mario_palette(rom, world: World): from .Aesthetics import mario_palettes, fire_mario_palettes, ow_mario_palettes - chosen_palette = world.mario_palette[player].value + chosen_palette = world.options.mario_palette.value rom.write_bytes(0x32C8, bytes(mario_palettes[chosen_palette])) rom.write_bytes(0x32F0, bytes(fire_mario_palettes[chosen_palette])) @@ -723,9 +2836,9 @@ def handle_swap_donut_gh_exits(rom): rom.write_bytes(0x26371, bytes([0x32])) -def handle_bowser_rooms(rom, world, player: int): - if world.bowser_castle_rooms[player] == "random_two_room": - chosen_rooms = world.per_slot_randoms[player].sample(standard_bowser_rooms, 2) +def handle_bowser_rooms(rom, world: World): + if world.options.bowser_castle_rooms == "random_two_room": + chosen_rooms = world.random.sample(standard_bowser_rooms, 2) rom.write_byte(0x3A680, chosen_rooms[0].roomID) rom.write_byte(0x3A684, chosen_rooms[0].roomID) @@ -737,8 +2850,8 @@ def handle_bowser_rooms(rom, world, player: int): rom.write_byte(chosen_rooms[len(chosen_rooms)-1].exitAddress, 0xBD) - elif world.bowser_castle_rooms[player] == "random_five_room": - chosen_rooms = world.per_slot_randoms[player].sample(standard_bowser_rooms, 5) + elif world.options.bowser_castle_rooms == "random_five_room": + chosen_rooms = world.random.sample(standard_bowser_rooms, 5) rom.write_byte(0x3A680, chosen_rooms[0].roomID) rom.write_byte(0x3A684, chosen_rooms[0].roomID) @@ -750,9 +2863,9 @@ def handle_bowser_rooms(rom, world, player: int): rom.write_byte(chosen_rooms[len(chosen_rooms)-1].exitAddress, 0xBD) - elif world.bowser_castle_rooms[player] == "gauntlet": + elif world.options.bowser_castle_rooms == "gauntlet": chosen_rooms = standard_bowser_rooms.copy() - world.per_slot_randoms[player].shuffle(chosen_rooms) + world.random.shuffle(chosen_rooms) rom.write_byte(0x3A680, chosen_rooms[0].roomID) rom.write_byte(0x3A684, chosen_rooms[0].roomID) @@ -763,12 +2876,12 @@ def handle_bowser_rooms(rom, world, player: int): rom.write_byte(chosen_rooms[i-1].exitAddress, chosen_rooms[i].roomID) rom.write_byte(chosen_rooms[len(chosen_rooms)-1].exitAddress, 0xBD) - elif world.bowser_castle_rooms[player] == "labyrinth": + elif world.options.bowser_castle_rooms == "labyrinth": bowser_rooms_copy = full_bowser_rooms.copy() entrance_point = bowser_rooms_copy.pop(0) - world.per_slot_randoms[player].shuffle(bowser_rooms_copy) + world.random.shuffle(bowser_rooms_copy) rom.write_byte(entrance_point.exitAddress, bowser_rooms_copy[0].roomID) for i in range(0, len(bowser_rooms_copy) - 1): @@ -777,13 +2890,13 @@ def handle_bowser_rooms(rom, world, player: int): rom.write_byte(bowser_rooms_copy[len(bowser_rooms_copy)-1].exitAddress, 0xBD) -def handle_boss_shuffle(rom, world, player): - if world.boss_shuffle[player] == "simple": +def handle_boss_shuffle(rom, world: World): + if world.options.boss_shuffle == "simple": submap_boss_rooms_copy = submap_boss_rooms.copy() ow_boss_rooms_copy = ow_boss_rooms.copy() - world.per_slot_randoms[player].shuffle(submap_boss_rooms_copy) - world.per_slot_randoms[player].shuffle(ow_boss_rooms_copy) + world.random.shuffle(submap_boss_rooms_copy) + world.random.shuffle(ow_boss_rooms_copy) for i in range(len(submap_boss_rooms_copy)): rom.write_byte(submap_boss_rooms[i].exitAddress, submap_boss_rooms_copy[i].roomID) @@ -794,21 +2907,21 @@ def handle_boss_shuffle(rom, world, player): if ow_boss_rooms[i].exitAddressAlt is not None: rom.write_byte(ow_boss_rooms[i].exitAddressAlt, ow_boss_rooms_copy[i].roomID) - elif world.boss_shuffle[player] == "full": + elif world.options.boss_shuffle == "full": for i in range(len(submap_boss_rooms)): - chosen_boss = world.per_slot_randoms[player].choice(submap_boss_rooms) + chosen_boss = world.random.choice(submap_boss_rooms) rom.write_byte(submap_boss_rooms[i].exitAddress, chosen_boss.roomID) for i in range(len(ow_boss_rooms)): - chosen_boss = world.per_slot_randoms[player].choice(ow_boss_rooms) + chosen_boss = world.random.choice(ow_boss_rooms) rom.write_byte(ow_boss_rooms[i].exitAddress, chosen_boss.roomID) if ow_boss_rooms[i].exitAddressAlt is not None: rom.write_byte(ow_boss_rooms[i].exitAddressAlt, chosen_boss.roomID) - elif world.boss_shuffle[player] == "singularity": - chosen_submap_boss = world.per_slot_randoms[player].choice(submap_boss_rooms) - chosen_ow_boss = world.per_slot_randoms[player].choice(ow_boss_rooms) + elif world.options.boss_shuffle == "singularity": + chosen_submap_boss = world.random.choice(submap_boss_rooms) + chosen_ow_boss = world.random.choice(ow_boss_rooms) for i in range(len(submap_boss_rooms)): rom.write_byte(submap_boss_rooms[i].exitAddress, chosen_submap_boss.roomID) @@ -820,8 +2933,8 @@ def handle_boss_shuffle(rom, world, player): rom.write_byte(ow_boss_rooms[i].exitAddressAlt, chosen_ow_boss.roomID) -def patch_rom(world, rom, player, active_level_dict): - goal_text = generate_goal_text(world, player) +def patch_rom(world: World, rom, player, active_level_dict): + goal_text = generate_goal_text(world) rom.write_bytes(0x2A6E2, goal_text) rom.write_byte(0x2B1D8, 0x80) @@ -829,19 +2942,23 @@ def patch_rom(world, rom, player, active_level_dict): intro_text = generate_text_box("Bowser has stolen all of Mario's abilities. Can you help Mario travel across Dinosaur land to get them back and save the Princess from him?") rom.write_bytes(0x2A5D9, intro_text) - handle_bowser_rooms(rom, world, player) - handle_boss_shuffle(rom, world, player) + handle_bowser_rooms(rom, world) + handle_boss_shuffle(rom, world) + + # Handle ROM expansion + rom.write_bytes(0x07FD7, bytearray([0x0A])) + rom.write_bytes(0x80000, bytearray([0x00 for _ in range(0x80000)])) # Prevent Title Screen Deaths rom.write_byte(0x1C6A, 0x80) # Title Screen Text player_name_bytes = bytearray() - player_name = world.get_player_name(player) + player_name = world.multiworld.get_player_name(player) for i in range(16): char = " " if i < len(player_name): - char = world.get_player_name(player)[i] + char = player_name[i] upper_char = char.upper() if upper_char not in title_text_mapping: for byte in title_text_mapping["."]: @@ -869,33 +2986,58 @@ def patch_rom(world, rom, player, active_level_dict): rom.write_bytes(0x2B88E, bytearray([0x2C, 0x31, 0x73, 0x31, 0x75, 0x31, 0x82, 0x30, 0x30, 0x31, 0xFC, 0x38, 0x31, 0x31, 0x73, 0x31, 0x73, 0x31, 0x7C, 0x30, 0xFC, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # 1 Player Game - rom.write_bytes(0x2B6D7, bytearray([0xFC, 0x38, 0xFC, 0x38, 0x16, 0x38, 0x18, 0x38, 0x0D, 0x38, 0xFC, 0x38, 0x0B, 0x38, 0x22, 0x38, + rom.write_bytes(0x2B6D7, bytearray([0x16, 0x38, 0x18, 0x38, 0x0D, 0x38, 0xFC, 0x38, 0x0B, 0x38, 0x22, 0x38, 0xFC, 0x38, 0x19, 0x38, 0x18, 0x38, 0x1B, 0x38, 0x22, 0x38, 0x10, 0x38, 0x18, 0x38, 0x17, 0x38, - 0x0E, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # Mod by PoryGone + 0x0E, 0x38, 0xFC, 0x38, 0x15, 0x38, 0x21, 0x38, 0x05, 0x38])) # Mod by PoryGone + lx5 # Title Options rom.write_bytes(0x1E6A, bytearray([0x01])) rom.write_bytes(0x1E6C, bytearray([0x01])) rom.write_bytes(0x1E6E, bytearray([0x01])) + # Save current level number to RAM (not translevel) + rom.write_bytes(0x2D8B9, bytearray([0x20, 0x46, 0xDC])) # org $05D8B9 : jsr level_num + rom.write_bytes(0x2DC46 + 0x0000, bytearray([0xA5, 0x0E])) # level_num: lda $0E + rom.write_bytes(0x2DC46 + 0x0002, bytearray([0x8D, 0x0B, 0x01])) # sta $010B + rom.write_bytes(0x2DC46 + 0x0005, bytearray([0x0A])) # asl + rom.write_bytes(0x2DC46 + 0x0006, bytearray([0x60])) # rts + # Always allow Start+Select rom.write_bytes(0x2267, bytearray([0xEA, 0xEA])) # Always bring up save prompt on beating a level - if world.autosave[player]: + if world.options.autosave: rom.write_bytes(0x20F93, bytearray([0x00])) - if world.overworld_speed[player] == "fast": + if world.options.overworld_speed == "fast": rom.write_bytes(0x21414, bytearray([0x20, 0x10])) - elif world.overworld_speed[player] == "slow": + elif world.options.overworld_speed == "slow": rom.write_bytes(0x21414, bytearray([0x05, 0x05])) # Starting Life Count - rom.write_bytes(0x1E25, bytearray([world.starting_life_count[player].value - 1])) + rom.write_bytes(0x1E25, bytearray([world.options.starting_life_count.value - 1])) # Repurpose Bonus Stars counter for Boss Token or Yoshi Eggs rom.write_bytes(0x3F1AA, bytearray([0x00] * 0x20)) + # Make bonus star counter go up to 255 (999 in theory, but can't load a 16-bit addr there) + rom.write_bytes(0x00F5B, bytearray([0x4C, 0x73, 0x8F])) + rom.write_byte(0x00F95, 0x08) + rom.write_byte(0x00F97, 0x0C) + rom.write_byte(0x00FAC, 0x02) + rom.write_byte(0x00F9E, 0x1D) + rom.write_byte(0x00FA5, 0x1D) + rom.write_byte(0x00FA8, 0x02) + rom.write_byte(0x00FB0, 0x1D) + rom.write_byte(0x00FB8, 0x02) + rom.write_byte(0x00FBE, 0x1D) + rom.write_byte(0x00FC2, 0x03) + + # Move Dragon coins one spot to the left & fix tilemap + rom.write_byte(0x00FF0, 0xFE) + rom.write_byte(0x00C94, 0x3C) + rom.write_byte(0x00C9C, 0x38) + # Delete Routine that would copy Mario position data over repurposed Luigi save data rom.write_bytes(0x20F9F, bytearray([0xEA] * 0x3D)) @@ -904,6 +3046,10 @@ def patch_rom(world, rom, player, active_level_dict): rom.write_bytes(0x6EB1, bytearray([0xEA, 0xEA])) rom.write_bytes(0x6EB4, bytearray([0xEA, 0xEA, 0xEA])) + # Move Thwimps tilemap to another spot in VRAM in order to make them global + rom.write_bytes(0x09C13, bytearray([0x7E, 0x7E, 0x7F, 0x7F])) + rom.write_byte(0x3F425, 0x32) + handle_ability_code(rom) handle_yoshi_box(rom) @@ -913,44 +3059,97 @@ def patch_rom(world, rom, player, active_level_dict): handle_vertical_scroll(rom) + handle_ram(rom) + handle_bonus_block(rom) + handle_blocksanity(rom) + + handle_uncompressed_player_gfx(rom) + + # Handle Special Zone Clear flag + rom.write_bytes(0x02A74, bytearray([0x1E, 0x1F])) + rom.write_bytes(0x09826, bytearray([0x1E, 0x1F])) + rom.write_bytes(0x0B9CD, bytearray([0x1E, 0x1F])) + rom.write_bytes(0x12986, bytearray([0x1E, 0x1F])) + rom.write_bytes(0x62E0F, bytearray([0x1E, 0x1F])) + + handle_indicators(rom) + handle_map_indicators(rom) + + # Handle extra traps + handle_traps(rom) + + # Mario Start! -> Player Start! + text_data_top_tiles = bytearray([ + 0x00,0xFF,0x4D,0x4C,0x03,0x4D,0x5D,0xFF,0x4C,0x4B, + 0x4A,0x03,0x4E,0x01,0x00,0x02,0x00,0x4a,0x4E,0xFF + ]) + text_data_top_props = bytearray([ + 0x34,0x30,0x34,0x34,0x34,0x34,0x34,0x30,0x34,0x34, + 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x30 + ]) + text_data_bottom_tiles = bytearray([ + 0x10,0xFF,0x00,0x5C,0x13,0x00,0x5D,0xFF,0x5C,0x5B, + 0x00,0x13,0x5E,0x11,0x00,0x12,0x00,0x03,0x5E,0xFF + ]) + text_data_bottom_props = bytearray([ + 0x34,0x30,0xb4,0x34,0x34,0xb4,0xf4,0x30,0x34,0x34, + 0xB4,0x34,0x34,0x34,0xb4,0x34,0xb4,0xb4,0x34,0x30 + ]) + + rom.write_bytes(0x010D1, text_data_top_tiles) + rom.write_bytes(0x01139, text_data_top_props) + rom.write_bytes(0x01105, text_data_bottom_tiles) + rom.write_bytes(0x0116A, text_data_bottom_props) + # Handle Level Shuffle handle_level_shuffle(rom, active_level_dict) # Handle Music Shuffle - if world.music_shuffle[player] != "none": - handle_music_shuffle(rom, world, player) + if world.options.music_shuffle != "none": + handle_music_shuffle(rom, world) - generate_shuffled_ow_palettes(rom, world, player) + generate_shuffled_ow_palettes(rom, world) - generate_shuffled_header_data(rom, world, player) + generate_shuffled_header_data(rom, world) - if world.swap_donut_gh_exits[player]: + if world.options.level_palette_shuffle == "on_curated": + generate_curated_level_palette_data(rom, world) + + if world.options.overworld_palette_shuffle == "on_curated": + generate_curated_map_palette_data(rom, world) + + if world.options.sfx_shuffle != "none": + generate_shuffled_sfx(rom, world) + + if world.options.swap_donut_gh_exits: handle_swap_donut_gh_exits(rom) - handle_mario_palette(rom, world, player) + handle_mario_palette(rom, world) # Store all relevant option results in ROM - rom.write_byte(0x01BFA0, world.goal[player].value) - if world.goal[player].value == 0: - rom.write_byte(0x01BFA1, world.bosses_required[player].value) + rom.write_byte(0x01BFA0, world.options.goal.value) + if world.options.goal.value == 0: + rom.write_byte(0x01BFA1, world.options.bosses_required.value) else: rom.write_byte(0x01BFA1, 0x7F) - required_yoshi_eggs = max(math.floor( - world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1) + required_yoshi_eggs = world.required_egg_count rom.write_byte(0x01BFA2, required_yoshi_eggs) - #rom.write_byte(0x01BFA3, world.display_sent_item_popups[player].value) - rom.write_byte(0x01BFA4, world.display_received_item_popups[player].value) - rom.write_byte(0x01BFA5, world.death_link[player].value) - rom.write_byte(0x01BFA6, world.dragon_coin_checks[player].value) - rom.write_byte(0x01BFA7, world.swap_donut_gh_exits[player].value) + #rom.write_byte(0x01BFA3, world.options.display_sent_item_popups.value) + rom.write_byte(0x01BFA4, world.options.display_received_item_popups.value) + rom.write_byte(0x01BFA5, world.options.death_link.value) + rom.write_byte(0x01BFA6, world.options.dragon_coin_checks.value) + rom.write_byte(0x01BFA7, world.options.swap_donut_gh_exits.value) + rom.write_byte(0x01BFA8, world.options.moon_checks.value) + rom.write_byte(0x01BFA9, world.options.hidden_1up_checks.value) + rom.write_byte(0x01BFAA, world.options.bonus_block_checks.value) + rom.write_byte(0x01BFAB, world.options.blocksanity.value) from Utils import __version__ - rom.name = bytearray(f'SMW{__version__.replace(".", "")[0:3]}_{player}_{world.seed:11}\0', 'utf8')[:21] + rom.name = bytearray(f'SMW{__version__.replace(".", "")[0:3]}_{player}_{world.multiworld.seed:11}\0', 'utf8')[:21] rom.name.extend([0] * (21 - len(rom.name))) rom.write_bytes(0x7FC0, rom.name) - def get_base_rom_bytes(file_name: str = "") -> bytes: base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None) if not base_rom_bytes: diff --git a/worlds/smw/Rules.py b/worlds/smw/Rules.py index 82f22c3a34..a900b4fd20 100644 --- a/worlds/smw/Rules.py +++ b/worlds/smw/Rules.py @@ -2,19 +2,18 @@ import math from BaseClasses import MultiWorld from .Names import LocationName, ItemName -from worlds.AutoWorld import LogicMixin +from worlds.AutoWorld import World from worlds.generic.Rules import add_rule, set_rule -def set_rules(world: MultiWorld, player: int): +def set_rules(world: World): - if world.goal[player] == "yoshi_egg_hunt": - required_yoshi_eggs = max(math.floor( - world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1) + if world.options.goal == "yoshi_egg_hunt": + required_yoshi_eggs = world.required_egg_count - add_rule(world.get_location(LocationName.yoshis_house, player), - lambda state: state.has(ItemName.yoshi_egg, player, required_yoshi_eggs)) + add_rule(world.multiworld.get_location(LocationName.yoshis_house, world.player), + lambda state: state.has(ItemName.yoshi_egg, world.player, required_yoshi_eggs)) else: - add_rule(world.get_location(LocationName.bowser, player), lambda state: state.has(ItemName.mario_carry, player)) + add_rule(world.multiworld.get_location(LocationName.bowser, world.player), lambda state: state.has(ItemName.mario_carry, world.player)) - world.completion_condition[player] = lambda state: state.has(ItemName.victory, player) + world.multiworld.completion_condition[world.player] = lambda state: state.has(ItemName.victory, world.player) diff --git a/worlds/smw/__init__.py b/worlds/smw/__init__.py index 431287c32b..1916108102 100644 --- a/worlds/smw/__init__.py +++ b/worlds/smw/__init__.py @@ -1,3 +1,4 @@ +import dataclasses import os import typing import math @@ -5,9 +6,9 @@ import settings import threading from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification -from .Items import SMWItem, ItemData, item_table -from .Locations import SMWLocation, all_locations, setup_locations, special_zone_level_names, special_zone_dragon_coin_names -from .Options import smw_options +from .Items import SMWItem, ItemData, item_table, junk_table +from .Locations import SMWLocation, all_locations, setup_locations, special_zone_level_names, special_zone_dragon_coin_names, special_zone_hidden_1up_names, special_zone_blocksanity_names +from .Options import SMWOptions from .Regions import create_regions, connect_regions from .Levels import full_level_list, generate_level_list, location_id_to_level_id from .Rules import set_rules @@ -50,11 +51,14 @@ class SMWWorld(World): lost all of his abilities. Can he get them back in time to save the Princess? """ game: str = "Super Mario World" - option_definitions = smw_options + settings: typing.ClassVar[SMWSettings] + + options_dataclass = SMWOptions + options: SMWOptions + topology_present = False - data_version = 3 - required_client_version = (0, 3, 5) + required_client_version = (0, 4, 4) item_name_to_id = {name: data.code for name, data in item_table.items()} location_name_to_id = all_locations @@ -62,9 +66,9 @@ class SMWWorld(World): active_level_dict: typing.Dict[int,int] web = SMWWeb() - def __init__(self, world: MultiWorld, player: int): + def __init__(self, multiworld: MultiWorld, player: int): self.rom_name_available_event = threading.Event() - super().__init__(world, player) + super().__init__(multiworld, player) @classmethod def stage_assert_generate(cls, multiworld: MultiWorld): @@ -72,37 +76,34 @@ class SMWWorld(World): if not os.path.exists(rom_file): raise FileNotFoundError(rom_file) - def _get_slot_data(self): - return { - #"death_link": self.multiworld.death_link[self.player].value, - "active_levels": self.active_level_dict, - } - def fill_slot_data(self) -> dict: - slot_data = self._get_slot_data() - for option_name in smw_options: - option = getattr(self.multiworld, option_name)[self.player] - slot_data[option_name] = option.value + slot_data = self.options.as_dict( + "dragon_coin_checks", + "moon_checks", + "hidden_1up_checks", + "bonus_block_checks", + "blocksanity", + ) + slot_data["active_levels"] = self.active_level_dict return slot_data def generate_early(self): - if self.multiworld.early_climb[self.player]: + if self.options.early_climb: self.multiworld.local_early_items[self.player][ItemName.mario_climb] = 1 - def create_regions(self): - location_table = setup_locations(self.multiworld, self.player) - create_regions(self.multiworld, self.player, location_table) + location_table = setup_locations(self) + create_regions(self, location_table) # Not generate basic itempool: typing.List[SMWItem] = [] - self.active_level_dict = dict(zip(generate_level_list(self.multiworld, self.player), full_level_list)) - self.topology_present = self.multiworld.level_shuffle[self.player] + self.active_level_dict = dict(zip(generate_level_list(self), full_level_list)) + self.topology_present = self.options.level_shuffle + + connect_regions(self, self.active_level_dict) - connect_regions(self.multiworld, self.player, self.active_level_dict) - # Add Boss Token amount requirements for Worlds add_rule(self.multiworld.get_region(LocationName.donut_plains_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 1)) add_rule(self.multiworld.get_region(LocationName.vanilla_dome_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 2)) @@ -110,18 +111,29 @@ class SMWWorld(World): add_rule(self.multiworld.get_region(LocationName.chocolate_island_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 5)) add_rule(self.multiworld.get_region(LocationName.valley_of_bowser_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 6)) - if self.multiworld.exclude_special_zone[self.player]: - exclusion_pool = set() - if self.multiworld.dragon_coin_checks[self.player]: - exclusion_pool.update(special_zone_level_names) + exclusion_pool = set() + if self.options.exclude_special_zone: + exclusion_pool.update(special_zone_level_names) + if self.options.dragon_coin_checks: exclusion_pool.update(special_zone_dragon_coin_names) - elif self.multiworld.number_of_yoshi_eggs[self.player].value <= 72: - exclusion_pool.update(special_zone_level_names) + if self.options.hidden_1up_checks: + exclusion_pool.update(special_zone_hidden_1up_names) + if self.options.blocksanity: + exclusion_pool.update(special_zone_blocksanity_names) + exclusion_rules(self.multiworld, self.player, exclusion_pool) total_required_locations = 96 - if self.multiworld.dragon_coin_checks[self.player]: + if self.options.dragon_coin_checks: total_required_locations += 49 + if self.options.moon_checks: + total_required_locations += 7 + if self.options.hidden_1up_checks: + total_required_locations += 14 + if self.options.bonus_block_checks: + total_required_locations += 4 + if self.options.blocksanity: + total_required_locations += 582 itempool += [self.create_item(ItemName.mario_run)] itempool += [self.create_item(ItemName.mario_carry)] @@ -137,31 +149,53 @@ class SMWWorld(World): itempool += [self.create_item(ItemName.green_switch_palace)] itempool += [self.create_item(ItemName.red_switch_palace)] itempool += [self.create_item(ItemName.blue_switch_palace)] + itempool += [self.create_item(ItemName.special_world_clear)] - if self.multiworld.goal[self.player] == "yoshi_egg_hunt": - itempool += [self.create_item(ItemName.yoshi_egg) - for _ in range(self.multiworld.number_of_yoshi_eggs[self.player])] + if self.options.goal == "yoshi_egg_hunt": + raw_egg_count = total_required_locations - len(itempool) - len(exclusion_pool) + total_egg_count = min(raw_egg_count, self.options.max_yoshi_egg_cap.value) + self.required_egg_count = max(math.floor(total_egg_count * (self.options.percentage_of_yoshi_eggs.value / 100.0)), 1) + extra_egg_count = total_egg_count - self.required_egg_count + removed_egg_count = math.floor(extra_egg_count * (self.options.junk_fill_percentage.value / 100.0)) + self.actual_egg_count = total_egg_count - removed_egg_count + + itempool += [self.create_item(ItemName.yoshi_egg) for _ in range(self.actual_egg_count)] + self.multiworld.get_location(LocationName.yoshis_house, self.player).place_locked_item(self.create_item(ItemName.victory)) else: + self.actual_egg_count = 0 + self.required_egg_count = 0 + self.multiworld.get_location(LocationName.bowser, self.player).place_locked_item(self.create_item(ItemName.victory)) junk_count = total_required_locations - len(itempool) trap_weights = [] - trap_weights += ([ItemName.ice_trap] * self.multiworld.ice_trap_weight[self.player].value) - trap_weights += ([ItemName.stun_trap] * self.multiworld.stun_trap_weight[self.player].value) - trap_weights += ([ItemName.literature_trap] * self.multiworld.literature_trap_weight[self.player].value) - trap_weights += ([ItemName.timer_trap] * self.multiworld.timer_trap_weight[self.player].value) - trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.multiworld.trap_fill_percentage[self.player].value / 100.0)) + trap_weights += ([ItemName.ice_trap] * self.options.ice_trap_weight.value) + trap_weights += ([ItemName.stun_trap] * self.options.stun_trap_weight.value) + trap_weights += ([ItemName.literature_trap] * self.options.literature_trap_weight.value) + trap_weights += ([ItemName.timer_trap] * self.options.timer_trap_weight.value) + trap_weights += ([ItemName.reverse_controls_trap] * self.options.reverse_trap_weight.value) + trap_weights += ([ItemName.thwimp_trap] * self.options.thwimp_trap_weight.value) + trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.options.trap_fill_percentage.value / 100.0)) junk_count -= trap_count trap_pool = [] for i in range(trap_count): - trap_item = self.multiworld.random.choice(trap_weights) + trap_item = self.random.choice(trap_weights) trap_pool.append(self.create_item(trap_item)) itempool += trap_pool - itempool += [self.create_item(ItemName.one_up_mushroom) for _ in range(junk_count)] + junk_weights = [] + junk_weights += ([ItemName.one_coin] * 15) + junk_weights += ([ItemName.five_coins] * 15) + junk_weights += ([ItemName.ten_coins] * 25) + junk_weights += ([ItemName.fifty_coins] * 25) + junk_weights += ([ItemName.one_up_mushroom] * 20) + + junk_pool = [self.create_item(self.random.choice(junk_weights)) for _ in range(junk_count)] + + itempool += junk_pool boss_location_names = [LocationName.yoshis_island_koopaling, LocationName.donut_plains_koopaling, LocationName.vanilla_dome_koopaling, LocationName.twin_bridges_koopaling, LocationName.forest_koopaling, LocationName.chocolate_koopaling, @@ -176,18 +210,18 @@ class SMWWorld(World): def generate_output(self, output_directory: str): rompath = "" # if variable is not declared finally clause may fail try: - world = self.multiworld + multiworld = self.multiworld player = self.player rom = LocalRom(get_base_rom_path()) - patch_rom(self.multiworld, rom, self.player, self.active_level_dict) + patch_rom(self, rom, self.player, self.active_level_dict) rompath = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.sfc") rom.write_to_file(rompath) self.rom_name = rom.name patch = SMWDeltaPatch(os.path.splitext(rompath)[0]+SMWDeltaPatch.patch_file_ending, player=player, - player_name=world.player_name[player], patched_path=rompath) + player_name=multiworld.player_name[player], patched_path=rompath) patch.write() except: raise @@ -243,7 +277,15 @@ class SMWWorld(World): if level_index >= world_cutoffs[i]: continue - if self.multiworld.dragon_coin_checks[self.player].value == 0 and "Dragon Coins" in loc_name: + if not self.options.dragon_coin_checks and "Dragon Coins" in loc_name: + continue + if not self.options.moon_checks and "3-Up Moon" in loc_name: + continue + if not self.options.hidden_1up_checks and "Hidden 1-Up" in loc_name: + continue + if not self.options.bonus_block_checks and "1-Up from Bonus Block" in loc_name: + continue + if not self.options.blocksanity and "Block #" in loc_name: continue location = self.multiworld.get_location(loc_name, self.player) @@ -271,7 +313,7 @@ class SMWWorld(World): return created_item def get_filler_item_name(self) -> str: - return ItemName.one_up_mushroom + return self.random.choice(list(junk_table.keys())) def set_rules(self): - set_rules(self.multiworld, self.player) + set_rules(self) diff --git a/worlds/smw/data/blocksanity.json b/worlds/smw/data/blocksanity.json new file mode 100644 index 0000000000..e3737d2597 --- /dev/null +++ b/worlds/smw/data/blocksanity.json @@ -0,0 +1,747 @@ +{ + "000_bonus": [], + "001_vanilla_secret_2": [ + ["yoshi", "0170", "0130", []], + ["green", "02F0", "0170", ["greenswitch carry", "greenswitch cape"]], + ["power", "0660", "0110", []], + ["power", "0B70", "0100", []], + ["multi", "0DC0", "0120", []], + ["gray", "0E70", "0120", []], + ["single", "1180", "0130", []], + ["single", "1190", "0130", []], + ["single", "11A0", "0130", []], + ["single", "11B0", "0130", []], + ["single", "11C0", "0130", []], + ["single", "11D0", "0130", []] + ], + "002_vanilla_secret_3": [ + ["power", "0270", "00D0", ["swim"]], + ["power", "06E0", "00E0", ["swim"]] + ], + "003_top_secret_area": [], + "004_donut_ghost_house": [ + ["vine", "0120", "0120", []], + ["dir", "0070", "0140", ["pswitch"]], + ["life", "0610", "0140", ["run cape"]], + ["life", "0640", "0140", ["run cape"]], + ["life", "0670", "0140", ["run cape"]], + ["life", "06A0", "0140", ["run cape"]] + ], + "005_donut_plains_3": [ + ["green", "01B0", "00E0", ["greenswitch"]], + ["single", "0450", "00F0", []], + ["single", "0480", "00F0", []], + ["vine", "04E0", "0130", ["mushroom spin"]], + ["power", "0BD0", "0140", []], + ["bonus", "1250", "00F0", []] + ], + "006_donut_plains_4": [ + ["single", "0660", "0130", []], + ["power", "0670", "0130", []], + ["single", "0680", "0130", []], + ["yoshi", "0AF0", "0150", []] + ], + "007_donut_plains_castle": [ + ["yellow", "01E0", "00C0", ["yellowswitch"]], + ["single", "00A0", "0680", []], + ["power", "00B0", "0680", []], + ["single", "00C0", "0680", []], + ["vine", "0050", "0450", []], + ["inlife", "0030", "0320", ["climb"]], + ["single", "0050", "0250", []], + ["single", "0080", "0250", []], + ["single", "00B0", "0250", []], + ["green", "0090", "0060", ["greenswitch"]] + ], + "008_green_switch_palace": [], + "009_donut_plains_2": [ + ["single", "00D0", "0120", []], + ["single", "00E0", "0120", []], + ["single", "00F0", "0120", []], + ["yellow", "0100", "0120", ["yellowswitch"]], + ["power", "0330", "00D0", []], + ["multi", "03C0", "00C0", []], + ["fly", "0820", "00E0", []], + ["green", "0560", "00E0", ["greenswitch"]], + ["yellow", "0050", "0140", ["yellowswitch"]], + ["vine", "02B0", "00E0", ["carry spin mushroom", "yoshi"]] + ], + "00A_donut_secret_1": [ + ["single", "02C0", "0130", ["swim"]], + ["single", "02D0", "0130", ["swim"]], + ["power", "02E0", "0130", ["swim"]], + ["single", "02F0", "0130", ["swim"]], + ["power", "00E0", "0480", ["swim"]], + ["power", "0060", "0250", ["swim balloon"]], + ["life", "0110", "0070", ["swim balloon"]], + ["power", "01A0", "0250", ["swim balloon"]], + ["power", "0570", "0150", ["swim"]], + ["key", "0940", "0150", ["swim carry pswitch"]] + ], + "00B_vanilla_fortress": [ + ["power", "04E0", "0130", ["swim"]], + ["power", "0220", "0130", ["swim"]], + ["yellow", "0780", "0110", ["yellowswitch swim"]] + ], + "00C_butter_bridge_1": [ + ["power", "08A0", "0110", []], + ["multi", "08B0", "00D0", []], + ["multi", "0860", "0090", []], + ["multi", "08E0", "0050", []], + ["life", "0840", "0050", []], + ["bonus", "0BD0", "0130", []] + ], + "00D_butter_bridge_2": [ + ["power", "0310", "0100", ["carry"]], + ["green", "0AC0", "0120", ["greenswitch"]], + ["yoshi", "0C70", "0110", ["carry"]] + ], + "00E_twin_bridges_castle": [ + ["power", "01B0", "0370", ["climb"]] + ], + "00F_cheese_bridge": [ + ["power", "00C0", "0140", []], + ["power", "0560", "00E0", []], + ["wings", "0A10", "0140", []], + ["power", "0B60", "0150", []] + ], + "010_cookie_mountain": [ + ["single", "01C0", "0130", []], + ["single", "01D0", "0130", []], + ["single", "01E0", "0130", []], + ["single", "01F0", "0130", []], + ["single", "0200", "0130", []], + ["single", "0210", "0130", []], + ["single", "0220", "0130", []], + ["single", "0230", "0130", []], + ["single", "0240", "0130", []], + ["power", "0200", "00F0", []], + ["life", "0A40", "0070", ["climb", "swim"]], + ["vine", "0B20", "0140", []], + ["yoshi", "0C40", "0140", ["redswitch"]], + ["single", "11C0", "0140", []], + ["single", "11D0", "0140", []], + ["power", "11E0", "0140", []], + ["single", "11F0", "0140", []], + ["single", "1200", "0140", []], + ["single", "1210", "0140", []], + ["single", "1220", "0140", []], + ["single", "1230", "0140", []], + ["single", "1240", "0140", []], + ["single", "1250", "0140", []], + ["single", "11B0", "0100", []], + ["single", "11C0", "0100", []], + ["single", "11D0", "0100", []], + ["single", "11E0", "0100", []], + ["single", "11F0", "0100", []], + ["single", "1200", "0100", []], + ["single", "1210", "0100", []], + ["single", "1220", "0100", []], + ["single", "1230", "0100", []], + ["single", "1240", "0100", []], + ["single", "1250", "0100", []], + ["single", "1360", "0140", []] + ], + "011_soda_lake": [ + ["power", "0200", "0110", ["swim"]] + ], + "012_test": [], + "013_donut_secret_house": [ + ["power", "0480", "0140", []], + ["multi", "0310", "0140", []], + ["life", "04A0", "0140", ["pswitch"]], + ["vine", "01E0", "0110", ["pswitch"]], + ["dir", "0180", "0130", ["pswitch"]] + ], + "014_yellow_switch_palace": [], + "015_donut_plains_1": [ + ["single", "0710", "0140", []], + ["single", "0720", "0140", []], + ["yoshi", "0D20", "00F0", []], + ["vine", "0DB0", "0130", []], + ["green", "11A0", "0070", ["greenswitch cape"]], + ["green", "11A0", "0080", ["greenswitch cape"]], + ["green", "11A0", "0090", ["greenswitch cape"]], + ["green", "11A0", "00A0", ["greenswitch cape"]], + ["green", "11A0", "00B0", ["greenswitch cape"]], + ["green", "11A0", "00C0", ["greenswitch cape"]], + ["green", "11A0", "00D0", ["greenswitch cape"]], + ["green", "11A0", "00E0", ["greenswitch cape"]], + ["green", "11A0", "00F0", ["greenswitch cape"]], + ["green", "11A0", "0100", ["greenswitch cape"]], + ["green", "11A0", "0110", ["greenswitch cape"]], + ["green", "11A0", "0120", ["greenswitch cape"]], + ["green", "11A0", "0130", ["greenswitch cape"]], + ["green", "11A0", "0140", ["greenswitch cape"]], + ["green", "11A0", "0150", ["greenswitch cape"]], + ["green", "11A0", "0160", ["greenswitch cape"]], + ["yellow", "1240", "0120", ["yellowswitch"]], + ["yellow", "1280", "0140", ["yellowswitch"]], + ["yellow", "1290", "0140", ["yellowswitch"]] + ], + "016_test": [], + "017_test": [], + "018_sunken_ghost_ship": [ + ["power", "0110", "0070", ["swim"]], + ["star", "0100", "0C80", ["swim"]] + ], + "019_test": [], + "01A_chocolate_castle": [ + ["yellow", "09C0", "0110", ["yellowswitch"]], + ["yellow", "0150", "0110", ["yellowswitch"]], + ["green", "0750", "0140", ["greenswitch"]] + ], + "01B_chocolate_fortress": [ + ["power", "0380", "0140", []], + ["power", "0360", "0150", []], + ["single", "0370", "0150", []], + ["single", "0380", "0150", []], + ["green", "0AC0", "0130", ["greenswitch"]] + ], + "01C_chocolate_island_5": [ + ["yoshi", "0170", "0130", []], + ["power", "0180", "0150", []], + ["life", "0340", "0170", ["carry", "cape"]], + ["yellow", "0560", "0140", ["yellowswitch pswitch"]] + ], + "01D_chocolate_island_4": [ + ["yellow", "0700", "0140", ["yellowswitch blueswitch"]], + ["pow", "0920", "00A0", []], + ["power", "0B50", "0040", []] + ], + "01E_test": [], + "01F_forest_fortress": [ + ["yellow", "02B0", "00E0", ["yellowswitch"]], + ["power", "0750", "00D0", []], + ["life", "0ED0", "0140", ["run cape"]], + ["life", "0F10", "0140", ["run cape"]], + ["life", "0F10", "0100", ["run cape"]], + ["life", "0F40", "0130", ["run cape"]], + ["life", "0F70", "0140", ["run cape"]], + ["life", "0F70", "00F0", ["run cape"]], + ["life", "0FA0", "0130", ["run cape"]], + ["life", "0FD0", "0140", ["run cape"]], + ["life", "0FD0", "0100", ["run cape"]] + ], + "020_forest_castle": [ + ["green", "0CC0", "0120", ["greenswitch"]] + ], + "021_chocolate_ghost_house": [ + ["power", "0910", "0140", []], + ["power", "0110", "0140", []], + ["life", "05D0", "0140", []] + ], + "022_chocolate_island_1": [ + ["fly", "0490", "0120", ["pswitch"]], + ["fly", "0CD0", "0100", ["pswitch"]], + ["yoshi", "0E10", "0110", ["pswitch"]], + ["green", "0F00", "0140", ["greenswitch blueswitch", "greenswitch cape", "yellowswitch blueswitch", "yellowswitch cape"]], + ["life", "0070", "0120", ["pswitch"]] + ], + "023_chocolate_island_3": [ + ["power", "0530", "0140", []], + ["power", "0A20", "0140", []], + ["power", "0F50", "00F0", []], + ["green", "1080", "00F0", ["greenswitch"]], + ["bonus", "11D0", "0140", []], + ["vine", "1220", "0140", []], + ["life", "1640", "0140", ["run cape"]], + ["life", "1670", "0140", ["run cape"]], + ["life", "16A0", "0140", ["run cape"]] + ], + "024_chocolate_island_2": [ + ["multi", "00E0", "00A0", []], + ["invis", "00F0", "00D0", []], + ["yoshi", "0280", "0040", []], + ["single", "0080", "0140", []], + ["single", "05C0", "0140", []], + ["multi" , "05F0", "0120", []], + ["power", "0620", "0100", []], + ["pow", "0040", "0140", []], + ["yellow", "0190", "0110", ["yellowswitch"]], + ["yellow", "01A0", "0110", ["yellowswitch"]], + ["green", "0240", "0110", ["greenswitch"]], + ["green", "0250", "0110", ["greenswitch"]], + ["green", "0260", "0110", ["greenswitch"]], + ["green", "0270", "0110", ["greenswitch"]], + ["green", "0280", "0110", ["greenswitch"]], + ["green", "0290", "0110", ["greenswitch"]] + ], + "101_yoshis_island_castle": [ + ["single", "0280", "00F0", ["climb"]], + ["single", "0290", "00F0", ["climb"]], + ["power", "02A0", "00F0", ["climb"]], + ["single", "02B0", "00F0", ["climb"]], + ["single", "02C0", "00F0", ["climb"]], + ["fly", "0250", "0150", ["climb"]] + ], + "102_yoshis_island_4": [ + ["yellow", "00D0", "00F0", ["yellowswitch"]], + ["power", "0160", "0140", []], + ["multi", "0290", "0140", []], + ["star", "04E0", "0120", []] + ], + "103_yoshis_island_3": [ + ["yellow", "0250", "00C0", ["yellowswitch"]], + ["yellow", "0290", "0140", ["yellowswitch"]], + ["yellow", "02F0", "00E0", ["yellowswitch carry", "yellowswitch yoshi", "yellowswitch run cape"]], + ["yellow", "0300", "00E0", ["yellowswitch carry", "yellowswitch yoshi", "yellowswitch run cape"]], + ["yellow", "0310", "00E0", ["yellowswitch carry", "yellowswitch yoshi", "yellowswitch run cape"]], + ["yellow", "0320", "00E0", ["yellowswitch carry", "yellowswitch yoshi", "yellowswitch run cape"]], + ["yellow", "0330", "00E0", ["yellowswitch carry", "yellowswitch yoshi", "yellowswitch run cape"]], + ["yellow", "0340", "00E0", ["yellowswitch carry", "yellowswitch yoshi", "yellowswitch run cape"]], + ["yellow", "0350", "00E0", ["yellowswitch carry", "yellowswitch yoshi", "yellowswitch run cape"]], + ["single", "04B0", "00A0", []], + ["yoshi", "04C0", "00A0", []], + ["single", "0AC0", "0140", []], + ["power", "0B00", "00C0", []], + ["yellow", "0CD0", "0120", ["yellowswitch"]], + ["yellow", "0CE0", "0120", ["yellowswitch"]], + ["yellow", "0DA0", "00F0", ["yellowswitch"]], + ["bonus", "10A0", "0080", []] + ], + "104_yoshis_house": [], + "105_yoshis_island_1": [ + ["fly", "0250", "0140", []], + ["yellow", "09C0", "0140", ["yellowswitch"]], + ["life", "0D10", "00F0", []], + ["power", "0F30", "0110", []] + ], + "106_yoshis_island_2": [ + ["fly", "0080", "00F0", ["carry", "yoshi"]], + ["fly", "00C0", "00E0", ["carry", "yoshi"]], + ["fly", "0130", "00F0", ["carry", "yoshi"]], + ["fly", "0140", "00D0", ["carry", "yoshi"]], + ["fly", "0180", "0100", ["carry", "yoshi"]], + ["fly", "01C0", "00E0", ["carry", "yoshi"]], + ["single", "0260", "0140", []], + ["yellow", "0270", "0140", ["yellowswitch"]], + ["single", "0280", "0140", []], + ["single", "0350", "0150", []], + ["yoshi", "0360", "0150", []], + ["single", "0B20", "0150", []], + ["yoshi", "0B30", "0150", []], + ["single", "0B40", "0150", []], + ["vine", "0C80", "0100", []], + ["yellow", "0DF0", "0120", ["yellowswitch"]] + ], + "107_vanilla_ghost_house": [ + ["power", "0200", "0100", []], + ["vine", "0750", "0150", []], + ["power", "0860", "0140", []], + ["multi", "0A00", "0140", []], + ["pow", "05E0", "0120", []] + ], + "108_test": [], + "109_vanilla_secret_1": [ + ["single", "0030", "0590", []], + ["power", "0040", "0590", []], + ["multi", "0110", "0490", []], + ["vine", "01B0", "0520", []], + ["vine", "0180", "0470", ["climb"]], + ["single", "0190", "0350", ["climb"]], + ["single", "01A0", "0350", ["climb"]], + ["power", "01B0", "0350", ["climb"]] + ], + "10A_vanilla_dome_3": [ + ["single", "01C0", "0140", []], + ["fly", "0200", "0160", []], + ["fly", "0230", "0120", []], + ["power", "02D0", "0110", []], + ["fly", "0480", "0150", []], + ["invis", "0800", "0130", []], + ["power", "0830", "0130", []], + ["multi", "0D90", "0120", []], + ["power", "03D0", "0130", []], + ["yoshi", "10A0", "0100", ["carry", "yoshi"]], + ["power", "1A60", "0140", []], + ["pswitch", "1E40", "0090", ["run cape pswitch"]], + ["pswitch", "1E50", "00A0", ["run cape pswitch"]], + ["pswitch", "1E60", "00B0", ["run cape pswitch"]], + ["pswitch", "1E70", "00C0", ["run cape pswitch"]], + ["pswitch", "1E80", "00D0", ["run cape pswitch"]], + ["pswitch", "1E90", "00E0", ["run cape pswitch"]] + ], + "10B_donut_secret_2": [ + ["dir", "00A0", "0170", []], + ["vine", "0220", "0100", []], + ["star", "0250", "0040", ["climb", "yoshi"]], + ["power", "0060", "0140", []], + ["star", "0B00", "0140", []] + ], + "10C_test": [], + "10D_front_door": [], + "10E_back_door": [], + "10F_valley_of_bowser_4": [ + ["yellow", "0370", "0130", ["yellowswitch"]], + ["power", "0210", "0130", []], + ["vine", "05E0", "0110", []], + ["yoshi", "0610", "0040", ["climb"]], + ["life", "07A0", "00D0", ["mushroom spin climb"]], + ["power", "0B60", "0110", ["yellowswitch climb"]] + ], + "110_valley_castle": [ + ["yellow", "0290", "0030", ["yellowswitch"]], + ["yellow", "0330", "0110", ["yellowswitch"]], + ["green", "0980", "0140", ["greenswitch"]] + ], + "111_valley_fortress": [ + ["green", "0220", "0140", ["greenswitch"]], + ["yellow", "0940", "0100", ["yellowswitch"]] + ], + "112_test": [], + "113_valley_of_bowser_3": [ + ["power", "0130", "0110", []], + ["power", "08A0", "00E0", []] + ], + "114_valley_ghost_house": [ + ["pswitch", "0160", "0100", ["pswitch"]], + ["multi", "0570", "0110", ["pswitch"]], + ["power", "00E0", "0100", []], + ["dir", "0270", "0140", ["pswitch"]] + ], + "115_valley_of_bowser_2": [ + ["power", "0330", "0130", []], + ["yellow", "0720", "0140", ["yellowswitch"]], + ["power", "0010", "00A0", []], + ["wings", "00D0", "0140", []] + ], + "116_valley_of_bowser_1": [ + ["green", "0810", "0140", ["greenswitch"]], + ["invis", "0D40", "0100", []], + ["invis", "0D50", "0100", []], + ["invis", "0D60", "0100", []], + ["yellow", "0D60", "0080", ["yellowswitch cape"]], + ["yellow", "0D60", "0090", ["yellowswitch cape"]], + ["yellow", "0D60", "00A0", ["yellowswitch cape"]], + ["yellow", "0D60", "00B0", ["yellowswitch cape"]], + ["vine", "0F20", "0120", []] + ], + "117_chocolate_secret": [ + ["power", "04A0", "0120", []], + ["power", "0960", "0140", []] + ], + "118_vanilla_dome_2": [ + ["single", "0240", "0100", ["swim"]], + ["power", "0250", "0100", ["swim"]], + ["single", "0260", "0100", ["swim"]], + ["single", "0270", "0100", ["swim"]], + ["vine", "03B0", "0100", ["swim"]], + ["inlife", "0720", "00F0", ["swim climb", "swim yoshi"]], + ["single", "0760", "00F0", ["swim climb", "swim yoshi"]], + ["single", "0770", "00F0", ["swim climb", "swim yoshi"]], + ["power", "0780", "00F0", ["swim climb", "swim yoshi"]], + ["power", "0880", "0100", ["swim climb", "swim yoshi"]], + ["power", "0730", "0040", ["swim climb", "swim yoshi"]], + ["power", "0D10", "0100", ["swim climb", "swim yoshi"]], + ["multi", "0290", "0130", ["swim climb", "swim yoshi"]], + ["multi", "1150", "0140", ["swim climb", "swim yoshi"]] + ], + "119_vanilla_dome_4": [ + ["power", "0690", "0100", []], + ["power", "0CB0", "0140", []], + ["single", "0E10", "0120", []], + ["single", "0E20", "0120", []], + ["single", "0E30", "0120", []], + ["life", "0E40", "0120", []], + ["single", "0E50", "0120", []], + ["single", "0E60", "0120", []], + ["single", "0E70", "0120", []], + ["single", "0E80", "0120", []], + ["single", "0E90", "0120", ["carry"]] + ], + "11A_vanilla_dome_1": [ + ["fly", "0250", "0110", []], + ["power", "0400", "0120", []], + ["power", "0450", "00E0", []], + ["single", "0460", "0120", []], + ["life", "04D0", "0120", []], + ["power", "0640", "0180", []], + ["vine", "0680", "00E0", ["carry", "redswitch"]], + ["star", "00F0", "00E0", []], + ["power", "13A0", "0140", ["run star", "run mushroom"]], + ["single", "17D0", "0150", ["run star", "run mushroom"]] + ], + "11B_red_switch_palace": [], + "11C_vanilla_dome_castle": [ + ["life", "0110", "0100", ["carry", "mushroom"]], + ["life", "0210", "0100", ["carry", "mushroom"]], + ["power", "03A0", "0130", []], + ["life", "0170", "0140", ["pswitch"]], + ["green", "0B90", "0140", ["greenswitch"]] + ], + "11D_forest_ghost_house": [ + ["single", "0950", "0110", []], + ["power", "0990", "0110", []], + ["fly", "0190", "0150", []], + ["power", "0370", "0140", []], + ["life", "0640", "0160", []] + ], + "11E_forest_of_illusion_1": [ + ["power", "01A0", "0110", []], + ["yoshi", "0360", "0130", []], + ["power", "0FA0", "0150", []], + ["key", "0E00", "0160", ["pballoon"]], + ["life", "0610", "0130", []] + ], + "11F_forest_of_illusion_4": [ + ["multi", "0540", "0140", []], + ["single", "05E0", "0140", []], + ["single", "05F0", "0140", []], + ["single", "0600", "0140", []], + ["single", "0620", "0140", []], + ["power", "0630", "0140", []], + ["single", "0640", "0140", []], + ["single", "0E30", "0140", []], + ["single", "0E40", "0140", []], + ["power", "0E40", "0100", []], + ["single", "0EF0", "0140", []], + ["single", "0F00", "0140", []], + ["single", "0EF0", "0100", []] + ], + "120_forest_of_illusion_2": [ + ["green", "0070", "0130", ["greenswitch swim"]], + ["power", "0480", "0040", ["swim"]], + ["invis", "0600", "0120", ["swim"]], + ["invis", "0610", "0120", ["swim"]], + ["inlife", "0620", "0120", ["swim"]], + ["invis", "0630", "0120", ["swim"]], + ["yellow", "0950", "0160", ["yellowswitch swim"]] + ], + "121_blue_switch_palace": [], + "122_forest_secret": [ + ["power", "0330", "00A0", []], + ["power", "0450", "0110", []], + ["life", "06A0", "00B0", ["blueswitch", "carry"]] + ], + "123_forest_of_illusion_3": [ + ["yoshi", "0350", "0150", []], + ["single", "04C0", "0150", []], + ["multi", "04D0", "0140", []], + ["single", "04F0", "0120", ["carry", "yoshi"]], + ["multi", "0D90", "0110", ["carry", "yoshi"]], + ["single", "0D80", "0150", ["carry", "yoshi"]], + ["single", "0D90", "0150", ["carry", "yoshi"]], + ["single", "0DA0", "0150", ["carry", "yoshi"]], + ["single", "0E40", "0140", ["carry", "yoshi"]], + ["single", "0E50", "0120", ["carry", "yoshi"]], + ["single", "0E70", "0150", ["carry", "yoshi"]], + ["single", "0E90", "0110", ["carry", "yoshi"]], + ["single", "0EB0", "0130", ["carry", "yoshi"]], + ["single", "0EE0", "0140", ["carry", "yoshi"]], + ["single", "0EF0", "0100", ["carry", "yoshi"]], + ["single", "0F10", "0120", ["carry", "yoshi"]], + ["single", "0F50", "0130", ["carry", "yoshi"]], + ["single", "0F70", "0150", ["carry", "yoshi"]], + ["single", "0F80", "0110", ["carry", "yoshi"]], + ["single", "0F90", "0130", ["carry", "yoshi"]], + ["single", "0FC0", "0150", ["carry", "yoshi"]], + ["single", "0FD0", "0120", ["carry", "yoshi"]], + ["single", "11A0", "0150", ["carry", "yoshi"]], + ["single", "11B0", "0120", ["carry", "yoshi"]], + ["single", "1230", "0150", ["carry", "yoshi"]], + ["single", "1240", "0140", ["carry", "yoshi"]], + ["single", "1250", "0130", ["carry", "yoshi"]] + ], + "124_test": [], + "125_special_zone_8": [ + ["yoshi", "0390", "0100", ["carry", "yoshi"]], + ["single", "04A0", "0130", []], + ["single", "04B0", "0130", []], + ["single", "04C0", "0130", []], + ["single", "04D0", "0130", []], + ["single", "04E0", "0130", []], + ["pow", "0560", "0140", []], + ["power", "05D0", "0140", []], + ["star", "0750", "00F0", []], + ["single", "0670", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0680", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0690", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "06A0", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "06B0", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "06C0", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "06F0", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0700", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0710", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0720", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0730", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0740", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "0750", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["multi", "0CA0", "0100", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "1100", "0120", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "1110", "0120", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "1120", "0120", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "1130", "0120", ["mushroom spin", "cape", "carry", "yoshi"]], + ["single", "1140", "0120", ["mushroom spin", "cape", "carry", "yoshi"]], + ["power", "13F0", "0140", ["mushroom spin", "cape", "carry", "yoshi"]], + ["fly", "1570", "00F0", ["mushroom spin", "cape", "carry", "yoshi"]] + ], + "126_special_zone_7": [ + ["power", "0350", "0150", ["mushroom"]], + ["yoshi", "0C80", "0140", ["mushroom"]], + ["single", "0F90", "0140", ["mushroom"]], + ["power", "0FA0", "0140", ["mushroom"]], + ["single", "0FB0", "0140", ["mushroom"]] + ], + "127_special_zone_6": [ + ["power", "0370", "00F0", ["swim"]], + ["single", "0610", "0140", ["swim"]], + ["single", "0630", "0120", ["swim"]], + ["yoshi", "0650", "0100", ["swim"]], + ["life", "07D0", "0140", ["swim"]], + ["multi", "0950", "0140", ["swim"]], + ["single", "0D80", "0140", ["swim"]], + ["single", "0D90", "0140", ["swim"]], + ["single", "0DA0", "0140", ["swim"]], + ["single", "0DB0", "0140", ["swim"]], + ["single", "0DC0", "0140", ["swim"]], + ["single", "0DD0", "0140", ["swim"]], + ["single", "0DE0", "0140", ["swim"]], + ["single", "0DF0", "0140", ["swim"]], + ["single", "0E00", "0140", ["swim"]], + ["single", "0E10", "0140", ["swim"]], + ["single", "0E20", "0140", ["swim"]], + ["single", "0E30", "0140", ["swim"]], + ["single", "0E40", "0140", ["swim"]], + ["single", "0E50", "0140", ["swim"]], + ["single", "0E60", "0140", ["swim"]], + ["single", "0E70", "0140", ["swim"]], + ["single", "0D80", "0100", ["swim"]], + ["single", "0D90", "0100", ["swim"]], + ["single", "0DA0", "0100", ["swim"]], + ["single", "0DB0", "0100", ["swim"]], + ["single", "0DC0", "0100", ["swim"]], + ["single", "0DD0", "0100", ["swim"]], + ["single", "0DE0", "0100", ["swim"]], + ["single", "0DF0", "0100", ["swim"]], + ["single", "0E00", "0100", ["swim"]], + ["single", "0E10", "0100", ["swim"]], + ["power", "0E20", "0100", ["swim"]], + ["single", "0E30", "0100", ["swim"]], + ["single", "0E40", "0100", ["swim"]], + ["single", "0E50", "0100", ["swim"]], + ["single", "0E60", "0100", ["swim"]], + ["single", "0E70", "0100", ["swim"]] + ], + "128_special_zone_5": [ + ["yoshi", "01D0", "0160", ["mushroom"]] + ], + "129_test": [], + "12A_special_zone_1": [ + ["vine", "0020", "03C0", []], + ["vine", "0050", "03C0", []], + ["vine", "0080", "03C0", []], + ["vine", "00B0", "03C0", []], + ["life", "0110", "0340", ["climb"]], + ["vine", "0120", "0280", ["climb"]], + ["pow", "0080", "01F0", ["climb"]], + ["vine", "00B0", "01F0", ["climb"]], + ["power", "00F0", "00D0", ["climb"]], + ["pswitch", "0190", "00C0", ["climb pswitch cape"]], + ["pswitch", "01C0", "0130", ["climb pswitch cape"]], + ["pswitch", "0180", "01A0", ["climb pswitch cape"]], + ["pswitch", "01D0", "01A0", ["climb pswitch cape"]], + ["pswitch", "01C0", "0270", ["climb pswitch cape"]], + ["pswitch", "01A0", "02C0", ["climb pswitch cape"]], + ["pswitch", "0190", "0310", ["climb pswitch cape"]], + ["pswitch", "01B0", "0370", ["climb pswitch cape"]], + ["pswitch", "0180", "03D0", ["climb pswitch cape"]], + ["pswitch", "0200", "0120", ["climb pswitch cape", "climb pswitch carry"]], + ["pswitch", "0210", "0130", ["climb pswitch cape", "climb pswitch carry"]], + ["pswitch", "0220", "0140", ["climb pswitch cape", "climb pswitch carry"]], + ["pswitch", "0230", "0150", ["climb pswitch cape", "climb pswitch carry"]] + ], + "12B_special_zone_2": [ + ["power", "02E0", "0120", []], + ["single", "0380", "0110", ["pballoon"]], + ["single", "0450", "0140", ["pballoon"]], + ["power", "04A0", "00F0", ["pballoon"]], + ["single", "05C0", "0150", ["pballoon"]], + ["single", "05C0", "00F0", ["pballoon"]], + ["power", "0760", "0140", ["pballoon"]], + ["multi", "07E0", "00E0", ["pballoon"]], + ["single", "0850", "0100", ["pballoon"]], + ["single", "0920", "0140", ["pballoon"]] + ], + "12C_special_zone_3": [ + ["power", "03F0", "0110", []], + ["yoshi", "0080", "0140", []], + ["wings", "0A50", "0140", []] + ], + "12D_special_zone_4": [ + ["power", "0490", "0140", ["flower"]], + ["star", "0AF0", "00F0", ["flower carry", "flower pswitch"]] + ], + "12E_test": [], + "12F_test": [], + "130_star_road_2": [ + ["star", "0460", "0130", ["swim"]] + ], + "131_test": [], + "132_star_road_3": [ + ["key", "0080", "0030", ["carry"]] + ], + "133_test": [], + "134_star_road_1": [], + "135_star_road_4": [ + ["power", "0540", "0090", []], + ["green", "0C00", "0140", ["greenswitch yoshi carry"]], + ["green", "0C10", "0140", ["greenswitch yoshi carry"]], + ["green", "0C20", "0140", ["greenswitch yoshi carry"]], + ["green", "0C30", "0140", ["greenswitch yoshi carry"]], + ["green", "0C40", "0140", ["greenswitch yoshi carry"]], + ["green", "0C50", "0140", ["greenswitch yoshi carry"]], + ["green", "0C60", "0140", ["greenswitch yoshi carry"]], + ["key", "0D40", "0160", ["carry yoshi", "greenswitch redswitch carry"]] + ], + "136_star_road_5": [ + ["dir", "0510", "0140", []], + ["life", "07D0", "0150", ["pswitch"]], + ["vine", "08E0", "0100", ["pswitch"]], + ["yellow", "08F0", "0050", ["yellowswitch pswitch climb carry", "yellowswitch specialworld yoshi carry"]], + ["yellow", "0900", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0910", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0920", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0930", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0940", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0950", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0960", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0970", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0980", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0990", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "09A0", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "09B0", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "09C0", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "09D0", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "09E0", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "09F0", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0A00", "0050", ["yellowswitch specialworld yoshi carry"]], + ["yellow", "0A10", "0050", ["yellowswitch greenswitch yoshi carry", "yellowswitch greenswitch pswitch climb carry cape"]], + ["yellow", "0A10", "0060", ["yellowswitch greenswitch yoshi carry", "yellowswitch greenswitch pswitch climb carry cape"]], + ["green", "0A20", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0A30", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0A40", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0A50", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0A60", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0A70", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0A80", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0A90", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0AA0", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0AB0", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0AC0", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0AD0", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0AE0", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0AF0", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0B00", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0B10", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0B20", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0B30", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0B40", "0080", ["greenswitch specialworld yoshi carry"]], + ["green", "0B50", "0080", ["greenswitch specialworld yoshi carry"]] + ], + "137_test": [], + "138_test": [], + "139_test": [], + "13A_test": [], + "13B_test": [] +} \ No newline at end of file diff --git a/worlds/smw/data/graphics/indicators.bin b/worlds/smw/data/graphics/indicators.bin new file mode 100644 index 0000000000000000000000000000000000000000..70e7036533c98150c4b24254ea55bb0470faacc7 GIT binary patch literal 384 zcmZRuF!1r%60sy>ipLg%GYl0B=)gcBAYp<+001SYgZ~ry?XZr8_ zzvVFbS`)d@|EcoTAo+8a3=9&f>6-yfoXyV37-1||jO2h0o@ z0Azk4uYC>BHNyXK$ct;pJ7~JDjTA`3&?`~AU_iy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVW#@zquT z>p}Evxq54mJOe|ulAZm2@B7jBvl$rv1NjQfVhr*O^^EhGAo5}i(hTv8@=Wr~F!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C4p{pbK>e<81Z z4bU~h|8dBRYsfojx~`2BNJG~Rv9FL9a9WY3=9RjW==PQq~qu2Gcf!I@)elH7~~o18Rs)W^GErg%>Vr%`nMbXPG?|J)_=gvfB``Ef915V zkyYNWejjK)IsnP<^_Um9CQ&bMLKV6!#J)makYD1HWh1y4C{B8we7N9TIhZ`ce<1mli8@)AtB~ap{sYNR;<+Uf ytqGAwcOgigh3^4Vr#Wu+HAw!P zB?E&*vPu2a`X4~O5d96zALV~C|M!RJ-){6foqS0 z4nXoC*J!$~jTA^jmxb5|@@c(we6nl=7lXXz5f=`>g7j?$_f7vp-Fwb*N{~eIoZ@&L znEMd^1G)DtGAkMJLe&yl+}*RT#*9^pTbydZ-((1j3rbQgl;A22>( odH^*aoBT1ykm6tUf9pAN(Pbg-F)^`nnV%}gSPyg`Driyx0DN|Hp8x;= literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/dollhouse.mw3 b/worlds/smw/data/palettes/level/castle_pillars/dollhouse.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..06849ceaf1d56e8efed4daa1df681ef3abcb1c59 GIT binary patch literal 514 zcmZQzxLe& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}p|2rA` z8kqg)3SjO#X^|iMwH93#VqYOI$S?89vJqSi@|H(jIQ$CIw;9|w{SUMc< kz>Hh|m}5xsulm3B9J%PaA?`6Tv2vN8D#ln3bRRkZ09~Db`2YX_ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/gold_caslte.mw3 b/worlds/smw/data/palettes/level/castle_pillars/gold_caslte.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f4c03d2cb17a6f69a5082b7016d2370311e332fd GIT binary patch literal 514 zcmZQzm{Z)xX~cGo$&z^v^MB^a#S9F;d0y*-=tADvatuIueHBv^YnT5K^@;XbAo0~z z|LZ~YY`J=CkURqeLO%n;|9S=n1!ge@d4_t%`AiUbkPQ&?Ve+*ma-siI<*PyR=PVf* zB$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3f88E`Wu)(%Kv2k?+?+x-RO5Z1Cs*t17-#c z05ZRj*S-em8sYyqg7j?$_f0|O zf!uS>a!Qay@|@y$9hmzN{sYPXXOw6D&%B+%9_U|)`w{*F@i}tW<{H)^%Om^;k{4tU z2Zk3!9^Hi?`3H;-m>xjQ$0mQwF{Joc{oi_yTy$B8drVBMT;`{WG1dd!hYC6b0FJqQ Al>h($ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/original_gray.mw3 b/worlds/smw/data/palettes/level/castle_pillars/original_gray.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..37143fb2b8892a981d671d3484adc747c5a55b6b GIT binary patch literal 514 zcmZQzxLdzi!NYKk?Kw*$yKP>Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVfR)m8uN zLGrWZ>a9WY3=D5P{ew0|iKgEMvi}3I0<#!{JVQO>d?tvz7=tuJJfl35JTpwb)nNdBB91A|1eN&VFNA8`E*%pc`{GXM97=-+PiJDq_^f%ySYKRN)}U&w1;19Xk> ze;o4S8uAXBu4^L&($IB7+*8O4@=JWOYy=mByyX!W4!?r*Z3g#ELFR${bIx)~kVNvF z;&>gH`w{*F$^U1RXa3K;oxvXHUx@z^{sZwja@Xb>)*;Iy{0EX3WDp027epT2g&_F{ oj1QO|K+VS{f6OtY_*ebkdX8LlS%`Z~Osrhyr;0Jw1Ko!X0BN&%n*aa+ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/original_green.mw3 b/worlds/smw/data/palettes/level/castle_pillars/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..4124e1900166d1399ba09d8b5064a1f79efbcc40 GIT binary patch literal 514 zcmZQzxLcpVxrFfrqYl$Vrmswsiy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe(j^$+Sn;;XCv zgX!6F_0}MH28N?5p1NywgOw!g85lsS6_~{sDDF2iBzduC(cB9|v3``2l4}kj70m%MBUi%uL zYlQ#fkQdjGchGcQ8!3>6t{Y-sAuq@;@yW6gTnzG-M_f4k3evY3+&2Z82XfCj%PBz; z$#aV1bzts8_zxuipHZIqKl645d!TByERXOXNM4XZ92i~@d2|D7f+HAw!P zB?E&*vPu2a`X4~O5d96zALV~C|M!RJ-){6foq*fP|1-)n|7YILU=Q>!#Qg~Wf%qJ`YjX|jkmV8n1IY_Ahy%k5B9HDuko*J22TTv3 l=3|pT<``1^tNw32M=rW7#62b^Rxa~X#Te^>?n4DivH+X+brk>r literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/original_white.mw3 b/worlds/smw/data/palettes/level/castle_pillars/original_white.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f235216f1da2e7d822ea64899b28253d7f7ab7da GIT binary patch literal 514 zcmZQzxLbeCPa-@jeop$m{Qu>Xiy0Vx^Sssv(Rb_XbwT9+dIkoC`iA-kKnN0FUG*PK z&z7sV2FWupyz%r8+7u<4ejCUJt7aBskY}i8oX-T27h{lSh-Z{%l4pj=*P6(M{!f*! z2FahZWMGg;HmRRl{{ybSf%&8SPv-yr5dGVYey1}qDKI|(>PH74`wMyPYk;m1{*Oam zTtnVL({*j6KpMJkh36e;jQyi}Y zb3ej=Ao>4{^34C4w=>uS{R{Cw!haw>NAB8O!#ZSng#SSDf(+uo@Pf#ryAUM*fbjv- n1E~4fvwiHViV{8TZJstYLNUnO9lpsWRv=-^*?}mA^IDbKg$1P{_hXbzuo9}Is=me^8=uMbO5rykk`Hj z=o;bwION4O8_2KP-t=7HRE&T>kS zMDm>CcpaGg5dH(n|7VnE{?ELf!5-*ei2D)#1MxX>*XA15A}FR tAo&N3511Z6&BrEx%rT_+SN-35j$CwEhU41pv|Hd71zK literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/purple_pink.mw3 b/worlds/smw/data/palettes/level/castle_pillars/purple_pink.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5bea72483006a71241be6d52843c36883e07f1b8 GIT binary patch literal 514 zcmZQzm{ZK5!|lSKAXKugrlNLoF$2SIp4a*yx{!Ca90O2ZU&YkK+U0*leWHC9NPKnG z|9TKTTdv+3B+tNrP{F|Pzn+0Xfmw_}o}r#`J`+S9Vgty0n0&2?Ty8QeDonFn&uIm;u4nX!7^4iw` zT_gM-hrGCkyo09e+DL&kblnj93VA_(iBFb|;9`)sJmSLPSCGEV;JzuyJdk_NSxyO( zNS;$1uLE-*!haz7|BUj?|CzTl*aQ6waX-R;AU;R#+FZjrWO;=DK=OhN;=u5N$fLUu rB>#Z%0n-Dh`Pk%-IffMfs{dQhk&7-1agT|KmCO88F~)kJ`_KUZh7Wj` literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/sand_green.mw3 b/worlds/smw/data/palettes/level/castle_pillars/sand_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5757d8fbfaa1584b28898d2532f44253d37fd77e GIT binary patch literal 514 zcmZQzxLdzmz(;YTZiv}7I}7j0#S9F;d0y*-=)3jxx*&3qf~szYX_x5}l^`#W`0A?v z^&on-T)j0&o`IoDR8MWA)n~U*Zw7|{K)wRA7=t`RJ>z^Ph`bnsG($Y2Jd->#Oup7c zF7$t@d^Je^oFxN;M6yZ!)cPMly%7Bk%pc`{GXM97=-+PiJDq_^f%ySYKRN)}U&w1; z19Xk>e;o4S8uAXBu4^L&($IB7>?`C2`6WJCHiC;m-tveGhhIVZHiP@7AoD=(IcGT~ zNFsSoal8)9eF*=7yYIU{sYMiGKd4i3nGv1 sLXi9e#s^Ffpyp$fKjs)x{Hy+NJx4COEW|w~CRQ%G0D^aT0RR91 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/shenhe.mw3 b/worlds/smw/data/palettes/level/castle_pillars/shenhe.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..93dc170a525e495da6d936d262e48c0a4db03d74 GIT binary patch literal 514 zcmZQzxLdzip^qm(RoL!hRC)H~Vg`oaJg@aZ^xgV;T@blQK~*=yw9E8~N{|;we0A0T zdJsKZuHG6X&%n^4tL3yIEHwKzko_Ns6_~{sBm4*AbL6hgHLOFHNB9pU-^X)B;HL;g p9^Hi?d5GU}%O7(LDgIUex1J*xT{px%CMH%c^Haqb>w)e=2LJ}Les}-? literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_pillars/whatsapp.mw3 b/worlds/smw/data/palettes/level/castle_pillars/whatsapp.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..198f46eca8a90c9fe2ebbad1e53e254daa9d12c0 GIT binary patch literal 514 zcmZQzxLd!7gPGSwaH;4sNp-o&#S9F;d0y*-=)3jxx*#%h<(PNSz@zquT z>p}Evxq54mJOe|E;8VfVdb!5e!WkI;1NjQfVhr*O^^EhGAo2>#4a^_qe=`5~hsoEP z$c6q-m9GZLpR;6OkVrPEpIZL|s28Fip&n%ZcB9|v3``2l511J+07$-&*S-em8sYyq zg7j?$_f0|Of!uS>a!Qay@|@y$ z9hmzN{sYPXXOw6D&%B+%9_U|)`w{*F@i}tW<{H)^%Om^;k{4tU2Zk3!9^Hi?`3H;- mm>xjQ$0mQwF{Joc{oi_yTy$B8drVBMT;`{WG1dd!hYkR=M0!a8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/dark_lava.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/dark_lava.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..477701e86a9bda2b95fd8b41c15acc4eedccd012 GIT binary patch literal 514 zcmZQzxLcnl(joFnCD-)4t6|vWVg`oaJg@aZ^xgV;T@aZnkSdU2x>}-5;GGOee0A0T zdJsKZuHG6X&%kg(hEr8bH{W!VB?H5MAYXx5j6t5Eo^d`CM4pRbBSQtFJd->#Oup7c zF7$t@d^Je^98i};vPu2a`X4~O5d96zALV~C|M!RJ-){6foq*fP|1-)n|7YILU=Q>!#Qg~Wf%qJ`YjX|jkmV8n1IY_Ahy%k5B9HDu tko*J22TTv3=3|pT<``1^tNw32M=rW7#62b^Rxa~X#Te^>?n4Es0syKqc#Z%7 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/dark_purple.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/dark_purple.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..29eff5aeffa30eeb48f5d158f3cdcba0f81e99d9 GIT binary patch literal 514 zcmZQzxLbczfnC$XFw1ha<6Ga!#S9F;d0y*-=)3jxx*#$|L{&G#ludPs#2H7B`0A?v z^&on-T)i~|!}cr&hNTk6HMmTD9M^|3F#NA)U{GKdV~}U4XPnQ(z+jQhz~Ijj!ciu8 zMX-zyCSPkJ7y3U{z8WO&rOCih7^WMyG3^V`EQtOF=8y6}ng9Dk^lvx%ovzILOtHg= z0Rw={*ORob`K~%k&Q>2o8f<@o$To>%3L2)}f!O7JL__6nYsDwaMsP96TOM)Y@GD5) zW^mv1KQqLB4#gfr0jDit+eKjRL-k*=sD#*Tq4gZs1Yz>X{$pU^$X%OjScfc+>OUWj z0FG@U5P5VLg8awAo508-hFgB6>E|T#?5g7P!0<;0ApIsLRxa~X#Te^>@qr4QH~`L| BZ(jfa literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/dollhouse.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/dollhouse.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..73f69240205bd32096a8b301ad63b7d04578b653 GIT binary patch literal 514 zcmZQzxLez^Ph`g1|ZVg$}d5-^mVe+*ma-siI<*PyR=PVf* zB$7?)r`G=f>V@cUVE!oolli|tME`c9-{~!~3d|3f8886I{&zC=H8A_p6~Nqg(jq_h zYc0Ag#J)makYD1HWh1y4RiKaf1c z?(GcrK>tGAkMJLe&yl+}*RT#*9^pTbyr~2zd?51ZE(FOxV0^&zfEl;^F~^YNU-f_M YIdai;L)>FxV&yVFRgAG7=st7+0M!V9?f?J) literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/forgotten_temple.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/forgotten_temple.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..35d97033f84735c0b0cf9a3d60736834483f3622 GIT binary patch literal 514 zcmZQzxLe;MaZDjgm(OgIQ<(SUVg`oaJg@aZ^xgV;T@blQK~*=y^r^}c2{m1i`0A?v z^&on-T)j0&o`KV@cUVE!oolli|tME`c9-{}lY3d|3H`q2T%{z6{+ z8lY>0|KpGs*N}J6bX^-MkcO@sVqYOI$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE} zK@!PxisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*{4vLn;$QWD>p61KWg+e{F|l%)pDM;!4|E?YNEQJAM7((c literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/original_gray.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/original_gray.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..37143fb2b8892a981d671d3484adc747c5a55b6b GIT binary patch literal 514 zcmZQzxLdzi!NYKk?Kw*$yKP>Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVfR)m8uN zLGrWZ>a9WY3=D5P{ew0|iKgEMvi}3I0<#!{JVQO>d?tvz7=tuJJfl35JTpwb)nNdBB91A|1eN&VFNA8`E*%pc`{GXM97=-+PiJDq_^f%ySYKRN)}U&w1;19Xk> ze;o4S8uAXBu4^L&($IB7+*8O4@=JWOYy=mByyX!W4!?r*Z3g#ELFR${bIx)~kVNvF z;&>gH`w{*F$^U1RXa3K;oxvXHUx@z^{sZwja@Xb>)*;Iy{0EX3WDp027epT2g&_F{ oj1QO|K+VS{f6OtY_*ebkdX8LlS%`Z~Osrhyr;0Jw1Ko!X0BN&%n*aa+ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/original_volcanic.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/original_volcanic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..21d82d7c84a14040cc3cd7c5df0feac6bf07fd93 GIT binary patch literal 514 zcmZQzxLdzi!NYKk?Kw*$yKP>Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVfR)m8uN zLGrWZ>a9WY3=BtAJayOV1}jO}Gcf!I@)elH7~~o18Rs)Wy8QeDonFn&uIm;Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVfR)m8uN zLGrWZ>a9WY3=AhC&lR1vG_c$3#lY|%$X8$%V~}U4XPnOjkr!i-W{78$XOd@z$=905 zh5k>KuLjAVvt(e9NH(dTTK@y67oxv``J?<#=KuZ>{o9Rxr!z1qFh2n5M+YGL3wiBp zfUXh#k3(KuL*7Btb#0_T8oF+XeTBRrzr-iYMsP96TOM)Y@GD5)W^msWWFE*p=PaiL zNhHrHj@N;?58*$M{C`Gy=Ksvw8SH`ng}5K#KM96#~ee7f7So3=g38ug}BGW#L8uUsu*KE(0%9t0F}Ubvj6}9 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/sand_gray.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/sand_gray.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5b11808ae6b95c2de07c589fc05b2662555af87b GIT binary patch literal 514 zcmZQzxLdzmz(;YTZiv}7I}7j0#S9F;d0y*-=)3jxx*&3qf~szY>3P)`B4u_U@zquT z>p}Evxq54mJW#|jAnZ$;X?9pP1H*qHUx8VSL7t(WaXu47UW`GSA)Zm5NuC)dUuz;4 z`ae~^8YF+tl7T@Y*`$7I{STmCi2erVkMcj6|NBGqZ#Vj#&cLL=`~avQ9f0gF zx<>dv4ta46c?V6`wUGj8=(-{H74m}o5}zy^!NnkNdBlaouONM!!F^MZc_8z^Ph`bnsG($Y2Jd->#Oup7c zF7$t@d^Je^oFxN;M6yZ!)cPMly%7Bk%pc`{GXM97=-+PiJDq_^f%ySYKRN)}U&w1; z19Xk>e;o4S8uAXBu4^L&($IB7>?`C2`6WJCHiC;m-tveGhhIVZHiP@7AoD=(IcGT~ zNFsSoal8)9eF*=7yYIU{sYMiGKd4i3nGv1 sLXi9e#s^Ffpyp$fKjs)x{Hy+NJx4COEW|w~CRQ%G01k0?!TBm4*AbL6hgHLOFHNB9pU-^X)B;HL;g p9^Hi?d5GU}%O7(LDgIUex1J*xT{px%CMH%c^Haqb>w)e=2LJ}Les}-? literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/water.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/water.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9822a3c2eaa268eda71e8bfbd8ae929ccf3836e0 GIT binary patch literal 514 zcmZQz*j0W+ro-@+t&Urs-DR)I#S9F;d0y*-=)3jxx(q=1MGC6A8K&u)iv?cWg2Y!> z{jUenv*qfoLGnpFZMx5Gy@S>#iDWY{{I6$VP+%5gkY}i8oX-T27vZ$v{mb}|t(F-k zUuz;4`ae~^8YKV5k%7T1ePa2R>K#BnM1KSGNBN)3|NSBQw;TOVf2e!F?twD{1_0Ur zLD0VDmRz*@ZG8-Bu=_T1SV?*qz7Eul!!DmEIYTejIX+o7f{Q`k@`wwEUqSjdgZrlc zf$jyF&*QW?%q)FIajh%NeW?Dk7OLmJrynAChYco=>_1@m1p4KDtV5PZ^9a+#kh##j%G4^)uE0{~N!gh2oR literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_small_windows/whatsapp.mw3 b/worlds/smw/data/palettes/level/castle_small_windows/whatsapp.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..198f46eca8a90c9fe2ebbad1e53e254daa9d12c0 GIT binary patch literal 514 zcmZQzxLd!7gPGSwaH;4sNp-o&#S9F;d0y*-=)3jxx*#%h<(PNSz@zquT z>p}Evxq54mJOe|E;8VfVdb!5e!WkI;1NjQfVhr*O^^EhGAo2>#4a^_qe=`5~hsoEP z$c6q-m9GZLpR;6OkVrPEpIZL|s28Fip&n%ZcB9|v3``2l511J+07$-&*S-em8sYyq zg7j?$_f0|Of!uS>a!Qay@|@y$ z9hmzN{sYPXXOw6D&%B+%9_U|)`w{*F@i}tW<{H)^%Om^;k{4tU2Zk3!9^Hi?`3H;- mm>xjQ$0mQwF{Joc{oi_yTy$B8drVBMT;`{WG1dd!hYkR=M0!a8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_wall/cheese.mw3 b/worlds/smw/data/palettes/level/castle_wall/cheese.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..913ad39778755fba300dd2b321b776473ff1f906 GIT binary patch literal 514 zcmZQzxLfZlc~RBW=%&>?`~AU_iy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVW#@zquT z>p}Evxq52`hW)_|4An|@_WQl>N8it8VEA9pz@We^#vsp7&p4k6q@RHSVFOIQ)nNdBB91A|1eN&VFNA3(Jb{SC|?<$p5&_lM};ZuC2yfk}b+0W$*z0GVINYhMF& zjqraQ^5Pou4w|lOBL&hhw1e#{`=%iCK<+tbIVDIU zc}{V>4$OTB|AFNHGs-jnXWq_W5A-j@{Rsbo_#C-wa}Dc|z^Ph`g1|ZVg$}d5-^mVe+*ma-siI<*PyR=PVf* zB$7?)r`G=f>V@cUVE!oolli|tME`c9-{~!~3d|3f8886I{&zC=H8A_p6~Nqg(jq_h zYc0Ag#J)makYD1HWh1y4RiKaf1c z?(GcrK>tGAkMJLe&yl+}*RT#*9^pTbyr~2zd?51ZE(FOxV0^&zfEl;^F~^YNU-f_M YIdai;L)>FxV&yVFRgAG7=st7+0M!V9?f?J) literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_wall/grand_marshall.mw3 b/worlds/smw/data/palettes/level/castle_wall/grand_marshall.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..574d557f1eadc3cf447eff1f3bce37bad9cd25f9 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM=jB5Q4;4SN#Xm zv*qfoLGla?OC+8taAKA^_iCET;rXB+n_1 z*MYeY;Xjc4e@1!c|IFJN?1BD;xF6v^5T7G=ZLVP*vOL0nAbCLsabS2sVg> ze;o4S8uAXBu4^L&(lE4x?JML3`6WJCHiC;m-tveGhhIVZHiP@7AoD=(IcGT~NFsSo zal8)9eF*=7yYIU{sYMiGKd4i3nGv1LXi9e o#s^Ffpyp$fKjs)x{Hy+NJx4COEW|w~CRQ%G0L;vM0|KpGs z*N}J6bX^-MkcO@s;+{fYkYD1HWh1y4h`dNd7;gJoA6%?F{xn|3dta@E?fJk-Ik6unt)s;XjbPAcHtCydd)EE(FOxV0^&z l0BSxq`D2bD#lPzR)^p^d%R<~^Vq)boKUIve9_T)F002widoTb1 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_wall/sand_green.mw3 b/worlds/smw/data/palettes/level/castle_wall/sand_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5757d8fbfaa1584b28898d2532f44253d37fd77e GIT binary patch literal 514 zcmZQzxLdzmz(;YTZiv}7I}7j0#S9F;d0y*-=)3jxx*&3qf~szYX_x5}l^`#W`0A?v z^&on-T)j0&o`IoDR8MWA)n~U*Zw7|{K)wRA7=t`RJ>z^Ph`bnsG($Y2Jd->#Oup7c zF7$t@d^Je^oFxN;M6yZ!)cPMly%7Bk%pc`{GXM97=-+PiJDq_^f%ySYKRN)}U&w1; z19Xk>e;o4S8uAXBu4^L&($IB7>?`C2`6WJCHiC;m-tveGhhIVZHiP@7AoD=(IcGT~ zNFsSoal8)9eF*=7yYIU{sYMiGKd4i3nGv1 sLXi9e#s^Ffpyp$fKjs)x{Hy+NJx4COEW|w~CRQ%G0D^aT0RR91 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_wall/shenhe.mw3 b/worlds/smw/data/palettes/level/castle_wall/shenhe.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..93dc170a525e495da6d936d262e48c0a4db03d74 GIT binary patch literal 514 zcmZQzxLdzip^qm(RoL!hRC)H~Vg`oaJg@aZ^xgV;T@blQK~*=yw9E8~N{|;we0A0T zdJsKZuHG6X&%n^4tL3yIEHwKzko_Ns6_~{sBm4*AbL6hgHLOFHNB9pU-^X)B;HL;g p9^Hi?d5GU}%O7(LDgIUex1J*xT{px%CMH%c^Haqb>w)e=2LJ}Les}-? literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_wall/water.mw3 b/worlds/smw/data/palettes/level/castle_wall/water.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a0955e820349da62f84748d19bd6cd4ad55b6f55 GIT binary patch literal 514 zcmZQz*j0W+ro-@+t&Urs-DR)I#S9F;d0y*-=)3jxx(p2A*^5P<$gnB8Yj&ve=z+vn zSN*RC(X-|1tr>v&lX%*6pWAu|txpokW?=YV&%mI-EXE+uP|rA@2_i4TX~FxK@gG|) zGfckLL@xAys(dv_{*5C8gIW5-@-5XnfP9Gl2Ii0QKbimgL-cPq`knqz_ki64X9f%a zvj2miea$VoX!YCr7}8+(ZRW6&^e}uKs2hh}K2LInUaWI`vTOtwgS_Pt7Y@II^lb+B zP5%Sk3o@U_X>*ua`i$aQSD5=y{bwyy&wo!pMDPw9Odi>P!0-w5%llY|ERX8HevWHA zGQ1FZbQgl`Kd5=otT`OF{7TD@N#)tQ%k{$0bwk{5Vq)boKUIve9vB~}Ac+S6-r|Dm literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/brawler_pink.mw3 b/worlds/smw/data/palettes/level/castle_windows/brawler_pink.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..69c496fc5d07949af94a1b203eb275589a595434 GIT binary patch literal 514 zcmZQzxLfaI5a>B2^hTsj+PXNJkw zn#hIzPnE9*$)B@iV30^Qsh?W^1E?0Fzk&Iq{7>fp{t*4!jee&yFexxU0P05vAoB}( z?Q4Lp5&n-uUR*=oLDO|@q(BRiKal)?MtSD{%-b34f&PWKAK^a`pCfl|u3;UrJi>ngPyZ1Tq(LyCXZ|E=f9MVE!R$Hc_SWqzs{V?EG)=l}o}uzREc literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/cheese.mw3 b/worlds/smw/data/palettes/level/castle_windows/cheese.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d91826e8647a061c9dcf6971e7b05f325e531e43 GIT binary patch literal 514 zcmZQzxLfZlc~RBW=%&>?`~AU_iy0Vx^Sssv(Rb_XbwT7Z9&O1S#S5y!T0fjX;;XCv z*MsQUa`o0Ac?O1RB|H25-uI*LXEQMT2l5q|#Teun>KW%VLFC04q#5EF<(cG}Ve+*m za-siI<*PyR=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3H`q2T%{z6{+ z8lY>0|KpGs*N}J6bX^-MkcO@sVqYOI$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE} zK@!PxisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*{4vLn;$QWD>p61KWg+e{F|l%)pDM;!4|E?o002{;d5-`9 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/dark_aqua_marine.mw3 b/worlds/smw/data/palettes/level/castle_windows/dark_aqua_marine.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..501f11d1a95448f15b53c23769d3654c04e315cc GIT binary patch literal 514 zcmZQzm{ZKaut4O11cPFN?g7imK;Cbj*ZLs3kaxBm15n<9qd@?s0wlh=>VG|mo-J2z z4U%VIfaq0lTM)*;@V}mcL4jF}L7t(WaXu47UW`GSA)Zm5NuC)dUuz;4`ae~^8YF+t zl7T@Y*`$7I{STmCi2erVkMcj6|NBGqZ#Vj#&cLL=`~avQ9oz-#DdhcM40Mg~e;o24 z*J!$~jTA^j*A1}`xjQ k$0mQwF{Joc{oi_yTy$B8drVBMT;`{WG1dd!hYFfh0I76y&;S4c literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/dollhouse.mw3 b/worlds/smw/data/palettes/level/castle_windows/dollhouse.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d3e5fe4b407f7e9f907cd0496673edce9147644b GIT binary patch literal 514 zcmZQzxLez^Ph`g1|ZVg$}d5-^mVe+*ma-siI<*PyR=PVf* zB$7?)r`G=f>V@cUVE!oolli|tME`c9-{~!~3d|3f8886I{&zC=H8A@b7#=V#m(8~{ z3xz0!x$mS!e(cv;4DDe13VA_(iBFb|;9`)sJmSLPSCGEV;J)d9pnV|soU@z~B#}I) zI9>#Z%0n-C! i-15g9LyCXZ|E=f9Mb`~+kBNzu%luR^#(JRp&;bA^{)5H< literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/original_brown.mw3 b/worlds/smw/data/palettes/level/castle_windows/original_brown.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..0bcc7305b7aa91c58bc8ebdca8f486cecebe6572 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kh!!%yFayJXAYXx5j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 vg&_F{j1QO|K+VS{f6OtY_*ebkdX8LlS%`Z~Osrhyr;0Jw1Ko!T4yynFNDg@( literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/original_gray.mw3 b/worlds/smw/data/palettes/level/castle_windows/original_gray.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..37143fb2b8892a981d671d3484adc747c5a55b6b GIT binary patch literal 514 zcmZQzxLdzi!NYKk?Kw*$yKP>Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVfR)m8uN zLGrWZ>a9WY3=D5P{ew0|iKgEMvi}3I0<#!{JVQO>d?tvz7=tuJJfl35JTpwb)nNdBB91A|1eN&VFNA8`E*%pc`{GXM97=-+PiJDq_^f%ySYKRN)}U&w1;19Xk> ze;o4S8uAXBu4^L&($IB7+*8O4@=JWOYy=mByyX!W4!?r*Z3g#ELFR${bIx)~kVNvF z;&>gH`w{*F$^U1RXa3K;oxvXHUx@z^{sZwja@Xb>)*;Iy{0EX3WDp027epT2g&_F{ oj1QO|K+VS{f6OtY_*ebkdX8LlS%`Z~Osrhyr;0Jw1Ko!X0BN&%n*aa+ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/original_water.mw3 b/worlds/smw/data/palettes/level/castle_windows/original_water.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d61f6dba36f6fca7c93c3764bd9a43c16022c64b GIT binary patch literal 514 zcmZQzxLfaJ$q{reODH)sdq(l(Vg`oaJg@aZ^xgV;T@VS8hmaug)m8uNLG*07dTWq8 z1H*~Pb48~u4eU01F);iG@)elH7~~o18Rs)Wy8QeDonFn&uIm;87j zo*5=zYa$o=KUKaOB!AA5fk7hKq<(7s51?9z{s!ic@;{mX`$P0^H~O8Bm4*AbL6hgHLOFHNB9pU-^X)B;HL;g p9^Hi?d5GU}%O7(LDgIUex1J*xT{px%CMH%c^Haqb>w)e=2LJ}Les}-? literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/underwater.mw3 b/worlds/smw/data/palettes/level/castle_windows/underwater.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..db5c1a996ccb3c7dd95ec0caee5079dbb9474eb4 GIT binary patch literal 514 zcmZQzxLe;Mb5w=R(A_e_ai!& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}pe<81Z z4bU~h|8dBRYsfojx~`2BNW;($wy%&E literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/water.mw3 b/worlds/smw/data/palettes/level/castle_windows/water.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a0955e820349da62f84748d19bd6cd4ad55b6f55 GIT binary patch literal 514 zcmZQz*j0W+ro-@+t&Urs-DR)I#S9F;d0y*-=)3jxx(p2A*^5P<$gnB8Yj&ve=z+vn zSN*RC(X-|1tr>v&lX%*6pWAu|txpokW?=YV&%mI-EXE+uP|rA@2_i4TX~FxK@gG|) zGfckLL@xAys(dv_{*5C8gIW5-@-5XnfP9Gl2Ii0QKbimgL-cPq`knqz_ki64X9f%a zvj2miea$VoX!YCr7}8+(ZRW6&^e}uKs2hh}K2LInUaWI`vTOtwgS_Pt7Y@II^lb+B zP5%Sk3o@U_X>*ua`i$aQSD5=y{bwyy&wo!pMDPw9Odi>P!0-w5%llY|ERX8HevWHA zGQ1FZbQgl`Kd5=otT`OF{7TD@N#)tQ%k{$0bwk{5Vq)boKUIve9vB~}Ac+S6-r|Dm literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/castle_windows/whatsapp.mw3 b/worlds/smw/data/palettes/level/castle_windows/whatsapp.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..198f46eca8a90c9fe2ebbad1e53e254daa9d12c0 GIT binary patch literal 514 zcmZQzxLd!7gPGSwaH;4sNp-o&#S9F;d0y*-=)3jxx*#%h<(PNSz@zquT z>p}Evxq54mJOe|E;8VfVdb!5e!WkI;1NjQfVhr*O^^EhGAo2>#4a^_qe=`5~hsoEP z$c6q-m9GZLpR;6OkVrPEpIZL|s28Fip&n%ZcB9|v3``2l511J+07$-&*S-em8sYyq zg7j?$_f0|Of!uS>a!Qay@|@y$ z9hmzN{sYPXXOw6D&%B+%9_U|)`w{*F@i}tW<{H)^%Om^;k{4tU2Zk3!9^Hi?`3H;- mm>xjQ$0mQwF{Joc{oi_yTy$B8drVBMT;`{WG1dd!hYkR=M0!a8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/brawler_dark.mw3 b/worlds/smw/data/palettes/level/cave/brawler_dark.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9197e99e15d5423640d948542383bfb75363a3f6 GIT binary patch literal 514 zcmZQzxLeP_;KVhqv@@r?3J^2{*#S`)d@ z|EcoTAo+8a3=9&f>6-yfoXyV37-1||jO2SEMk0Azn5uYC>B zHNyXK$ct;pJ7~JDjTA^j*A20+kQd~a_+;4#E(UqaBQ6|%1?k%i?wf+l1G(p%<&+?a zz^Pi2Ml=PT3sI^QJ~lF!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}pe<81Z z4bU~h|8dBRYsfojx~`2BNW;($wy%&Ek{G%$Kx@&cVl_czu-H(u8r)y-l&Fg2-XP|!ooydZ; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/brawler_red.mw3 b/worlds/smw/data/palettes/level/cave/brawler_red.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..e3f5cdfaaf02453750d8396e33a511a4682070f2 GIT binary patch literal 514 zcmZQzxLfaJ$q{reODH)sdq(l(Vg`oaJg@aZ^xgV;T@X1@;HHF);#^rdsW>T+`0A?v z^&on-T)j0&o`GRKZ>64*WVzx`Lk5QbK)wRA7=t`RJ>z^Pi2MYWDI7aEZgc$OfXUaI z$c6q-m9GZLpR;6OkVrPEpIZL|s28HYf%&8SPv-yr5dGVYey1}qDKI}^X21X-`wMyP zYk;m1{*OamTtnVL({*j6KpKX2uziKRAiu;X%SLc9$Xgz9;qWU+-)3;%6l5OAJ?AW^ z1W6>%DUR2Hxewt#koJstYLNUnO9lpsWRv=-^*?}mA^IDbKg$1P{_hXbzuo9}db%u^R*n$^1_0S#$ZKB% zbdB(TW(;Yt`@}Wm9W-6nMhc{1%7g4H`=%iCK=S7- zrvynP&nb@Afw>RiKal)?MtSD{%-b34f&PWKAK^a`pCfl|u3;UrJi>ngPyZ1N784{RHP5auJ|6WRR;`E|NRcH6vu27Lzl2LO!egcbk* literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/bright_magma.mw3 b/worlds/smw/data/palettes/level/cave/bright_magma.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..92e059d863c9d8cd0611069f71cf58ca5981004d GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@cB_;K9(tAjG(xv5E;KzPjpv zJ&2wyS8olHXJ9zV;V0Q9@& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}pe<81Z z4bU~h|8dBRYsfojx~`2BNW;($wy%&Ekd_;UAyB{IHPS?n8o7c~v&p`hG0DX~xDF6Tf literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/dark_red.mw3 b/worlds/smw/data/palettes/level/cave/dark_red.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b2cc6068059096dcbd367b40890b7fcb95dc6c47 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@dNalgg3K(;>j4sHX}NUtRUT z9z@TUtG5QpGcc%W_(`@1XsE7rWnlOZKuLjAVvt(e9NH(dTTK@y67oxv``J?<#=KuZ>{o9Rxr!z1qFh5{szyKio3wiBp zfUXh#k3(KuL*7Btb#0_T8isbTeTBRrzr-iYMsP96TOM)Y@GD5)W^msWWFE*p=PaiL zNhHrHj@N;?58*$M{C`Gy=Ksvw8SH`ng}5K#KM964w?^a8-ft#BjOX;{RsJWx<+=}ynY6K2Kom8j$nSo literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/glowing_mushroom.mw3 b/worlds/smw/data/palettes/level/cave/glowing_mushroom.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5b5531c7ef2d07ee1f87979af80c1999de696da1 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@dM};$_np&=SL5*j)+|UtRUT z9z@TUtG5QpGcXubU9EF5Xb;((!@%$#$X8$%V~}U4XPnOjk!R&x!JBO6;@%k!ldm^GErg%>Vr%`nMbXPG?|JV1B^NfB``E7xLQI z09_;eABViShP;EO>)J?xGz{%v`wDqMeu+<(jo@OCw>;v);a8Bp&EUQ%$UKmH&RI?g zl1QFY9Ipd&AHshi`Tvaa%>S9UGuQ+D3voZfe;__b?%G_#I%Ii-|3LDB4C27>g2LsJ19Kn3e<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! p|A6rU(*vma*yJ5FAJ{eoAd&PAbAFc3q|GSrqwg*Z`U(0{0CwMW-$hNhI+>NOc42t5}~p?WUI~osKMlG zP2@uVr^;7@he3GF!v+-Z>dBiU!3wjaZ|y0N-%k3|1FhJk6jU~U4|^*!2D7E zC-Z-Qi242sQ95&NA@b-h1o^L7u|+G@7`J?@p{Cc`IEXw*{WAqG%^t%Kx?8;<<{S8l Wr$=QYI#{KT7A}GU;qHv>5^{% literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/magma_cave.mw3 b/worlds/smw/data/palettes/level/cave/magma_cave.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ca297deb25781716a786e000559beb2390427ff0 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@abhk;&oB;mZ-kVa5UyUtRUT z9z@TUtG5QpGcasZykphPaf#zQ3j@P{AYXx5j6t5Eo^d`CL_UXSlfZP&Jz{qHF!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}pe<81Z z4bU~h|8dBRYsfojx~`2BNW;($wy%&Ekd_;UAyB{IHPS?n8o7c~v&p`hG07lq>ng9R* literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/original_chocolate.mw3 b/worlds/smw/data/palettes/level/cave/original_chocolate.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..db2693d6be989e7dbabb14dd22f313cae46319dc GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kh!!%yFayJXAYXx5j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 rg&_F{j1QO|K+VS{@1Xg>wjl^%J|aGm-H(u8r)y-l&Fg2-XP|!o@5h1T literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/original_gray.mw3 b/worlds/smw/data/palettes/level/cave/original_gray.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2e01f09820c82ddd4c95fe1fd2e947082ee462a3 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kgZ@?6nrO9Q*jUJMNXfqVsKF$Q^tddB%o5P2~MX@+=4c_w*gn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 rg&_F{j1QO|K+VS{@1Xg>wjl^%J|aGm-H(u8r)y-l&Fg2-XP|!o<;Z~^ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/original_ice.mw3 b/worlds/smw/data/palettes/level/cave/original_ice.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..6d17d16efefb033235542a15d3997fd2f80ec50b GIT binary patch literal 514 zcmZQzxLfaJ$q{reODH)sdq(l(Vg`oaJg@aZ^xgV;T@VS8hmaug)m8uNLG*07dTWsU z`_Qd<-^(oPtLyjHGcf!IVg+U~26={h#`#Pjc?O1)I)09qLo4!R;qtX6a-siI<*PyR z=PVf*B$7?)r`G>~%QrB8l>f>6-yfoXyV37-1||jO2h0o@0Azk4uYC>BHNyXK$ct;p zJ7~JDjTA`3&<=KQAuq@;@yW6gTnzG-M_f4k3evY3+&2Z82lCH3%PBz;$#aV1buj%0 zlK;;r&-|ZxJA*yYzYzZ;{0HK5k{G%$Kx@&cVl_czu-H(u8r)y-l&Fg2-XP|!oT`7oS literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/original_mustard.mw3 b/worlds/smw/data/palettes/level/cave/original_mustard.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..001ed133195bd4ed71a53ceedcb86de5716982b8 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%p4Kfmf-I)mUn~5d*`2AYXx5j6t5Eo^d`CL|%+RnjxN1o=Kh=CSPkJ z7y3U{z8WNd&XR#aBH5&VYW)wOUWon%=8y6}ng9Dk^lvx%ozB3d!2AHHA02?~FXXka z0lG%`KMr|u4S5Gm*R_!XY3RBk_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~ zB#}I)I9>+_kxeb;$Av|AFKM8N`9%1(8R0 rAxQoK;{&D#Q1h|LJ7_+zZ3se`kBCoX_ao%j=^EK>^ZFU|8R#DXk$itI literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/original_volcanic.mw3 b/worlds/smw/data/palettes/level/cave/original_volcanic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..96befdfa3d55f38e0766ba31d0118b851dd59beb GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6XkF1}8;XjbCz%0ff&rr`ep9vx_#vsiQ&nV9%&kU2VHIWPbpDJGsl0Rq3 zz#x%qQa`o+2T(6We*^PJ`Jc@H{UQ3d8~sjaU{YXy0Mw5TK=v2%+SdSGBm5tSytszE zgQn}+NP#qT-4OcLsJ19Kn3 ze<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6!|A6rU(*vma h*yJ5FAJ{eoAd&PAbAD`zBsY!LRE9UTYd}-|LYkT6qv;rN$Q#dGA!nmM*BD(EqJO4|jN=MV?xemv?D87~Z%NH_j!%}2;9`)sJmSLPSCGEV z;J)d9W{CcGu3O?P^Q+76gu>j9?7yWFk$iE=`@~HJ=PAMDk^Q$+LOpgxtacf)d;{}G z`Jc@H{UPT2D@5tcwS~x|yAb5RX2lk*RAb!ot%jOjYvUmDAob4_yfk|ZKj?1tf|zgM XC!QXajga?NU8^f(7Haibhk*eA6NZpJ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/toxic.mw3 b/worlds/smw/data/palettes/level/cave/toxic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a78538ddba77375eaf781000fd04c3c71426fffa GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@dNa(#mmMfI~D}a*ZTNe0A0T zdJsKZuHG6X&%nUtv?eTDR$uRm8w10CAYXx5j6t5Eo^d`CL|%+RnjxN1o=Kh=CSPkJ z7y3U{z8WNd&XR#aBH5&VYW)wOUWon%=8y6}ng9Dk^lvx%ozB3d!2AHHA02?~FXXka z0lG%`KMr|u4S5Gm*R_!XY3RBk_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~ zB#}I)I9>+_kxeb;$Av|AFKM8N`9%1(8R0 rAxQoK;{&D#Q1h|LJ7_+zZ3se`kBCoX_ao%j=^EK>^ZFU|8R#DXq4|G8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave/toxic_moss.mw3 b/worlds/smw/data/palettes/level/cave/toxic_moss.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9afe6110309837b40676296ef6a9d03876b2d874 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@cA2kSMWO=BNsrW|}TYe0A0T zdJsKZuHG6f&v25%Pjab*yQ!xc1H*ryc?!&84Dt;1jPscw@~pDyiZ3)fl(@BF^0g*% zq5o6mt3mSTEEyOil1=KT*8c$Nh3Ic!{wV*G`M*Cz|8}F_=?qK?%nz6uFaXH?g}nAP zK-UQW$00ASA@88+x;9cE4MRKFzCvD*U*eNxBe)pkEswZx_!XpYGq`UGG7sdQbCy$r zB$DS8$Lqk{hwvXr{y(EU^MB^;4E8|(Lfnt=ABfM9yEfOb4p|=IKajj2gE%m}AoA!g r1j#>Oe8BVoYCbl32h9hz4M7O=5%G!aeuVrwT_d|~UO$6A1N{R4q3?i> literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave_rocks/bocchi_rock_hair_cube_things.mw3 b/worlds/smw/data/palettes/level/cave_rocks/bocchi_rock_hair_cube_things.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..0fb33b2d6a380aa40e8ca073ed8350eb9bd2ac53 GIT binary patch literal 514 zcmZQzxLfZn6QX17`Y&=`l6>~$Vg`oaJg@aZ^xgV;T@dLZF+n54w9E9P&EHUv`0A?v z^&on-T)j0&o`K;+K=ywiR$vxmkY}i8oX-T2hnT+~Xg*B7)n zNdBB91A|1eN&VFNA8`E*%pc`{GXM97=-+PiJDq_^f%yS50|o%uU&w1;19Xk>e;o4S z8uAXBu4^L&(lE4x-CM{D@=JWOYy=mByyX!W4!?r*Z3g#ELFR${bIx)~kVNvF;&>gH z`w{*F$^U1RXa3K;oxvXHUx@z^{sZwja@Xb>)*;Iy{0EX3WDp027epT2g&_F{j1QO| WK+VS{@1Xg>wjl_&eu(?A%L4!^5PVbs literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave_rocks/brawler_volcanic.mw3 b/worlds/smw/data/palettes/level/cave_rocks/brawler_volcanic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5a3cf230f04df8c4c561247c61b8355424aecf8f GIT binary patch literal 514 zcmZQzxLZF>=epuwArsXbI=6Hu7c(&Y=6S6TqVLw%>w-uD$J*-cseHa~JjxS6;;XCv z*MsQUa`o0Ac?O0PDn7a!bR(6d?HL&U1NjQfVhr*O^^EhGpzy8QeDonFn&uIm;d&PAbAD`9?4QG)9M-Zx9b@g{sXZBvlxRsLp|esCW!n+iBQ=cvejmP)L`

z*`Q1+)(x zfaD8#)v$+8h#4DyyoTsZs+(zhAh zH~r5H(f`hMOPpnXb@`o8nER3aw^SmMFHU)%xT)YgC73+2|CUOq$F7LgE<=`YVE!oo zlli|t#C(5+D4n^s5P5VLg8bL4*rJtcj9nfS-VT}%Y#V~MGuQ*e8y$e;&sk0hl1Rob F4*)fog=hc( literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave_rocks/layer_2.mw3 b/worlds/smw/data/palettes/level/cave_rocks/layer_2.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ff354e34fefadbbee66984960563071d2397b343 GIT binary patch literal 514 zcmZQzxLdzi!NYKk?Kw*$yKP>Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVfR)m8uN zLGrWZ>a9WY3=AhC&lLfA!vC2W82$tK3d~{*@(lHi^O+#>Vhqv@@r?3J@^JZD6S>g; zsq)nz`E!;G3=+vE^;7GA0QExjH!y#c|H=H{AEJM|(eHEyCI#jPK>g?dWPc&AeGSZh zZ1Un7@(!A=Ya<2H&}AX^74m}o5}zy^!NnkNdBlaouONM!!F^Mhf6iG>36e;jQyi}Y zb05NgAou=flxP0Wyq&=w=wFEY5&i@5Ida$L8rC7pBm4)F7i16zh8IL0-Gw0e2aFGx X9ze~w|Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=O8|DnVfR)m8uN zLGrWZ>a9WY3=AhC&lR1vG_c$3#lY|%$X8$%V~}U4XPnOjkr!i-W{78$XOd@z$=905 zh5k>KuLjAVvt(e9NH(dTTK@y67oxv``J?<#=KuZ>{o9Rxr!z1qFh2n5M+YGL3wiBp zfUXh#k3(KuL*7Btb#0_T8oF+XeTBRrzr-iYMsP96TOM)Y@GD5)W^msWWFE*p=PaiL zNhHrHj@N;?58*$M{C`Gy=Ksvw8SH`ng}5K#KM964w?^a8-j4_hqxcRJOD($c&PvY literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave_rocks/original_mustard.mw3 b/worlds/smw/data/palettes/level/cave_rocks/original_mustard.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8150d4687553f90c4e65aea1f8b15d570836f2f6 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%p4Kfmf-I)mUn~5d*`2AYXx5j6t5Eo^d`CL|%+RnjxN1o=Kh=CSPkJ z7y3U{z8WNd&XR#aBH5&VYW)wOUWon%=8y6}ng9Dk^lvx%ozB3d!2AHHA02?~FXXka z0lG%`KMr|u4S5Gm*R_!XY3RBk_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~ zB#}I)I9>+_kxeb;$Av|AFKM8N`9%1(8R0 dAxQoK;{&D#Q1h|LJ7_+zZ3x1xAL4%O@&K0!ba?;( literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave_rocks/pyra_mythra_ft_pneuma.mw3 b/worlds/smw/data/palettes/level/cave_rocks/pyra_mythra_ft_pneuma.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8f2b2817d8054bed1bdfd8d9073a69fb4710f227 GIT binary patch literal 514 zcmZQzxLdzi!NYKk?Kw*}`)yv6iy0Vx^Sssv(Rb_XbwMPfV54M)X_slUVyh8Ie0A0T zdJsKZuHG6X&%kgZ@?6n6k((0xOc@yd1NjQfVhr*O^^EhGAo2@&oF$hiy6Umn!{lpC z*fj9Jyd&PAbAD`9?4RxLRE9UTYd}-|LYkT6qv;rN$Q#dGA!nmM*BD(EqJO4|jN=MV?xemv?D87~Z%NH_j!%}2;9`)sJmSLPSCGEV z;J)d9W{CcGu3O?P^Q+76gu>j9?7yWFk$iE=`@~HJ=PAMDk^Q$+LOpgxtacf)d;{}G z`Jc@H{UPT2D@5tcwS~x|yAb5RX2lk*RAcP&pzwCkd|=xUw4K2o7~bdrB!A9wN{~b{ Gc6k7U?u2Rp literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/cave_rocks/toxic.mw3 b/worlds/smw/data/palettes/level/cave_rocks/toxic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..4f98b11bc175b53cbc37e5cb633966e404599c40 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@bmPp}Evxq54mJOcxl)0(hsS$(}LZVU|nfqVsKF$Q^tddB%o5P2~MX@+=4c_w*gn0&2? zT;v);a8Bp&EUT2f2e!U zSxyO(NS;$1uLE-*!hazB{~6_(|1)oAum}1V;(mnxKzxqewYi3M$npsPf#d}l#DU=j gkwNOd$DV5~no`4J%Be++>1b z^0g*%q5o6mtAYITbC$;>B$B0){wB@OhRHWDf0X~p{NEpSFXXka0lG%` zKMr|u4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK r;{&D#Q1h|LA64#(3v!RL>Jd{_yEeDye)10J^1{^s?wEXP literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/clouds/cloudy.mw3 b/worlds/smw/data/palettes/level/clouds/cloudy.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b7d07d348c420a90492bdd105f53ec279a624841 GIT binary patch literal 514 zcmZQzkjVD5>UKKo#UC6PJvn)DF$2SIp4a*y`fh!_E{ObJ&%mHi-%$Sm2tnejtNw%O z*>d&P3=Ge8isKB!-utfg%y!hYWMBZRW)@?RXQ*eK&jixXz;IH>&+&3-MV>5>4Uw-k zkqiBwDqqb2v|rPdfuT6cr2bmk_cWM%1M^4upUnULA^Nu){Z40KQeb|-%zyzv<`?qX z*8p83{2zzBxQ4ugrt8{B0igNl0OX!RUXWknlVu~g800OFxN!Itq;E60ZwfLGB!A9w zN{~eIoZ@&LnEMd^1IhnqlxP0Wyq&=w=wEdIf%qJ`YjX|jkmV8n1IY_Ahy%k5B9F~| t4;UXXJ%E~zP5!8gr|w$aU?mBAbXkyllvR(Is@k==J@=D$K$pLk1^_(oe6auk literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/clouds/cotton_candy.mw3 b/worlds/smw/data/palettes/level/clouds/cotton_candy.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f9ddeb89c87de921311bde0f2cb67ef47e9d5d3d GIT binary patch literal 514 zcmZQzxKr}Q@k1h*xkFx3!Q&qb*x95KH4(Rg6^#CM7eq;au literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/clouds/original_green.mw3 b/worlds/smw/data/palettes/level/clouds/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..79af508740ade55e9958691a077933c26c99be22 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM=jB5Q4;4SN#Xm zv*qfoLGtfIx8{8>v#hVK-wRX;R?RHNAkR?GIG+h5&%kg}$ItO{XhohZT)x&sF7$t@ zd^Je^oFxN;M6yZ!)cPNA`3B~X@;{mX`$P0^H~O8`=%iCK>j&rIVDIUc}{V> z4yOM=^8Xp-ng26yXRrtQ7vg_}|3G|>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK;{&D# nQ1h|LA64#(3v!RL>Jd{_yEeDye)10J^1t%|+hKuC literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/clouds/original_orange.mw3 b/worlds/smw/data/palettes/level/clouds/original_orange.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..453b717b9038d5e68d016baa245dbfd5cd5c9e22 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM=jB5Q4;4SN#Xm zv*qfoLGtfIx8{8>v#hVK-wRX;R?RHNAkR?GIG+h5&%kg}$ItO{XhohZT)x&sF7$t@ zd^Je^oFxN;M6yZ!)cPNA`3B~X@;{mX`$P0^H~O8`=%iCK>j&rIVDIUc}{V> z4yOM=^8Xp-ng26yXRrtQ7vg_}|3G|>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK;{&D# nQ1h|LA64#(3vtgnT_d|~UO$6A1Kp1b=0^hn<}87Z literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/forest/agnian_queen.mw3 b/worlds/smw/data/palettes/level/forest/agnian_queen.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f187d8a1abb47b6d168742b1bdfb21058bb0908f GIT binary patch literal 514 zcmZQzxLcpYW1xE3vfR%){a*FtVg`oaJg@aZ^xgV;T@d-do`K;(okD#$$Afy1`0A?v zV0yM(y){Ulf#F(Ib$$-dz3Old1_qGoa1JpBd4_t%`AiV`Y~A;^#eNdWbAY-b^0g*% zq5o6mt3mSTEEyOil1=KT*8c$Ng~&HBf0X~p{NEp<05u<*{81H8-L<;GN)q;s~#~`wQF;G?kDenE+1YG0Ihs}V*mgE literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/forest/atardecer.mw3 b/worlds/smw/data/palettes/level/forest/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..95e07701c24ecfc33f23fff8746f0ddcdbea60a8 GIT binary patch literal 514 zcmZQzxL>Xzct-G|Qi$|y^}E)Siy0Vx^Sssv(Rb_Xbs2#2|LYkT9@Ht+Pvm}34-#Kp z^&d>nmaDf0$tUv|ivChu$@c_fn0r++K{1GEVuFUWn1`=0duWC(w|(eHFkHedD&>roS&TuRp`LL*6GVOvYaH8urYO#MEtq_*iCpOaRQYO%d~2$H zo?$(*d;{}G`Jc@H{UP!OELA+Qnh<$(7lQnElJzXx6?WY6M^!v^*Xjl<`ls^A#S9F;d0y*-=)3jxx*+m@Jp;poI)(aKGs1r$K1c4_T*EqKd4&H!@`4QF!0>{| wqq`6!|A6rU(*vma*yN9@cd>|hrpRN1ew%AW1c@9uFM84KU zF7$t@d^Je^oFxN;M6yZ!)cPMlwGjCR=8y6}ng9Dk^lvx%ozB3d!2E!j0Rw={FXXka z0lG%`KUBWUV6DYPhc7PTz7YN58uAXBu4^L&(lE4x?JML3`6WJCHiC;m-tveGhhIVZ zHiP@7AoD=(IcGT~2;};B9SC268R0*W{C`Gy=Ksvwf&PZcBm4)F=g3`~YgmUYkMJKz zUXVc?7+w&0bQgl;A22>(dH^*aoBUA~Pu;b;!AcVL=&~U9D61YZRkdq#d+sOifG*#v F008ilqjx)G5@nhd!tWiLb8u z52k0!)mww)85ovIXlfpF=rLsvWnciQW)Br(kY}i8oX-T2&(?i!TkI#1JO`*7B42AF z7y3U{z8WN-Wy!#BEonyG?mB6pUWj}H^GErg%>Vr%`nMbXPG?|JV1B^NfB``E7xLQI z09_;eABViShP;EO>)J?xGz{%v`wDqMeu+<(jo@OCw>;v);a8Bp&EUQ%$UKmH&RI?g z0=Yh32f|liM)(gT|DREw`9Je^2791?L3{;fg#SQ%j@-4mhIPpD2>*fP1sTMF;RTUL wcOgjr0pkOv2T=2|$sbkm)Lp9^tR!KNE(>yxvg#32Rl7E~=YH}I=<>R{09|l>m;e9( literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/forest/original_dark.mw3 b/worlds/smw/data/palettes/level/forest/original_dark.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..7c28daa0d3a68859aa714f1336a6023ff43ff20c GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=822~v$rZpe0A0T zdJsKZuHG6X&%m&rw^Hwcs*JV*GXukaAYXx5j6t5Eo^d`CL_S;hy=}3dMDiSo`l7xoIda$L8rC7pBm4)F7i16zh8IL0-Gw0e l2aFGx9ze~Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=OBPMnPct)m8uN zLGrWZ>a9WY3=A(Bc$NBCjit65F);iG^0ym_F~~F2GtOs%$Uo415L7Q3Z)EQcldm^GErg%>Vr%`nMbXPG?|JV1B^NfB``E7xLQI z09_;eABViShP;EO>)J?xGz{%v`wDqMeu+<(jo@OCw>;v);a8Bp&EUQ%$UKmH&RI?g zl1QFY9Ipf6D=;Jc2a^BKD9`+#c{_tW(7zzQ0yDyYAU;R#+FZjrWO;=DK=OhN;=u5N y$fLUuB>#Z%0n-Dh`Pk%-s(9+I)eTmXut%2#xkp*`h^eYwo7;0gc?Wd)-}wMS#eK>E literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/forest/original_green.mw3 b/worlds/smw/data/palettes/level/forest/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9139338c3158de0604b83766bdd3977d0b83e024 GIT binary patch literal 514 zcmZQzxLcpVxrFfrqYl$Vrmswsiy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe(g%n#~8;;XCv zgX!6F_0}MH28Q*#m3j|UWwaHT85lsS6_~{sKuLjAVvt(e9NH(dTTK@y67b4%l{89cV^M8Mc{_RG;(;1k6_5;mF2O#?kdF^X} zt`Yu^Ltb1%-a*rKZKOaNx^9Slg}flY#3#!}a52bR9&zFDD@fmFaNiVU9>_iCET;s4 zTpzCkb05NgAo>4{^34C4w=>uS{fq8D5T7G=ZLVP*vOL0nAbCLsabS2sIN%G*rUsW+@q{|#8lO;&F#6LyaT%Y?|cBq=7sYRqNJ7#KjRWy{1EH|p-7JF1*P6(M z{!f*!2FahZWMGg;HmRRl{{yHOqQ8Opqx?_i|NapD+l_vwKVW>o^njTG1Ay!= zx<>dv4ta46c?V6`wUGj87}~-174m}o5}zy^!NnkNdBlaouONM!!F^MZc_8$gLp7}rXb_RQ(e?fc&W`zGhe2(0;xrTMf@(BNdjt?;S@npis$HAgb3b_pbou$w0B{_E4gdfE literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/forest/snow_dark_leaves.mw3 b/worlds/smw/data/palettes/level/forest/snow_dark_leaves.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..320256986039c9f78b33679b884188f295190230 GIT binary patch literal 514 zcmZQz*jxTgMZ?zHwLkKGY-Qf$Vg`oaJg@aZ^xgV;T?U|hrt6#7O+}fmbILarfy7r= z{jUenv*qfoLGnu_-b-xPEQ*VEn^O+q&nYjKiPDiVjh6!P85lfG&$pnd27WPc&A zeNBa&js9F?bXkc0nI%n0&2?T}Q@kFFbH UzJBP3+=)d-<<&sq@`<{l7znNiM zDpzD%4U%7LyHvs=`%_VA`A#r@sl=ReW&acA@5O(IL(JQ5^gI2z?n$#%K>N@E$o@iJ z`z^Ph&xzPWq@=*V% z$F7LgE<=`YVE!oolli|tM8Cg6luoTBL>}FRApbQhwrHgq#S9F;d0y*-=)3jxx*)QNV-e305miYRNfl9$`0A?v z^&on-T)j0&UQtw0>YKuLjAVvt(e9NH(dTTK@y67oxv``J?<#=Kua6c?O2DvtMn}W;( zx#yhalpu-ZImPihF!v$+2a^BKD9`+#c{_tW(7zD(Bm4*AbL6hgHLOFHNB9pUFUTMc n3@?a0x(h+_4;UXXJ%E~zO}?P+a-CWI%zAkTbXiRIqpJV_gm8JI literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/brawler_orange.mw3 b/worlds/smw/data/palettes/level/ghost_house/brawler_orange.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..750def41f99befdaf52b901569f3800f2ec30359 GIT binary patch literal 514 zcmZQzxLfbSvYJO>O$TQS4&S!$ipW+bYEaAN-YUBiyuQibi z{humd4U#`+$-p3yY*Ih9{s&MmM1KSGNBN)3|NSBQw;TOVXJArbe!$Ft0YL66 zx<>dv4ta46c?V6`wUGj87}~-174m}o5}zy^!NnkNdBlaouONM!!F^MZc_83(z-0OQ1XrT_o{ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/brawler_purple.mw3 b/worlds/smw/data/palettes/level/ghost_house/brawler_purple.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..60ac884bf7af4d8c9496772c41d0ca1076fc2161 GIT binary patch literal 514 zcmZQzxLe;YvqI&qiGbr5pQxAE&j0O&q+0J5);7vz`tWZ4KV26@XPE*yRZ>DvtMn}W;($)B^F z5+sp4r#M~*=01e~K=S_?<(dC8Z)dOv`WNDUg#SQ%j@-4mhIPpD2>*fP1sTMF;RTV$ h=Dr7v511Z6&BrERPa9WY3=GReUdw!txhgVCfPvvZkgvcj#vsp7&p4k6B7a=srHqcMpJoBjJcxX)iCpOa zRQYO<{5eYo28m>o`l3&od9vlE)MSG0^ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/crimson_house.mw3 b/worlds/smw/data/palettes/level/ghost_house/crimson_house.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..fc7369f7efb1dfae084baefc9480880b4d48d64e GIT binary patch literal 514 zcmZQzu-9W@;9%fmkY=!FsaKp_%)s!Q=e0hFzFS|f3nHB?IfBk*K}eAJ>Zd&PAbAFcVAk1uvhwx%_w9lFdIkmsW-$hNhI+>NOc41MJi3CH1tY}%ioxV- zP2@uVr^;7@Dnt$bLai z`m-uAa2rdSB%Ofrveg)~<4DOr$2igZR z|GnmQyJ+{>@ph^(_o4bPo++OBzxXZIdSRG6vi}$uR5PFFzO6%+NA=%EmLDu~tPpv0 j7lQ16&iIDuD>H6+WcOjyf6j7BkVNvF;&>f&SuRlkZV-R8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/halloween_pallet.mw3 b/worlds/smw/data/palettes/level/ghost_house/halloween_pallet.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f73c16e461017810a7ea3e7ead5d0b1767b856f7 GIT binary patch literal 514 zcmZQzxLf~#!GZAr;{vM$?}yQoiy0Vx^Sssv(Rb_XbwQ+)B}dS?EC>k_UtRUT9z@TU ztG5QpGcdeoFlG#6oXxnOk%8eqkgvcj#vsp7&p4k6BF}3g5+Ic!U-Q2PCSPkJ7y3U{ zz8WNd&XR#aBH5&VYW)wOUWon%=8y6}ng9Dk^lvx%ozB3d!2E!j0Rw>SFXXka0lG%` zKMr|u4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK f;{&D#Q1h|L7t~#@GpnCjFYkaZi|Kw;748ZE4*`2g literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/orange_lights.mw3 b/worlds/smw/data/palettes/level/ghost_house/orange_lights.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8eddf82fd34ef08dc9bb833c177a38de28a82c74 GIT binary patch literal 514 zcmZQzxLbcrk_UtRUT9z@TU ztG5QpFOzwru}L*T>9^H9e+GvC^$ZLO%wi1k4E2ojnLzSOB#tV)($F&vwk>ys$=905 zh5k>KuLjAVvt(e9NH(dTTK@y67oxv``J?<#=KnzR?gGWO8~sjaU{YXyz|4RFK=OsW z_BBA)2>-_+FRmf)py|3cQXmaOJJ`NLUXWknlVu~g800OFxN!Itq;E60ZwfLGtGAkMJLe&yl+}*RT#*9^pTbydZ-(FuWl0 l=q?1wKVW>o^Z;r;Hu-|O%XMb;GwbCY&}A{*kE-IB3IHUlf8YQB literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/original_aqua.mw3 b/worlds/smw/data/palettes/level/ghost_house/original_aqua.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..fec63947beaad9cc35209b449c6dee93b0001380 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM=jB5Q4;4SN#Xm zv*qfoLGla?Cpr8iFKbrV$p$kpfK@Y#F~~F2GtOs%$e$45l+DpRZ))TOldmSFXXka0lG%` zKMr|u4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK f;{&D#Q1h|L7t~#@GpnCjFYkaZi|Kw;760o2ea(J8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/original_blue.mw3 b/worlds/smw/data/palettes/level/ghost_house/original_blue.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b46979edd84e64bd8aca975625ffd7f32daf5f44 GIT binary patch literal 514 zcmZQzxLfaJ$q{reODH)sdq(l(Vg`oaJg@aZ^xgV;T@VS8hmaug)m8uNLG*07dTWq8 z1H(xUKgr9Q6?U@03=IE)dy8QeDonFn&uIm;-nC?ea@xLAb1-g7- literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/original_dark.mw3 b/worlds/smw/data/palettes/level/ghost_house/original_dark.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..eb6152098a04082fe556948c8bc4f3cd45f58114 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kh!!%yFayJXAYXx5j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 kg&_F{j1QO|K+VS{Ur=|s&a8fBy}SduET;QWRUB3U06}tj(EtDd literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house/original_white.mw3 b/worlds/smw/data/palettes/level/ghost_house/original_white.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..0d5c43f3b913762f13d854b75c804a34075a0c6f GIT binary patch literal 514 zcmZQzxLbeCPa-@jeop$m{Qu>Xiy0Vx^Sssv(Rb_XbwT9+dIkoC`iA-kKnN0FUG*PK z&z7sV2FWupoaFG6ysTMaCmYPb09MT`#vsp7&p4k6B7Z`JQ#MEQys42BOup7cF7$t@ zd^Je^oFxN;M6yZ!)cPMlvmp8#m_N$@Wd83D(ZAj3cRB-;0`miA1`GhQzmV6y2Iv~$ z|2X8uHRK&MUDrkmq+w_W+gHd7@=JWOYy=mByyX!W4!?r*Z3g#ELFR$nbIx)~kVNvF z;&>gH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2g&_F{ gj1QO|K+VS{Ur=|s&a8fBy}SduET;QWRs6390KAxge;o4S8uAXBu4^L&(lE4x?JML3`6WJCHiC;m-tveGhhIVZHiP@7AoD=(IcGT~ zNFsSoal8)9eF*=7yYIU{sYMiGKd4i3nGv1 oLXi9e#s^Ffpyp%BBgY@QEXX~|sz*#!?b_U)`^h_?%g34n0E-uTmjD0& literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house_exit/golden_house.mw3 b/worlds/smw/data/palettes/level/ghost_house_exit/golden_house.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..45f5c6701ab330a23be3fb11143af114833973ce GIT binary patch literal 514 zcmZQz_@5mhctx^8?vGl%`hEAw#S9F;d0y*-=)3jxx*#$^piyG6%o7<-O>b3@`0A?v z^&on-T)j0&o`K;cho9tS%?dl&Uz^Pi2Ml=PT3sI^QJ~lF!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}pe<81Z z4bU~h|8dBRYsfojx~`2BNW;($wy%&EV!Z literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house_exit/original.mw3 b/worlds/smw/data/palettes/level/ghost_house_exit/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..3856df591aadbe01ae684091675ada83490c3846 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kh!!%yFayJXAYXx5j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 og&_F{j1QO|K+VS{kBC2XS&(~_Rgaje+O@eo_mg)(mp`lm0QE6=Z2$lO literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house_exit/original_blue_door.mw3 b/worlds/smw/data/palettes/level/ghost_house_exit/original_blue_door.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b43818c578274c2bf468d43dfca69633519d56e7 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kh!!%yFayJXAYXx5j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 gg&_F{j1QO|K+VS{@1Xg>wjl_&eu(?A$sbk$0QUZP6aWAK literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ghost_house_exit/underwater.mw3 b/worlds/smw/data/palettes/level/ghost_house_exit/underwater.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a92bc7a1ba7400a9bb69e641009d1e3b1a58ed09 GIT binary patch literal 514 zcmZQzxLe;MaZDk@kjt$nOfP+MF$2SIp4a*y`fh!_E{IGJXp~qi^F)SI(_0lJzPjpv zJ&2wyS8olHPZnvF;WnJ;7#8&_iGksNJp+RRvlxRsLp|esCXhS>!wC^i*&NODrbbRM z`C1dX(Eq9O)gXCKO9qDTY58d(#XEs~i2erVkMcj6|NBGC-){6fUEMIvPt~0P1Axpg zx<>dvGln$S{`=%iC zK=S7-rvynP&nb@Afw>RiKal)?MtSD{%-b34f&PWKAK^a`pCfl|u3;UrJi>ngPyOnKz^Lze})M_KiVsj6L@+jBp82XuK=T>yexeJ20_ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/atardecer.mw3 b/worlds/smw/data/palettes/level/grass_clouds/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2b055f2fe658d20e7e05d399ad5d48e13e1e5bd1 GIT binary patch literal 514 zcmZQzn4j-y)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T?U~1|9S=nh5CkiBjyM7Ao0~z z|H1TZxq52`hW$X1BEf2-SB!u3irFE2Bj&3tajf!e|JWe>T-}ehrGAphbAf6>>W!G^ zD8$&x`Prv~%wKQH!0y8QeGh53~+Mxx?nCvT9NRs%c;PD?c2Y3;S`)d@|EcoT5I$dKf39gAvU~&cNBN)3|NSBI z7g)qN>sTT3=q?1=|C;d~(t(wFPrI@RE-WFYc GpA`T}A$TkR literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/crimson.mw3 b/worlds/smw/data/palettes/level/grass_clouds/crimson.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..aefeb5d356809ad9276aa7faf8a38877aeeee7d1 GIT binary patch literal 514 zcmZQzxLe;Xa7p5aOoghI)9#?j#S9F;d0y*-=)3jxx*!rF?_{Z|^g{+DzPjpvJ&2wy zS8olHXJGJ=3~}lfxDob4hJoQfkgusE#vsp7&p4k6BA>1M-nQ6JB6$u_7ev0+L@xAy zs(dv_{+uNPgG92BWQFSPAeeju^GErg%>Vr%`nMbXPIs5oRO-=VzyKio3wiBpJ_-I( zla$Ah2D?vOL*79{H_P#KD5gBfJ%zj=zr-iYMsP96TOM)Y@GD5)W^mv1KQqKV=PaiL zfm|Q21K}$$Bm4)_53>6|^L7S%pnpMp1!jc*KzxYZ$npsPf#k&)#DU=jkw#M* literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/electro.mw3 b/worlds/smw/data/palettes/level/grass_clouds/electro.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8a3971982011180cb6e3848aeab88bbe6f8d4eef GIT binary patch literal 514 zcmZQzxLdzW$J_S2XGqk~tlIL)#S9F;d0y*-=)3jxx*&3y&T)g|CNC`1^dQFYIzQ@f0>VnAE zn#hIzPnE9*$)B@iV30`Wvjn*SCf~sPQT`|Me}9Pn?MA=T7xSvit=3||03iDddF^XL z)vojXXU32QyH8w0-a*r~KNRFXbO3TsAuq@;@yW6gTnzG-M_f4k3evY3+&2Z82a-Q$ zIVDIUc}{V>4ur43jPM^w9%A=)2791?L3{;fg#SSNQyyz`4eOBQ5&i?oZ(yllk!OI& qV{;$G@3`fUs(9+I)eTmXut(Poa*wj=5mQyWHn-<~@($?oD`Wt47Jw=M literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/geo.mw3 b/worlds/smw/data/palettes/level/grass_clouds/geo.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f085c6f368ebc772b2b379c8624fc2242376fe16 GIT binary patch literal 514 zcmZQzxLe;Qa8l%xYLwY-t3Otgiy0Vx^Sssv(Rb_XbwMOV-pP_*>ys)-e0A0TdJsKZ zuHG6X&%gjP;g1yq!+#*3UrUTZo}r#`J`+SfTlc+fv7bcp9H1_Ue65LG=>JstYLNUn zO9lps(w7lPy= ne#b3;RK-(wt!}WAggv@$kb9I>kC>|3wYfd_lXpOuU!w>B%ZGhr literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/miku.mw3 b/worlds/smw/data/palettes/level/grass_clouds/miku.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..3b009fbc0f67ca53fbc5c3e22315015100936092 GIT binary patch literal 514 zcmZQzxLcpBdPLXNZbO(!@{Hoi#S9F;d0y*-=)3jxx*#%HHO6e0A0T zdJsKZuHG6X&%kg*ubCwJY63JZAQ}b_@!{i&7Kg$1P{_hXbzuo9}x{A^pug&oc7yx8{A+LQ+ zrJ9ZSe`XA6u=~U{8_2KP-t=7HqT zSxyN8xjtS8!dGBM_zxuipHZIqKl645d!T+_kxeb;$Av|AFKM8N`9% u1(8R0AxIwLcii$vRXlaq>IN%G*rV$Pxkp*`h^eYwo7;0gc?WcPO+x@;f>6-yfoXyV37-1}32WK=aW7$o@iJ`x>BY zg#Y7^7uS$?&~#lJDUgP)8)9D}FUT+P$+8h#4DyyoTsZs+(zhAhHwBpoa?d%-DM29D z$Lqk{hwvXr{y(EU^MB^;4E8|(qWcfT=g3`~YgmUYkMJKzUXVc?7+w&0bQgl;A22>( pdH^*aoBUA~Pu;b;!AcVL=&~U9D61YZRkdq#d+sOifG*z<3jmy9dvyQ+ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/original_green.mw3 b/worlds/smw/data/palettes/level/grass_clouds/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..e896e0dce38ba4cab348a36f6cddc6ffc5476668 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM)=$`9VEMe09}- zFg;tY-Wnv&!0?iB4U<0eOy+;V3=Ck^%wi1k4E2ojnIQ5EK+tbtGAkMJLe&yl+}*RT#*9^pTbydZ-(FuWl0=q?1w tKVW>o^Z;r;Hu<9}p1NywgOw!g(PcsIQC2--s%qEf_S{e20bPD_F#v7?dvyQ+ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/pizza.mw3 b/worlds/smw/data/palettes/level/grass_clouds/pizza.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2be2f2db72ee79f505eab6693a29eed838d54c15 GIT binary patch literal 514 zcmZQzxLf~C)LgDYYp2moD=Fv6#S9F;d0y*-=)3jxx*+m@Jp+S6eM7wh^MiVj`0A?v zV0yM(y){Ulfg##xzH_kXFUDvi1_rQdW-$hNhI+>NOc418x(|ZtMdOX^yZjKK0Gb8S-@yD){wMQ)e~A9=M!(Y;n1J>(GhhIa{e`^tH9*%0 z{|C$eVg$Kp9?&i+XNZ1r4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ik zka-~YoU@z~B#}I)I9>+_kxeb;$Av|AFKM z8N`9%1(8R0AxQoK;{&D#Q1h|LA64#(3vtgnT_d|~UO$6A1Kp1b*7^Ye Dku864 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/sakura.mw3 b/worlds/smw/data/palettes/level/grass_clouds/sakura.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9a0d8d868733599bfcd7f029a0b2d63d8cc8a4d3 GIT binary patch literal 514 zcmZQzxLa=+I5qM|tWDbdEcxQe#S9F;d0y*-=)3jxx*+m@Jp;poI)(ZNOb_Zo;;XCv zgX!6F_0}MH28NfSg4$C8rkl%_F))BtGl?8Sp<`>HIWPb zpDJGsl0Rq3z#x%qQa`o+2hc2t{s!ic@;{mX`$P0^H~O9afDvdvGXn+y*yYIU{sYMiGKd4i3nGv1 qLXbSf@3`fUs(9+I)eTmXut(Poa*wj=5mQyWHn-<~@($?oH>&}N;DQ|h literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/shukfr.mw3 b/worlds/smw/data/palettes/level/grass_clouds/shukfr.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..635d22c98abbfad7a277830f284640cf9738a4aa GIT binary patch literal 514 zcmZQz*i-Lm)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM)=$`9VEMe09}- zFg;tY-Wnv&!0=qb%hXWfoTsG(0|Qt!vlxRsLp|esCWt%(5csQ@E7&T)4$OTB|AFNHGs-jnXWq_W5A-j@{Rsbo_#C-wa}Dc|<&Ua(>aNudR+6ws*9~%yvg#32Rl7E~=YH}I=<>N)09|Kyod5s; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_clouds/snow_day.mw3 b/worlds/smw/data/palettes/level/grass_clouds/snow_day.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8a7c632110cfc650f68e642d6947cbd6ec99feb4 GIT binary patch literal 514 zcmZQz*jv6__l2ptU5DSRIKA}A#S9F;d0y*-=)3jxx(q=1OxHKDn~E}BPnvBi0*SA# z`d<&CXUo-FgXEV=yqDOnSrixTHm4lIKWSDh6Qv_#8ZQOnGcb6Xo^>q@`<{l7znNiM zDpzD%4U%7LyHvs=`%_VA`A#r@sl-V$W&acA@5O(IL(JQ5^gI2z?n$#%K>N@E$o@iJ z`dRJkW-ynEPYMyg^vTOtwgS_Pt7Y@II^lb+BP5(1P z^uKf65@(rTU4AE&f#H8W1A_vy7=t`RJ>z^Ph&xzPWq@=*V% z$F7LgE<=`YVE!oolli|tM8Cg6luoTBL>}FRApbQhwrHgqK zuVw(+f6kJDK_b~M?0%L#kPp${!2D7EC-Z-Qi2m(Hztb6*fc7(kOhN@9`wMyPYk;m1 z{*OamTtnVL({*j6KpLuE5D#QuAuq@;@yW6gTnzG-M_f4k3evY3+&2Z82a-Q$IVDIU zc}{V>4$OTB|AFNHGs-jnXWq_W5A-j@{Rsbo_#C-wa}Dc|Xzct-G|Qi$|y^}E)Siy0Vx^Sssv(Rb_Xbs2#2|LYkT9@Ht+`?5c%2Z^t) z`VXdO%hg+hQp@|D0tqk3{nM^l!y~fHpzo1-Wl=-;=(d4B>A#`kk)H=F5J8odE-Y)SC#} z*WA&nH~-I%Aq_T9TtnWW)0HQ#FAuxCA+L>|y>Wc9Yy=mByyX!W4!?r*Z3g#E|1(4E zKW8~5NCN2kcpU}?P-rMHi!sPE)HBX!g2>Ndjbr=I6vY{@1(UBekqiBwDqjteZ%x(D zGpt9JZ(#l?|C9N@KSbVurHUt36C#i9LXiJXvYutT!j4=1sEViVTHRnJ343(iAoG<~ TkC>|3wYfd_lXpOu|8E8WyYGc- literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/autumn.mw3 b/worlds/smw/data/palettes/level/grass_forest/autumn.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..89d75ed27fcf43223f5e976be54ab643331df81c GIT binary patch literal 514 zcmZQzxLbdkg`YK;bsFn0)_S4I#S9F;d0y*-=)3jxx*+m@Jp;poI)(b1j1THT;;XCv zgX!6F_0}MH28K?Cjk5fVl1%gY7#KjRZ!(H8$TQS4&S!$iKhS*;R4*EDWbX}=uQibi z{humd4U#`+$-p3y93NaCzCRfz-@yD){wMQ)e~AA1Li5uF7;iGx1I?Q4Lp z5&qANE(_5wt|9MmQMJtMrW2+-$i0QUAiu;X%SLc9$Xgz9;qWU+-)3;%6l5Mq{+#8M zAc^ET#ql~2z5+ACe<1n)jPlI?nYT081KkJWD=;Jc2jX+&uFW;9LzYMQ4&p$GLK@zquT z!SrmodTWq81H(xUKS_VB3cDHZ3=AOEx4|E>{)r-a(*?Ys}Yfa=r z|EJ1VgXGUyGB8Lao77LO{{hqs(ci%QQT`|Me}9Pn?MA=TSMll!Z4hI?03iDddF^X} zt`Yvvj3EtnpSXs+gQn}+NP#p=d60dDydb~CC(A}~G00mUapCYQNZ)2~-xOpXNdBDV zlpu-ZImPih5WWI4!haz7|BUj?|CzTl*aQ6w;wvyC{0HK5^ZFU|8R&jgFw-9ZG>v^% literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/brawler_atardecer.mw3 b/worlds/smw/data/palettes/level/grass_forest/brawler_atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..39b73646578db2923e2f86ec21e12edbd0b9fd02 GIT binary patch literal 514 zcmZQzxLcnlaZ18hQdn%e)Lya4#S9F;d0y*-=)3jxx**b-=Oj>my{wLqq!LJcb=CiR z5ItM2-Wnv&z>v?gS9U7fed%a+28RDYzK)O>gFHh$<9sHF{0R|G*&NODrbbRM`C1dX z(Eq9O)gbwEmJAFM$tLwv>wf_CLi9H`=%iCK=S7- zrvynP&nb@Af$$ZW5&i?o|7VnE{?ELf!5-*75MO~A;Xe?cBX@1CVI8tO!haxnK?ZSP zctPaRT?mqY!1#da0n~hK@<&xXb=T?!D@oX+%Yxjata`*$)vnF$xu3iPy8Qfb0O-GY A8vpuiy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe)5LJ#Ue;;XCv zgX!6F_0}MH28QD@x{5C(E4=!d7#KjRb%ewi7BefLLl?e0m%G9Ui%uL zYlQzZqsv0{i)+X`Xu7VA6iCCA2iaH13-U{RvTOtwgS_Pt7Y@II^lb+BO+n^?xjQ$0mPN#Zz~!Zm^PsJ-RH&y~?UbOjYgL+@AZ%JD|&#YXbmxS9`<& literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/crimson.mw3 b/worlds/smw/data/palettes/level/grass_forest/crimson.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..48465a548a19ed8921f65ccd00a1ad546ca80666 GIT binary patch literal 514 zcmZQzxLe;Xa7p5aOoi$UKk4|%#S9F;d0y*-=)3jxx*!rF?_{Z|^g{+DzPjpvJ&2wy zS8olHXJGJ=3~}lfxDob4hJoQfkgusE#vsp7&p4k6BA>1M-nQ6JB6$u_7ev0+L@xAy zs(dv_{+uNPgG91P{nYv&K)n$82Ii0QKbimgL-cPq`kn4Bsj1YX$AAGq_80Qn*L)KE zr6wtlAq{q)xQ4ughHjSQ=}=60kbQ-`Aiu;X%SLc9$Xgz9;qWU+-)3;%^glDiJ?AW^ z1c6*1uLI#LFeCg2(*K`Pp7}rXb_RQ(e?fc&W`zGhe2(0;xrTMf@(BNd}Q@k1h*xkFx3!Q&qb*x95KH4(RePBmm@$eYXGr literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/deep_forest.mw3 b/worlds/smw/data/palettes/level/grass_forest/deep_forest.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..91517aa15e2782b262e319d208a44a90add1daac GIT binary patch literal 514 zcmZQzxLbcjhE>&7vrY53CcDz)Vg`oaJg@aZ^xgV;T@d-do`K;(okG0=^MiVj`0A?v zV0yM(y){Ulfnlk{a}{?@4qXi`1_qF71!ge@d4_t%`AiV`Y~A;^#eNdWbAY-b^0g*% zq5o6mt3mSTEEyOil1=KT*8c$Ng~&HBf0X~p{NEpB zHNyXK$ct;pJ7~JDjTA`3&*IA`?nC$wB>$gLp7}rXb_RQ(f6@I1;&bG#%{8n;mPhyxBrnJy4h%1dJh}@(@(&mv qFg<{pk4^rlil^>c-C!jNdvsZldz4j=n5x>fxjpxjcR-idFaiMJx_T1; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/electro.mw3 b/worlds/smw/data/palettes/level/grass_forest/electro.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d462646a48d82dfff712776db834061c36bd00a9 GIT binary patch literal 514 zcmZQzxLdzW$J_S2XGqk~tlIL)#S9F;d0y*-=)3jxx*&3y&T)g|CNC`1^dQFYIzQ@f0>VnAE zn#hIzPnE9*$)B@iV30^Qsh?W^1E?1w-@yD){wMQ)e~A9=M!(Y+^Qz0O)?&Z_Ao~k> z?Q25SuJiq8#*hZPPh3OZLDRKA6y!d10J5);7vz`tWZ4KV26@XPE*yRZ>DvtMn}W;( z$)B^F5+sp4r#M~*!dGBM_zxuipHZIqKl645d!TyYIU{sYNx zV5wk{XMo6KbKe8T2TTv3=3|pTs^Y1;RySBl!X8}~rESI7VW D=5&Fs literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/geo.mw3 b/worlds/smw/data/palettes/level/grass_forest/geo.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f085c6f368ebc772b2b379c8624fc2242376fe16 GIT binary patch literal 514 zcmZQzxLe;Qa8l%xYLwY-t3Otgiy0Vx^Sssv(Rb_XbwMOV-pP_*>ys)-e0A0TdJsKZ zuHG6X&%gjP;g1yq!+#*3UrUTZo}r#`J`+SfTlc+fv7bcp9H1_Ue65LG=>JstYLNUn zO9lps(w7lPy= ne#b3;RK-(wt!}WAggv@$kb9I>kC>|3wYfd_lXpOuU!w>B%ZGhr literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/miku.mw3 b/worlds/smw/data/palettes/level/grass_forest/miku.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5eeaf6c571d8d219c44d366e30490526be5b9bb5 GIT binary patch literal 514 zcmZQzxLcpBdPLXNZbO(!@{Hoi#S9F;d0y*-=)3jxx*#%HHO6e0A0T zdJsKZuHG6X&%kg*ubCwJY63Hg@Q|o^K^+Mzum_N$@Wd83D(ZAj3ce;ww8?Vjr3>W}pe<81Z zO{JQR_$X|VgmHRK)KEP4DkCSl5h>?`C2`6WJCHiC;m-tveGhhIVZHiP@7AoD=- z=PaiLfm|Q21K}$$Bm4)F|IaAT{GWL{gFVo{Aie@K!haw>NAB8O!#ZSng#SSDf(+uo v@Pf#ryAUJ~@jGt$qbi=dYjuN_B<#_3gWRL6dc;)KuFdVapS%OQe04DZCOLoB literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/myon.mw3 b/worlds/smw/data/palettes/level/grass_forest/myon.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8420ad56ec5c393fc3bbc514acca2b2ff72024a9 GIT binary patch literal 514 zcmZQzxLe;UvrOlt&0C*O5h00_iy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe(g%n#~8;;XCv zgX!6F_0}MH1_m|FbfcvT`R1CI3=AOE3d~{*@(lHi^O+#>&vmkG*Sb!Ln*-Dhk*_t8 z3;mxeUk#GavSnb{npRY0Ts;G*7b4%l{89cV^M8Mc{_RG;(^uFkFrVXRzyKio-;3DS z{8as?_MaI;8tlHw7Pmb(bh88XvoPgB_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~a zbCy$rB$DS8$Lqk{hwvXre!3yZ?#Ti&d@y;0|3LB@u4{8A)*;Iy{0EZvR}p8BXN1V3 vyAUM5!uA2vIey&oM^!v^*Xjlg; zsq)nz`E!;G3=+vE^;7GA0L_BvZ(#l?|C9N@KScj_qu=QaOhEgY8886I{z6{+8lY>0 z|KpGs*N}J6bX^-MkcOchY+oTS$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE}K@!Px zisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*{81H8-L<;GN)q;s~#~`wQF;G?kDenF8@0p0E3x(@Bjb+ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/original_green.mw3 b/worlds/smw/data/palettes/level/grass_forest/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..607d80cc9b924227a3a2735a68740982286b2b89 GIT binary patch literal 514 zcmZQzxLcpVxrFfrqYl$Vrmswsiy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe(g%n#~8;;XCv zgX!6F_0}MH28Q*#m3j|UWwaHT85lsS6_~{sKuLjAVvt(e9NH(dTTK@y67b4%l{89cV^M8Mc{_RG;(;1k6_5;mF2O#?kdF^X} zt`Yu^Ltb1%-a*rKZKOaNx^9Slg}flY#3#!}a52bR9&zFDD@fmFaNiVU9>_iCET;s4 zTpzCkb05NgAo>4{^34C4w=>uS{fq8D5T7G=ZLVP*vOL0nAbCLsabS2sIN%G*rUsW+@q{|#8lO;&F#6LyaT%Y{Ad8%aeFlY literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/pizza.mw3 b/worlds/smw/data/palettes/level/grass_forest/pizza.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2be2f2db72ee79f505eab6693a29eed838d54c15 GIT binary patch literal 514 zcmZQzxLf~C)LgDYYp2moD=Fv6#S9F;d0y*-=)3jxx*+m@Jp+S6eM7wh^MiVj`0A?v zV0yM(y){Ulfg##xzH_kXFUDvi1_rQdW-$hNhI+>NOc418x(|ZtMdOX^yZjKK0Gb8S-@yD){wMQ)e~A9=M!(Y;n1J>(GhhIa{e`^tH9*%0 z{|C$eVg$Kp9?&i+XNZ1r4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ik zka-~YoU@z~B#}I)I9>+_kxeb;$Av|AFKM z8N`9%1(8R0AxQoK;{&D#Q1h|LA64#(3vtgnT_d|~UO$6A1Kp1b*7^Ye Dku864 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/sakura.mw3 b/worlds/smw/data/palettes/level/grass_forest/sakura.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5b7627fe74f241ea63801075421c77925867eaf9 GIT binary patch literal 514 zcmZQzxLa=+I5qM|tWDbdEcxQe#S9F;d0y*-=)3jxx*+m@Jp;poI)(ZNOb_Zo;;XCv zgX!6F_0}MH28NfSg4$C8rkl%_F))BtGl?8Sp<`>HIWPb zpDJGsl0Rq3z#x%qQa`o+2hc2t{s!ic@;{mX`$P0^H~O9afDvdvGXn+y*yYIU{sYMiGKd4i3nGv1 qLXbSf@3`fUs(9+I)eTmXut(Poa*wj=5mQyWHn-<~@($?o^P>TXOo77y literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_forest/snow_dark_leaves.mw3 b/worlds/smw/data/palettes/level/grass_forest/snow_dark_leaves.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..47bbd42b97a73fb83d8db5e553e0c5f3033cd178 GIT binary patch literal 514 zcmZQz*jxTgMZ?zHwLkKGY-Qf$Vg`oaJg@aZ^xgV;T?U|hrt6#7O+}fmC(Sk$fy7r= z{jUenv*qfoLGnu_-b-xPEQ*VEn^O+qpEN6$iPDiVjh6!P85lfG&$pnd27WPc&A zeNBa&js9F?bXkc0nI%n0&2?T}Q@kFFbH UzJBP3+=)d-<<&sq@`<{l7znNiM zDpzD%4U%7LyHvs=`%_VA`A#r@sl-V$W&acA@5O(IL(JQ5^gI2z?n$#%K>N@E$o@iJ z`z^Ph&xzPWq@=*V% z$F7LgE<=`YVE!oolli|tM8Cg6luoTBL>}FRApbQhwrHgqId~8@zquT z!SrmodTWq81B13>aMJqF;Od<~Hb`}FwHSjuLp|esCW!n4-3LMSqVY!d-Z1%E6S>g; zsq)nz`E!;G3=+ww%8>OpFn^T)$^73RqW@>n{B)Q+0~!F?U&w1;19Xk>e`YjEAQvPr zt|9MmQMJtMrW2+-$i0QUAiu;X%SLc9$Xgz9;qWU+-)3;%6l5Mq{+#8MAc^ET#ql~2 zz5+ACe<1n)jPlI?nYT081N{r)D=;Jc2jX+&uFW;9LzYMQ4Kvt1pwb3iaKYGRN5WW%fRhBqbdA5IS5Pq)iN83_A$>g~}wIKCI%ySfCY~}py z(?RC1H)UY>88_ESF1#MdhsX!9|KR?|zCRqo4^#V{&c$TJ{DqkT1Ax_Y+Sgbs*-Ovo z#*hY^ca6oCRoAsYQYa0(d?0VM(toS?WZ4KV26@XPE*yRZ>DvtMoBjvd2Qq)XDa7^m zsxbGV`cIDS9$UQd6%IQon0&2?TSolGj921Dx8LWnqL%eTA}NPnEz5SPf1kSQvR0&y8J#X0HbqwMF0Q* literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_hills/brawler_green.mw3 b/worlds/smw/data/palettes/level/grass_hills/brawler_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..612dcce98c7e3a8d3af8774ca257640fb30e7d09 GIT binary patch literal 514 zcmZQzxLcnf(5kUq_qA%jlYacVG|mo-J2z z4U%VI==U@ZyPg(Z{2R#r55yKW%Vf#h3xvUT6v`WhK}-$;hZ*P6(M{!f*! z2FahZWMGg;HmRRl{{ybSf%&8SPv-yr5dGVYey1@VcCuK~J7_&*ML zaSeF~P1m)N0%_YB?164V1|atq@`C&lpDY`}#UO8a#D&AJAbp#`eN&KmAo+8aQ-UOt z=M=~5K==yG2>*fP|1-)n|7V7n4dN>>Bm4*AbL6hgHLOFHNB9pUFUTMc3@=Q#f!qm_ vf57;F=>gPyWVgfQkE(d;uGI}zlCVdY1?g8-Jz}bA*XH)zPu>At{#rBuHX?(a literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_hills/crimson.mw3 b/worlds/smw/data/palettes/level/grass_hills/crimson.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9f56757809fe1820e702f06d645f8ce224f5e40e GIT binary patch literal 514 zcmZQzxLe;Xa7p5aOoi$UKk4|%#S9F;d0y*-=)3jxx*!rF?_~Ky=7$VOe0A0TdJsKZ zuHG6X&%od#8RFC}a3k!83o`lMQd6l%j{yUK>@VcCulXeS zOHEQ9LmKQpaSeF~4c#oq)1jF1Ao~h=L4Ju(mW|+IkheVI!r@ntzRlpi>3?R3d(K%- z2?Du3UI)TgU`F^4r2jvoJoA6%?F{xn|AP1m%n1L1_#C-wa}Dc|nnBd23UT5b8{Vg`oaJg@aZ^xgV;T@VSA2dM#xude!E529zw)mww) z85mya2!!SNRHR)=WMKFYpk9c41M^4upUnULA^Nu){Z3!Zt1h=%iva_G>@VcCuL)JV&i9`g zLmKQpaSeF~P1pWVko(X9$i6~ekYD1HWh1y4ehUx69nKaf1c?(GcrK>vdH3d{)qf%p)+k>wHo1Ice-sbG<3fXHKW-vdUF-*L+y jRq@nas~fB&VUMmGrESI7VWUfF&r literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_hills/geo.mw3 b/worlds/smw/data/palettes/level/grass_hills/geo.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ac56278a9fc417e061935f664ead05f4f6eef3f3 GIT binary patch literal 514 zcmZQzxLe;Qa8l%xYLwY-t3Otgiy0Vx^Sssv(Rb_XbwMOV-pR60_LC||e0A0TdJsKZ zuHG6X&%gjP;g1yq!+#*3UrUTZo}r#`J`+SfTlc+fv7bcp9H1_Ue65LG=>JstYLNUn zO9lps(w7lPy= ne#b3;RK-(wt!}WAggv@$kb9I>kC>|3wYfd_lXpOuU!w>BobP?s literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_hills/miku.mw3 b/worlds/smw/data/palettes/level/grass_hills/miku.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..49c78fadba25456b64c583e363d2952b1b134ede GIT binary patch literal 514 zcmZQzxLcpBn&#vYogXBUJfnDWF$2SIp4a*y`fh!_E{KH4J6U=}dqji8S6BV72hp?T z>a9WY3=Bs^jwz^E@dHg^VE7N@zwr`dkY}i8oX-T2&(?i!TkI#1JO`)?B42AF7y3U{ zz8WNd&XR#aBH5&VYW)wOUWj}H^GErg%>Vr%`nMbXPFGQSSFXXkasZ_HO z|Idse4R)WnhP;EDC6C|6BusgbeTBRrzr-iYMsP96TOM)Y@GD5)W^msWWFAQVoaK}t zkn7`hAbbU8g#SSD{~6_(|1)oAum}1V#8+TO_z%SA$X%OjScfc+@E=HCkU<<6UJ!Y7 r7lPy=e#b3;RK-(wt!}WAggv@$kb9I>kC>|3wYfd_lXpOuuPz1v|F?d% literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_hills/mogumogu.mw3 b/worlds/smw/data/palettes/level/grass_hills/mogumogu.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..88af74ceafcba91876e6e5fa21300926b8c484cb GIT binary patch literal 514 zcmZQzxLfb*xiQhCsIu%SoK;TZ7~o z7>>zk8gkqIEDFkGVE7N@D=>>O$TQS4&S!$iKUeX#?GG$XvI6Rc$k&?4h5k>KuLj9; znldnyqzR>6D%%0n3z2VN{wV*G`M*Cz|8}F_>CY`(!&1B%FaXH@_b&D|5rK2v;)F4z z!S1_g6J`5c$H(^y(0%9tWM3gK$S?89vJqSi@|H(jIQ$CIw;9|w{m%?>56Jx>*GoCV z+=uWVNdJ2mDW^E$i#pLpFnNUkK=RKGa$`T{BFiKE2a-RfBkX9U36aOK|oLtPn@SEqgK8U_sU$4u6MSgYF|9X)8Y`J=CkSYd-lM2O_$)*x+ z%~lKy|ABl3W-$hNhI+>NOc42O-S@V|eiF%ZfVv>^wI*_*|5N3wLGtG;85kszP3ouC z{{ZTR$Tu*5l>f>6-yfoXyV39T2aF2L511J+0LcDAUi%uLYlQ#fkQdjGchGcQ8!3>6 zp&e{rAuq@;@yW6gTnzG-M_f4k3evY3+&2Z82XfCj%PB!1*T?I?+=uWVNd7;gJoA6% z?F{xn|DyX3#OKIen`>ByERXOXNM4XZ92i~@d2|V?QRFn^T)$^73RqJO*5?{o$x1?C4p^U(pw{z6{+8lY>0|KpGs z*N}J6bX^-MkcO@sVqYOI$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE}K_J)1>%iQH z@E=J2KchVJf9CBB_CWul`wztD$X%OjScfc+@E=HCkU<<6UJ!Y77lPy;Fg{><05u<* k{81H8-L<;GN)q;s~#~`wQF;G?kDenF5eIf0B9I`(*OVf literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_hills/sakura.mw3 b/worlds/smw/data/palettes/level/grass_hills/sakura.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..6c65dc4ff010fd8050c2c46162422816227149e3 GIT binary patch literal 514 zcmZQzxLa=+I5qM|tWDbdEcxQe#S9F;d0y*-=)3jxx*!rF4LkgXr0E_0}MH z28NfSg4$C8rkl%_F);iG@*gmXF~~F2GtOs%$fq0d#coP9&AM3xldm^GErg%>Vr%`nMbXPJh7ofaw7<0|o%uU&w1;19Xk>e;o4S z8uAXBu4^L&(lE4x?JML3`6WJCHiC;m-tveGhhIVZHiP@7AoD=(IcGT~NFsSoal8(M zufUA(A4vW`qdfC}=IspjK>vdH3d{)qf%qJ`YjX|jkmV8n1IY_Ahy%k5B9HDukUYfi lxaE(kc*5b`%OY)j>eY^y=?Yi*ZG zSY&@HDlOj$<}Z~vX{PLd!u-AX?{J8D+l_vwKi55JwhCw;Isn;U$ZKCyA!nmM*BD(E zqJO4|jH9OO+DL&k?D87~Z%NH_j!%}2;9`)sJmSLPSCGEV;J)d9W{CcGu3O?P^Q+76 zgfcMvuV-LTU>0MLXQ*eK&jgW=AjnAa9RB1Vg`oaJg@aZ^xgV;T?V*3L={MUb=CiR5ItM2-Wnv& zz+l8Ui_uNcUg)JH1H=D%28NfCVhr*O^^EhGAo5NPewpkk_@S>U>)j z2w#C2;Xjc49mYFM)y&%%WPtt!@fDa6{sZxka={cOgiA s0b>JG0@QqL@<&xXb=T?!D@oX+%Yxjata`*$)vnF$xu3iPx_pHd0O>G!F8}}l literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_hills/toothpaste.mw3 b/worlds/smw/data/palettes/level/grass_hills/toothpaste.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..7c108ae348aef9e50761a7f0a7d74da10b299434 GIT binary patch literal 514 zcmZQzxLf}|Bq;T2Wd&P zAbAD`1NOb~f5&9$ZiPS>I&l40_-CUT+wQ{}56 z<})w^r54wO)kf99`=*fndx!B3Q#JE81{t7#L3{;fg#SSNV>#KG=W3DV5&i?o^D~GtNHaj>(On3VU%=SF plmIm!oBUA~Pu;b;!AcVL=&~U9D61YZRkdq#d+sOifG!^w2mod`f?5Co literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/brawler_lifeless.mw3 b/worlds/smw/data/palettes/level/grass_mountains/brawler_lifeless.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b9979692f09e9982bd6cf352a4902c41a3a9ec31 GIT binary patch literal 514 zcmZQzh$wz3!>#D6nx{EIca!PlVg`oaJg@aZ^xgV;T@d-do`FH3zM+1L)q{GF`0A?v zV0yM(y){Ulf#IU1u+urs?O{en3=AOETdc$wKuVw(+uN%j}Ffr{@l}U94P%lKjf%&8SPv-yr5dGVYey0~2ZL#|1#()7p_80Qn z*8p83{GS;^8tguC4S5Gm*R_!XX_)dL`wDqMeu+<(jo@OCw>;v);a8Bp&EUQ%$UKnz zIm;*fP|1-)n|7YILU=Q>!h_Aqm@E?fJk-Ik6unt)s;XjbPAcHtC zydd)EE(FOxV0^&z0BSxq`J*bHx@&cVl_c!ZWkK#yRy|^>YS-rW+)v&CT|Uzi0Bt&d AMF0Q* literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/classic_sm.mw3 b/worlds/smw/data/palettes/level/grass_mountains/classic_sm.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..0e77cc017034d032ad060dd9c0430a989b4397d8 GIT binary patch literal 514 zcmZQzxLcngx=NB)$zSb~o~ZrgVg`oaJg@aZ^xgV;T@d-do`FH3zM-C1=|Me6e09}- zFg;tY-Wnv&!0=kcNAi;1B~?*-1_qF7UL`RGd4_t%`AiV`Y~A;^#eNdWbAY-b^0g*% zq5o6ms~H$>)t|FuV30^Qsb>n)E{DlCFn^T)$^73RqJO*5?{tV88886I{z6{+8lY>0 z|1)DqgWV^tA@88+x;9cE4O1TEoi+ z$o26$5WWI4!haz7|BUj?|CzTl*aQ6w;wvyC{0HK51M-nQ6JB6$u_7ev0+L@xAy zs(dv_{+uNPgG91P{nYv&K)n$82Ii0QKbimgL-cPq`kn4Bsj1YX$AAGq_80Qn*L)KE zr6wtlAq{q)xQ4ughHjSQ=}=60kbQ-`Aiu;X%SLc9$Xgz9;qWU+-)3;%^glDiJ?AW^ z1c6*1uLI#LFeCg2(hsuxKl645d!TIN%G*rV$Pxkp*`h^eYwo7;0gc?Wd)7ZLz$XMKkN literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/dry_hills.mw3 b/worlds/smw/data/palettes/level/grass_mountains/dry_hills.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..61bdc7b82e90d8eb3d7633cc8ac403b190bd9462 GIT binary patch literal 514 zcmZQzxLYr*RIatt>X%zg_`LMV#S9F;d0y*-=)3jxx*+m@Jp+S6eM9{(w+Hng@zquT z!SrmodTWq81A{N;CEj|m3ZeT(3=AOEzud$aKuLjAVvt(e9NH(dTTK@y67b4%l{89cV^M8Mc{_RG;(;+TozyKio3wiBpfUXh# z&x|1rcAvP0yo09e+DL&kOnH!fg}flY#3#!}a52bR9&zFDD@fmFaNiVU9!UP2<&+?h z>*IAGdnnBd23UT5b8{Vg`oaJg@aZ^xgV;T@VSASC`{-1c|S%`d<&CXUo-F zgX9?)Ug-#g<@r>kT}fnM_z&c(%ZV|_Gt@KAXM)I|Q0O%^^7^^Y~c?V6`{!ozn&;iK4LSB$x;*(_~xESOukGOF76{K%7xNizF4*fj5WA7(5&i?oZ(yllk!OI&V{_jFMv&ie l%O6$o)Lp9^tR!KNt{dbYWz{35s&;K|&;8^b(B)Ui0033aek1?@ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/geo.mw3 b/worlds/smw/data/palettes/level/grass_mountains/geo.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f085c6f368ebc772b2b379c8624fc2242376fe16 GIT binary patch literal 514 zcmZQzxLe;Qa8l%xYLwY-t3Otgiy0Vx^Sssv(Rb_XbwMOV-pP_*>ys)-e0A0TdJsKZ zuHG6X&%gjP;g1yq!+#*3UrUTZo}r#`J`+SfTlc+fv7bcp9H1_Ue65LG=>JstYLNUn zO9lps(w7lPy= ne#b3;RK-(wt!}WAggv@$kb9I>kC>|3wYfd_lXpOuU!w>B%ZGhr literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/late_sandish.mw3 b/worlds/smw/data/palettes/level/grass_mountains/late_sandish.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d94156adda5ccdb3b4b02e310e0ed7b0848dc653 GIT binary patch literal 514 zcmZQzxLdzT^Q*48QI**pD>?hg#S9F;d0y*-=)3jxx*+m@Jp+S6eM7wg^MiVj`0A?v zV0yM(y){Ulfg#XxyXkk!NT(Qo1_qF717d4_t%`Ai`B7c#o0lN`S|?g*>NhsoEP z$c6q-m9GZLYZ@{z6vxdriu2x|43lqQ{wV*G`9IJ+kom&uztb6*447v#GhhIae1M>R zO_Wl-@PBg*X|R5A4S9#>787F2i!kLu?k(g6`6WJCHiC;m-tveGhhIVZHiP@7|AF>_ z6e0A0T zdJsKZuHG6X&%kg*ubCwJY63Hg@Q|o^K^+Mzum_N$@Wd83D(ZAj3ce;ww8?Vjr3>W}pe<81Z zO{JQR_$X|VgmHRK)KEP4DkCSl5h>?`C2`6WJCHiC;m-tveGhhIVZHiP@7AoD=- z=PaiLfm|Q21K}$$Bm4)F|IaAT{GWL{gFVo{Aie@K!haw>NAB8O!#ZSng#SSDf(+uo v@Pf#ryAUJ~@jGt$qbi=dYjuN_B<#_3gWRL6dc;)KuFdVapS%OQe04DZCOLoB literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/original_aqua.mw3 b/worlds/smw/data/palettes/level/grass_mountains/original_aqua.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..fda1d358f7f2b177b30d191173455e744cd288e8 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM)=$`9VEMe09}- zFg;tY-Wnv&z_6aTQtyGPjJ5(Z0|Qt!vlxRsLp|esCWw5t?t9x}KZ)cyK;01eS`)d@ z|EcoTAo+8a3=9&f>6-yfoXyV37-1}32WK=aW7$o@iJ`x>BY zg#Y7^7uS$?&~#lJDUgP)8)9D}FUT+P$+8h#4DyyoTsZs+(zhAhHwBpoa?d%-DM29D z$Lqk{hwvXr{y(EU^MB^;4E8|(qWcfT=g3`~YgmUYkMJKzUXVc?7+w&0bQgl;A22>( pdH^*aoBUA~Pu;b;!AcVL=&~U9D61YZRkdq#d+sOifG+<#9{`a&UtRUT9z@TU ztG5QpGcc^@t<-ye3nE`@A{Y8U zRlXV|f6kJDK_c0tero*>pk9c41M^4upUnULA^Nu){Z40KQeb`nG#?#+>@VcCuK~J7 z_&*MLaSeF~P1m)N0%_>FA@&vWg8UMnEE~baAa8lZg~P8PeVf63Q;>Ne_nfnw5(IL6 zybjEL2>*fP|1-)n|7YILU=Q>!y8l3Yj@-4mhIPpD2>*fP1sTMF;RTULcOgjr0pkOv o2T=2|$sbkm)Lp9^tR!KNE(>yxvg#32Rl7E~=YH}I=<<_`0RyRe#Q*>R literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/original_green.mw3 b/worlds/smw/data/palettes/level/grass_mountains/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..607d80cc9b924227a3a2735a68740982286b2b89 GIT binary patch literal 514 zcmZQzxLcpVxrFfrqYl$Vrmswsiy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe(g%n#~8;;XCv zgX!6F_0}MH28Q*#m3j|UWwaHT85lsS6_~{sKuLjAVvt(e9NH(dTTK@y67b4%l{89cV^M8Mc{_RG;(;1k6_5;mF2O#?kdF^X} zt`Yu^Ltb1%-a*rKZKOaNx^9Slg}flY#3#!}a52bR9&zFDD@fmFaNiVU9>_iCET;s4 zTpzCkb05NgAo>4{^34C4w=>uS{fq8D5T7G=ZLVP*vOL0nAbCLsabS2sIN%G*rUsW+@q{|#8lO;&F#6LyaT%Y{Ad8%aeFlY literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/original_white.mw3 b/worlds/smw/data/palettes/level/grass_mountains/original_white.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..7ecd4e3ccb0b0228f86f96f78655c486e0fa97ee GIT binary patch literal 514 zcmZQzxLbeCPa-@jeop$m{Qu>Xiy0Vx^Sssv(Rb_XbwT9+dIkoC`i6Q1<_Gm4@zquT z!SrmodTWq81H*dWO1%fFGTI8v3=Ck^%wi1k4E2ojnIQ7ny6?Q4Lp z5&n-uUR*=oLDO|@q(BS9UGuQ+Di|#)VpCfl|u3;UrJi>ngPyZ1P7{JayOV1}jO}qsxNaqpW(wRMoD{?YW=41G;=eECAaqeH;J) literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/recksfr.mw3 b/worlds/smw/data/palettes/level/grass_mountains/recksfr.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b5da161c2cb5e88c2ff4bc3e1f18f50f7615122a GIT binary patch literal 514 zcmZQz*i#=EH#zA_mT10taYgy$Vg`oaJg@aZ^xgV;T@d-do`FH3zM)=$`9VEMe09}- zFg;tY-Wnv&!0=qb%k-GZIZyXU1_rQdW-$hNhI+>NOb~enAUI~?9?6vjldm2Sq0_~+#r)s0m%MBUi%uL zYlQzZqsoDJAbD{Oc?V6`wUGj8nDQX|3VA_(iBFb|;9`)sJmSLPSCGEV;JzuyJdpf3 z%PBz;$#aV1bzts8_zxuipHZIqKl645d!TByERXOXNM4XZ92i~@ wd2|KuV!F~FF$9=z#x%qQg55|FApZ)!2D7EC-Z-Qh<>}`-|4qq_Jr1^F<=0Y{e`^t zH9*%0|7XUK2D?vOL*7Btb#0^o7X2Xi6!L=n5}zy^!NnkNdBlaouONM!!F^MZc_8_7 zmQ#X2u8-G&@D-R5{sYPXXOw6D&%B+%9_U{XUx69nKMp34^=< literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_mountains/snow_day.mw3 b/worlds/smw/data/palettes/level/grass_mountains/snow_day.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..3b182c3b7b217548e4d21cbb60891d514920f601 GIT binary patch literal 514 zcmZQz*jpazG~MrK++;&ByIWC{iy0Vx^Sssv(Rb_Xbs2#2PL>=&=dzqEPnw;}0*SA# z`d<&CXUo-FgXEV=yqDOnSrixTHm4lIKWSDh6Qv_#8ZQOnGcb6Xo^>q@`<{l7znNiM zDpzD%4U%7LyHvs=`%_VA`A#r@sl-V$W&acA@5O(IL(JQ5^gI2z?n$#%K>N@E$o@iJ z`z^Ph&xzPWq@=*V% z$F7LgE<=`YVE!oolli|tM8Cg6l+IjRh&;LrLH=u2Y|%)$%WU0`5^fq_8;8;*!PD+)NePs8_vZf%=}H50Rw={GvbVA zwpOy2p3jXT4YuzZi!H0JYk#Cr8g}_W-e{%&R`JQQ5nK%NmPcGT{0h>y8QeGh&kV7D zy(z@?_NoxR5t{$x*zU2#3t!=|lY+_Dn#hIzPnEBR@cA% H@3R5`5-D~h literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/crimson.mw3 b/worlds/smw/data/palettes/level/grass_rocks/crimson.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9527a0a24af2fb9f4c4bd1a016fcf9439a3070fd GIT binary patch literal 514 zcmZQzxLe;Xa7p5aOoghI)9#?j#S9F;d0y*-=)3jxx*!rF?_{Z|^g{+DzPjpvJ&2wy zS8olHXJGJ=3~}lfxDob4hJoQfkgusE#vsp7&p4k6BA>1M-nQ6JB6$u_7ev0+L@xAy zs(dv_{+uNPgG91P{nYv&K)n$82Ii0QKbimgL-cPq`kn4Bsj1YX$AAGq_80Qn*L)KE zr6wtlAq{q)xQ4ughHjSQ=}=60kbQ-`Aiu;X%SLc9$Xgz9;qWU+-)3;%^glDiJ?AW^ z1c6*1uLI#LFeCg2(hsuxKl645d!TIN%G*rV$Pxkp*`h^eYwo7;0gc?Wd)7ZLz$XMKkN literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/dark.mw3 b/worlds/smw/data/palettes/level/grass_rocks/dark.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..1f6aa06a19e97ac792f2b8d18b06d5ffacd3550b GIT binary patch literal 514 zcmZQzxLcnjvQ&gavByxrX-d%KVg`oaJg@aZ^xgV;T@d-do`FH3zM-B)?Lj?Ae09}- zFg;tY-Wnv&z`&;JVYtfnji-MQ0|Q7ki<%gNJVQO>d?twe1KkHf^`h}c_TDi0S`)d@ z|EcoTAo+8a3=9&f>6-yfoXyV39TWJwmar)CTo0Azn5uYC>B zHNyXyF{Hun6W5S;&~#lJDUgOK53;Y27vz`tWZ4KV26@XPE*yRZ>DvtMn}W;($)B^F z5+sp4r#M~*=01e~K=S_?<(dC8Z)dOv`WNDUg#SQ%j@-4mhIPpD2>*fP1sTMF;RTUL vcOgjr0pkOv2T=2|$sbkm)Lp9^tR!KNE(>wbI$a~XZC*cvJ_Fs43aaw~WKMi- literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/electro.mw3 b/worlds/smw/data/palettes/level/grass_rocks/electro.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..684b84a6af3fb391d7cb226b51fbb370cf3bdee3 GIT binary patch literal 514 zcmZQzxLdzW=a>nnBd23UT5b8{Vg`oaJg@aZ^xgV;T@VSASC`{-1c|S%`d<&CXUo-F zgX9?)Ug-#g<@r>kT}fnM_z&c(%ZV|_Gt@KAXM)I|Q0O%^^7^^Y~c?V6`{!ozn&;iK4LSB$x;*(_~xESOukGOF76{K%7xNizF4*fj5WA7(5&i?oZ(yllk!OI&V{_jFMv&ie l%O6$o)Lp9^tR!KNt{dbYWz{35s&;K|&;8^b(B)Ui0033aek1?@ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/geo.mw3 b/worlds/smw/data/palettes/level/grass_rocks/geo.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f085c6f368ebc772b2b379c8624fc2242376fe16 GIT binary patch literal 514 zcmZQzxLe;Qa8l%xYLwY-t3Otgiy0Vx^Sssv(Rb_XbwMOV-pP_*>ys)-e0A0TdJsKZ zuHG6X&%gjP;g1yq!+#*3UrUTZo}r#`J`+SfTlc+fv7bcp9H1_Ue65LG=>JstYLNUn zO9lps(w7lPy= ne#b3;RK-(wt!}WAggv@$kb9I>kC>|3wYfd_lXpOuU!w>B%ZGhr literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/ice.mw3 b/worlds/smw/data/palettes/level/grass_rocks/ice.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..349ce8e099d27437b0de972b33bb157d0f72b7fb GIT binary patch literal 514 zcmZQzxLeO;+3w06)E_639#K5Gn1SIp&ue`UeYd_|7eqQ)as-{ra0 z|1)DqgY6gBkay5@T^lKohA9tnZy_(pFY(E;5nK%NmPcGT{0h>y8QeDonFo?TXE`NE zB6&`6ybgq~z>M%8*w2je%>S9UGuQ+D3*sv6e0A0T zdJsKZuHG6X&%kg*ubCwJY63Hg@Q|o^K^+Mzum_N$@Wd83D(ZAj3ce;ww8?Vjr3>W}pe<81Z zO{JQR_$X|VgmHRK)KEP4DkCSl5h>?`C2`6WJCHiC;m-tveGhhIVZHiP@7AoD=- z=PaiLfm|Q21K}$$Bm4)F|IaAT{GWL{gFVo{Aie@K!haw>NAB8O!#ZSng#SSDf(+uo v@Pf#ryAUJ~@jGt$qbi=dYjuN_B<#_3gWRL6dc;)KuFdVapS%OQe04DZCOLoB literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/napolitano.mw3 b/worlds/smw/data/palettes/level/grass_rocks/napolitano.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..bc6ebc6621d9ff7114dc9d5482716febe0ac4c6d GIT binary patch literal 514 zcmZQzxLf}#);euY*4;eW^0?~B#S9F;d0y*-=)3jxx*+m@Jp+S6eM7wh^MiVj`0A?v zV0yM(y){Ulfx%o()|y-Je)<NOc418x(|ZtMdOX^yy8QeDonFsREIm;i literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/original_aqua.mw3 b/worlds/smw/data/palettes/level/grass_rocks/original_aqua.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..fda1d358f7f2b177b30d191173455e744cd288e8 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM)=$`9VEMe09}- zFg;tY-Wnv&z_6aTQtyGPjJ5(Z0|Qt!vlxRsLp|esCWw5t?t9x}KZ)cyK;01eS`)d@ z|EcoTAo+8a3=9&f>6-yfoXyV37-1}32WK=aW7$o@iJ`x>BY zg#Y7^7uS$?&~#lJDUgP)8)9D}FUT+P$+8h#4DyyoTsZs+(zhAhHwBpoa?d%-DM29D z$Lqk{hwvXr{y(EU^MB^;4E8|(qWcfT=g3`~YgmUYkMJKzUXVc?7+w&0bQgl;A22>( pdH^*aoBUA~Pu;b;!AcVL=&~U9D61YZRkdq#d+sOifG+<#9{`FayJXAYXx5j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 og&_F{j1QO|K+VS{kBC2XS&(~_Rgaje+O@eo_mg)(mv4v#0NH?eQ~&?~ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/original_ice.mw3 b/worlds/smw/data/palettes/level/grass_rocks/original_ice.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..041aa9edb1c368f843d5c8ba4954bff09d3e8520 GIT binary patch literal 514 zcmZQzxLfaJ$q{reODH)sdq(l(Vg`oaJg@aZ^xgV;T@VS8cd}GqK9>a&UtRUT9z@TU ztG5QpzYpD-_r1)rzPf&IJp;pkAXZ=&V~}U4XPnOjl4oEzspIE(IkX~A7A{|FA{Y8U zRlXV|f6kJDK_c0tero*>xO@ZiNBN)3|NSBQw;TOVXJArbe!$Ft0YK&#^4iw`T_gM- zhrGCkyo09e+DL&k4DDd|7V?7p5}zy^!NnkNdBlaouONM!!F^MZc_9Csvz!tnkvyk3 zUI){EAo>4{^34C4w=>uS{R{Cw!haw>NAB8O!#ZSng#SSDf(+uo@Pf#ryAUM*fbjv- o1E~4faNudR+6wsmj$^;S@npis$HAgb3b_pbou}F0RF6hOaK4? literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/original_volcanic.mw3 b/worlds/smw/data/palettes/level/grass_rocks/original_volcanic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d7a19dc3bcb262498519c6c0fbdac81d3179d996 GIT binary patch literal 514 zcmZQzxLdzi!NYKk?Kw*$yKP>Riy0Vx^Sssv(Rb_XbwT7J1y$V)(=Jm5<{+^A>Zwf_CLi9HDDF2iBzduC(cB9|v3`{`#f%?$_$o@iJ`x>BY zg#Y7^7uS$?&~#lJDUgP)8)9D}FUT+P$+8h#4DyyoTsZs+(zhAhHwBpoa?d%-DM1p+ zbBg12VD3Zs4(dH^*an>=#(W6CS59x+w5Yjb<J^wD0L2*? z66)>6LG*ta1!j;u1H*dWO1%fFGTIwf^vg6MBx{wV*G`M*Cz|8}F_=?qLj`+?@81CafNy!JJ- zc-C!jNdvsZldz4j=n5x>fxjpxjcR-h)Tnqpd40<5| literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/original_white_2.mw3 b/worlds/smw/data/palettes/level/grass_rocks/original_white_2.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..596e5b93b404d142b5333e64a9dd4ffc58fc6f69 GIT binary patch literal 514 zcmZQzxLbeCPa-@jeop$m{Qu>Xiy0Vx^Sssv(Rb_XbwT9+dIkoC`i6Q1<_Gm4@zquT z!SrmodTWq81H(%OUZp-(W2x;%3=Ck^%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@fp{t*4!jee&yFahmnX21X-`wMyPYk;m1 z{*OamTtnVL({*j6KpKX2uziKRAiu;X%SLc9$Xgz9;qWU+-)3;%6l5OAJ?AW^1W6>% zDUR2Hxewt#ko8_2KP<>1MLIJpR=42 zB#}I)I9>+_kxeb;$Av|AFKM8N`9%1(8R0 vAxQoK;{&D#Q1h|LA64#(3vtgnT_d|~UO$6A1Kp1bHq-$CHNAc1 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/sakura.mw3 b/worlds/smw/data/palettes/level/grass_rocks/sakura.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a339b4a62d15d843a22d44d485684349ad7335d3 GIT binary patch literal 514 zcmZQzxLfZbcv@6XYNMQq@^tmd#S9F;d0y*-=)3jxx*+m@Jp;poI)(ZNOb_Zo;;XCv zgX!6F_0}MH28NfSg4$C8rkl%_F))BtGl?8Sp<`>HIWPb zpDJGsl0Rq3z#x%qQa`o+2hc2t{s!ic@;{mX`$P0^H~O9afDvdvGXn+y*yYIU{sYMiGKd4i3nGv1 qLXbSf@3`fUs(9+I)eTmXut(Poa*wj=5mQyWHn-<~@($?oGwK0aD}X}) literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/grass_rocks/thanks_doc.mw3 b/worlds/smw/data/palettes/level/grass_rocks/thanks_doc.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2359c277f3764723464c94c2fa233fae98c13c80 GIT binary patch literal 514 zcmZQzxLeOF86Z1JQCzRmNhW%7F$2SIp4a*y`fh!_E{IGJXp~qi^F)S4&07^DzPjpv zJ&2wyS8olHXJGI*-R7Gewzq17Is?OhAfH7|j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zT8_2KP-t=7HqT zSxyO(NS;$1uLI#LFeCg2lK;;r&-|ZxJA*yYzaYK>Gs1r$K1c4_T*EqKd4&H!@`4QF z!0>{|qq`6!|A6rU(*vma*yN9@cP BdIkUh literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/logs/brawler.mw3 b/worlds/smw/data/palettes/level/logs/brawler.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ed25ef97949818757bcf172f6ae4d637a980bdc9 GIT binary patch literal 514 zcmZQzxLbc(>zxt5wXt_;_>B0;#S9F;d0y*-=)3jxx*+m@Jp+S6eM9{NAOwl8uKEwA zXUo-FgX9?)PICB3Ue>IzlMQBI0IOyeV~}U4XPnOjkv}2ADVw8t-qgqmCSPkJ7y3U{ zz8WNd&XR#aBH5&VYW)wOSrGjV%pc`{GXM97=-+PiJDq_^f%yS50|o%uU&w1;19Xk> ze;o4S8uAXBu4^L&(lE4x?JML3`6WJCHiC;m-tveGhhIVZHiP@7AoD=(IcGT~NFsSo zal8)9eF*=7yYIU{sYMiGKd4i3nGv1LXi9e r#s^Ffpyp$fKdR!XyH+_oEET;rXB+n_1 z*MYeY;Xjc4e@1!c|IFJN?1BD;_#fdv5T7G=ZLVP*vOL0nAbCLsabS2sIN%G*rUsW+@q{|#8lO;&F#6LyaT%Y{bT^TW_(fr literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/logs/mahogany.mw3 b/worlds/smw/data/palettes/level/logs/mahogany.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..80d5c2c1adfcd47b15b97c71aadf8b23c1441d51 GIT binary patch literal 514 zcmZQzxL@pP)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM=jB5Q4;4SN#Xm zv*qfoLGla?d=etM#v&4$Hf{_IVAafG4Dt;1jPscw@(*+$1l5bi8`*oq!(`0-of)JS6@ct7x<>dv z4ta46c?V6`wUGj8sCq#>kb4VxL4Ju(mW|+IkheVI!r@ntzRlpiDabsK{5i`hK@!Px zisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*{81H8-L<;GN)q;s~#~`wQF;G?kDenF8{wC03pbEu>b%7 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/logs/not_quite_dawnbreak.mw3 b/worlds/smw/data/palettes/level/logs/not_quite_dawnbreak.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ecce214b80fb83396478275dfdfd2b8d58b081ac GIT binary patch literal 514 zcmZQzm=Nb_)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T?U~1|9S=nh5Cm22S5lCUtRSd zOwX39w+6{GFf5hfRXV2PYx^aTfdQxCf=b|1fCs3oUiwl6o(d~^VEZy_(pFY(E;5nK%NmPcGT{0h>y8QeGh&kS+zIm;SFXXka0lG%` zKMr|u4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK r;{&D#Q1h|LA64#(3v!RL>Jd{_yEeDye)10J^8f1r$9sK1 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/logs/riesgo_de_chubascos.mw3 b/worlds/smw/data/palettes/level/logs/riesgo_de_chubascos.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..0a7e877996b9d17f580af8d38b7732521c6e1772 GIT binary patch literal 514 zcmZQzxRT{*)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T?U~1|9S=nh5Cm22S5lCUtRSd zOwX39w`O3dDsK^Z$-t|mqqxy9+=+n!teRPjL7t(WaXu47{(JstYLNMwsx1ORUMmA%NBSqhgH`%wM2U9nnEM*4z?l^RSQ;Xjc3x+3|~K2;&hqx#REV~2>eB19hDg&_TH sys2Vt^0?)Xs(9+I)eTmXut(R;zz|uita`*$)vnF$xu3iPx_pl%05~mvz^Pi2NHBVM9~ZTdKE(VDhyl za-siI<*PyR=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9isTHW}pe<81Z z4bU~h|CuqQ!R`~+kay5@T^lKohA9uSuaFnym-uAa2rdSB%Ofrveg)~<4DOqP%mc}v zvz!tnkvyk3UI*qrg#SSD{~6_(|1)oAum}1V;(mnxKzxqewYi3M$npsPf#d}l#DU=j gkwTvI?MXW#S9F;d0y*-=)3jxx**a`#mlBIpe2UAu)7o_zPjo^ zSlw*7dTR!teg+0jALqpW8llQ5l?)93>lqjnn8g_68R{A5GeP7Z=spONWvdsvuLqN_ zHIWPbpDJGslJBo!U@!-g$od^^Y~d56~~dX9y@nDQX^7V?7p5}zy^!NnkNdBlaouONM!!F|*J%n!#QzBYf%qJ`YjX|jkmV8n1IY_Ahy%k5B9HDuko*J2 q2TTv3=3|pTs^Y1;RySBl!X8}~;+}Q7Mt0l0eg=I8x*ruJhyVcm1%BuN literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_cave/green_aqua.mw3 b/worlds/smw/data/palettes/level/mushroom_cave/green_aqua.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..dcd6d0f0940e3ea2bf9060489acf768b5fbed102 GIT binary patch literal 514 zcmZQz_)(u`aID6w_I>TvI?MXW#S9F;d0y*-=)3jxx*+nPjHB)&+hoqCoNYoN@zquT z!Rltq)mt+F^)oOe3bYA9R53982l5q|#Teun>KW%VLF6CkJ_wR!s~5Yk2a~TgkqiBw zDqjtfcLdtfT;v);a8Bp&EUT2e`bh#&RI?gl1QFY z9Ipd&AHshi{r?%|ng26yXRrtQ7vg_}|3G|>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK q;{&D#Q1h|LA64#(3vtgnT_d|~UO$6A1Kp1b5<~#6+kVCX literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_cave/ice.mw3 b/worlds/smw/data/palettes/level/mushroom_cave/ice.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ec308ed93b4af4ef7d593fc85d0e2f05e386e6f8 GIT binary patch literal 514 zcmZQz*jvuPa8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T?U|hx9hu5|Flh6U-Kf0LE@{c z{?~)(*>d&PAbAD`9?4RxLRE9UTYd}-|LYkT6qv;rN$Q#dGA!nmM*BD(EqJO4|jN=MV?xemv?D87~Z%NH_j!%}2;9`)sJmSLPSCGEV z;J)d9W{CcGu3O?P^Q+76gu>j9?7yWFk$iE=`@~HJ=PAMDk^Q$+LOpgxtacf)d;{}G z`Jc@H{UPT2D@5tcwS~x|yAb5RX2lk*RAcP&pzwCkd|=xUw4K2o7~bdrB!A9wN{~b{ Gc6k5;euS$4 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_cave/original.mw3 b/worlds/smw/data/palettes/level/mushroom_cave/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..7d97ca364024b2a0a58712e3aed6d42483b51379 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kgZ@?6nrO9Q*jUJMNXfqVsKF$Q^tddB%o5P2~MX@+=4c_w*gn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 eg&_F{j1QO|K+VS{@1Xg>wjl_&eu(?A%L4%GRd#3q literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_cave/really_dark.mw3 b/worlds/smw/data/palettes/level/mushroom_cave/really_dark.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..696f6df3bb766de8bcf1c12f27eee72c2d32b459 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T?U3^i6j981c|S%`d<&CXUo-F zGcY6xv`Dl7)qrr400YB+pm_?+Vhr*O^^EhGAo3s?RQXyHxzPWq^3@=Dh#abX1M^4u zpUnULVfrCy8QeGh z&kXU;Im;u&_<-pF)O>964w?^a8-j4_hqxb`e3AeFln-v} literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_cave/toxic.mw3 b/worlds/smw/data/palettes/level/mushroom_cave/toxic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..75f87d3c389a58d8c717d3d6ad48e30f0b1105d7 GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@dNa(#mmMfI~D}a*ZTNe0A0T zdJsKZuHG6X&%ltWyUO&mrGedMF9wGHK)wRA7=t`RJ>z^Ph`bnsG($Y2Jd->#Oup7c zF7$t@d^Je^oFxN;M6ywOS^iF-sSy1Q%pc`{GXM97=-+PiJN=O2VZBAp3>W}pe<81Z z4bU~h|AFSC1CYG9hP;EO>)J?xG;~>reTBRrzr-iYMsP96TOM)Y@GD5)W^msWWFE*p z=PaiLNhHrHj@N;?58*$M{C`Gy=Ksvw8SH`ng}5K#KM964w?^a8-j4_hqxcRJOCJdc0d3C literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_clouds/atardecer.mw3 b/worlds/smw/data/palettes/level/mushroom_clouds/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8e3b464f8b538a27618dd8d89de920257a7c05f2 GIT binary patch literal 514 zcmZQz*k9~v)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T?U~1|9S=nh5Cm22S5lCUtRSd zOwX39w+6{GFuY_4kSb=Ckh^8ZzyMNh#C(+{j#ZxR9~(qISNEfBsh?!>T%cNzdL!mJ z3Nf~Fe)j1g{(4gehM#eBo#evn!F-T>5c?1Af9(6iA?m}_ey4LW88LrhX21Yo^EmBm ztd;Dg=W}C7gYCP8_2KP<>1MLHu zzupw$dV5uv`%(QT$99h`Uib=!ofJ&I)ngwL1RpKDr&EZ@NVQT`|Me}9Pl z1r{;RI#!50x(h+}zh->L^obd_ypQKgH$t9jlQU4EYx E0D~WSU;qFB literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_clouds/greenshroom.mw3 b/worlds/smw/data/palettes/level/mushroom_clouds/greenshroom.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..4ad23210af6238afb1f4a3287b7cf3e064fd2379 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM=jB5Q4;4SN#Xm zv*qfoLGla?2N)Tc5||X2A22g8fK@Y#F~~F2GtOs%$Uo415L7Q3Z)EQcldm#%n0y2CNBN)3|NWu*nSZAzRS z`=%iCK>j&rIVDIUc}{V> z4$OTB|AFNHGs-jnXWq_W5A-j@{|Ntq_#C-wa}Dc|9Q1sGdU;wLT7GscSsArtd1d)HB`yi-ZG~USG8zx_CA{Y8U zRlXV|&knT3Ff7~medH9NSrGjV%pc`{GXM97==ak69(P!x-LPGc0Rw>SFXXka0lG%` zKQo3j*nQ#}@(!A=Ya<2HFy%q^74m}o5}zy^!NnkNdBlaouONM!!F^MZc_8_7mQ#Wx zlIIl1>%iQH@E=J2KchVJf9CBB_CWta+>h`dh|iI`HrKEYSsvj(kh~y+I54~*^5`y{ s1q>sI-?7Vs^k)a=`fc{#Zy;-qt{dbYBRyWP4goL4T+Q>g=SFXXka0lG%` zKMr|u4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK r;{&D#Q1h|LA64#(3vtgnT_d|~UO$6A1Kp1bCKm$$(k^{@ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_clouds/original_blue.mw3 b/worlds/smw/data/palettes/level/mushroom_clouds/original_blue.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..268518d3a692d63ee8d59c5997feb5d8e31c4c25 GIT binary patch literal 514 zcmZQzxLfaO)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T@d-do`FH3zM=jB5Q4;4SN#Xm zv*qfoLGla?FBy21`dE#nwi_`pfK@Y#F~~F2GtOs%$Uo415L7Q3Z)EQcldmSFXXka0lG%` zKMr|u4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK r;{&D#Q1h|LX9wo`ZT8=9AZv~;3v!Q<9SFXXka0lG%` zKMr|u4S5Gm*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK r;{&D#Q1h|LA64#(3vtgnT_d|~UO$6A1Kp1b=0^hn(k^{% literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_clouds/riesgo_de_chubascos.mw3 b/worlds/smw/data/palettes/level/mushroom_clouds/riesgo_de_chubascos.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d515e876d315ffbf7ad43ee00777345b4cd0488d GIT binary patch literal 514 zcmZQzxRT{*)$MfFi$6FpdUEpQVg`oaJg@aZ^xgV;T?U~1|9S=nh5Cm22S5lCUtRSd zOwX39w+6|#2%HePqN}60(JDvtMoBn5p*uUNs z;(B{knEO%vC&zY=EnfHvhn*BmzScx8^na>+HH6QX*`I4#hb-T~{89cV^M8Mc`~?;< z&N^0zJh}@({(H^%j_DIKcKQ22`J*bHx@&cVl_c!Zbu%!44|E>{)r-a(*?Ys}Yfa=r z|EJ1VgXGUyGB8La#|PJk?@xxwH!y#c|H=H{AEJN0(EN0MCKKiv%nTR+WPc&AeGSkx z!vAr|i)+X`TvRPHyXl0X9qishUXWknlVu~g800OFxN!Itq;E60ZwfLGtGgkMJLe&yl+}*RT#*9^pTbydZ-(FuWl0=q?1w sKVW>o^Z;r;Hu<9}p1NywgOw!g(Pbg-S*L4cx6SKk&}X3gQNizg0JY3}s{jB1 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_forest/count_shroomcula.mw3 b/worlds/smw/data/palettes/level/mushroom_forest/count_shroomcula.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..74e336cf6f76a2511149f2f9101d85f2970def4f GIT binary patch literal 514 zcmZQzxLcph(;~7|;+V`c6?V^suztnviF9`*P6(M z{!f*!2FahZWMGg;HmRRl{{yHOqQ8Opqx?_i|NapD+l~HZr6{t9pJQgg03iDddF^X} zt`Yu^Ltb1%-a*rKZKOaNhIX)hg}flY#3#!}a52bR9&zFDD@fmFaNiVU9>_iCET;rX zB+n_1*MYeY;Xjc4e@1!c|IFJN?1BD;xF6v^5T7G=ZLVP*vOL0nAbCLsabS2sIN%G*rUrr+_O&C$Znh0&!Eph_oIR&0RUyLeP#dv literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_forest/cursed_gold.mw3 b/worlds/smw/data/palettes/level/mushroom_forest/cursed_gold.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..f0c7d6124fc6488512235418850c933adb91bae2 GIT binary patch literal 514 zcmZQzxLaS(T`aa%(M$5Vz*2$9#S9F;d0y*-XrPQPi2PsA!0@0>p}wL1K|M%(b=7|` zJzK8c8YIua;IBAC?waf$w)y-F3?S7C%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@^ZFU|8R&jg(82=%xU+p2 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_forest/dark_green.mw3 b/worlds/smw/data/palettes/level/mushroom_forest/dark_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2b1f15cbb1e0c83ef37f037f83936f374a5a7d8b GIT binary patch literal 514 zcmZQzxLd!N=ZS!-Xqx15*%ykFiy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe(j^$+Sn;;XCv zgX!6F_0}MH28Lq{3XB|#3m6rc7#KjR6_~{s%5Li9HBHNyXyF{Huvi)+X`TvRPHyXk}}53;Y27vz`tWZ4KV26@XPE*yRZ>DvtMn}W;( z$)B^F5+sp4r#M~*=01e~K=S_?<(dC8Z)dQF`yb&ykUU53+FZjrWO;=DK=OhN;=u5N x$fLUuB>#Z%0n-Dh`Pk%-s(9+I)eTmXut%4LxObhdk=-`0pFy92?nebloB+{eyat`0A?v zV0yM(y){Ulf#H~lmnMf|kKs8>1_qF71!ge@d4_t%`AiV`2f7b}>P6#??7d;~wI*_* z|5N3wLGmD763JWYEb6O)dLjB7m_N$@Wd85Zz)%^_z>py+>V8_$PivzQ0|o%uU&w1; z19Xk>e`XA6u=~U{8_2KP-t=7HqT zSxyO(NS;$1uLE-*!haz7|BUj?|CzTl*aQ6waX-R;AU;R#+FZjrWO;=DK=OhN;=u5N v$fLUuB>#Z%0n-Dh`Pk%-s(9+I)eTmXut%4LxM!WNk=-`0pFy92?negz(7Ak% literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_forest/original.mw3 b/worlds/smw/data/palettes/level/mushroom_forest/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..cab6dd134869338d9efedbd2ee146f0b759046ca GIT binary patch literal 514 zcmZQzxLcpVxrFfrqYl$Vrmswsiy0Vx^Sssv(Rb_XbwT9+dIp9Ebqe(j^$+Sn;;XCv zgX!6F_0}MH28Ndmyh?qn#!}mj7#KjR6_~{s^suztnviF9`*P6(M z{!f*!2FahZWMGg;HmRRl{{yHOqQ8Opqx?_i|NapD+l_vwGcYMIKVW9S03iDddF^X} zt`Yu^Ltb1%-a*rKZKOaNhIX)hg}flY#3#!}a52bR9&zFDD@fmFaNiVU9>_iCET;rX zB+n_1*MYeY;Xjc4e@1!c|IFJN?1BD;xF6v^5T7G=ZLVP*vOL0nAbCLsabS2sIN%G*rUrr+_O&C$Znh0&!Eph_oIT}`2b;#eINh; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_forest/snow_dark.mw3 b/worlds/smw/data/palettes/level/mushroom_forest/snow_dark.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..cf3390d5f186777ea4e124579d9c2da93929412c GIT binary patch literal 514 zcmZQz*jxTgMZ?zHwLkKGY-Qf$Vg`oaJg@aZ^xgV;T?U|hrt6#7O+^qAB)+=pe?5qv zEmv<1l3yzEUShjuiK4mHuOJBjq*<{{l#YyPycCGfz~E_m*0nI~d)gcz8>IfE+06{w zQn@1AY7l>|?NSMg>`z6dXUqKN5NwZ>^C>uJSCWXt%+Rd|5SOXf7D}F z#A=rz%QrB8l>f>6-yfpiUm;4T))FF*?n03NniX5LQjKxTA64%P8)CkG S=!e{iMMmY-K=-49s%ijA+mAm0 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_hills/atardecer.mw3 b/worlds/smw/data/palettes/level/mushroom_hills/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..19d9d32451714d3386e12dd46192f91856524237 GIT binary patch literal 514 zcmZQz*kAlSwmZo%{ZDvtMoBn5p*uUNs;(B{knEO%v zC&zY=EnfHvhn*BmzScx8^na>+HH6QX*`I4#hb-T~{89cV^M8Mc`~?;<&N^0zJh}@( w{(H^%j_DIKcKQ22`J*bHx@&cVl_c!Zbu%!4ZDvtMoBn5p*uUNs;(B{knEO%v zC&zY=EnfHvhn*BmzScx8^na>+HH6QX*`I4#hb-T~{89cV^M8Mc`~?;<&N^0zJh}@( w{(H^%j_DIKcKQ22`J*bHx@&cVl_c!Zbu%!4 s$MlIAyZn8i{81H8-L<;GN)q`Ih*dS(9PVg`oaJg@aZ^xgV;T@VS8hmaug)m8uNLG*07dTWq8 z1H%%L)u!xKuLj9$ zsxmMX1&Jm{WX}eg3en%d{89cV^M8Mc{sO-_#p8_2KP<>Geg|-)^>B4dHS5< zcpaGg5dH({hq!IMs)!y;9^pUi@(BN-%cHxH82O_rp1NywgOw!g(RD-IvrgB@ZkyN7 MpwB?}qk_CB0OTBb$N&HU literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_hills/original.mw3 b/worlds/smw/data/palettes/level/mushroom_hills/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..3e4854584838b4d79557679d1f869b60536b2d6f GIT binary patch literal 514 zcmZQzxLfaJ$q{reODH)sdq(l(Vg`oaJg@aZ^xgV;T@VS8hmaug)m8uNLG*07dTWq8 z1H(%OUZp-(W2x;%3=IE)dy8QeDonFn&uIm;MVg`oaJg@aZ^xgV;T?V*3L={MUb=CiR5ItM2-Wnv| zB5*?Fims00M#FF?28RFj3=9g)Vhr*O^^EhGK=KR>S(fiSi=)10%_(PK*bmfc#5_kK z##YYHJ{=^lsoEkC)jgwi{KIbBL`};?ZWn03i8^ zvhmCjYO?w@${5mM{Z}n!hd$HrbX*gPUA~YPgH`w;#EyHBxNPe%HJh?N>lzScx8^na>+HAH_`BwyO6Dr9+7|M_$5 w5Rq1d$fLUuWIn|2xaE(kc<99VnCB?O z*vk3Yr-S4*Ra*ptyjBLjj`UB0>2F~EDF2iBzdr**Re6iRcB86t4zZO=JlYHx03<(A zHl8^`O;*1~8ABSZ|Ek68&}SN+j%z}(%NO#3{1Trm8^OgOZ+XOp!>=HHo56k4|I85k z&sk0hl1QFY9Ipd&AHsiN_bFEE$w*%iu~LJ{*P6(M{!f*!hUo8#ZO4FBsH7!;Vr7~~o18Rs*B2II!InqwM8JvYh~c;NdF|5{s!ic@;{mX`!g_9mA43NH>xV<5L>Clqs@Q;K=Ko1 zy8QeGh&kV8u zoaK}tiR3xO@j5W~A^Zn+pJKJ1jPwN&D>ayWt%+Rd|5W*Ei2klfzO+wO$nvQE^XJ$h wBCQCKM|UB}e2Cw1%O6$o)Lp9^tR!KNt{Y6DG#!*kQd~a_+;4#E(UqaBQ6|%1?k%i?wf+l1IeGWoDw9FJf}Eb z2j)J6|3LEp8ReP(GjC_G2l^M{euV!(e2(0;xrTMf@(BNd}Q@k1h*w&pKTryKP=SgFXY@j|yZI0WX(%HUIzs literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_rocks/atardecer.mw3 b/worlds/smw/data/palettes/level/mushroom_rocks/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..4540f32bf586fae9a2e499cf2a0db820a10a5a67 GIT binary patch literal 514 zcmZQz*k8=dn$F727Ra`ht(tvuF$2SIp4a*y`fh!_E(1{he?0@kgF1!!hWZEfAo0~z z|H1TZxq54mJOjf^h5)HzRtdRVW)Qv+^Hr8OR(ZC6Y!H5~?nm2FKgr~|K(!$CM$B^* zVr=F7?9)N~^`;CAKjY>)$%WU0`5^fq_8;8;*!PD+)NePs8_vZf%=}H50Rw=|>O$TQS4&S!$iKhS*;R4*EDWbX}=uQibi z{humd4U#`+$-p3yY*Ih9{s&MmM1KSGNBN)3|NSBQ???Ym=hV|x{-)1>0YLT_^4iw` zT_gOT8ABTEK5-3s2TfPbtWcm@bO5rikQd~a_+;4#E(UqaBQ6|%1?k%i?wf+l1IeGW zoDw9FJf}Eb2j)J6|3LEp8ReP(GjC_G2l^M{euV!(e2(0;xrTMf@(BNd^suztnviF9`*P6(M z{!f*!2FahZWMGg;HmRRl{{yHOqQ8Opqx?_i|NapD+l_vwGcYMIKVW9S03iDddF^X} zt`Yu^Ltb1%-a*rKZKOaNhIX)hg}flY#3#!}a52bR9&zFDD@fmFaNiVU9>_iCET;rX zB+n_1*MYeY;Xjc4e@1!c|IFJN?1BD;xF6v^5T7G=ZLVP*vOL0nAbCLsabS2sIN%G*rUrr+_O&C$Znh0&!Eph_oITz#Qy8QeDonFn&uIm;gH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 vg&_F{j1QO|K+VS{pBYEXX}Zdc0m80$z%_n&)lNXiy0Vx^Sssv(Rb_XbwT9+dIkoC`iA-kKnN0FUG*PK z&z7sV2FWupyky{2>SHyQ+HS(Oup7cF7$t@ zd^Je^oFxN;M6yZ!)cPMlvmp8#m_N$@Wd83D(ZAj3cRB-;0`miA1`GhQzmV6y2Iv~$ z|2X8uHRK&MUDrkmq+w_W+gHd7@=JWOYy=mByyX!W4!?r*Z3g#ELFR$nbIx)~kVNvF z;&>gH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2g&_F{ rj1QO|K+VS{e^kX&cdc%)l7v0FEW|zQbdBt`dHoFf40Jy#_?-^`5!8Q# literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_rocks/riesgo_de_chubascos_cafe.mw3 b/worlds/smw/data/palettes/level/mushroom_rocks/riesgo_de_chubascos_cafe.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c8da0fa178818e329cfd38ba3fe45e3033c9cc65 GIT binary patch literal 514 zcmZQzFfZoT)iupGz33?HH7#m#F$2SIp4a*y`fh!_E(61rtpD{43<~uP^$&m$B)+=p zKbW2^S8vV0P*vU{a6;sYu8!hH!*C}C2C!;oF$Q^tddB%o5cvnX4}$7NW}p|3q2) zng}&n{TgKqX|VgQTFef8rs3(hCKS7TAuq@;@yW6gTnzG-M_f4k3evY3+&BHt46*;5 z<&+?arEvn>G&TYRqo literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_rocks/riesgo_de_chubascos_negro.mw3 b/worlds/smw/data/palettes/level/mushroom_rocks/riesgo_de_chubascos_negro.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..868945e9f427713dd200f8dfebd814fc4f7484fd GIT binary patch literal 514 zcmZQzxRTW(vQ*-^il%P1=~~Ch#S9F;d0y*-=)3jxx(q=1|Md(E3iS>34}cIPzPjo^ zn4T?HZw-=f5jY`oMOR00qhYuc0|Qt!vlxRsLp|esCW!n4-3LMSqVY!d-Z1%E6S>g; zsq)nzc}>+8fgrDyfv+R|lVI`<%pc`{GXM8yV5ll@5!h~2Rn8%{Qi(^K0Rw>KC(7E_ zM5xK?*C=C1gY{pvm>v2|!_#q1D0cZmUXWknlVu~g800OFxN!Itq;E60Z~C7ZV*feI zDM1p+bBg12VD3Zs59~h0YCRe03nEr(FnNUkK=NIYd}*JmkmXVR=g+Z2L|PFdkM2T{ qeu&?3%O6$o)Lp9^tR!KNuA6}&vRGO5h^eYwo7;0gc?Wd)=NbTG*MEZm literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_rocks/shuk_ft_reyn.mw3 b/worlds/smw/data/palettes/level/mushroom_rocks/shuk_ft_reyn.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..4fa3e7600a154feee12065d5cf90573876021953 GIT binary patch literal 514 zcmZQzxLdzeghSQKG)VHMY_;0tVg`oaJg@aZ^xgV;T@d-do`K;(okD#>{eyat`0A?v zV0yM(y){Ulf#IdWcUvFd4~gI77#KjR6_~{s^suztnviF9`*P6(M z{!f*!2FahZWMGg;{^K;ye}6hmzJd9p{7>fp{t*4&<9??zFexxUU}nGoAo~k>?Q4Lp z5&n-uUR*=oLDO|@q(B;mcCdR3c|m@OPnM0~Vvx5y;=LsJ19Kn3e<1n)jPlI?nYT081N{r}Kf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! s|A6rU(*vma*yN9@ct<8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_stars/atardecer.mw3 b/worlds/smw/data/palettes/level/mushroom_stars/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d64a4bb2298285ab8361056cd7ae64d93e611e7c GIT binary patch literal 514 zcmZQzkoTXTFYgb7lZzP`e)GK62hn%y>vb6z=I1jo$W_m;o>~8`{!cwfe09}-Fg;tY z-Wnv|BJh%dS4l^4qhYuc1H=D%1_lLYF$Q^tddB%o5dFEjA8kwhe#O;iGcfE2nqb5{ zMm&d)v_B){I2f#GM|Tqn8kdLSPnAH@EH`yc!Ma0ow4?RPpClM(Y5W(EuZR?ivF zY^`K3J)avx8f@M*7F$+b*ZxSMH0<($ywOVkt>TkqBe)pkEswZx_!XpYGq`X1A7~%Q z{Pm`#ev-*^i|tim?z_qo$12bEj}5|?W4p%|FMNf=P6{SpYa$o=KUKaO!spBE&o!+> zmTzGGDF2iBzduC&0*e@D9VIN%G*rV%)#K$^a RBfD*0KZ8E&pv%kq0|5WQcJlxL literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_stars/cool.mw3 b/worlds/smw/data/palettes/level/mushroom_stars/cool.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..326b693e141bde3e41e44aaa8bfaa10153da21a9 GIT binary patch literal 514 zcmZQzxLePrn_>ILw=n8zR%H3)Vg`oaJg@aZ^xgV;T@blcLaus#_00Nj^?&L?;;XCv zgX!6F_0|jwd&`$fyqDOnS)yoe^(zR%KWSDh6Qv_#8ZQOnGcb6Xo^>q@`<^xj$OfrD zX?8Qiwp6ajwi?7=Yr9m!BKuQOY57htA0)5rf5QB|`0sFt`t3%))1T{}G+PC<4;_Ha zE98x5u8_0QpKFXR3(-H*M8;9mb#0_T8g}^&g14mRImaikMcj6|NBGq`zu80)LKI1(On4gU$bJ1R;n>>`J*bHx@&cVl_c!Z XbwkY85B-okvB;>r8t8shkm(Bmpze(RERxTNO;cf%&8SPv-yr3=BWh85kZgJz##okie(_G!Gqs z>@VcCuK~J7_&?BmbP$!zz#y(6@6e*~+{7yoT^3?rAuq@;@yW6gTnzG-M_f4k3evY3 z+&2Z82lCH3%PBz;$#aV1bzts8_zxuipHZIqKl645d!YLu{zv!^#OKIen`>ByERXOX nNM4XZ92i~@d2|z^Pi2MWH2SN3s@kaLEF!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqW{0v@AOPtcRzPy1`GhQzmV6y z2Iv~$|I8TDVE2h@$UA7du8kB(!;}ZvSI7(UOMJ3y1Q&z68_2KP-t=7HqT zSxyO(NS;$1uLE-*!haz7|BUj?|CzTl*aQ6waX-R;AU;R#+FZjrWO;=DK=OhN;=u5N x$fLUuB>#Z%0n-Dh`Pk%-s(9+I)eTmXut%4LxM!WNk=-`0pFy92?nebnB>d&P zAbAFc7Lnt+$5gT{-v=@<{0H(Cn8g_68R{A5GeP7Z=spN4m9f=~vxCXkn#hIzPnEA` zVAxZC&XR#aB6&iZPnAg&?rz+u=Es-J}^53;Y27vz`tWZ4KV26@XPE*yRZ>DvtMoBn5pxaXYZ zlpu-ZImPihF!v$+2h#taQJ(of^L7S%pnoCmNB9rK=g3`~YgmUYkMJKzUXVc?7+w&0 wbQgl;A22>(dH^*aoBUA~Pu;b;!AcVL=&}&^tkX5J+vfE%=rhp$sNksz0AXHy#{d8T literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_stars/midas.mw3 b/worlds/smw/data/palettes/level/mushroom_stars/midas.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9adffb69bd5f2a5705eb84d423da9e6d5a32daef GIT binary patch literal 514 zcmZQzxR?H#=L+X+E;;%6=KsAX7c(&Y=6S6TqVLw%>oNf485rcM=U30H|5pE}9wffH z>OYvCEmv<1k>_CDEOe1`x>k%k1H=D%1_lLYF$Q^tddB%o5czeoLPn)dKf~3ohTl{89cV^M8MceoO5+{%=^nuvM}%U;vQ&@;U8m zq^16H#Yc6Wj=B)cTA@b-h s1o`hI>qWLQcHHtuRXlaq>IN%G*rV%)hQF?n-8QeEL7#!{M+K8P0m+4a^#A|> literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_stars/original_green.mw3 b/worlds/smw/data/palettes/level/mushroom_stars/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9abb79150620ce048da970ef845b24068098187f GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%p4Kfmf-I)mUn~5d*`2AYXx5j6t5Eo^d`CME-&9gP?lRcq4mnn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 ng&_F{j1QO|K+VS{kBC2XS%`bq=^EK>^ZFU|8R&jgpdfp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszEgQn}+NP#pA?O^)~c|m@OPnM0~Vvx5y;=LsJ19Kn3e<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! s|A6rU(*vma*yN9@cfp{t*2$>&)t3l=@U{sA9kXAo~k>?Q6uvs^#t& zVMv4BC$1sy@Y+PrvCtP&9^~FaUXWknlVu~g800OFxN!Itq;E60Z~C7Z;@)$XQ-UOt z=M=~5z}%1UA4vayMtSD{%-b34f&PW~AK^a`pCfl|u3;UrJi>ngPyZ1P7{JayOV1}jO}qsv0vvrgB@ZkyN7pwB?}qk;qx0FbA6`Tzg` literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/mushroom_stars/riesgo_de_chubascos.mw3 b/worlds/smw/data/palettes/level/mushroom_stars/riesgo_de_chubascos.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b17323af65559ee0197747e00867e0adebd6ba25 GIT binary patch literal 514 zcmZQz(2vv9)Q^L~$;Au|zj z3{~YV0xubOm2?z08iqSDF#HFqS6~)nkY}i8oX-T&|3LRa&~4QkJKJEGe65LG=>Jst zYLNbH-4=ltBd4%IO2_BDvZE}tt~W@P0bpDY`}#UO8a#D&AJAbp#`ebfKU5c|(rP6?7o zo>LsJ19Kn3e<1s}D^}~tNM8`KQiI7O`>#cyE0QnmQx&p2s{i~sc8EwTLgdk12r|Eo rH&x6{9=kj!ypO7Q>aNudR+6ws*9~#cI$a~XZC*cvJ_Fs43iRUuum^qR literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/palettes.json b/worlds/smw/data/palettes/level/palettes.json new file mode 100644 index 0000000000..9690c2069d --- /dev/null +++ b/worlds/smw/data/palettes/level/palettes.json @@ -0,0 +1,358 @@ +{ + "grass_hills": [ + "atardecer.mw3", + "brawler_green.mw3", + "crimson.mw3", + "electro.mw3", + "geo.mw3", + "miku.mw3", + "mogumogu.mw3", + "nocturno.mw3", + "original.mw3", + "sakura.mw3", + "snow.mw3", + "sunsetish_grass_hills.mw3", + "toothpaste.mw3" + ], + "grass_forest": [ + "atardecer.mw3", + "autumn.mw3", + "brawler.mw3", + "brawler_atardecer.mw3", + "brawler_green.mw3", + "crimson.mw3", + "deep_forest.mw3", + "electro.mw3", + "geo.mw3", + "miku.mw3", + "myon.mw3", + "original_aqua.mw3", + "original_green.mw3", + "pizza.mw3", + "sakura.mw3", + "snow_dark_leaves.mw3", + "snow_green.mw3", + "winter.mw3" + ], + "grass_rocks": [ + "atardecer.mw3", + "crimson.mw3", + "dark.mw3", + "electro.mw3", + "geo.mw3", + "ice.mw3", + "miku.mw3", + "napolitano.mw3", + "original_aqua.mw3", + "original_choco_volcanic.mw3", + "original_ice.mw3", + "original_volcanic.mw3", + "original_volcanic_green.mw3", + "original_white.mw3", + "original_white_2.mw3", + "recks.mw3", + "sakura.mw3", + "thanks_doc.mw3" + ], + "grass_clouds": [ + "atardecer.mw3", + "crimson.mw3", + "electro.mw3", + "geo.mw3", + "miku.mw3", + "original_blue.mw3", + "original_green.mw3", + "pizza.mw3", + "sakura.mw3", + "shukfr.mw3", + "snow_day.mw3", + "volcanic_rock.mw3" + ], + "grass_mountains": [ + "brawler_lifeless.mw3", + "classic_sm.mw3", + "crimson.mw3", + "dry_hills.mw3", + "electro.mw3", + "geo.mw3", + "late_sandish.mw3", + "miku.mw3", + "original_aqua.mw3", + "original_blue.mw3", + "original_green.mw3", + "original_white.mw3", + "recksfr.mw3", + "sakura_hills.mw3", + "snow_day.mw3" + ], + "cave": [ + "brawler_dark.mw3", + "brawler_purple.mw3", + "brawler_red.mw3", + "brawler_teal.mw3", + "bright_magma.mw3", + "dark_red.mw3", + "glowing_mushroom.mw3", + "green_depths.mw3", + "ice.mw3", + "magma_cave.mw3", + "original_chocolate.mw3", + "original_gray.mw3", + "original_ice.mw3", + "original_mustard.mw3", + "original_volcanic.mw3", + "snow.mw3", + "toxic.mw3", + "toxic_moss.mw3" + ], + "cave_rocks": [ + "bocchi_rock_hair_cube_things.mw3", + "brawler_volcanic.mw3", + "ice.mw3", + "layer_2.mw3", + "original_gray.mw3", + "original_mustard.mw3", + "pyra_mythra_ft_pneuma.mw3", + "snow.mw3", + "toxic.mw3" + ], + "water": [ + "dark_water.mw3", + "deep_aqua.mw3", + "deep_chocolate.mw3", + "harmless_magma.mw3", + "murky.mw3", + "oil_spill.mw3", + "original_brown.mw3", + "original_gray.mw3", + "original_green.mw3", + "original_mustard.mw3", + "original_volcanic.mw3", + "pickle_juice.mw3" + ], + "mushroom_rocks": [ + "atardecer.mw3", + "brightshroom.mw3", + "original_green.mw3", + "original_ice.mw3", + "original_volcanic.mw3", + "original_white.mw3", + "riesgo_de_chubascos_cafe.mw3", + "riesgo_de_chubascos_negro.mw3", + "shuk_ft_reyn.mw3" + ], + "mushroom_clouds": [ + "atardecer.mw3", + "greenshroom.mw3", + "oilshroom.mw3", + "original_aqua.mw3", + "original_blue.mw3", + "original_yellow.mw3", + "riesgo_de_chubascos.mw3" + ], + "mushroom_forest": [ + "atardecer.mw3", + "autumn.mw3", + "count_shroomcula.mw3", + "cursed_gold.mw3", + "dark_green.mw3", + "lifeless_gray.mw3", + "original.mw3", + "snow_dark.mw3", + "snow_green.mw3" + ], + "mushroom_hills": [ + "atardecer.mw3", + "atardecer_naranjo.mw3", + "atardecer_verde.mw3", + "future.mw3", + "original.mw3", + "riesgo_de_chubascos_azul.mw3", + "riesgo_de_chubascos_cafe.mw3", + "riesgo_de_chubascos_negro.mw3", + "watermelon_skies.mw3" + ], + "mushroom_stars": [ + "atardecer.mw3", + "cool.mw3", + "dark_night.mw3", + "halloween.mw3", + "light_pollution.mw3", + "midas.mw3", + "original_green.mw3", + "original_night.mw3", + "purpleish_night.mw3", + "riesgo_de_chubascos.mw3" + ], + "mushroom_cave": [ + "argent_cave.mw3", + "glowing_mushroom.mw3", + "green_aqua.mw3", + "ice.mw3", + "original.mw3", + "really_dark.mw3", + "toxic.mw3" + ], + "forest": [ + "agnian_queen.mw3", + "atardecer.mw3", + "frozen.mw3", + "halloween.mw3", + "kevesi_queen.mw3", + "original_dark.mw3", + "original_fall.mw3", + "original_green.mw3", + "sakura.mw3", + "snow_dark_leaves.mw3", + "snow_green_leaves.mw3" + ], + "logs": [ + "brawler.mw3", + "evening.mw3", + "mahogany.mw3", + "not_quite_dawnbreak.mw3", + "original.mw3", + "riesgo_de_chubascos.mw3" + ], + "clouds": [ + "atardecer.mw3", + "charcoal.mw3", + "cloudy.mw3", + "cotton_candy.mw3", + "original_green.mw3", + "original_orange.mw3" + ], + "castle_pillars": [ + "agnus_castle.mw3", + "cheese.mw3", + "chocolate_blue.mw3", + "dark_aqua_marine.mw3", + "dollhouse.mw3", + "gold_caslte.mw3", + "keves_castle.mw3", + "original_gray.mw3", + "original_green.mw3", + "original_mustard.mw3", + "original_white.mw3", + "pink_purple.mw3", + "purple_pink.mw3", + "sand_gray.mw3", + "sand_green.mw3", + "shenhe.mw3", + "whatsapp.mw3" + ], + "castle_windows": [ + "brawler_pink.mw3", + "cheese.mw3", + "dark_aqua_marine.mw3", + "dollhouse.mw3", + "original_brown.mw3", + "original_gray.mw3", + "original_water.mw3", + "red_castle.mw3", + "shenhe.mw3", + "underwater.mw3", + "water.mw3", + "whatsapp.mw3" + ], + "castle_wall": [ + "cheese.mw3", + "dollhouse.mw3", + "grand_marshall.mw3", + "hot_wall.mw3", + "original.mw3", + "sand_green.mw3", + "shenhe.mw3", + "water.mw3" + ], + "castle_small_windows": [ + "dark_lava.mw3", + "dark_purple.mw3", + "dollhouse.mw3", + "forgotten_temple.mw3", + "original_gray.mw3", + "original_volcanic.mw3", + "original_water.mw3", + "sand_gray.mw3", + "sand_green.mw3", + "shenhe.mw3", + "water.mw3", + "whatsapp.mw3" + ], + "ghost_house": [ + "brawler_cyan.mw3", + "brawler_orange.mw3", + "brawler_purple.mw3", + "creepypasta.mw3", + "crimson_house.mw3", + "golden_house.mw3", + "halloween_pallet.mw3", + "orange_lights.mw3", + "original_aqua.mw3", + "original_blue.mw3", + "original_dark.mw3", + "original_white.mw3" + ], + "ghost_house_exit": [ + "evening_exit.mw3", + "golden_house.mw3", + "original.mw3", + "original_blue_door.mw3", + "underwater.mw3" + ], + "ship_exterior": [ + "blue_purple.mw3", + "doc_ship.mw3", + "grey_ship.mw3", + "original.mw3", + "reddish.mw3" + ], + "ship_interior": [ + "blue_purple.mw3", + "bocchi_hitori.mw3", + "bocchi_rock.mw3", + "brawler.mw3", + "grey_ship.mw3", + "original.mw3" + ], + "switch_palace": [ + "blue_grid.mw3", + "brawler_brown.mw3", + "cafe_claro.mw3", + "color_del_gato_2.mw3", + "color_de_gato.mw3", + "green_grid.mw3", + "gris.mw3", + "mario_pants.mw3", + "monado.mw3", + "morado.mw3", + "negro.mw3", + "onigiria.mw3", + "original.mw3", + "original_bonus.mw3", + "pink.mw3", + "red_grid.mw3", + "verde.mw3", + "verde_agua.mw3", + "yellow_grid.mw3", + "youbonus.mw3" + ], + "yoshi_house": [ + "atardecer.mw3", + "brawler_green.mw3", + "choco.mw3", + "crimson.mw3", + "miku.mw3", + "mogumogu.mw3", + "monocromo.mw3", + "neon.mw3", + "nieve.mw3", + "night.mw3", + "nocturno.mw3", + "original.mw3", + "sakura.mw3", + "snow.mw3", + "strong_sun.mw3", + "sunsetish_grass_hills.mw3" + ] +} \ No newline at end of file diff --git a/worlds/smw/data/palettes/level/ship_exterior/blue_purple.mw3 b/worlds/smw/data/palettes/level/ship_exterior/blue_purple.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2e098de76404e6c399e3b5e06fbd264d83c28b36 GIT binary patch literal 514 zcmZQzxLdzU=d6X0FPmkS@7c)7#S9F;d0y*-=)3jxx**b#CsAaP3POH$)&F{s{A{^; zYmhtx14NcT=}H*`!+#)Ofmw_}o}r#`J`+S9VFFCP)nNdBB91A|1eN&VFN zA3(hj{SC|?<$p5&_lM};ZuC2yfk}b+0W$*z0NLLlU|++a_`p^n9YY%IK5-3s2Tj+t zkpgL$@*w*Pc|m@OPnM0~Vvx5y;=%iQH@E=J2 zKchVJf9CBB_CWta+>h`dh|iI`HrKEYSsvj(kh~y+I54~*^5`xE$v)Z^(Ve+*ma-siI<*PyR z=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3f8886IP8MGK8i)%pq`~eJ z*N}J6bX^-MkcKG_vagUA*fj9JyK@zquT z>p}Evxq54mJOhK5=2}xjw<$rE=?o12fqVsKF$Q^tddB%o5c#Dd&t)KLVDhyla-siI z<*PyR=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3f8886I{%pnn>PA}E z&8odIq`~eJ*N}J6bX^-MkcKG_vagUA*fj9JygnDPLa{Cvs) literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ship_exterior/original.mw3 b/worlds/smw/data/palettes/level/ship_exterior/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..20eec6ee80bedadf37912970c3927695055d3c49 GIT binary patch literal 514 zcmZQzxLbcB;7nw0(CY}F)C*CQiy0Vx^Sssv(Rb_XbwOl9tY!V=x)rG&VH)8e@zquT z>p}Evxq54mJOjf?4nN7uniY1k!3+%lfqVsKF$Q^tddB%o5cv}#oU%EZ=S_{AVDhyl za-siI<*PyR=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3f8886I{z6{+ z8lY>0|KpGs*N}J6bX^-MkcOchY+oTS$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE} zK@!PxisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*e0E^2-)8^)2D0YpvLN>u>G67X2zV*xYM!^nlm`H@hI|kJ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ship_exterior/reddish.mw3 b/worlds/smw/data/palettes/level/ship_exterior/reddish.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..674aafd0c0a6a2dda0b9a295989935373b814a51 GIT binary patch literal 514 zcmZQzxLfZka9TlFH$&u|hMDc;Vg`oaJg@aZ^xgV;T@cw2Ygun@XlT04^_MS5e0A0T zdJsKZuHG6X&%lr&@lK`K^rvH;9|OaGAYXx5j6t5Eo^d`CM1F+~x2m7+2Gh^BF!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}pXNH7* z4a5Z)(qQ+AYsfojx~`2BNW+u|*;mL5@=JWOYy=mByyX!W4!?r*Z3g#E{{!s<$)B^F z5+sp4r#M~*=01e~K=S_?<(dC8Z)dOv`WNDUg#SQ%j@-4mhIPpD2>*fP1sTMF;RTUL vcOgjr0pkOv2T=2|$!7=V`fc{#Zy;-qE(>yxkshyChk%!2uI71Q_@e^=o!@%I literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ship_interior/blue_purple.mw3 b/worlds/smw/data/palettes/level/ship_interior/blue_purple.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9ac0f022af3db2dcb4559286a7c215015b18d7a7 GIT binary patch literal 514 zcmZQzxLdzU=d6X0@Akx~ESciT#S9F;d0y*-=)3jxx**b#CsAaP3Y%q?@7YL@`0A?v z^&on-T)j0&o`C@(%b#?mjDg`lkgvcj#vsp7&p4k6B9AZuCSPkJ7y3U{z8WNd&XR#a zBH5&VYW)wOUWon%=8y6}ng9Dk^lvx%ozB3d!2E!j0Rw>SZxFDrVNiTvtB{T%4R)Wn zhP;EO>)J?xG)#GreTBRrzr-iYMsP96TOM)Y@GD5)W^mv1KhQpq{5i`hK@!PxisN-) z?nC$wB>$gLp7}rXb_RQ(e< a05u<*d_mpiIb3@`0A?v z^&on-T)j0&o`Io7=9qz|V|M7;R0f9sK)wRA7=t`RJ>z^Pi2O+bZc#ni0>$ZmF!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C6L3>W}pe<81Z z4bU~h|8dBRYsfojx~`2BNW;($wy%&EJstYLNUnO9lpsWRv=-^*?}mA^IDbKg$1P{_hXbzuo9}Is=me^8;oE3;?pfkk`Hj z=o;bwION4O8_2KP-t=7HRE&T>kS zMDm>CcpaGg5dH(n|7VnE{?ELf!5-*ei2D)#1MxX>*XA15A}FR hAo&N3511Z6&BrERPz^Ph&-FDhhmrJ8$&-Un0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 ig&_F{j1QO|K+VS{Ur=|s&a8fBy}SduET;R>RR93Jdw87y literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ship_interior/grey_ship.mw3 b/worlds/smw/data/palettes/level/ship_interior/grey_ship.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..786802304f335dde42c0a687bff76a19fc2d42ce GIT binary patch literal 514 zcmZQzxLe;U@KPpE_p@!8-_N+o#S9F;d0y*-=)3jxx*#%J^Sx!U*R?3i^f|>K@zquT z>p}Evxq54mJOhK5=2}xjw<$rE=?o12fqVsKF$Q^tddB%o5c#Dd&t)KLVDhyla-siI z<*PyR=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3f8886Ye%1f#=PZNV zzDHq5gWV^tA@88+x;9cE4O1RuUm-8ZFY(E;5nK%NmPcGT{0h>y8QeGh53~;?f6j7B zkVNvF;&>gH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 ig&_F{j1QO|K+VS{Ur=|s&a8fBy}SduET;R>RR92&9Dc(9 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/ship_interior/original.mw3 b/worlds/smw/data/palettes/level/ship_interior/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a208db211f51dd7967c5d1e2d5702488d0b9d7ed GIT binary patch literal 514 zcmZQzxLeP_a8$)pcdc%)l7#)_Vg`oaJg@aZ^xgV;T@aZd&?vE3=7|iarnf3ce0A0T zdJsKZuHG6X&%kh!!%yFayJXAYXx5j6t5Eo^d`CME-;br)-Yqc~c`Nn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 ig&_F{j1QO|K+VS{Ur=|s&a8fBy}SduET;R>RR91#$av}i literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/blue_grid.mw3 b/worlds/smw/data/palettes/level/switch_palace/blue_grid.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d613b8061deb3310e59c1ff98d2adeb268aa28e4 GIT binary patch literal 514 zcmZQzxLcnj!tKid1RImet0xyTF#P6utq-E_*4OKTNCpPE>iN|(>%Z0isRxO#uKEwA zXUo-FL*!pF@GAAO8cS_AVqo|WRIk7+#vsp7&p4k6BL6`5K~TMDypg>(Oup7cF7$t@ zd^Je^oFxN;M6yZ!)cPMly%7Bk%pc`{GXM97=-+PiJDq_^f%yS5$epMFBY zg#TlaXJFv=71xk=K-Godf$S^f1^FdDSvG=;LEiF+3x{7p`Zk06rXce`^5-n41W6>% zDUR2Hxewt#koc-C!jNdvsZldz4j=n5x>fxjpy842Aj804FSX7XSbN literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/brawler_brown.mw3 b/worlds/smw/data/palettes/level/switch_palace/brawler_brown.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a3073c31adca276933a73da4fe5187fd14cb73e7 GIT binary patch literal 514 zcmZQzxLcnj;%0i*uv>FuQhD{{Vg`oaJg@aZ^xgV;T@cB@AXh!VdS?B%`aks`@zquT z!SrmodTWUMO9o!0)0PHyo4ptq{sYx3FpDwBGt@KAXM)H-(0ve8FB)%T?+uf$HIWPb zpDJGsl0Rq3z#x%qQa`o+2T(6We*^PJ`Jc@H{UQ3d8~sjaU{YXyz|4RFK<+E#wXXrX zM)*Gtd2tPS2V=WXw`qPD+QIe}@`C&lpDY`}#UO8a#D&AJAbp#`eN&KmAorZJoDw9F zJf}Eb2j)J6|3LEp8ReP(GjC_G2l^M{euV!(e2(0;xrTMf@(BNd}Q@k1h*xkFx3!Q&qb*x95KH4(RgpqX8dweTD!4 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/cafe_claro.mw3 b/worlds/smw/data/palettes/level/switch_palace/cafe_claro.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..90ffc5cf73f8caf0c9e92d7ce04a6b688c9b556a GIT binary patch literal 514 zcmZQzxLcnj;%2HNyHR&zQhD{{Vg`oaJg@aZ^xgV;T@cB@AXh!VdS?B%`aks`@zquT z!SrmodTWUMO9o!0K2~F??M4g?|AFcin8g_68R{A5GeP7Z=spOl7mYWv_lC*Wn#hIz zPnE9*$)B@iV30^Qsh?W^1E?3Gzk&Iq{7>fp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszE1IUM=b{N{h_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK r;{&D#Q1h|LA64#(3v!RL>Jd{_yEeDye)10J^7Eqswefr( literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/color_de_gato.mw3 b/worlds/smw/data/palettes/level/switch_palace/color_de_gato.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b5ba743bfae9cf2bb8443b692f0b4f6ae023912d GIT binary patch literal 514 zcmZQzxLcnj;$|AlSj)6Asl0k}F$2SIp4a*y`fh!_E{J4ckgJ|wJ+uB>{hxY}`0A?v zV0yM(y){JsB?GTgAFHv{b|VIc|3LK$%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@DvtMn}W;($)B^F5+sp4 zr#M~*=01e~K=S_?<(dC8Z)dOvnh$Y5!haw>NAB8O!#ZSng#SSDf(+uo@Pf!=bKe8T r2TTv3=3|pTs^Y1;RySBl!X8}~rE=SKqoqbPe_ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/color_del_gato_2.mw3 b/worlds/smw/data/palettes/level/switch_palace/color_del_gato_2.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9c52a56a872a27b8dff95fb1439873ffd3a28293 GIT binary patch literal 514 zcmZQzxLcnj;%53?pjvWcQhD{{Vg`oaJg@aZ^xgV;T@cB@AXh!VdS?B%`aks`@zquT z!SrmodTWUMO9o!0K2~F??M4g?|AFcin8g_68R{A5GeP7Z=spOl7mYWv_lC*Wn#hIz zPnE9*$)B@iV30^Qsh?W^1E?3Gzk&Iq{7>fp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszE1IUN}fc`-TAo~h=L4Ju(mW|+IkheVI!r@ntzRlpiDabsK{5i`hK@!Px zisN-)?nC$wB>$gLp7}rXb_RQ(eIN%G*rUsW+@q{|#8lO;&F#6LyaT%Y{Ad8bl6{{5 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/green_grid.mw3 b/worlds/smw/data/palettes/level/switch_palace/green_grid.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..3a8ded956b435a03b03666b57f3ea4cd54bcc57b GIT binary patch literal 514 zcmZQzxLcnj!tKid1RImet0xyTF#P6utq-E_*4OKTNCpPE>iN|(>%Z0isRxO#uKEwA zXUo-FL*!pF@GAAO8cS_AVqo|WRIk7+#vsp7&p4k6BL6`5K~TMDypg>(Oup7cF7$t@ zd^Je^oFxN;M6yZ!)cPMly%7Bk%pc`{GXM97=-+PiJDq_^f%yS5$epMFBY zg#Tla2dZWi*N}HW)rH`J>?`C2`6WJCHiC;m-tveGhhIVZHiP@7AoD=-=PaiLNhHrH zj@N;?58*$M{C`Gy=Ksvw8SH`ng}5K#KM;5h569{#y5As literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/gris.mw3 b/worlds/smw/data/palettes/level/switch_palace/gris.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8e8df8008bb40d0a7d1988bb227c4fa1731010db GIT binary patch literal 514 zcmZQzxLcnj;$}J}NFsS-QhD{{Vg`oaJg@aZ^xgV;T@cB@AXh!VdS?B%`aks`@zquT z!SrmodTWUMO9o!0K2~F??M4g?|AFcin8g_68R{A5GeP7Z=spOl7mYWv_lC*Wn#hIz zPnE9*$)B@iV30^Qsh?W^1E?3Gzk&Iq{7>fp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszE!#PVsw<$pw+QIe}@`C&lpDY`}#UO8a#D&AJAbp#`eN&KmAorZJ1clF> z;&>gH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2g&_F{ sj1QO|K+VS{e^kX&cdc%)l7v0FEXX~|sz*#!?b_U)`^h_?%g>Jn0OBZp0{{R3 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/mario_pants.mw3 b/worlds/smw/data/palettes/level/switch_palace/mario_pants.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b18aee2e184171a3b62dc46b3b9f725efe844799 GIT binary patch literal 514 zcmZQzxLcnj!tKk&AaA)bsl0k}F$2SIp4a*y`fh!_E{J4ckgJ|wJ+uB>{hxY}`0A?v zV0yM(y){JsB?GTgAFHv{b|VIc|3LK$%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK;{&D# nQ1h|LA64#(3v!RL>Jd{_yEeDye)10J^7EqsawvPU literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/monado.mw3 b/worlds/smw/data/palettes/level/switch_palace/monado.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c37acf989847366753986709d39c92b78c2dee1b GIT binary patch literal 514 zcmZQzxLcnj;%1sFpkcZ(sl0k}F$2SIp4a*y`fh!_E{J4ckgJ|wJ+uB>{hxY}`0A?v zV0yM(y){JsB?GTgAFHv{b|VIc|3LK$%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@4{^34C4w=>uS{R?qF!haw>NAB8O!#ZSng#SSDf(+uo@Pf#r wyAUM*fbjv-1E~4faNudR+6wsmj$^;S@npis$HAgb3b_pbou$w0C>QBCIA2c literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/morado.mw3 b/worlds/smw/data/palettes/level/switch_palace/morado.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ab495c8b33b658f4539317aa5dc7da23923d8cf5 GIT binary patch literal 514 zcmZQzxLcnj;%2Jn8xp!Psl0k}F$2SIp4a*y`fh!_E{J4ckgJ|wJ+uB>{hxY}`0A?v zV0yM(y){JsB?GTgAFHv{b|VIc|3LK$%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@tGAkMJLe&yl+}*RT#*9^pTbydZ-(FuWl0=q?1w tKVW>o^Z;r;Hu<9}p1NywgOw!g(PcsIQC2--s%qEf_S{e20bPE6GyuHnd?)|_ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/negro.mw3 b/worlds/smw/data/palettes/level/switch_palace/negro.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..dd9db46ffdea238a8bc241c3948f2fe143f2385e GIT binary patch literal 514 zcmZQzxLcnj;%0hGB3pN3QhD{{Vg`oaJg@aZ^xgV;T@cB@AXh!VdS?B%`aks`@zquT z!SrmodTWUMO9o!0K2~F??M4g?|AFcin8g_68R{A5GeP7Z=spOl7mYWv_lC*Wn#hIz zPnE9*$)B@iV30^Qsh?W^1E?3Gzk&Iq{7>fp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszE0|UcS5lvML?O^)~c|m@OPnM0~Vvx5y;=LsJ19Kn3e<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! t|A6rU(*vma*yN9@cG*(EyN*d%FMt literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/onigiria.mw3 b/worlds/smw/data/palettes/level/switch_palace/onigiria.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..7632dc08b226eca8998e5e06798767184ed6748d GIT binary patch literal 514 zcmZQzxLcnj;%2I;tLwQjsl0k}F$2SIp4a*y`fh!_E{J4ckgJ|wJ+uB>{hxY}`0A?v zV0yM(y){JsB?GTgAFHv{b|VIc|3LK$%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@LsJ19Kn3e<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! t|A6rU(*vma*yN9@cfp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszEgQn}+NP#pA?O^)~c|m@OPnM0~Vvx5y;=LsJ19Kn3e<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! t|A6rU(*vma*yN9@cy8QeDonFn&uIm;~8`{!cwfe09}- zFg;tY-WnqRl7UyLkJVUeyAcD!f1r8=W-$hNhI+>NOc418x(|ZtMdOX^yZjKK0P2P4Z(#l?|C9N@KScj_qu=QaObW~om>Dnt$bE&p_BBA) z2>-_+FRmf)z;FA_=WYy!cCdYgydb~CC(A}~G00mUapCYQNZ)2~-xOpX$UWyQrvynP z&nb@Afw>RiKal)?MtSD{%-b34f&PWKAK^a`pCfl|u3;UrJi>ngPyZ1P7{JayOV1}jO}qsxNaqpW(wRMoD{?YW=41G@bDXaI5gdhP%K literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/red_grid.mw3 b/worlds/smw/data/palettes/level/switch_palace/red_grid.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..1336dc83468039d90876692cc112596cd79bd549 GIT binary patch literal 514 zcmZQzxLcnj!tKid1RImet0xyTF#P6utq-E_*4OKTNCpPE>iN|(>%Z0isRxO#uKEwA zXUo-FL*!pF@GAAO8cS_AVqo|WRIk7+#vsp7&p4k6BL6`5K~TMDypg>(Oup7cF7$t@ zd^Je^oFxN;M6yZ!)cPMly%7Bk%pc`{GXM97=-+PiJDq_^f%yS5$epMFBY zg#TlaX8^iHTtnUgRTqK>vagUA+_kxeb;$Av|AFKM8N`9EgvcXY24R8Z rA22>(dH^*aoBUA~Pu;b;!AcVL=&~U9D61YZRkdq#d+vuB3iG1@=e&2` literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/verde.mw3 b/worlds/smw/data/palettes/level/switch_palace/verde.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..92515d0c32f5169b0017cd26063b42750298e4be GIT binary patch literal 514 zcmZQzxLcnj;%3^;`;vEKQhD{{Vg`oaJg@aZ^xgV;T@cB@AXh!VdS?B%`aks`@zquT z!SrmodTWUMO9o!0K2~F??M4g?|AFcin8g_68R{A5GeP7Z=spOl7mYWv_lC*Wn#hIz zPnE9*$)B@iV30^Qsh?W^1E?3Gzk&Iq{7>fp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszEgB$M(UM@Zi?O^)~c|m@OPnM0~Vvx5y;=LsJ19Kn3e<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! t|A6rU(*vma*yN9@cfp{t*4!jee&yFexxUU}nGoAomsW+SdSG zBm5tSytszE1IUL7ei+)p_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~B#}I) zI9>+_kxeb;$Av|AFKM8N`9%1(8R0AxQoK r;{&D#Q1h|LA64#(3v!RL>Jd{_yEeDye)10J^7Eqs$>Mz4 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/yellow_grid.mw3 b/worlds/smw/data/palettes/level/switch_palace/yellow_grid.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c41276492eb0ccc73add33198c80b001d1874c60 GIT binary patch literal 514 zcmZQzxLcnj!tKid1RImet0xyTF#P6utq-E_*4OKTNCpPE>iN|(>%Z0isRxO#uKEwA zXUo-FL*!pF@GAAO8cS_AVqo|WRIk7+#vsp7&p4k6BL6`5K~TMDypg>(Oup7cF7$t@ zd^Je^oFxN;M6yZ!)cPMly%7Bk%pc`{GXM97=-+PiJDq_^f%yS5$epMFBY zg#TlaXJDuo7T1t>K-Godf$S^f1^FdDSvG=;LEiF+3x{7p`Zk06rXce`^5-n41W6>% zDUR2Hxewt#koc-C!jNdvsZldz4j=n5x>fxjpy842Aj80BACJQ2+n{ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/switch_palace/youbonus.mw3 b/worlds/smw/data/palettes/level/switch_palace/youbonus.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b213f566079581f1d272ed2ce0207c6749b38fab GIT binary patch literal 514 zcmZQzxLcnj;%2ID$q}|Osl0k}F$2SIp4a*y`fh!_E{J4ckgJ|wJ+uB>{hxY}`0A?v zV0yM(y){JsB?GTgAFHv{b|VIc|3LK$%wi1k4E2ojnIQ5HbRPuOi^dz-d&A^wP2@uV zr^;7@LsJ19Kn3e<1n)jPlI?nYT081N{qeKf-??K1c4_T*EqKd4&H!@`4QF!0>{|qq`6! t|A6rU(*vma*yN9@cp}Evxq54mJOjf~6;It`I?HVH^B5TZ1NjQfVhr*O^^EhGAo5}i(hTv8@=Wr~F!@>& zxzPWq^3@>ubCwJY63Hg@Q|o^K^+NPFFn^T)$^73RqJO*5?{o$x1?C4p{pbK>e<81Z z4bU~h|8dBRYsfojx~`2BNJG~Rv9FL9JuvF%l%5xn}&z{i9#S9F;d0y*-=)3jxx(q=1hFHsbzPLpaZl=q9LE@{c z{?~)(*>d&PAbAD`4!?qQR?TIOE0Y)){?{`wC@_mL$TQS4&S!$ib2IQV7zutAHIstL z*P6(M{!f*!2FYuxGB5;rt<4k2E(e+g(ci%QQT`|Me}9Pn51PNz(?vCv)@U(c0FeEK zy!JJhWp}CBm}5wT-RCKjZ*a_n!_zAkyZmd8O}rI+@yW6gTnzG-M_fSu*=BIx^glDi zeofULLjk8^zsn9V_o4c4n`niQ75`b0uaYo%WdAWRyl~+RU6+Y0kLo``2613`LFCb0 r2=bq+=n2IvE!^_ifw_L0{r4NlV)eg~9lVAo0~z z|LZ~YY`J=CkURqehhIT@8_z3=Tulas|Md(E3d~{*@(lHi^O+#>+zh-7MuJ~O&7@%R zwI*_*|5N3wLGqfa3=BbDYx4xM%YkM=^fxenl>f>6-yfp?gXZt_bWu&EHChZ90Azn5 zuYJvB*gH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 wg&_F{j1QO|K+VS{pBYEXX}Zdc0m80$z%_n&)lNb%7 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/murky.mw3 b/worlds/smw/data/palettes/level/water/murky.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..57ea1ce44f5e72698c17e239141e7b54c163b17a GIT binary patch literal 514 zcmZQz*j2t*f=y9PHBd&PAo;~2shY% zUuz;4`ae~^8YKV5aj}S5`o!`r)jNQEi2erVkMcj6|NBGqZ#Vj#{!sUT-2-O^3;?qK zgP?uQExBm*+xi&NVE1k2u#)sJd>yD8hh08Ta)w^4b9}OF1Q&z68_2KP<> zGehj>aoQYamOi7n))nSHRR38E)$`xe4-ve>29rnj-(r!rK)<|?b;$Cl{_E$s#v{WE wkwF7s2x80&%YfeM-h096fzpa1{> literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/oil_spill.mw3 b/worlds/smw/data/palettes/level/water/oil_spill.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ac1ffed27f62b1137ec363aebc34115fd4b19d87 GIT binary patch literal 514 zcmZQzxLcph1A#39EdrB^85n-^yw(TNckAnQL1aU$W&JUU7J;QAOGQB9tE>LkgXr0E z_0}MH28I)n=Zabcj!9^$GBErH@)elH7~~o18Rs)W(dH^*an|yX)uHR<={RXn;=&~U980qnPbqIJV=4zg|MVEKt002gCeFp#l literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/original_brown.mw3 b/worlds/smw/data/palettes/level/water/original_brown.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5f5366cebd110b6b7a55f1fbf5a4f1665ef1d4db GIT binary patch literal 514 zcmZQzxLbcB;7nw0(CY}F)C*CQiy0Vx^Sssv(Rb_XbwOl9tY!V=x)rG&VH)8e@zquT z>p}Evxq54mJOjf?4nN7uniY1k!3+%lfqVsKF$Q^tddB%o5cv}#oU%EZ=S_{AVDhyl za-siI<*PyR=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3f8886I{z6{+ z8lY>0|KpGs*N}J6bX^-MkcOchY+oTS$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE} zK@!PxisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*e0E^2-)8^)2D0YpvLN>u>G67X2zV*xYM!@6mv4v#0J7tJ?EnA( literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/original_gray.mw3 b/worlds/smw/data/palettes/level/water/original_gray.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b5087eccbed5ca09f590dc7d4c7288b950064b7b GIT binary patch literal 514 zcmZQzxLbcB;7nw0(CY}F)C*CQiy0Vx^Sssv(Rb_XbwOl9tY!V=x)rG&VH)8e@zquT z>p}Evxq54mJOjgt$a6)fEe-58doeKl2l5q|#Teun>KW%VLFC04q#5EF<(cG}Ve+*m za-siI<*PyR=PVf*B$7?)r`G=f>V@cUVE!oolli|tME`c9-{}lY3d|3H`q2T%{z6{+ z8lY>0|KpGs*N}J6bX^-MkcO@sVqYOI$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE} zK@!PxisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*e0E^2-)8^)2D0YpvLN>u>G67X2zV*xYM!@6mv4v#0I1}AC;$Ke literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/original_green.mw3 b/worlds/smw/data/palettes/level/water/original_green.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..6697f2839edc0baec036037589d7dc6746935572 GIT binary patch literal 514 zcmZQzxLbcB;7nw0(CY}F)C*CQiy0Vx^Sssv(Rb_XbwOl9tY!V=x)rG&VH)8e@zquT z>p}Evxq54mJOjf^#x+d(%rlw)1v4=G2l5q|#Teun>KW%VLF5^Lpx@?3VtpM+HAw!PB?E&*vPu2a`X4~O5d96zALV~C|M!RJ-){6foqtGAkMJLe&yl+}*RT#*9^pTbydZ-(FuWl0 x=q?1wKVW>o^Z;r;Hu>zpT))l!`we8x(PcsIG1BAp>Jac!%+)+^i!R>~3jj0+eLMgF literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/original_mustard.mw3 b/worlds/smw/data/palettes/level/water/original_mustard.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..bf14a8cb157e0ac7a87163cea6a81c71e0e9d307 GIT binary patch literal 514 zcmZQzxLbcB;7nw0(CY}F)C*CQiy0Vx^Sssv(Rb_XbwOl9tY!V=x)rG&VH)8e@zquT z>p}Evxq54mJOjf^241B;R%5B{Mhp!9fqVsKF$Q^tddB%o5cvnX4}$7NV@cUVE!oolli|tME`c9-{}lY3d|3f8886I{z6{+ z8lY>0|KpGs*N}J6bX^-MkcOchY+oTS$S?89vJqSi@|H(jIQ$CIw;9|w1(^qO&pFE} zK@!PxisN-)?nC$wB>$gLp7}rXb_RQ(e<05u<*e0E^2-)8^)2D0YpvLN>u>G67X2zV*xYM!@6mv4v#07%k(Qvd(} literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/original_volcanic.mw3 b/worlds/smw/data/palettes/level/water/original_volcanic.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ef22bf7bf6a0f10c77cd5cc8c7e52859bfb75d04 GIT binary patch literal 514 zcmZQzxLbcB;7nw0(CY}F)C*CQiy0Vx^Sssv(Rb_XbwOl9tY!V=x)rG&VH)8e@zquT z>p}Evxq54mJOjf~6;Iu@y1_~k_6!XFfqVsKF$Q^tddB%o5P2~MX@+=4c_w*gn0&2? zTgH`w;#E$^U1RXa3K;oxvXHUx@n={sZwja@Xb>)*;Iy{0EX3WDp027epT2 wg&_F{j1QO|K+VS{pBYEXX}Zdc0m80$z%_n&)lN0F>W)X8-^I literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/water/pickle_juice.mw3 b/worlds/smw/data/palettes/level/water/pickle_juice.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a27ebcfd89750ea2e47c9b4979b175c517aa673d GIT binary patch literal 514 zcmZQzxLePoR;kTzo+(u%7UDm-n1SIp&ue`UeYd_|7eqG1TGmI#rwFpky;K8ByERXOXNM4XZ z92i~@d2|Rd$>ZUW8WVR;fJaHPUm7OX8*#>fB``2jX3RVtd;Dg z=W}C7gU!3fV#})Q+8-&DhFw08H(KexReZ8+1Q&z68_2KP<>1MLHuzupw$ zdV5s}--sF2e{yX1*y4q+aM($~VG|mo-J2z z4U%VI==U@ZyPg(Z{2R#r55&Lg#Teun>KW%Vf#h3xvUT6v`WhK}-$;hZ*P6(M{!f*! z2FahZWMGg;HmRRl{{ybSf%&8SPv-yr5dGVYey3l|`d$BknE?ZU>@VcCuK~J7_&*ML zaSeF~P1m)N0%_YB?164V1|atq@`C&lpDY`}#UO8a#D&AJAbp#`eN&KmAo+8aQ-UOt z=M=~5K==yG2>*fP|1-)n|7V7n4dN>>Bm4*AbL6hgHLOFHNB9pUFUTMc3@=Q#f!qm_ vf57;F=>gPyWVgfQkE(d;uGI}zlCVdY1?g8-Jz}bA*XH)zPu>At{#rBulJG_-`$;6v0qTOt*P6(M{!f*!2I)U%$-p3y zY*Ih9{s&MkM81Lfqx?_i|Nap3w;TOVzpN=6{D7GO1Axpg3^VoAo+8aQ-VOQkJo{@58*$M{C`Gy=Ksvw8SI%L z@(Rod|AFK=a@Xb>)*;Iy{0EX3WDsYNXMo6KbKe8T2TTv3=3|pTs^Y1;RySBl!X8}~ WrE8)5+k)PX|) literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/crimson.mw3 b/worlds/smw/data/palettes/level/yoshi_house/crimson.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..e334904a372b04e6ddeb0cc1f681ee7283c5e8f1 GIT binary patch literal 514 zcmZQzxLe;Xa7p5aOoi$UKk4|%#S9F;d0y*-=)3jxx*!rF?_~Ky=7$VOe0A0TdJsKZ zuHG6X&%od#8RFC}a3k!83z^Phg; zsq)nz`E!;G3=+vE^;7GA0QExT8<;=J|78B}57EEf=y!Uzzz>-oJq8Q_vcHhmzUGtQ zFEvSd3~8|Y#5Lp{G<35ZPlsa4gX}Bh1^FdDSvG=;LEiF+3x{7p`Zk06rvI5C?m1^U zB?#pDcpV5|ff?aHkpBOS^34C4w=>uS{R`qNFeCg2;&bG#%{8n;mPhyxBrnJy4h%1d yJh}@(@(&mvFg<{pk4^rlil^>c-C!jNdvsZldz4j=n5x>fxjpxjcR-haAprnZw1M9M literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/miku.mw3 b/worlds/smw/data/palettes/level/yoshi_house/miku.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5d3b9e81144a649d6b51d4f089eb7eaa7bb8cd4d GIT binary patch literal 514 zcmZQzxLcpBn&#vYogXBUJfnDWF$2SIp4a*y`fh!_E{KH4J6U=}dqji8S6BV72hp?T z>a9WY3=Bs^jwz^E@dHg^VE7N@dqj&d$TQS4&S!$iXY0PVE%uX0o&(eck*_t83;mxe zUk#E!XUV`Ik!(^wwf+ZCFGRk9`J?<#=KuZ>{o9Rxr>j_bL~o8~zyKio3wiBpD%EVn z|1)DqgWV^tA@AU3$>X;%2~!?qUm-8ZFY(E;5nK%NmPcGT{0h>y8QeDonFo?TXE`MZ z)*;Iy{0EX3WDp027epT2 ug&=tqr8i!i<8jL$Rq@nas~fB&VUMmGrEtBV1!;Cz7q literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/mogumogu.mw3 b/worlds/smw/data/palettes/level/yoshi_house/mogumogu.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..cf76396c8fb0360e684214e03ce05fded5fa2e92 GIT binary patch literal 514 zcmZQzxLfb*xiQhCsIu%Vr%`nMbXPJeC@l$qkqfB``Ezjv{(i3ptQ z7AK4$4R+r}n<(4oIzGNvfbK&FAo~h=L4Ju(mW|+IkheVI!r@ntzRlpi>3?R3dqD07 zxn9ZIN%G*rV$Pxkp*`h^eYwo7;0gc?WcPi6Q{FsD)|( literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/monocromo.mw3 b/worlds/smw/data/palettes/level/yoshi_house/monocromo.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..8e1529f5149896fd2b6552cde7e7e59dba5fb36a GIT binary patch literal 514 zcmZQzxLdEOnyvfZw%AW1c~0@>0W$*z0NG#2YhMF#KZZ1h`_NT@>?`C2`6WJCHiC;m-tveGhhIVZ zHiP@7|AF>_*fPAv{nxLF5&f5&pw2kMJM5JT~_sn~zQYsEViV dTHRnJ343%|kb9I>kC>|3wYfd_lXt+B2LNGMh~NMK literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/neon.mw3 b/worlds/smw/data/palettes/level/yoshi_house/neon.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d3e183a770fd5c5a6e7721f0ef3212d8030f2ea9 GIT binary patch literal 514 zcmZQzxLeOq!vF$ca&j>P!*8C~`XKsleZ4M-gvx^zfy7r={jUenv*qfoL4pd*U@15u z4`)Fb=<;%*$O`V(pR;6OkVrPEpIZN;9wgI%V&2_)1?KHWztcf74^U)4A|UtuXD;Nm zhxh>^ghry|3wYfd_lXpOf!&m@77fJj8 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/nieve.mw3 b/worlds/smw/data/palettes/level/yoshi_house/nieve.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..07db0b1339ddcd516ef120e3783183d9ac0b80cd GIT binary patch literal 514 zcmZQzxLf}|bZg%CGRykv`n~m&iy0Vx^Sssv(Rb_XbwMOV{(b1)`tM~R@zquT!Rltq z)mtOvA^I5@{?{`w?5*d>%`QAwX;=r5&(?i!TkI#1JO`*7B42AF7y3U{z8WNd&XR#a zBH5&VYW)wOUWj}H^GErg%>VsC@(c{yjee(pFWX!HfSCaUfZSKeYhMGiA6)^={kY^o z_7(Di{1Trm8^OgOZ+XOp!>=HHo56k4|3Ldd^5-n41c6*1uLE-*!haz7|BUj?|CzTl z*fT-o6_^qJ1IcsbuFW;9LzYMQ4#(3v!RL>Jd{_yEeDye)10J@(r;7;SHAz literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/night.mw3 b/worlds/smw/data/palettes/level/yoshi_house/night.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..7cc0122339b0e41c8d372496b934ffcdf9743ac6 GIT binary patch literal 514 zcmZQzXpupNlZzP`e)GK62hn%y>vb8BKuLjAVvt(e9NH(dT zTK@y67b4%l{89cV^M8Mc{_RG;(^)m$-5xMAU;vQ)g}nAPTU;&ND*Z5|!R`~+kay5@ zT^lKohA9uSuaFnym-uAa2rdSB%Ofrveg)~<4DOr$2igacKW8~52;};B9SC268R0*W z{C`Gy=Ksvw8SH`n1@RS_5&i@5Ida$L8rC7pBm4)F7i16zh8IL0-Gw0e2aFGx9ze~< lCVy1LQ+KUyu#$v5x-7^&%Bn|9Rqfi`p8Lr=pvy0j0RS0@dUyZ; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/nocturno.mw3 b/worlds/smw/data/palettes/level/yoshi_house/nocturno.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..de764ef9e823f6e40030de28d50f132a76c5ef1e GIT binary patch literal 514 zcmZQzSf;Z~XQ>K|oLtPn@SEqgK8U_sU$4u6B;RbcOa~;sy6S&Dh@LH1Zw*q#z;IHb z*fQBv!mZhgf#E-p-)tquAkR?GIG+h3pRN1ew%AW1c@9t)M84KUF7$t@d^Je^oFxN; zM6yZ!)cPMly%6~Z=8y6}ng9Dk^lvx%ot|vkZ1sSd0Rw>SFXXka0lG%`KMr|u4S5Gm z*R_!XX&BnU_7(Di{1Trm8^OgOZ+XOp!>=HHo56ikka-~YoU@z~1af`64ur43jPM^w z{y(EU^MB^;4E8|(g7^x|2>*fj9JyG;SV_VjT^8gXWz{35s&;K|&;8^b(B+q^008FUeqaCq literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/original.mw3 b/worlds/smw/data/palettes/level/yoshi_house/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..051d266fbd86097ec67979f677f41cccc748400c GIT binary patch literal 514 zcmZQzxLfaJ$q{reODH)sdq(l(Vg`oaJg@aZ^xgV;T@VS8cd}GqK9>a&UtRUT9z@TU ztG5QpGcc^@t<-ye3nE`@A{Y8U zRlXV|f6kJDK_c0tero*>pk9c41M^4upUnULA^Nu){Z40KQeb`nG#?#+>@VcCuK~J7 z_&*MLaSeF~P1m)N0%_>FA@&vWg8UMnEE~baAa8lZg~P8PeVf63Q;>Ne_nfnw5(IL6 zybjEL2>*fP|1-)n|7YILU=Q>!y8l3Yj@-4mhIPpD2>*fP1sTMF;RTULcOgjr0pkOv o2T=2|$sbkm)Lp9^tR!KNE(>yxvg#32Rl7E~=YH}I=<@TU0RyRexc~qF literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/sakura.mw3 b/worlds/smw/data/palettes/level/yoshi_house/sakura.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d099ba93531275332326a6a5b04e9d7d76a46d19 GIT binary patch literal 514 zcmZQzxLa=+I5qM|tWDbdEcxQe#S9F;d0y*-=)3jxx*!rFZx|?B_9GS~zPjpvJ&2wy zS8olHXJB|KDyTgrV7j?%83V(AAYZmjj6t5Eo^d`CL_XbsFLqO^Y1Yjmn0&2?TW}pe<81Z4bU~h z|8dBRYsfojx~`2BNW;($wy%&EkC>|3wYfd_lXpOuFRupxL+*fT literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/snow.mw3 b/worlds/smw/data/palettes/level/yoshi_house/snow.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..4fea26a690b26e3b84314d2871e9fc2a1a769840 GIT binary patch literal 514 zcmZQz*jt|I`X+W$(fKsf;#t*`iy0Vx^Sssv(Rb_Xbs6CDnXYrnHx+@zS6BV72hp?T z>a9WYOC{b*Y}YJ`i*}n+4&l!!FP4eYkui;z0`VCbJWbEK7KVLKL&)FEuq~AqFPPwxG3G?^jzr!KsZ8!RzUKBT{d==0>bO5rykk`JZLe55i zt}(hSME^_^8AnamwUGj8*yT3}-jbT<9G@&3!NnkNdBlaouONM!!F|*J%n<$WT(`to z=2w^B31wjTU(djxz%0ff&rr`ep9vx#$rq=*Pux^+o)S#H)%P8)CkG=!e{i OMMmY-K=-49s%ijSagbO5 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/strong_sun.mw3 b/worlds/smw/data/palettes/level/yoshi_house/strong_sun.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..7c671aa368ed47023734baf45ab897f7b3cf5f5a GIT binary patch literal 514 zcmZQzxLeLF$2SIp4a*y`fh!_E{KH4w;Qf!*2@Noude!E529zw z)mww)85llu-Zopw6lc7inStRykiVW;j6t5Eo^d`CL_S;hy=}3dMDiSo`lBY zg#Y7^7uS$?&~#lJDUgP)8)9D}FUT+P$+8h#4DyyoTsZs+(zhAhHwBpoa?d%-DM29D z$Lm1&3P}C~$^U1RXa3K;oxvXHUl3n`8R0(=pCfl|u3;UrJi>ngPyZ1P7{JayOV1}jO}qsxNaqpW(wRMoD{?YW=41G@bGYyjEIe}(`6 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/level/yoshi_house/sunsetish_grass_hills.mw3 b/worlds/smw/data/palettes/level/yoshi_house/sunsetish_grass_hills.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c51bdfc6a7d3c0784d33fe3b73dca7557de88146 GIT binary patch literal 514 zcmZQzsLpm1d?~qB>AjnAa9RB1Vg`oaJg@aZ^xgV;T?V*3L={MUb=CiR5ItM2-Wnv& zz+l8Ui_uNcUg)JH1H=D%28NfCVhr*O^^EhGAo5NPewpkk_@S>U>)j z2w#C2;Xjc49mYFM)y&%%WPtt!@fDa6{sZxka={cOgiA s0b>JG0@QqL@<&xXb=T?!D@oX+%Yxjata`*$)vnF$xu3iPx_pHd0O>G!F8}}l literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/atardecer.mw3 b/worlds/smw/data/palettes/map/forest/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..5ce855399b9857bb393bf4cb8002786baa090204 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3OrBfJ#bm_%g&D->QtH*i)c>D(f3bWGNZwkhnBA7uh|`O4GaHBx zF~45dTmPdw1H*oxPYQYKng9F8C(A}~G00mUapCYQNZ)2~-}FDwe31M*rnR-7n6Gfy zNrCjE0+75IXB{g??p@vZWK=m24Kp1G03qq}3=Gl? Sx^AE2TE!s#!88GXd;kDyk!$P# literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/burnt_forest.mw3 b/worlds/smw/data/palettes/map/forest/burnt_forest.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..58b0648f18e36da4365a6d545a70ecf5a73d739a GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3K=gg*ZFCx z?h=uZi!tW}+h-W`Ep1M9tC+X`M|Y6=1TzJ1P1Ptrt6*gP|C#Sq%h!P9%fmEPx0v>u zg6skDA?DZXLiB^&P{>=){NF!5SvG=;LEiF+3x{7p`Zk06rvI6Np#hYCz__-yfq6TF zJrhVjDgeogF~~D;K=ggTb6T} zu?I@X#h7z~?K2GemNuulRm@xeqdQ1_f|-Ihhgp=LRWP#t|IGKQ>+4b>ov!Kp1G03qq}3=Gl? Qx^AE25aEGt2LAW}0O1;G(EtDd literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/halloween.mw3 b/worlds/smw/data/palettes/map/forest/halloween.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c3899751bf31b65cccd242e0402f0b9ea5c3c3be GIT binary patch literal 514 zcmZQzKn0VF85sUEU-p??+-1rP4qYC^f3A~l``))W z?t9++Pu#k}=Dx`X5s%x)&USBmnp3P#rd zpZQ+3d<{rG-u-66T*LcnAR9n@i23!p5d9$c6!O+H|M!nimW|+IkheVI!r@ntzRlpi zDabsK`~$|dwGGVMf$j$BM+G2xkZ(A0@9M@UqsoDJAo&KS2h1F~Qfildu**NFQ>bsK be*lD}%QG-YGw8Z~jzfe8x*4ePfi4RGbnI~U literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/ice_forest.mw3 b/worlds/smw/data/palettes/map/forest/ice_forest.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..32d62829bd5c4e0a1a2f6e8c2b46efc9275d8f9a GIT binary patch literal 514 zcmZQzKn0VF85sUE7spL5e(#%Y`&W3-_OWUx1ad|^PhT%ytd=|(BPy}sh#z~)gaaWk`;D#;RK=ggTb2hW z1y@VR#h7z~?K2GemNuulRm@xeqdQ1_f?06Vd!;Bpt6*gP|C#Sq%h!P9f#xR7H4Lr> z*#qK3%&*sl=m)u>khh-szkhtPYy=mByyX!W4!?r*Z3g#E|1$$a11SH1acyk_^L7S% zCXjwq0FoDDkZ0h?y{j9aj4B7>f#e&Q9x!v{N~smcVV8eUr%>Ne{{RR{muFy*X3%x} N9ES)GbTjbB2LNimaKZop literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/lost_woods.mw3 b/worlds/smw/data/palettes/map/forest/lost_woods.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ba9486b627ba4eeeb266c7448b718355e9a0e136 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3p>D%45QYyH3>X%a6ciW)7z7xE7#J8B94Igt2{14SIB2jJ2n@_C1okxo149b~ z3pbq%CYMY*$+CWZ|DArH0qW8bU?v@PBrnX;))aur_ZQ!M(7kikr|YPMneg1R^S$z* z?9zsWZqJ2}>gdR$)6q$Gr)I*CR;}z7ScgR3No92uhPAS<&zV*|A*TRXT4l*U?sfm3 z_gwNn?&O#D=r|So%ly-|^mB$$>A2@Sq^AE6=6PB5xlaxGnE;r}+tCT*Bzf+yi}~{+ pZ%(4iL(N!~`RJIJytRk9vgjtl57*L$T>sYvI9T99gg$qGBWaD}=Dbq~P$Ez934 zCDcmD#h7z~?K2GemNuulRm@xeqdQ1_f|-K%d!;Bpt6*gP|C#Sq%h!P9tBu|(Nh*G0 ze5Sj?48(_+U#|<%4{}2xZ$0yW|M+Ct2rdSB%Ofrveg)~<4DOr$X9k7_Q2qhq+S&%@ z?F{xzApNKSBrnDw&%lv;S2sQxRSv`h$u}@PVCKk`QnL=nF8`oTp}wL10T7Zd&%hwf QpzHQI4iO&cX5fzx0My@Y{r~^~ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/original_special.mw3 b/worlds/smw/data/palettes/map/forest/original_special.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..57fcf7dea59b1949ea5d66e58b10ea4d7744f92a GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3OD(0>K(H*2d!A!yXy;4<>RWP#t|IGKQ>+4b>ov!Kp1G03qq}3=Gl? Qx^AE25aEGt2LAW}057X;AOHXW literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/sepia.mw3 b/worlds/smw/data/palettes/map/forest/sepia.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b265f978060dd60e3aaea39f9a833111d1e074a7 GIT binary patch literal 514 zcmZQzKm|7O3=DI#ZQ^a>E1X1)Hmjn_GBAK-{?~(O5DvFPmk05A1t%(s8qIK$4hN}3 z2es*DW}8)GlEdxpmqX+yDt^%|w+pwkjt-CnsVn^eur%I$W#q3XY1e!qMZ*!?@*%I!9*el?r~bQMTF z#C$$ch<=b8CMnv)-!HGtE|kq+5jA=%a9LA2yim5>Zf-UM14v$9^oy>jS%74P6G%TQ z0Li}*(3cF547aNVsz(P9^TUBY2)Bc{7gYsF-pnlAZid@UKZt)xlV@Py6BRYO>4yjp JRQ-hF0{}_CVnYA` literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/forest/snow_day.mw3 b/worlds/smw/data/palettes/map/forest/snow_day.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c76540325baea28db53e1f9d91a6201488a4219d GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3%#7e1I1Ko=bKwOrBfJ#bm_%g&EAZ`WaM{jjsPc^ZsJ_8j$?GYU^;2{v#Hj!0I99 z*Xw%ge{^SH*bnqcA#XkNfB*Po*$6HMdCMa%9DW7q+YIiT{s*cD$-iS-TlkK7{ouACg6_`0H{H5f&c&j literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/brawler.mw3 b/worlds/smw/data/palettes/map/main/brawler.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..731696fcfc8204cffabd03f308427fc880a45460 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3o!k`;D#;RK=ggn-_dg%K9GvBM0uK~&5tM<(U=|5uOAq?U} z%&*sl=m)u>khh-szkhtPYy=mByyX!W4!?r*Z3g#E|1$$a11SH1acyk_^L7S%CXjwq z0FoDDkZ0h?y{j9aj4B7>f#e&Q9x!v{N~u|gW0!wWr%>Ne{{RR{muFy*X3%x}9ES)G JbTjbB2LL%pZ?pga literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/cake_frosting.mw3 b/worlds/smw/data/palettes/map/main/cake_frosting.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..aec0fd7e40c9db6eeb5d2ebf27bebc231a6535a5 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3Vfj+|CvFi83uhzn^WB?=B@wH9mJoK6jgi=B#)y1Kl8n6`5KTsO#cxJ4`C1=Vt&0Y zL_f$4g}n95|NY~WWh1y4Xn(W@*gSv93Ol=Sg}MiI55W5GRa=K^ z)B)wq|1*P3GYtBcHmAB(%v=AXJBY6#v_i;37+wE==6luhH6VGI{v#G1!XQ4x{CZu8 zevlgqdFz?~`^P8CMsP96TOM)Y@GD5)W^msWWFJWW0pr@*2IlPy_DmrCr~o7{#vsqY zk$YD+J{eUG!~@AUFg;-A$dyvF4#zJ4piZH_q5c67k}l7{AkCob_Bjp_9_VJ^j}HK& Crfz}& literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/mono.mw3 b/worlds/smw/data/palettes/map/main/mono.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d4d0f72d29550b6f60468a93058340f9db106760 GIT binary patch literal 514 zcmb7>ACtr|7{-GO3&BEVVWCh66ap)OLZI-%LSUs32owSbf&BuD#eRk2;^|?r7%eUy z?#(lSn^bP@oylaL`MrOhykRU4X&IZmw9@*HtGUT3V<7K4ZXD8k4t+R11Xm*!Ju>$Z z2GP!qain8Nd~RMB($DMX2Uo~;^+?7oQnagqj)62+&+FtT4=vj7+vFEH5?nCGmG7k8 z*T3&EB>yo;i~6r3`Az+|GS$PwLr5D#7+l>Sx!TG_7QL%|hk4-D`E}t+SH8o%JixcI pI_rvb7;*-c`jZAve)Ak~(UKl%HR-+otNGnWUjNsB`~ZFMY90Up literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/morning.mw3 b/worlds/smw/data/palettes/map/main/morning.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b2fe88e2cf89d9ad5e4dc2e3e714a09ce015444e GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3K=gg$Jg(z z3@8oP+;9G$86D|DTroZU{TGfLzf5fpX+4XzV|JT z`=0l|9#j5f{eDJ_wGSIbk;rOV_AOccz;K8K z#D|z)uj{S<(Vc<8GM#~;khh-szkhtPYy=mByyX!W4!?r*Z3g#ELH2>J;i5>K_0h>GBK=(hRz8 QpW|A^ApXHL0e^e|0GO{{UjP6A literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/night_time.mw3 b/worlds/smw/data/palettes/map/main/night_time.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..13a5af30c2e5e2144df1c975df6449f31d7bbdc7 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3FZHL`v$J=4gEkLUMB`fUg!WHTs)I9*}H_zve zdv3AWaliRSA&|Ub(6_WX)vaRQ`XAjvd~L%`uH`}K`u{WEtCp_;$;0#?)zCBp@ge5d z>q7K{+)&6{&-~v%K3O(`i$UJ`=SKPmvp zi!sPEaOB?AjZa3E1Mxue4NMQ1IdY}cti!R(Kd4ivZ>WC&grv(eFi11#x_ypAga^7A H_~Qcra8Pkk literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/original.mw3 b/worlds/smw/data/palettes/map/main/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..cb655d882e715528ba6092ec5ea9ca66a0d39290 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3ZBBKon795%cMxC5sMO9n99{o^=6luhH6ZzW)z;x4{YNZ3gh70W z`SrRG{UA3K^42r|_m5AOjo@OCw>;v);a8Bp&EUQ%$Ucz#1ID$r4b0ma?3qCNQ2|I^ zj6t4(BloUud@`yWhzF8yV0ysJkt?NU9gbc8L7hTwk0y@gXd9{r{QoRm<0aq7K{+)&6{&-~v%K3O(`i$UJ`=%iKK=Kb5*VZ;LZ)dP)0_jHuAbBwc zc?OQ$ySnkosB$14NWOvT0W(Lgl$v!ocKHW&3iS>34}g$#c?Je)23@z$aft9hHv@ls F007$Aa)1B; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/sepia.mw3 b/worlds/smw/data/palettes/map/main/sepia.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..3a6ece7743e941b78e5aa7daba2310af6678b62a GIT binary patch literal 514 zcmZQzKm|7O3=DI#ZQ^a>E1X1)Hmjn_GBAK-{?~(O5DvFPmk05A1t%(s8qIK$4hN}3 z2es*DW}8)GlEdxpmqX+?tA5c9x7+EquUOOwq`FXchFeVXWlb})n|>hv{qk@-QKOx1 zbF=4WgZO4vzk=rFU)G%A1abufgQ!sjkcF=Qe);|KO4ugxx$&0rBVdMj{QQ#!m*w%iV6A4pzb^oy>jS%74P6UaVP0Fr+rpf4F9 y8E#h#b|0qvB*kz$kUYe_nDS<3;dV3JZu&v|OPV|b1D~j<(M>-@c%bSh6dwSAuw_>O literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/main/snow_day.mw3 b/worlds/smw/data/palettes/map/main/snow_day.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..1ad307f078dc13fd67a195e16bc3b035c4f607d4 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3D^c_q_l0nDQUtVt?vE^2c>P zWP((gqycRP%lS)I*x7|E)IF$s09OlAQP2F}9Yh-jeM_5D-74m-{}IU7ar}_EDeY>y zJW%&>9gsXk|9|Ft)$%nUK15!}@v7CFXoP&dE<``b&O%#}bH$E9v4#We=H!wY5=E#*&!<2=Z iU#C#tQ2zi3F;#%=$0N_cAkCob_Bjp~9+)QJj}HK$18D^S literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/special/blood_star.mw3 b/worlds/smw/data/palettes/map/special/blood_star.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..bc778b202b99d347451c6490fd02d5bd54e698ff GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3K*{)U3mBz zBpKp0?Um}8|GR@sGYtBcHmAB(%v=8>kgwzTA#+pO)pU7=|MkapK=Kg%|C#Sq%hy26 z2g&O=UbUJNjgYU`h3E&_S;z}C+dn>8HiC;m-tveGhhIVZHiP@7|CxcI0hE8hxVE-| zc{_tW6G%TQ0LhCn$TM){-qnpyMwJ8cK=KVt512V}rPQp$vCBWGQ>bsKe*lD}%QG-Y RGw8Z~j)R2f#e&Q9x!v{N~u|gW0!wWr%>Ne{{RR{muFy*X3%x} N90v;zOcU_O2LP5hbAD^c_q_l0nDQU%)s!~}EAggC z{iz4ZAJ_Si2~uT})^86{?=M+lXBVze_n__pSiiE^6TKGiQ^xho|J^|<4THX=&8cn` z^Va_e+JfBkVCkUT{Hf98AD@--knL|(`7s@0rmgnYd&L_f&RLSCTR z{_)AO5nK%NmPcGT{0h>y8QeDog#<|c0pr@*2IlPy_DmrCr~o7{#vsqYk$YD+J{eUG x!~@AUFg;-A$dyvVl!cmKr%>Ne{{RRvRe*bm2ng6?kR2l|-OPf>OD(0>K5y;nZ{E)dR?P|I_!~go@Iv{z7{{PJPs^x1S=7Z#Q z9Islq7K{+)&61G}}KuSvG=;LEiF+3x{7p`Zk06rvI6Np#hYCz__-yfq6TF zJrhVjDgeogF~~D;eRLT9;MN{NEj9o?+0pv^mwSV&3{6fqWgu51E_NuBOW~{I5T*1Cod6|Id7{TD}IP zA0n^gc-3l7G(x^!7os0zXCW`pZ2$OV*$6HMdCMa%9DW7q+YIiT{$~b;22lP1d#! z-;kEz%D_<1{NEj9nqknlv^mwSV&3{6fqWgu51E_NuBOW~{I5T*1Cod6|Id7{TD}Hi zK1g22@v7CFXoP&dE<``b&O%x4WRr3#{R1E*U7mqK RnnBm?a~v!@FipT89{?(kc+UU; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/star/blood_moon.mw3 b/worlds/smw/data/palettes/map/star/blood_moon.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..42f155ef33e2d6114d8d27e32bbf88c02410d803 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3-GjOZV0m4Z zU=Ax5dlo4Md9Y!ILEqBmRJV$G>wk1-VDRIB=$B`Zbkk%(=>N}ruUftaVg6~It5$QO z5%TrA5d9!G6!O+H|M!nimW|+IkheVI!r@ntzRlpi>3?QmXaMCOFs`j_VBXGP&jfY= z3IUQA1G{R1E*U7mqKnnBm?a~v!@ JFipT89{_h-X&?Xq literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/star/mono.mw3 b/worlds/smw/data/palettes/map/star/mono.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..15d33bdf3a2378819ebd2e249a570bab1abede53 GIT binary patch literal 514 zcmaixudc%&7{!qjS0E>9CMpmJ!~|ld0)ePNT!EOWKp-j*6^Ok+Wo2Js^2)wKW#w$; zAkPbK9HVoN_wLXOS`B93ATn2M zg}NTCH~JRA*Fvbj-`IwF>QcPtgRy>=LM;}2cetOX?s1lG>X1#S$9W9191ObfJo#Dq zysQOy@=JG%=>MJHb5!|op^_gpdx7ZKdfxodYAt5DZ#)n67zhDp<^4n}%|Z?TR%r%S nYG!oG|DX55XmIqK3x1)D9?W7fZ?10~`=-@m-}}h@-~QtTOEYd; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/star/mountain_top.mw3 b/worlds/smw/data/palettes/map/star/mountain_top.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d2b96b0e3dd2731c9f1deaf3a467747982cc250a GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3yYJbTJJG*d&x(9U+!1C&@ zetCh_GwO@-XHLek|K7^E3=-9E>` L!UNL;{P6(*Ay{!c literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/star/original.mw3 b/worlds/smw/data/palettes/map/star/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2107a5555ebabc965facd1a3db5227009de6fa6d GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3$8|vR5dHs|?^Vm!Ak5csylOQk z8X;e=3(*gf#e&Q9x!v{N~u|gW0!wWr%>Ne{{RR{muFy*X3%x}90v;z JOcU_O2LQx1c!>Z2 literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/star/original_special.mw3 b/worlds/smw/data/palettes/map/star/original_special.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..d2bd439c97b52518cc44a75d80215d2e25a6b840 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3O!=v&&H>Q*st{f|ICOuszC|N7@LAbE)X|IGKQLek|K7^E3=-9E>`!UNL; H{P6(*hNO1x literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/star/pink_star.mw3 b/worlds/smw/data/palettes/map/star/pink_star.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..55f68ecf6ce2615a7bcd845c124aba707d75d654 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3E1X1)Hmjn_GBAK-{?~(O5DvFPmk05A1t%(s8qIK$4hN}3 z2es*DW}8)GlEdxpmxJWr3YeMgbgNA-x7$|?QC}!K!!0KHvZk5YO+S!4pXe9eefht` zY~uHogG@8C`V}-U|FY%`Cy*-&Wg+_YCI8pI6#&UY^jk;YFW&@oKg|3>*_~ds*$8bx5gV6t<`Cher4MP67&Q+^9(Fpl^U5I{=8wz>r zng9F8C(A}~G00mUapCYQNZ)2~-}FB-Ff@Sj4;a_hHZX5zuxA44M+G2xF$Q@Cj@-Mt z@yV!iARb7*f$0G=N3N8bbvSnU2XzYd4fPLzkaT$l25AOex6g5~@W3-GjOZVEy~U?n}rp zvDvtMoBju?2gyHRTwB|~yq&?G z38WttfaJv(XT7St3JG*d&x(9U+!20i1+qy+@ z0Oif=bwMf&gTAHBscseX*8k`Z;=4++D?L{N>5t+7@ge&EGvBM0uL1GzRa=K2Gm2%a zXRc>P$k*#a^n=_`$Xn0+-#S7c6Q+kbr0$ufc4+2{;z(Y z2`Fz~uM1KEQQs=&t^d&-#D}N{>A%l};Qv>@S1n%y;@_*b4nJlj!BEd!&y0|lV1Vcc zxuKA^p83Cje6nl=7lXXz5f=`>g7j?$_f7u;)q~_8Fs`j_VBXGP4>liU1_FTO#Teun zICAgm#wR1hVJwh*1JeU$j$A1<>u{JTf(Dykr%>Ne{{RRP;xHB=c?Je)23@z$aftAM K>4eev;{yQC=xv+; literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/dark cave.mw3 b/worlds/smw/data/palettes/map/valley/dark cave.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2b6c0f57cc614371d8f7671f472885839564eab9 GIT binary patch literal 514 zcmZQzKn0VF85sUEU$UHBtfR`Mcw7QimVse%@g>Xu^&pyo;gV%e9lAV-|6C{A_PuX$ z-1j_?N_6nCem^5a-G1f=%zx@3^2;v);a8Bp&EUT2f1rAh`~$|dwGGVM8SI%r`cVN$ zUW`GWfg|^>ZhSJT9Eb;!Z(w@B%#kal2J<1ZDzN!=3iS>34}cI^2EryJ&%hwfpzHQI M4iO&cX5fzx0DOOM5dZ)H literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/dream_world.mw3 b/worlds/smw/data/palettes/map/valley/dream_world.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..bcf8d9514213ab9280377dbbff6b92a1e9de38d9 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3S7c6Q+kbr0$ufc4+2Hc8U; z1j?J&>w;7m27ODLQ{5`&t^d&-#D8NTr(y!|Y;zRWRXTDc0UjyRbtF{h5W^}@! zp1GbGAz!Zx(GPM%A#XkNfB*Po*$6HMdCMa%9DW7q+YIiT{s*cD$vc%Id%7J(w`39y3%pAE=YS!V{W07BB`85pD)blpD3 MA;JUQ4E*r{0L7wk*Z=?k literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/fire cave.mw3 b/worlds/smw/data/palettes/map/valley/fire cave.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2980210dd233eaa0bfa804389754055f6a03dcb9 GIT binary patch literal 514 zcmZQzKn0VF85sUEODRn*mKD9lvxNgymVse%v6RyPdJxUPAf=R3hb|A|KiA2&eeYWw z_dO4!5*>W3-_OWUx1ad|^PhT%JeOpy;zdn87VB_`T7St3JG*d&x(9U+!218!2MbEF z=&|fKuh#{sFbw*ZHmAB(%v=AXJBYu5;TwY$BS^m_3y2TV|G)TNwR{bT&&?vp0@7d4 zT+fV<-_Hoq4{}2xZ$0yW|M+Ct2rdSB%Ofrveg)~<4DOr$2dW3jKVV#2+rYe?!JY}E z9~FS)#TeunICAgm#wVl7fp{SK2Brth9Jx|zQcBq6AJi$-H`G4>Lek|K7^E3=-9E=5 L!UNq5{P6(*j&WwS literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/invertido.mw3 b/worlds/smw/data/palettes/map/valley/invertido.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..37cf2e9f50d24ce7db77c7a9d4869aaad1eecbc5 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3w;7m27ODLQ{5`&t^d&-#DC+d7xpm;q+bK<9*F+`%=fD0Ye4e%s;$G18L1i8 zGuJbN_z?MeU5I{=8wz>rng9F8C(A}~G00mUapCYQNZ)2~-}FCFJxKlmp>o6^6h)t`s6eh*Q-MH4AXXq^5C}vBq5@G9fj~qcRv`KVk&*d@l`HobA|qp0 zMpm|Shw1FFrqegWFqiW#T!5%96^Q1ff(of)`f{o%5y5b}qfKnVgS{l4kW-*|G{u3qB`lpr!fxnA4&rhZIDDk8*F} zXBxWrZ|5zS{J(x=e{jKz9~nle!j|(8oBoyQ`*Bf+J~pYF6A`%Jd&{&Hse`{R@cU74 oE1bmG1voSoe2%YFaH@!m|Y{_!5Q|F8e}0n&(NlK=n! literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/orange.mw3 b/worlds/smw/data/palettes/map/valley/orange.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c9f6ac2ff2e90232ae61bc93765512936b7f356a GIT binary patch literal 514 zcmZQzKn0VF85sUE2gpt?)|2EGJuZMM%fK+XI6!u%9f)RN2$0RGLzf5fpX+4XzV|JT z`=0l|o`K;m5N}hwW7W-ZiQ_v9&~zYQfmw_}o}r#`J`+g&WWn!(d*s#%)H#EA3=9yJ z3Uv?a9st!cFx;!Q=M-RAE3n_ZUKhlFD-s}jSrnoR#D}O~D{$8g;#>&-Kl8n6`5KTs zOn-{3hcH5Yy{@S7c6Q+kbr0$ufc4+2o*J%E z2b4Fj*9ECC4EmNfr@B?lTmPdwh_7bYY5T?#q+bK<9*F+`%=fD0Ye4e%s;$G18L1i8 zGuJbN_z?MeU5I{=8wz>rng9F8C(A}~G00mUapCYQNZ)2~-}FCFJxKlm5v0G#0K|vr|Id7{TD}IvzgG>C$<}Q$ z@DN7G*Xu&`gWOQaThIL8KR#JDf{Q`k@`wwEUqSjdgZrlcnSr4Jlz+guwzh$JJA*wF zNIxn7$%`?_GjQbI)s0U^l>_lW@(oN6m^pH#)U3m?%Ri`7sBfr$0EDE=GcZUq=(>H5 MLxcyq8TjJ^0H*kEoB#j- literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/purple_blue.mw3 b/worlds/smw/data/palettes/map/valley/purple_blue.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2342f0acd205d0d9fa52a0f1a66488a4d74c4eab GIT binary patch literal 514 zcmZQzKn0VF85sUE_XSKYo@mjl(J6r{%fK+XxG!K!6^LeF=nKfHLzf5fpX+4XzV|JT z`=0l|o`K;m5VLZw;7vAjaqkQVnhxYEFxQ&Mh5k>KuLh}aiD577EN=Mj$m=JmQDzPD|@@7F{xo4$Za5ggi7=t_mNA6wS_+(T$5Dz5Z!1REbBUehTF95szgF1!! ehWZCUNV+@&gEWJ#+vm7eF^GRKO+bwgba?>wk8^(j literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/sepia.mw3 b/worlds/smw/data/palettes/map/valley/sepia.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..aa5aeb51d38b312a1873ec1334fd247f52534e2c GIT binary patch literal 514 zcmZQzKm|7O3=DI#ZQ^a>E1X1)Hmjn_GBAK-{?~(O5DvFPmk05A1t%(s8qIK$4hN}3 z2es*DW}8)GlEdxpmqX;g=$e`B^wJaER}4{GC_BR~Ci$|anb}Q0kjVXVn|M(pJ<++@ zW@aG1nbohLdHI($XE=de!N8y=I#Kb9E=a$q5r_}bzc2rO`6jUYVfsOCN670-LiB^& zFiFuS{(gCFcA;zri>T3CfypDVoIv_f0Z9IhfWBma zWVl@|P(3<;m>+Hjl84xjssbc$W)^NY!|kRY#J{A;GcfRpiW=SYLxcyaenRm90OQJG A%K!iX literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/valley/snow.mw3 b/worlds/smw/data/palettes/map/valley/snow.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..185d0d42c77a14450bf662802f4189397e97f64a GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@32sC!WN04)E% z{&u}VeYD$)MDHq)d|;S(_TFk9`+V<9;UNC{ywdtRK>7X224M9N{r}_d)yvm_zV)i$0y51a52bR9&zFDD@fmF zaNqPlGeo{cYi(_+v8muZC6Inp0MZ|&Q){^*_O5O`*aw*MEn2C@D`KV8tby)D2cR%` kP^VDeQ2zi3(Pe?LK|r2?L7G9=?Q>kK7{ouACg6_`0M-+IhyVZp literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/DOMO.mw3 b/worlds/smw/data/palettes/map/vanilla/DOMO.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..595638077050ab67064d7ce25977b4cd92cd9e71 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3-GjOZVEy%e|7Bzt z+64BSFO3DMFbw*ZHmAB(%v=AXJBZ)Pb3%k$7NlPW#ASf!|Id7{TD}IvpU+g!D8s-l zThCn2jF7L_h3E&lp^&$p`M-aBvTOtwgS_Pt7Y@II^lb+BP5%ScgXAADuB~lg-p*jp z1k#TRK=NV?@(digcXi{FQRP59kbDEv17?m~DK+bG?D7xl6zUu59{?fg@(c{p47zTg N;}GG2ZU+AN005Z&YH0uf literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/aqua_marine.mw3 b/worlds/smw/data/palettes/map/vanilla/aqua_marine.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..b382964de02c670e2c72b816639e5ed58d968d19 GIT binary patch literal 514 zcmZQzKn0VF85sUEzi^#gyxh=L^@$9sECa*j;uo&}>p?UF!wc7(I&^su|G7@K?R($i zxbJx&mFVDO{eDJOD(0>K(H+EhWNGGkA_3CxZVKW<^#5nRS1n%y;=}aUGuJaC z=HHo56k4|3LL1`3H<^Ya5uiGuShM^rHfh zycmN#14r&%-S}iwIS>yd-@x>MnIl(9?S(6L`3H3h^$qn8fRJ=~1_o&cUAND1i10u+ I1Alw~05OSj4gdfE literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/dark cave.mw3 b/worlds/smw/data/palettes/map/vanilla/dark cave.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2b6c0f57cc614371d8f7671f472885839564eab9 GIT binary patch literal 514 zcmZQzKn0VF85sUEU$UHBtfR`Mcw7QimVse%@g>Xu^&pyo;gV%e9lAV-|6C{A_PuX$ z-1j_?N_6nCem^5a-G1f=%zx@3^2;v);a8Bp&EUT2f1rAh`~$|dwGGVM8SI%r`cVN$ zUW`GWfg|^>ZhSJT9Eb;!Z(w@B%#kal2J<1ZDzN!=3iS>34}cI^2EryJ&%hwfpzHQI M4iO&cX5fzx0DOOM5dZ)H literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/fire cave.mw3 b/worlds/smw/data/palettes/map/vanilla/fire cave.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..2980210dd233eaa0bfa804389754055f6a03dcb9 GIT binary patch literal 514 zcmZQzKn0VF85sUEODRn*mKD9lvxNgymVse%v6RyPdJxUPAf=R3hb|A|KiA2&eeYWw z_dO4!5*>W3-_OWUx1ad|^PhT%JeOpy;zdn87VB_`T7St3JG*d&x(9U+!218!2MbEF z=&|fKuh#{sFbw*ZHmAB(%v=AXJBYu5;TwY$BS^m_3y2TV|G)TNwR{bT&&?vp0@7d4 zT+fV<-_Hoq4{}2xZ$0yW|M+Ct2rdSB%Ofrveg)~<4DOr$2dW3jKVV#2+rYe?!JY}E z9~FS)#TeunICAgm#wVl7fp{SK2Brth9Jx|zQcBq6AJi$-H`G4>Lek|K7^E3=-9E=5 L!UNq5{P6(*j&WwS literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/gold_mine.mw3 b/worlds/smw/data/palettes/map/vanilla/gold_mine.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ad5460a75e503f52ea46f721ad81310114e94831 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3BMkT7St3JG*d&x(9U+!20i1PYqx0 z29!6i*9ECC4EmNfr@B?lTmPdwh|eQAQTCf6NdIy-5FeudKl8n6`5F-aUbS`jF(XdV zdggj&gnYd&L_f$4g}n95|NY~WWh1y4#YMZEXYdb_RPU zkbYDEk{4r;XW+=as~ew;DhJ|$E!XJC+K&~^J9 MhX@aJGw{a;0KFq^6aWAK literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/invertido.mw3 b/worlds/smw/data/palettes/map/vanilla/invertido.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..37cf2e9f50d24ce7db77c7a9d4869aaad1eecbc5 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3w;7m27ODLQ{5`&t^d&-#DC+d7xpm;q+bK<9*F+`%=fD0Ye4e%s;$G18L1i8 zGuJbN_z?MeU5I{=8wz>rng9F8C(A}~G00mUapCYQNZ)2~-}FCFJxKlmp>o6^6h)t`s6eh*Q-MH4AXXq^5C}vBq5@G9fj~qcRv`KVk&*d@l`HobA|qp0 zMpm|Shw1FFrqegWFqiW#T!5%96^Q1ff(of)`f{o%5y5b}qfKnVgS{l4kW-*|G{u3qB`lpr!fxnA4&rhZIDDk8*F} zXBxWrZ|5zS{J(x=e{jKz9~nle!j|(8oBoyQ`*Bf+J~pYF6A`%Jd&{&Hse`{R@cU74 oE1bmG1voSoe2%YFaH@!m|Y{_!5Q|F8e}0n&(NlK=n! literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/original.mw3 b/worlds/smw/data/palettes/map/vanilla/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c165e81b818b54b39163774ae200a6a48ba7ac84 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3S7c6Q+kbr0$ufc4+2o*J%E z2b4Fj*9ECC4EmNfr@B?lTmPdwh_7bYY5T?#q+bK<9*F+`%=fD0Ye4e%s;$G18L1i8 zGuJbN_z?MeU5I{=8wz>rng9F8C(A}~G00mUapCYQNZ)2~-}FCFJxKlm5v0G#0K|vr|Id7{TD}IvzgG>C$<}Q$ z@DN7G*Xu&`gWOQaThIL8KR#JDf{Q`k@`wwEUqSjdgZrlcnSr4Jlz+guwzh$JJA*wF zNIxn7$%`?_GjQbI)s0U^l>_lW@(oN6m^pH#)U3m?%Ri`7sBfr$0EDE=GcZUq=(>H5 MLxcyq8TjJ^0H*kEoB#j- literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/purple.mw3 b/worlds/smw/data/palettes/map/vanilla/purple.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..db0008bca7cd3f70e23859b48b89c3b4b4578b05 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3@0M8eH0?l}YKU5Y$qGBWaD}=Dbq~Pu_o{E# z8`NtD?l+e)1*tF$`j$4Qx>d|u|D!udzjvfS+LSEqz{+X^uze8y|C#Sq%h!P9?^Roe zA2ZSptY@xg2I+^$*Xu&`gWOQaThIL8KR#JDf{Q`k@`wwEUqSjdgZrlcf$Bl>4;a_h zHZX5zuxA44M+G2xF$Q@Cj@-Mt@yV!iARb7*f$0G=N3N8bbvSnU2XzYd4fPLzkaT$l T25AOex6g5~@W3E1X1)Hmjn_GBAK-{?~(O5DvFPmk05A1t%(s8qIK$4hN}3 z2es*DW}8)GlEdxpmqX;g=$e`B^wJaER}4{GC_BR~Ci$|anb}Q0kjVXVn|M(pJ<++@ zW@aG1nbohLdHI($XE=de!N8y=I#Kb9E=a$q5r_}bzc2rO`6jUYVfsOCN670-LiB^& zFiFuS{(gCFcA;zri>T3CfypDVoIv_f0Z9IhfWBma zWVl@|P(3<;m>+Hjl84xjssbc$W)^NY!|kRY#J{A;GcfRpiW=SYLxcyaenRm90OQJG A%K!iX literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/vanilla/witches_cauldron.mw3 b/worlds/smw/data/palettes/map/vanilla/witches_cauldron.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..ef6a81e5d49de8b637df7da1cb7c326ffc509a0a GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3N&?W&-qGP}GXYW*cE?Cio7>K@cR0PDY39pJo5 zYpKkB^D0M>3d5jpX>+Pu#k}=Dx`X(~R6I;i+Jf}2(gN`z`u{WEtCp_;@$XezhaWRq zDpSu~&y0|-*M;Z@xuKA^p83Cje6nl=7lXXz5f=`>g7j?$_f7u;)q~_8Fs`j_VBXGP z&jiws3PAE=4Dt*dxp#HrlTqbBJdk_?(*tIXTq!l{aP0CA>J;i5>K_0h>GBK=(hRz8 OpW_hWfo=x=_y7Qrxo`#m literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/atardecer.mw3 b/worlds/smw/data/palettes/map/yoshi/atardecer.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..a75c898cee98948eef7a1a386a507995b6a208b5 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3OrBfJ#bm_%g&D->QtH*i)c>D(f3bWGNd8{6bvQ`>5sOb?^$_#x zb-ndJx-&5B2l}Ltx1RaGe|)lR1Q&z68_2KP<>1J#4%-!ZMN{lt8Q!%hlh z9x4FIi*eSma^&9CjZa3E1Mxue4NMQ1IdY}ctiv(oL1FNqPNBY`{s9n@F3-Rq&7kY{ PIj&U<;vY;C@W%%L&X;cj literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/gum.mw3 b/worlds/smw/data/palettes/map/yoshi/gum.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..cfde2f53bba4254934a8accd29a5a692f093e3bb GIT binary patch literal 514 zcmZQzKn0VF85sUE>jg|M*0#|!P?bTIWnh?GtQWAR4n#9B=mq2eS(xCtPPXlP-{QFM zdH?G%Wk1&MXJn|`&-{S-Pd!9l!LuP%rS5%5bnzS;ka~Z~3Ol=Sg}MiI55W4Pi!JKr z*t`$fZ(gqplArEj>p7`=e|!J{C?0N@ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/lava_island.mw3 b/worlds/smw/data/palettes/map/yoshi/lava_island.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..570bdee3aa9cab8df90100b5c9a771a876d82314 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3K=gg-w)m= zHdo+`#D4R7U68zC(6_WX)vaRQ`XAjv{G}q#WwLeu$JOT}>;KPuuUftaB!55HI($Lh zH^vo09>O3##Qb_)h<=b83VG|9|NF-$%SLc9$Xgz9;qWU+-)3;%^glB&G=TCC7}wS| zFmGqDX9DR*1t57b26+aK+`GE*$*6K59!S1{=>aoGu9TW}ICl95bqe(j^$&oMba@5_ SX$D=l&vA(GKsN(_d;kE?AaG6q literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/mono.mw3 b/worlds/smw/data/palettes/map/yoshi/mono.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..62c9761b4673734aa0e4edc80f8ccd0e93d2af97 GIT binary patch literal 514 zcmaixp>o6^6h)C0704B9DpnvO5D|zN1OgH9#0o@B1OgF(s6g}wRz~s*kt_EXA|qp0 zMpm|S2hp$$BdV<4aJ*s;hya`aCx7s>TRhXKmR zN~1J$>jK#=6+X9nNA`NYy;%WuXeM%DQPQjq{g%jDaXsfK4SH!lUUOX3L`cEd-bq7N z`5b@xmETgyza{0l-aDKEeVH#!@gu`ULY>CY49{HOkBd4Cp^1HtjDd^O-f?Y3?BTBq s{C*TCE6Ap?X6VX%+yEJW=g2?N>dJj<4g7y`yf@dY`+kqw|KERn0Uyk0>Hq)$ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/original.mw3 b/worlds/smw/data/palettes/map/yoshi/original.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..eb9451b1fe5c3a345c8fe04cefd208358367b772 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3j9wUd2>*|(&qvn(pZQ+3d<{tcUbS`jg1T>v zAX`9ui23!p5d9!G6!O+H|M!nimW|+IkheVI!r@ntzRlpi>3?QmXaMCOFs`j_VBXGP z&jiws3PAE=4Dt*dxp#HrlTqbBJdk_?(*tIXTq!l{aP0CA>J;i5>K_0h>GBK=(hRz8 OpW_hWfo=x=_y7QkXmBI| literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/original_special.mw3 b/worlds/smw/data/palettes/map/yoshi/original_special.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..269b45db617113eea999a51d7ae3edc8b8b95543 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3cLJ|9{Cf98AD@--lNp#E@>{uM$V!XQ4x z{CZu8evlgqdFz?~`^P8CMsP96TOM)Y@GD5)W^mv1KQk~ifbtI**VZ;LZ)dP)0_jHu zAbBwcc?OQ$ySnkosB$14NWOvT0W(Lgl$v!ocKHW&3iS>34}g$#c?Je)23@z$aft9h JHv@ls007S)aQpxO literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/sepia.mw3 b/worlds/smw/data/palettes/map/yoshi/sepia.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..3cbf6b0390bf10ab608d5765f20df390d3d9d083 GIT binary patch literal 514 zcmZQzKm|7O3=DI#ZQ^a>E1X1)Hmjn_GBAK-{?~(O5DvFPmk05A1t%(s8qIK$4hN}3 z2es*DW}8)GlEdxpmqX+?tA5c9x7+EquQ)&wq`FXchFeVXWlb})n|>hv{qk_T0Lh(h zbFvv9i^Za4iP{zX*-(vMG`fq_p{)aa%k LB0Ny_6N(Q2DI#SY literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/snow_day.mw3 b/worlds/smw/data/palettes/map/yoshi/snow_day.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..464b32bad17cfa0135d89d3cfaedc70423a89f08 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3;v);a8Bp&EUT2e`bh$i`LrORAW=Yc}nQM zfyhVc)LO2Hy{j9aj9tD(E7f>KtdyEH(7osY6b29K6zUu59{?e`EHE|*$TKiVGw8Z~ Pj%yWz_y^Mj{P6(*tigW< literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/sunset.mw3 b/worlds/smw/data/palettes/map/yoshi/sunset.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..9477a08cb8e69974c2be867e9e0d61af7474a796 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3v zD}+3RL41h$^}62rAKihz1=>-_ThIL8KR#JDf{Q`k@`wwEUqSjdgZrlcnIZBI7}wS| zFmGqDX9DR*1t9%m4Dt*dxp#HrlTqbBJdk_?(*tIXTq!l{aP0CA>J;i5>K_0h>GBK= U(hRz8pW|A^ApXHL0e^e|0OlcVq5uE@ literal 0 HcmV?d00001 diff --git a/worlds/smw/data/palettes/map/yoshi/tritanopia.mw3 b/worlds/smw/data/palettes/map/yoshi/tritanopia.mw3 new file mode 100644 index 0000000000000000000000000000000000000000..c90b7f9af0d2ad8b9261edccc53041384e0ac809 GIT binary patch literal 514 zcmZQzKn0VF85sUETZd0BF0~UfTCa*K%fK+X*gE`wJ&0ytuny0uLzf5fpX+4XzV|JT z`<@3=HHo56k4|IEP90LnjLTwB|~yq&?G z38WttfaJv(o!k`;D#;RK=gg->Y7y zrx8J;87bI^O^et^pb*q@S{zrEZAEN(%9IF2R%=fD0Ye4e%s;$Ep)O}-IA+( Date: Tue, 12 Mar 2024 14:03:57 -0700 Subject: [PATCH 40/49] Core: typing for `Option.default` and a few other ClassVars (#2899) * Core: typing for `Option.default` and a few other `Option` class variables This is a replacement for https://github.com/ArchipelagoMW/Archipelago/pull/2173 You can read discussion there for issues we found for why we can't have more specific typing on `default` instead of setting a default in `Option` (where we don't know the type), we check in the metaclass to make sure they have a default. * NumericOption doesn't need the type annotation that brings out the mypy bug * SoE default ClassVar --- Options.py | 20 ++++++++++++++------ worlds/soe/options.py | 6 +++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Options.py b/Options.py index 144220c8ee..e1ae339143 100644 --- a/Options.py +++ b/Options.py @@ -41,6 +41,11 @@ class AssembleOptions(abc.ABCMeta): aliases = {name[6:].lower(): option_id for name, option_id in attrs.items() if name.startswith("alias_")} + assert ( + name in {"Option", "VerifyKeys"} or # base abstract classes don't need default + "default" in attrs or + any(hasattr(base, "default") for base in bases) + ), f"Option class {name} needs default value" assert "random" not in aliases, "Choice option 'random' cannot be manually assigned." # auto-alias Off and On being parsed as True and False @@ -96,7 +101,7 @@ T = typing.TypeVar('T') class Option(typing.Generic[T], metaclass=AssembleOptions): value: T - default = 0 + default: typing.ClassVar[typing.Any] # something that __init__ will be able to convert to the correct type # convert option_name_long into Name Long as display_name, otherwise name_long is the result. # Handled in get_option_name() @@ -106,8 +111,9 @@ class Option(typing.Generic[T], metaclass=AssembleOptions): supports_weighting = True # filled by AssembleOptions: - name_lookup: typing.Dict[T, str] - options: typing.Dict[str, int] + name_lookup: typing.ClassVar[typing.Dict[T, str]] # type: ignore + # https://github.com/python/typing/discussions/1460 the reason for this type: ignore + options: typing.ClassVar[typing.Dict[str, int]] def __repr__(self) -> str: return f"{self.__class__.__name__}({self.current_option_name})" @@ -160,6 +166,8 @@ class FreeText(Option[str]): """Text option that allows users to enter strings. Needs to be validated by the world or option definition.""" + default = "" + def __init__(self, value: str): assert isinstance(value, str), "value of FreeText must be a string" self.value = value @@ -811,7 +819,7 @@ class VerifyKeys(metaclass=FreezeValidKeys): class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys, typing.Mapping[str, typing.Any]): - default: typing.Dict[str, typing.Any] = {} + default = {} supports_weighting = False def __init__(self, value: typing.Dict[str, typing.Any]): @@ -852,7 +860,7 @@ class OptionList(Option[typing.List[typing.Any]], VerifyKeys): # If only unique entries are needed and input order of elements does not matter, OptionSet should be used instead. # Not a docstring so it doesn't get grabbed by the options system. - default: typing.Union[typing.List[typing.Any], typing.Tuple[typing.Any, ...]] = () + default = () supports_weighting = False def __init__(self, value: typing.Iterable[typing.Any]): @@ -878,7 +886,7 @@ class OptionList(Option[typing.List[typing.Any]], VerifyKeys): class OptionSet(Option[typing.Set[str]], VerifyKeys): - default: typing.Union[typing.Set[str], typing.FrozenSet[str]] = frozenset() + default = frozenset() supports_weighting = False def __init__(self, value: typing.Iterable[str]): diff --git a/worlds/soe/options.py b/worlds/soe/options.py index cb9e9bb6de..c5ac02c22d 100644 --- a/worlds/soe/options.py +++ b/worlds/soe/options.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, fields -from typing import Any, cast, Dict, Iterator, List, Tuple, Protocol +from typing import Any, ClassVar, cast, Dict, Iterator, List, Tuple, Protocol from Options import AssembleOptions, Choice, DeathLink, DefaultOnToggle, Option, PerGameCommonOptions, \ ProgressionBalancing, Range, Toggle @@ -8,13 +8,13 @@ from Options import AssembleOptions, Choice, DeathLink, DefaultOnToggle, Option, # typing boilerplate class FlagsProtocol(Protocol): value: int - default: int + default: ClassVar[int] flags: List[str] class FlagProtocol(Protocol): value: int - default: int + default: ClassVar[int] flag: str From fb9ef19c1597c23c9022486d5554edc793bbd3fb Mon Sep 17 00:00:00 2001 From: Silvris <58583688+Silvris@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:08:12 -0500 Subject: [PATCH 41/49] Core: add list/dict merging feature to triggers (#2793) * proof of concept * add dict support, block top/game level merge * prevent key error when option being merged is new * update triggers guide * Add documentation about add/remove/replace * move to trailing name instead of proper tag * update docs * confirm types * Update Utils.py * Update Generate.py * pep8 * move to + syntax * forgot to support sets * specify received type of type error * Update Generate.py Co-authored-by: Fabian Dill * Apply suggestion from review * add test for update weights * move test to new test case * Apply suggestions from code review Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com> --------- Co-authored-by: Fabian Dill Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com> --- Generate.py | 28 ++++++++++++++++++--- Utils.py | 3 +++ test/general/test_player_options.py | 39 +++++++++++++++++++++++++++++ worlds/generic/docs/triggers_en.md | 29 ++++++++++++++++++++- 4 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 test/general/test_player_options.py diff --git a/Generate.py b/Generate.py index ecdc81833a..56979334b5 100644 --- a/Generate.py +++ b/Generate.py @@ -323,13 +323,29 @@ def roll_percentage(percentage: Union[int, float]) -> bool: return random.random() < (float(percentage) / 100) -def update_weights(weights: dict, new_weights: dict, type: str, name: str) -> dict: +def update_weights(weights: dict, new_weights: dict, update_type: str, name: str) -> dict: logging.debug(f'Applying {new_weights}') - new_options = set(new_weights) - set(weights) - weights.update(new_weights) + cleaned_weights = {} + for option in new_weights: + option_name = option.lstrip("+") + if option.startswith("+") and option_name in weights: + cleaned_value = weights[option_name] + new_value = new_weights[option] + if isinstance(new_value, (set, dict)): + cleaned_value.update(new_value) + elif isinstance(new_value, list): + cleaned_value.extend(new_value) + else: + raise Exception(f"Cannot apply merge to non-dict, set, or list type {option_name}," + f" received {type(new_value).__name__}.") + cleaned_weights[option_name] = cleaned_value + else: + cleaned_weights[option_name] = new_weights[option] + new_options = set(cleaned_weights) - set(weights) + weights.update(cleaned_weights) if new_options: for new_option in new_options: - logging.warning(f'{type} Suboption "{new_option}" of "{name}" did not ' + logging.warning(f'{update_type} Suboption "{new_option}" of "{name}" did not ' f'overwrite a root option. ' f'This is probably in error.') return weights @@ -452,6 +468,10 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b world_type = AutoWorldRegister.world_types[ret.game] game_weights = weights[ret.game] + if any(weight.startswith("+") for weight in game_weights) or \ + any(weight.startswith("+") for weight in weights): + raise Exception(f"Merge tag cannot be used outside of trigger contexts.") + if "triggers" in game_weights: weights = roll_triggers(weights, game_weights["triggers"]) game_weights = weights[ret.game] diff --git a/Utils.py b/Utils.py index 3c63b42ccb..70decf45d8 100644 --- a/Utils.py +++ b/Utils.py @@ -225,6 +225,9 @@ class UniqueKeyLoader(SafeLoader): if key in mapping: logging.error(f"YAML duplicates sanity check failed{key_node.start_mark}") raise KeyError(f"Duplicate key {key} found in YAML. Already found keys: {mapping}.") + if (str(key).startswith("+") and (str(key)[1:] in mapping)) or (f"+{key}" in mapping): + logging.error(f"YAML merge duplicates sanity check failed{key_node.start_mark}") + raise KeyError(f"Equivalent key {key} found in YAML. Already found keys: {mapping}.") mapping.add(key) return super().construct_mapping(node, deep) diff --git a/test/general/test_player_options.py b/test/general/test_player_options.py new file mode 100644 index 0000000000..9650fbe97a --- /dev/null +++ b/test/general/test_player_options.py @@ -0,0 +1,39 @@ +import unittest +import Generate + + +class TestPlayerOptions(unittest.TestCase): + + def test_update_weights(self): + original_weights = { + "scalar_1": 50, + "scalar_2": 25, + "list_1": ["string"], + "dict_1": {"option_a": 50, "option_b": 50}, + "dict_2": {"option_f": 50}, + "set_1": {"option_c"} + } + + # test that we don't allow +merge syntax on scalar variables + with self.assertRaises(BaseException): + Generate.update_weights(original_weights, {"+scalar_1": 0}, "Tested", "") + + new_weights = Generate.update_weights(original_weights, {"scalar_2": 0, + "+list_1": ["string_2"], + "+dict_1": {"option_b": 0, "option_c": 50}, + "+set_1": {"option_c", "option_d"}, + "dict_2": {"option_g": 50}, + "+list_2": ["string_3"]}, + "Tested", "") + + self.assertEqual(new_weights["scalar_1"], 50) + self.assertEqual(new_weights["scalar_2"], 0) + self.assertEqual(new_weights["list_2"], ["string_3"]) + self.assertEqual(new_weights["list_1"], ["string", "string_2"]) + self.assertEqual(new_weights["dict_1"]["option_a"], 50) + self.assertEqual(new_weights["dict_1"]["option_b"], 0) + self.assertEqual(new_weights["dict_1"]["option_c"], 50) + self.assertNotIn("option_f", new_weights["dict_2"]) + self.assertEqual(new_weights["dict_2"]["option_g"], 50) + self.assertEqual(len(new_weights["set_1"]), 2) + self.assertIn("option_d", new_weights["set_1"]) diff --git a/worlds/generic/docs/triggers_en.md b/worlds/generic/docs/triggers_en.md index a9ffebb466..dc5cf5c51e 100644 --- a/worlds/generic/docs/triggers_en.md +++ b/worlds/generic/docs/triggers_en.md @@ -121,4 +121,31 @@ For example: In this example (thanks to @Black-Sliver), if the `pupdunk` option is rolled, then the difficulty values will be rolled again using the new options `normal`, `pupdunk_hard`, and `pupdunk_mystery`, and the exp modifier will be rerolled using new weights for 150 and 200. This allows for two more triggers that will only be used for the new `pupdunk_hard` -and `pupdunk_mystery` options so that they will only be triggered on "pupdunk AND hard/mystery". \ No newline at end of file +and `pupdunk_mystery` options so that they will only be triggered on "pupdunk AND hard/mystery". + +Options that define a list, set, or dict can additionally have the character `+` added to the start of their name, which applies the contents of +the activated trigger to the already present equivalents in the game options. + +For example: +```yaml +Super Metroid: + start_location: + landing_site: 50 + aqueduct: 50 + start_hints: + - Morph Ball +triggers: + - option_category: Super Metroid + option_name: start_location + option_result: aqueduct + options: + Super Metroid: + +start_hints: + - Gravity Suit +``` + +In this example, if the `start_location` option rolls `landing_site`, only a starting hint for Morph Ball will be created. +If `aqueduct` is rolled, a starting hint for Gravity Suit will also be created alongside the hint for Morph Ball. + +Note that for lists, items can only be added, not removed or replaced. For dicts, defining a value for a present key will +replace that value within the dict. \ No newline at end of file From ecd84fd1ca0f5f8bed75dba2b96f0c7cc51f992b Mon Sep 17 00:00:00 2001 From: black-sliver <59490463+black-sliver@users.noreply.github.com> Date: Tue, 12 Mar 2024 22:27:17 +0100 Subject: [PATCH 42/49] CI: build: create setup (#2936) * CI: build: create setup also add /DNO_SIGNTOOL to inno_setup.iss * CI: build: trigger when changing setup-related files --- .github/workflows/build.yml | 25 ++++++++++++++++++++++--- inno_setup.iss | 5 ++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a40084b9ab..dc4e409783 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,11 +8,13 @@ on: - '.github/workflows/build.yml' - 'setup.py' - 'requirements.txt' + - '*.iss' pull_request: paths: - '.github/workflows/build.yml' - 'setup.py' - 'requirements.txt' + - '*.iss' workflow_dispatch: env: @@ -25,9 +27,9 @@ jobs: build-win-py38: # RCs will still be built and signed by hand runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.8' - name: Download run-time dependencies @@ -46,12 +48,29 @@ jobs: cd build Rename-Item "exe.$NAME" Archipelago 7z a -mx=9 -mhe=on -ms "../dist/$ZIP_NAME" Archipelago + Rename-Item Archipelago "exe.$NAME" # inno_setup.iss expects the original name - name: Store 7z - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ env.ZIP_NAME }} path: dist/${{ env.ZIP_NAME }} retention-days: 7 # keep for 7 days, should be enough + - name: Build Setup + run: | + & "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" inno_setup.iss /DNO_SIGNTOOL + if ( $? -eq $false ) { + Write-Error "Building setup failed!" + exit 1 + } + $contents = Get-ChildItem -Path setups/*.exe -Force -Recurse + $SETUP_NAME=$contents[0].Name + echo "SETUP_NAME=$SETUP_NAME" >> $Env:GITHUB_ENV + - name: Store Setup + uses: actions/upload-artifact@v4 + with: + name: ${{ env.SETUP_NAME }} + path: setups/${{ env.SETUP_NAME }} + retention-days: 7 # keep for 7 days, should be enough build-ubuntu2004: runs-on: ubuntu-20.04 diff --git a/inno_setup.iss b/inno_setup.iss index 7d089def95..5a6d608306 100644 --- a/inno_setup.iss +++ b/inno_setup.iss @@ -31,8 +31,11 @@ ArchitecturesAllowed=x64 arm64 AllowNoIcons=yes SetupIconFile={#MyAppIcon} UninstallDisplayIcon={app}\{#MyAppExeName} -; you will likely have to remove the following signtool line when testing/debugging locally. Don't include that change in PRs. +#ifndef NO_SIGNTOOL +; You will likely have to remove the SignTool= line when testing/debugging locally or run with iscc.exe /DNO_SIGNTOOL. +; Don't include that change in PRs. SignTool= signtool +#endif LicenseFile= LICENSE WizardStyle= modern SetupLogging=yes From d953927b3a1eb417975d6aa011107d813db87544 Mon Sep 17 00:00:00 2001 From: Kory Dondzila Date: Tue, 12 Mar 2024 17:17:18 -0500 Subject: [PATCH 43/49] Shivers: Renaming for clarity and consistency (#2869) * Moves plaque location to front for better tracker referencing. * Tiki should be Shaman. * Hanging should be Gallows. * Merrick spelling. * Clarity change. --- worlds/shivers/Items.py | 4 +- worlds/shivers/Options.py | 17 +- worlds/shivers/Rules.py | 8 +- worlds/shivers/data/excluded_locations.json | 80 ++++----- worlds/shivers/data/locations.json | 180 ++++++++++---------- worlds/shivers/data/regions.json | 12 +- 6 files changed, 155 insertions(+), 146 deletions(-) diff --git a/worlds/shivers/Items.py b/worlds/shivers/Items.py index caf24ded29..3b403be5cb 100644 --- a/worlds/shivers/Items.py +++ b/worlds/shivers/Items.py @@ -47,7 +47,7 @@ item_table = { "Key for Generator Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 29, "key"), "Key for Egypt Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 30, "key"), "Key for Library Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 31, "key"), - "Key for Tiki Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 32, "key"), + "Key for Shaman Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 32, "key"), "Key for UFO Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 33, "key"), "Key for Torture Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 34, "key"), "Key for Puzzle Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 35, "key"), @@ -90,7 +90,7 @@ item_table = { "Water Always Available in Lobby": ItemData(SHIVERS_ITEM_ID_OFFSET + 92, "filler2", ItemClassification.filler), "Wax Always Available in Library": ItemData(SHIVERS_ITEM_ID_OFFSET + 93, "filler2", ItemClassification.filler), "Wax Always Available in Anansi Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 94, "filler2", ItemClassification.filler), - "Wax Always Available in Tiki Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 95, "filler2", ItemClassification.filler), + "Wax Always Available in Shaman Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 95, "filler2", ItemClassification.filler), "Ash Always Available in Office": ItemData(SHIVERS_ITEM_ID_OFFSET + 96, "filler2", ItemClassification.filler), "Ash Always Available in Burial Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 97, "filler2", ItemClassification.filler), "Oil Always Available in Prehistoric Room": ItemData(SHIVERS_ITEM_ID_OFFSET + 98, "filler2", ItemClassification.filler), diff --git a/worlds/shivers/Options.py b/worlds/shivers/Options.py index 6d18804069..b70882f9a5 100644 --- a/worlds/shivers/Options.py +++ b/worlds/shivers/Options.py @@ -13,13 +13,16 @@ class LobbyAccess(Choice): option_local = 2 class PuzzleHintsRequired(DefaultOnToggle): - """If turned on puzzle hints will be available before the corresponding puzzle is required. For example: The Tiki + """If turned on puzzle hints will be available before the corresponding puzzle is required. For example: The Shaman Drums puzzle will be placed after access to the security cameras which give you the solution. Turning this off allows for greater randomization.""" display_name = "Puzzle Hints Required" class InformationPlaques(Toggle): - """Adds Information Plaques as checks.""" + """ + Adds Information Plaques as checks. + (40 Locations) + """ display_name = "Include Information Plaques" class FrontDoorUsable(Toggle): @@ -27,7 +30,10 @@ class FrontDoorUsable(Toggle): display_name = "Front Door Usable" class ElevatorsStaySolved(DefaultOnToggle): - """Adds elevators as checks and will remain open upon solving them.""" + """ + Adds elevators as checks and will remain open upon solving them. + (3 Locations) + """ display_name = "Elevators Stay Solved" class EarlyBeth(DefaultOnToggle): @@ -35,7 +41,10 @@ class EarlyBeth(DefaultOnToggle): display_name = "Early Beth" class EarlyLightning(Toggle): - """Allows lightning to be captured at any point in the game. You will still need to capture all ten Ixupi for victory.""" + """ + Allows lightning to be captured at any point in the game. You will still need to capture all ten Ixupi for victory. + (1 Location) + """ display_name = "Early Lightning" diff --git a/worlds/shivers/Rules.py b/worlds/shivers/Rules.py index 57488ff333..8aa8aa2c28 100644 --- a/worlds/shivers/Rules.py +++ b/worlds/shivers/Rules.py @@ -96,8 +96,8 @@ def get_rules_lookup(player: int): "To Lobby From Egypt": lambda state: state.has("Key for Egypt Room", player), "To Egypt From Lobby": lambda state: state.has("Key for Egypt Room", player), "To Janitor Closet": lambda state: state.has("Key for Janitor Closet", player), - "To Tiki From Burial": lambda state: state.has("Key for Tiki Room", player), - "To Burial From Tiki": lambda state: state.has("Key for Tiki Room", player), + "To Shaman From Burial": lambda state: state.has("Key for Shaman Room", player), + "To Burial From Shaman": lambda state: state.has("Key for Shaman Room", player), "To Inventions From UFO": lambda state: state.has("Key for UFO Room", player), "To UFO From Inventions": lambda state: state.has("Key for UFO Room", player), "To Torture From Inventions": lambda state: state.has("Key for Torture Room", player), @@ -145,7 +145,7 @@ def get_rules_lookup(player: int): "locations_puzzle_hints": { "Puzzle Solved Clock Tower Door": lambda state: state.can_reach("Three Floor Elevator", "Region", player), "Puzzle Solved Clock Chains": lambda state: state.can_reach("Bedroom", "Region", player), - "Puzzle Solved Tiki Drums": lambda state: state.can_reach("Clock Tower", "Region", player), + "Puzzle Solved Shaman Drums": lambda state: state.can_reach("Clock Tower", "Region", player), "Puzzle Solved Red Door": lambda state: state.can_reach("Maintenance Tunnels", "Region", player), "Puzzle Solved UFO Symbols": lambda state: state.can_reach("Library", "Region", player), "Puzzle Solved Maze Door": lambda state: state.can_reach("Projector Room", "Region", player), @@ -202,7 +202,7 @@ def set_rules(world: "ShiversWorld") -> None: forbid_item(multiworld.get_location("Ixupi Captured Water", player), "Water Always Available in Lobby", player) forbid_item(multiworld.get_location("Ixupi Captured Wax", player), "Wax Always Available in Library", player) forbid_item(multiworld.get_location("Ixupi Captured Wax", player), "Wax Always Available in Anansi Room", player) - forbid_item(multiworld.get_location("Ixupi Captured Wax", player), "Wax Always Available in Tiki Room", player) + forbid_item(multiworld.get_location("Ixupi Captured Wax", player), "Wax Always Available in Shaman Room", player) forbid_item(multiworld.get_location("Ixupi Captured Ash", player), "Ash Always Available in Office", player) forbid_item(multiworld.get_location("Ixupi Captured Ash", player), "Ash Always Available in Burial Room", player) forbid_item(multiworld.get_location("Ixupi Captured Oil", player), "Oil Always Available in Prehistoric Room", player) diff --git a/worlds/shivers/data/excluded_locations.json b/worlds/shivers/data/excluded_locations.json index a37285eb1d..29655d4a50 100644 --- a/worlds/shivers/data/excluded_locations.json +++ b/worlds/shivers/data/excluded_locations.json @@ -1,45 +1,45 @@ { "plaques": [ - "Information Plaque: Transforming Masks (Lobby)", - "Information Plaque: Jade Skull (Lobby)", - "Information Plaque: Bronze Unicorn (Prehistoric)", - "Information Plaque: Griffin (Prehistoric)", - "Information Plaque: Eagles Nest (Prehistoric)", - "Information Plaque: Large Spider (Prehistoric)", - "Information Plaque: Starfish (Prehistoric)", - "Information Plaque: Quartz Crystal (Ocean)", - "Information Plaque: Poseidon (Ocean)", - "Information Plaque: Colossus of Rhodes (Ocean)", - "Information Plaque: Poseidon's Temple (Ocean)", - "Information Plaque: Subterranean World (Underground Maze)", - "Information Plaque: Dero (Underground Maze)", - "Information Plaque: Tomb of the Ixupi (Egypt)", - "Information Plaque: The Sphinx (Egypt)", - "Information Plaque: Curse of Anubis (Egypt)", - "Information Plaque: Norse Burial Ship (Burial)", - "Information Plaque: Paracas Burial Bundles (Burial)", - "Information Plaque: Spectacular Coffins of Ghana (Burial)", - "Information Plaque: Cremation (Burial)", - "Information Plaque: Animal Crematorium (Burial)", - "Information Plaque: Witch Doctors of the Congo (Tiki)", - "Information Plaque: Sarombe doctor of Mozambique (Tiki)", - "Information Plaque: Fisherman's Canoe God (Gods)", - "Information Plaque: Mayan Gods (Gods)", - "Information Plaque: Thor (Gods)", - "Information Plaque: Celtic Janus Sculpture (Gods)", - "Information Plaque: Sumerian Bull God - An (Gods)", - "Information Plaque: Sumerian Lyre (Gods)", - "Information Plaque: Chuen (Gods)", - "Information Plaque: African Creation Myth (Anansi)", - "Information Plaque: Apophis the Serpent (Anansi)", - "Information Plaque: Death (Anansi)", - "Information Plaque: Cyclops (Pegasus)", - "Information Plaque: Lycanthropy (Werewolf)", - "Information Plaque: Coincidence or Extraterrestrial Visits? (UFO)", - "Information Plaque: Planets (UFO)", - "Information Plaque: Astronomical Construction (UFO)", - "Information Plaque: Guillotine (Torture)", - "Information Plaque: Aliens (UFO)" + "Information Plaque: (Lobby) Transforming Masks", + "Information Plaque: (Lobby) Jade Skull", + "Information Plaque: (Prehistoric) Bronze Unicorn", + "Information Plaque: (Prehistoric) Griffin", + "Information Plaque: (Prehistoric) Eagles Nest", + "Information Plaque: (Prehistoric) Large Spider", + "Information Plaque: (Prehistoric) Starfish", + "Information Plaque: (Ocean) Quartz Crystal", + "Information Plaque: (Ocean) Poseidon", + "Information Plaque: (Ocean) Colossus of Rhodes", + "Information Plaque: (Ocean) Poseidon's Temple", + "Information Plaque: (Underground Maze) Subterranean World", + "Information Plaque: (Underground Maze) Dero", + "Information Plaque: (Egypt) Tomb of the Ixupi", + "Information Plaque: (Egypt) The Sphinx", + "Information Plaque: (Egypt) Curse of Anubis", + "Information Plaque: (Burial) Norse Burial Ship", + "Information Plaque: (Burial) Paracas Burial Bundles", + "Information Plaque: (Burial) Spectacular Coffins of Ghana", + "Information Plaque: (Burial) Cremation", + "Information Plaque: (Burial) Animal Crematorium", + "Information Plaque: (Shaman) Witch Doctors of the Congo", + "Information Plaque: (Shaman) Sarombe doctor of Mozambique", + "Information Plaque: (Gods) Fisherman's Canoe God", + "Information Plaque: (Gods) Mayan Gods", + "Information Plaque: (Gods) Thor", + "Information Plaque: (Gods) Celtic Janus Sculpture", + "Information Plaque: (Gods) Sumerian Bull God - An", + "Information Plaque: (Gods) Sumerian Lyre", + "Information Plaque: (Gods) Chuen", + "Information Plaque: (Anansi) African Creation Myth", + "Information Plaque: (Anansi) Apophis the Serpent", + "Information Plaque: (Anansi) Death", + "Information Plaque: (Pegasus) Cyclops", + "Information Plaque: (Werewolf) Lycanthropy", + "Information Plaque: (UFO) Coincidence or Extraterrestrial Visits?", + "Information Plaque: (UFO) Planets", + "Information Plaque: (UFO) Astronomical Construction", + "Information Plaque: (Torture) Guillotine", + "Information Plaque: (UFO) Aliens" ], "elevators": [ "Puzzle Solved Office Elevator", diff --git a/worlds/shivers/data/locations.json b/worlds/shivers/data/locations.json index fdf8ed69d1..1d62f85d2d 100644 --- a/worlds/shivers/data/locations.json +++ b/worlds/shivers/data/locations.json @@ -13,7 +13,7 @@ "Puzzle Solved Columns of RA", "Puzzle Solved Burial Door", "Puzzle Solved Chinese Solitaire", - "Puzzle Solved Tiki Drums", + "Puzzle Solved Shaman Drums", "Puzzle Solved Lyre", "Puzzle Solved Red Door", "Puzzle Solved Fortune Teller Door", @@ -38,7 +38,7 @@ "Flashback Memory Obtained Theater Movie", "Flashback Memory Obtained Museum Blueprints", "Flashback Memory Obtained Beth's Address Book", - "Flashback Memory Obtained Merick's Notebook", + "Flashback Memory Obtained Merrick's Notebook", "Flashback Memory Obtained Professor Windlenot's Diary", "Ixupi Captured Water", "Ixupi Captured Wax", @@ -68,48 +68,48 @@ "Puzzle Hint Found: Gallows Information Plaque", "Puzzle Hint Found: Mastermind Information Plaque", "Puzzle Hint Found: Elevator Writing", - "Puzzle Hint Found: Tiki Security Camera", + "Puzzle Hint Found: Shaman Security Camera", "Puzzle Hint Found: Tape Recorder Heard", - "Information Plaque: Transforming Masks (Lobby)", - "Information Plaque: Jade Skull (Lobby)", - "Information Plaque: Bronze Unicorn (Prehistoric)", - "Information Plaque: Griffin (Prehistoric)", - "Information Plaque: Eagles Nest (Prehistoric)", - "Information Plaque: Large Spider (Prehistoric)", - "Information Plaque: Starfish (Prehistoric)", - "Information Plaque: Quartz Crystal (Ocean)", - "Information Plaque: Poseidon (Ocean)", - "Information Plaque: Colossus of Rhodes (Ocean)", - "Information Plaque: Poseidon's Temple (Ocean)", - "Information Plaque: Subterranean World (Underground Maze)", - "Information Plaque: Dero (Underground Maze)", - "Information Plaque: Tomb of the Ixupi (Egypt)", - "Information Plaque: The Sphinx (Egypt)", - "Information Plaque: Curse of Anubis (Egypt)", - "Information Plaque: Norse Burial Ship (Burial)", - "Information Plaque: Paracas Burial Bundles (Burial)", - "Information Plaque: Spectacular Coffins of Ghana (Burial)", - "Information Plaque: Cremation (Burial)", - "Information Plaque: Animal Crematorium (Burial)", - "Information Plaque: Witch Doctors of the Congo (Tiki)", - "Information Plaque: Sarombe doctor of Mozambique (Tiki)", - "Information Plaque: Fisherman's Canoe God (Gods)", - "Information Plaque: Mayan Gods (Gods)", - "Information Plaque: Thor (Gods)", - "Information Plaque: Celtic Janus Sculpture (Gods)", - "Information Plaque: Sumerian Bull God - An (Gods)", - "Information Plaque: Sumerian Lyre (Gods)", - "Information Plaque: Chuen (Gods)", - "Information Plaque: African Creation Myth (Anansi)", - "Information Plaque: Apophis the Serpent (Anansi)", - "Information Plaque: Death (Anansi)", - "Information Plaque: Cyclops (Pegasus)", - "Information Plaque: Lycanthropy (Werewolf)", - "Information Plaque: Coincidence or Extraterrestrial Visits? (UFO)", - "Information Plaque: Planets (UFO)", - "Information Plaque: Astronomical Construction (UFO)", - "Information Plaque: Guillotine (Torture)", - "Information Plaque: Aliens (UFO)", + "Information Plaque: (Lobby) Transforming Masks", + "Information Plaque: (Lobby) Jade Skull", + "Information Plaque: (Prehistoric) Bronze Unicorn", + "Information Plaque: (Prehistoric) Griffin", + "Information Plaque: (Prehistoric) Eagles Nest", + "Information Plaque: (Prehistoric) Large Spider", + "Information Plaque: (Prehistoric) Starfish", + "Information Plaque: (Ocean) Quartz Crystal", + "Information Plaque: (Ocean) Poseidon", + "Information Plaque: (Ocean) Colossus of Rhodes", + "Information Plaque: (Ocean) Poseidon's Temple", + "Information Plaque: (Underground Maze) Subterranean World", + "Information Plaque: (Underground Maze) Dero", + "Information Plaque: (Egypt) Tomb of the Ixupi", + "Information Plaque: (Egypt) The Sphinx", + "Information Plaque: (Egypt) Curse of Anubis", + "Information Plaque: (Burial) Norse Burial Ship", + "Information Plaque: (Burial) Paracas Burial Bundles", + "Information Plaque: (Burial) Spectacular Coffins of Ghana", + "Information Plaque: (Burial) Cremation", + "Information Plaque: (Burial) Animal Crematorium", + "Information Plaque: (Shaman) Witch Doctors of the Congo", + "Information Plaque: (Shaman) Sarombe doctor of Mozambique", + "Information Plaque: (Gods) Fisherman's Canoe God", + "Information Plaque: (Gods) Mayan Gods", + "Information Plaque: (Gods) Thor", + "Information Plaque: (Gods) Celtic Janus Sculpture", + "Information Plaque: (Gods) Sumerian Bull God - An", + "Information Plaque: (Gods) Sumerian Lyre", + "Information Plaque: (Gods) Chuen", + "Information Plaque: (Anansi) African Creation Myth", + "Information Plaque: (Anansi) Apophis the Serpent", + "Information Plaque: (Anansi) Death", + "Information Plaque: (Pegasus) Cyclops", + "Information Plaque: (Werewolf) Lycanthropy", + "Information Plaque: (UFO) Coincidence or Extraterrestrial Visits?", + "Information Plaque: (UFO) Planets", + "Information Plaque: (UFO) Astronomical Construction", + "Information Plaque: (Torture) Guillotine", + "Information Plaque: (UFO) Aliens", "Puzzle Solved Office Elevator", "Puzzle Solved Bedroom Elevator", "Puzzle Solved Three Floor Elevator", @@ -176,10 +176,10 @@ "Lobby": [ "Puzzle Solved Theater Door", "Flashback Memory Obtained Museum Brochure", - "Information Plaque: Jade Skull (Lobby)", - "Information Plaque: Transforming Masks (Lobby)", + "Information Plaque: (Lobby) Jade Skull", + "Information Plaque: (Lobby) Transforming Masks", "Accessible: Storage: Slide", - "Accessible: Storage: Eagles Head" + "Accessible: Storage: Transforming Mask" ], "Generator": [ "Final Riddle: Beth's Body Page 17" @@ -193,7 +193,7 @@ "Clock Tower": [ "Flashback Memory Obtained Beth's Ghost", "Accessible: Storage: Clock Tower", - "Puzzle Hint Found: Tiki Security Camera" + "Puzzle Hint Found: Shaman Security Camera" ], "Projector Room": [ "Flashback Memory Obtained Theater Movie" @@ -204,10 +204,10 @@ "Flashback Memory Obtained Museum Blueprints", "Accessible: Storage: Ocean", "Puzzle Hint Found: Sirens Song Heard", - "Information Plaque: Quartz Crystal (Ocean)", - "Information Plaque: Poseidon (Ocean)", - "Information Plaque: Colossus of Rhodes (Ocean)", - "Information Plaque: Poseidon's Temple (Ocean)" + "Information Plaque: (Ocean) Quartz Crystal", + "Information Plaque: (Ocean) Poseidon", + "Information Plaque: (Ocean) Colossus of Rhodes", + "Information Plaque: (Ocean) Poseidon's Temple" ], "Maze Staircase": [ "Puzzle Solved Maze Door" @@ -217,38 +217,38 @@ "Puzzle Solved Burial Door", "Accessible: Storage: Egypt", "Puzzle Hint Found: Egyptian Sphinx Heard", - "Information Plaque: Tomb of the Ixupi (Egypt)", - "Information Plaque: The Sphinx (Egypt)", - "Information Plaque: Curse of Anubis (Egypt)" + "Information Plaque: (Egypt) Tomb of the Ixupi", + "Information Plaque: (Egypt) The Sphinx", + "Information Plaque: (Egypt) Curse of Anubis" ], "Burial": [ "Puzzle Solved Chinese Solitaire", - "Flashback Memory Obtained Merick's Notebook", + "Flashback Memory Obtained Merrick's Notebook", "Accessible: Storage: Chinese Solitaire", - "Information Plaque: Norse Burial Ship (Burial)", - "Information Plaque: Paracas Burial Bundles (Burial)", - "Information Plaque: Spectacular Coffins of Ghana (Burial)", - "Information Plaque: Animal Crematorium (Burial)", - "Information Plaque: Cremation (Burial)" + "Information Plaque: (Burial) Norse Burial Ship", + "Information Plaque: (Burial) Paracas Burial Bundles", + "Information Plaque: (Burial) Spectacular Coffins of Ghana", + "Information Plaque: (Burial) Animal Crematorium", + "Information Plaque: (Burial) Cremation" ], - "Tiki": [ - "Puzzle Solved Tiki Drums", - "Accessible: Storage: Tiki Hut", - "Information Plaque: Witch Doctors of the Congo (Tiki)", - "Information Plaque: Sarombe doctor of Mozambique (Tiki)" + "Shaman": [ + "Puzzle Solved Shaman Drums", + "Accessible: Storage: Shaman Hut", + "Information Plaque: (Shaman) Witch Doctors of the Congo", + "Information Plaque: (Shaman) Sarombe doctor of Mozambique" ], "Gods Room": [ "Puzzle Solved Lyre", "Puzzle Solved Red Door", "Accessible: Storage: Lyre", "Final Riddle: Norse God Stone Message", - "Information Plaque: Fisherman's Canoe God (Gods)", - "Information Plaque: Mayan Gods (Gods)", - "Information Plaque: Thor (Gods)", - "Information Plaque: Celtic Janus Sculpture (Gods)", - "Information Plaque: Sumerian Bull God - An (Gods)", - "Information Plaque: Sumerian Lyre (Gods)", - "Information Plaque: Chuen (Gods)" + "Information Plaque: (Gods) Fisherman's Canoe God", + "Information Plaque: (Gods) Mayan Gods", + "Information Plaque: (Gods) Thor", + "Information Plaque: (Gods) Celtic Janus Sculpture", + "Information Plaque: (Gods) Sumerian Bull God - An", + "Information Plaque: (Gods) Sumerian Lyre", + "Information Plaque: (Gods) Chuen" ], "Blue Maze": [ "Puzzle Solved Fortune Teller Door" @@ -265,28 +265,28 @@ "Puzzle Solved UFO Symbols", "Accessible: Storage: UFO", "Final Riddle: Planets Aligned", - "Information Plaque: Coincidence or Extraterrestrial Visits? (UFO)", - "Information Plaque: Planets (UFO)", - "Information Plaque: Astronomical Construction (UFO)", - "Information Plaque: Aliens (UFO)" + "Information Plaque: (UFO) Coincidence or Extraterrestrial Visits?", + "Information Plaque: (UFO) Planets", + "Information Plaque: (UFO) Astronomical Construction", + "Information Plaque: (UFO) Aliens" ], "Anansi": [ "Puzzle Solved Anansi Musicbox", "Flashback Memory Obtained Ancient Astrology", "Accessible: Storage: Skeleton", "Accessible: Storage: Anansi", - "Information Plaque: African Creation Myth (Anansi)", - "Information Plaque: Apophis the Serpent (Anansi)", - "Information Plaque: Death (Anansi)", - "Information Plaque: Cyclops (Pegasus)", - "Information Plaque: Lycanthropy (Werewolf)" + "Information Plaque: (Anansi) African Creation Myth", + "Information Plaque: (Anansi) Apophis the Serpent", + "Information Plaque: (Anansi) Death", + "Information Plaque: (Pegasus) Cyclops", + "Information Plaque: (Werewolf) Lycanthropy" ], "Torture": [ "Puzzle Solved Gallows", - "Accessible: Storage: Hanging", + "Accessible: Storage: Gallows", "Final Riddle: Guillotine Dropped", "Puzzle Hint Found: Gallows Information Plaque", - "Information Plaque: Guillotine (Torture)" + "Information Plaque: (Torture) Guillotine" ], "Puzzle Room Mastermind": [ "Puzzle Solved Mastermind", @@ -296,17 +296,17 @@ "Puzzle Solved Marble Flipper" ], "Prehistoric": [ - "Information Plaque: Bronze Unicorn (Prehistoric)", - "Information Plaque: Griffin (Prehistoric)", - "Information Plaque: Eagles Nest (Prehistoric)", - "Information Plaque: Large Spider (Prehistoric)", - "Information Plaque: Starfish (Prehistoric)", + "Information Plaque: (Prehistoric) Bronze Unicorn", + "Information Plaque: (Prehistoric) Griffin", + "Information Plaque: (Prehistoric) Eagles Nest", + "Information Plaque: (Prehistoric) Large Spider", + "Information Plaque: (Prehistoric) Starfish", "Accessible: Storage: Eagles Nest" ], "Tar River": [ "Accessible: Storage: Tar River", - "Information Plaque: Subterranean World (Underground Maze)", - "Information Plaque: Dero (Underground Maze)" + "Information Plaque: (Underground Maze) Subterranean World", + "Information Plaque: (Underground Maze) Dero" ], "Theater": [ "Accessible: Storage: Theater" diff --git a/worlds/shivers/data/regions.json b/worlds/shivers/data/regions.json index 3e81136c45..963d100fad 100644 --- a/worlds/shivers/data/regions.json +++ b/worlds/shivers/data/regions.json @@ -27,9 +27,9 @@ ["Maze", ["To Maze Staircase From Maze", "To Tar River"]], ["Tar River", ["To Maze From Tar River", "To Lobby From Tar River"]], ["Egypt", ["To Lobby From Egypt", "To Burial From Egypt", "To Blue Maze From Egypt"]], - ["Burial", ["To Egypt From Burial", "To Tiki From Burial"]], - ["Tiki", ["To Burial From Tiki", "To Gods Room"]], - ["Gods Room", ["To Tiki From Gods Room", "To Anansi From Gods Room"]], + ["Burial", ["To Egypt From Burial", "To Shaman From Burial"]], + ["Shaman", ["To Burial From Shaman", "To Gods Room"]], + ["Gods Room", ["To Shaman From Gods Room", "To Anansi From Gods Room"]], ["Anansi", ["To Gods Room From Anansi", "To Werewolf From Anansi"]], ["Werewolf", ["To Anansi From Werewolf", "To Night Staircase From Werewolf"]], ["Night Staircase", ["To Werewolf From Night Staircase", "To Janitor Closet", "To UFO"]], @@ -109,13 +109,13 @@ ["To Tar River", "Tar River"], ["To Tar River From Lobby", "Tar River"], ["To Burial From Egypt", "Burial"], - ["To Burial From Tiki", "Burial"], + ["To Burial From Shaman", "Burial"], ["To Blue Maze From Three Floor Elevator", "Blue Maze"], ["To Blue Maze From Fortune Teller", "Blue Maze"], ["To Blue Maze From Inventions", "Blue Maze"], ["To Blue Maze From Egypt", "Blue Maze"], - ["To Tiki From Burial", "Tiki"], - ["To Tiki From Gods Room", "Tiki"], + ["To Shaman From Burial", "Shaman"], + ["To Shaman From Gods Room", "Shaman"], ["To Gods Room", "Gods Room" ], ["To Gods Room From Anansi", "Gods Room"], ["To Anansi From Gods Room", "Anansi"], From 1705213353b3d7fe1110d4d932c22ae09206d649 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:21:58 -0500 Subject: [PATCH 44/49] FFMQ: Update Map Shuffle Seed description (#2658) * Update Map Shuffle Seed description * Update worlds/ffmq/Options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --- worlds/ffmq/Options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/ffmq/Options.py b/worlds/ffmq/Options.py index 4b9f4a4a88..af3625f28a 100644 --- a/worlds/ffmq/Options.py +++ b/worlds/ffmq/Options.py @@ -207,10 +207,10 @@ class CrestShuffle(Toggle): class MapShuffleSeed(FreeText): - """If this is a number, it will be used as a set seed number for Map, Crest, and Battlefield Reward shuffles. + """If this is a number, it will be used as a set seed number for Map, Crest, Battlefield Reward, and Companion shuffles. If this is "random" the seed will be chosen randomly. If it is any other text, it will be used as a seed group name. All players using the same seed group name will get the same shuffle results, as long as their Map Shuffle, - Crest Shuffle, and Shuffle Battlefield Rewards settings are the same.""" + Crest Shuffle, Shuffle Battlefield Rewards, Companion Shuffle, and Kaeli's Mom settings are the same.""" display_name = "Map Shuffle Seed" default = "random" From c4ec8682d501cafeb916f9a7fac549df6af4a0bf Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Tue, 12 Mar 2024 17:29:32 -0500 Subject: [PATCH 45/49] Core: fix incorrect ordering on the always_allow static method (#2938) --- BaseClasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 446eea5b48..24dc074b63 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1032,7 +1032,7 @@ class Location: locked: bool = False show_in_spoiler: bool = True progress_type: LocationProgressType = LocationProgressType.DEFAULT - always_allow = staticmethod(lambda item, state: False) + always_allow = staticmethod(lambda state, item: False) access_rule: Callable[[CollectionState], bool] = staticmethod(lambda state: True) item_rule = staticmethod(lambda item: True) item: Optional[Item] = None From 67ed0fdca56220d885c81160ab6864bd30b0c163 Mon Sep 17 00:00:00 2001 From: black-sliver <59490463+black-sliver@users.noreply.github.com> Date: Wed, 13 Mar 2024 08:25:51 +0100 Subject: [PATCH 46/49] CI: update actions (#2943) --- .github/workflows/analyze-modified-files.yml | 4 ++-- .github/workflows/build.yml | 8 ++++---- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/release.yml | 8 ++++---- .github/workflows/unittests.yml | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/analyze-modified-files.yml b/.github/workflows/analyze-modified-files.yml index d01365745c..c9995fa2d0 100644 --- a/.github/workflows/analyze-modified-files.yml +++ b/.github/workflows/analyze-modified-files.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Determine modified files (pull_request)" if: github.event_name == 'pull_request' @@ -50,7 +50,7 @@ jobs: run: | echo "diff=." >> $GITHUB_ENV - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 if: env.diff != '' with: python-version: 3.8 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc4e409783..80aaf70c21 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,14 +76,14 @@ jobs: runs-on: ubuntu-20.04 steps: # - copy code below to release.yml - - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install base dependencies run: | sudo apt update sudo apt -y install build-essential p7zip xz-utils wget libglib2.0-0 sudo apt -y install python3-gi libgirepository1.0-dev # should pull dependencies for gi installation below - name: Get a recent python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install build-time dependencies @@ -119,13 +119,13 @@ jobs: source venv/bin/activate python setup.py build_exe --yes - name: Store AppImage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ env.APPIMAGE_NAME }} path: dist/${{ env.APPIMAGE_NAME }} retention-days: 7 - name: Store .tar.gz - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ env.TAR_NAME }} path: dist/${{ env.TAR_NAME }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6aeb477a22..b0cfe35d2b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cc68a88b76..2d7f1253b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV # tag x.y.z will become "Archipelago x.y.z" - name: Create Release - uses: softprops/action-gh-release@b7e450da2a4b4cb4bfbae528f788167786cfcedf + uses: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a with: draft: true # don't publish right away, especially since windows build is added by hand prerelease: false @@ -35,14 +35,14 @@ jobs: - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV # - code below copied from build.yml - - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install base dependencies run: | sudo apt update sudo apt -y install build-essential p7zip xz-utils wget libglib2.0-0 sudo apt -y install python3-gi libgirepository1.0-dev # should pull dependencies for gi installation below - name: Get a recent python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install build-time dependencies @@ -74,7 +74,7 @@ jobs: echo "TAR_NAME=$TAR_NAME" >> $GITHUB_ENV # - code above copied from build.yml - - name: Add to Release - uses: softprops/action-gh-release@b7e450da2a4b4cb4bfbae528f788167786cfcedf + uses: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a with: draft: true # see above prerelease: false diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 1a76a7f471..b2530bd06c 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -46,9 +46,9 @@ jobs: os: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python.version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python.version }} - name: Install dependencies From 72e6383cc799affce623290d3764fe7e2e2f6bb8 Mon Sep 17 00:00:00 2001 From: qwint Date: Wed, 13 Mar 2024 06:45:43 -0500 Subject: [PATCH 47/49] HK: Removes Vanilla Items from ItemPool and Uses Grimmchild1 when relevant (#2898) --- worlds/hk/Items.py | 1 + worlds/hk/Options.py | 11 ++++++++++- worlds/hk/__init__.py | 37 ++++++++++++++++++++++++++----------- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/worlds/hk/Items.py b/worlds/hk/Items.py index def5c32981..72878dfc71 100644 --- a/worlds/hk/Items.py +++ b/worlds/hk/Items.py @@ -35,6 +35,7 @@ item_name_groups = ({ "GeoChests": lookup_type_to_names["Geo"], "GeoRocks": lookup_type_to_names["Rock"], "GrimmkinFlames": lookup_type_to_names["Flame"], + "Grimmchild": {"Grimmchild1", "Grimmchild2"}, "Grubs": lookup_type_to_names["Grub"], "JournalEntries": lookup_type_to_names["Journal"], "JunkPitChests": lookup_type_to_names["JunkPitChest"], diff --git a/worlds/hk/Options.py b/worlds/hk/Options.py index ef7fbd0dfe..21e8c179e8 100644 --- a/worlds/hk/Options.py +++ b/worlds/hk/Options.py @@ -406,6 +406,15 @@ class ExtraPlatforms(DefaultOnToggle): """Places additional platforms to make traveling throughout Hallownest more convenient.""" +class AddUnshuffledLocations(Toggle): + """Adds non-randomized locations to the location pool, which allows syncing + of location state with co-op or automatic collection via collect. + + Note: This will increase the number of location checks required to purchase + hints to the total maximum. + """ + + class DeathLinkShade(Choice): """Sets whether to create a shade when you are killed by a DeathLink and how to handle your existing shade, if any. @@ -488,7 +497,7 @@ hollow_knight_options: typing.Dict[str, type(Option)] = { **{ option.__name__: option for option in ( - StartLocation, Goal, WhitePalace, ExtraPlatforms, StartingGeo, + StartLocation, Goal, WhitePalace, ExtraPlatforms, AddUnshuffledLocations, StartingGeo, DeathLink, DeathLinkShade, DeathLinkBreaksFragileCharms, MinimumGeoPrice, MaximumGeoPrice, MinimumGrubPrice, MaximumGrubPrice, diff --git a/worlds/hk/__init__.py b/worlds/hk/__init__.py index 8b07b34eb0..25337598ec 100644 --- a/worlds/hk/__init__.py +++ b/worlds/hk/__init__.py @@ -234,7 +234,7 @@ class HKWorld(World): randomized_starting_items.update(items) # noinspection PyShadowingNames - def _add(item_name: str, location_name: str): + def _add(item_name: str, location_name: str, randomized: bool): """ Adds a pairing of an item and location, doing appropriate checks to see if it should be vanilla or not. """ @@ -252,7 +252,7 @@ class HKWorld(World): if item_name in junk_replace: item_name = self.get_filler_item_name() - item = self.create_item(item_name) + item = self.create_item(item_name) if not vanilla or location_name == "Start" or self.multiworld.AddUnshuffledLocations[self.player] else self.create_event(item_name) if location_name == "Start": if item_name in randomized_starting_items: @@ -277,30 +277,35 @@ class HKWorld(World): for option_key, option in hollow_knight_randomize_options.items(): randomized = getattr(self.multiworld, option_key)[self.player] + if all([not randomized, option_key in logicless_options, not self.multiworld.AddUnshuffledLocations[self.player]]): + continue for item_name, location_name in zip(option.items, option.locations): if item_name in junk_replace: item_name = self.get_filler_item_name() if (item_name == "Crystal_Heart" and self.multiworld.SplitCrystalHeart[self.player]) or \ (item_name == "Mothwing_Cloak" and self.multiworld.SplitMothwingCloak[self.player]): - _add("Left_" + item_name, location_name) - _add("Right_" + item_name, "Split_" + location_name) + _add("Left_" + item_name, location_name, randomized) + _add("Right_" + item_name, "Split_" + location_name, randomized) continue if item_name == "Mantis_Claw" and self.multiworld.SplitMantisClaw[self.player]: - _add("Left_" + item_name, "Left_" + location_name) - _add("Right_" + item_name, "Right_" + location_name) + _add("Left_" + item_name, "Left_" + location_name, randomized) + _add("Right_" + item_name, "Right_" + location_name, randomized) continue if item_name == "Shade_Cloak" and self.multiworld.SplitMothwingCloak[self.player]: if self.multiworld.random.randint(0, 1): item_name = "Left_Mothwing_Cloak" else: item_name = "Right_Mothwing_Cloak" + if item_name == "Grimmchild2" and self.multiworld.RandomizeGrimmkinFlames[self.player] and self.multiworld.RandomizeCharms[self.player]: + _add("Grimmchild1", location_name, randomized) + continue - _add(item_name, location_name) + _add(item_name, location_name, randomized) if self.multiworld.RandomizeElevatorPass[self.player]: randomized = True - _add("Elevator_Pass", "Elevator_Pass") + _add("Elevator_Pass", "Elevator_Pass", randomized) for shop, locations in self.created_multi_locations.items(): for _ in range(len(locations), getattr(self.multiworld, shop_to_option[shop])[self.player].value): @@ -475,6 +480,10 @@ class HKWorld(World): item_data = item_table[name] return HKItem(name, item_data.advancement, item_data.id, item_data.type, self.player) + def create_event(self, name: str) -> HKItem: + item_data = item_table[name] + return HKItem(name, item_data.advancement, None, item_data.type, self.player) + def create_location(self, name: str, vanilla=False) -> HKLocation: costs = None basename = name @@ -493,9 +502,15 @@ class HKWorld(World): name = f"{name}_{i}" region = self.multiworld.get_region("Menu", self.player) - loc = HKLocation(self.player, name, - self.location_name_to_id[name], region, costs=costs, vanilla=vanilla, - basename=basename) + + if vanilla and not self.multiworld.AddUnshuffledLocations[self.player]: + loc = HKLocation(self.player, name, + None, region, costs=costs, vanilla=vanilla, + basename=basename) + else: + loc = HKLocation(self.player, name, + self.location_name_to_id[name], region, costs=costs, vanilla=vanilla, + basename=basename) if multi is not None: multi.append(loc) From 3e3965272da10b793ed1d4c803e6b80ee59840e3 Mon Sep 17 00:00:00 2001 From: Silvris <58583688+Silvris@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:05:38 -0500 Subject: [PATCH 48/49] KDL3: Ensure all abilities accessible on non-minimal (#2929) --- worlds/kdl3/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/worlds/kdl3/__init__.py b/worlds/kdl3/__init__.py index 66c9b17b84..6d0c196ab1 100644 --- a/worlds/kdl3/__init__.py +++ b/worlds/kdl3/__init__.py @@ -129,6 +129,8 @@ class KDL3World(World): # randomize copy abilities valid_abilities = list(copy_ability_access_table.keys()) enemies_to_set = list(self.copy_abilities.keys()) + unplaced_abilities = set(key for key in copy_ability_access_table.keys() + if key not in ("No Ability", "Cutter Ability", "Burning Ability")) # now for the edge cases for abilities, enemies in enemy_restrictive: available_enemies = list() @@ -143,6 +145,7 @@ class KDL3World(World): chosen_ability = self.random.choice(abilities) self.copy_abilities[chosen_enemy] = chosen_ability enemies_to_set.remove(chosen_enemy) + unplaced_abilities.discard(chosen_ability) # two less restrictive ones, we need to ensure Cutter and Burning appear before their required stages sand_canyon_5 = self.get_region("Sand Canyon 5 - 9") # this is primarily for typing, but if this ever hits it's fine to crash @@ -160,6 +163,13 @@ class KDL3World(World): if burning_enemy: self.copy_abilities[burning_enemy] = "Burning Ability" enemies_to_set.remove(burning_enemy) + # ensure we place one of every ability + if unplaced_abilities and self.options.accessibility != self.options.accessibility.option_minimal: + # failsafe, on non-minimal we need to guarantee every copy ability exists + for ability in sorted(unplaced_abilities): + enemy = self.random.choice(enemies_to_set) + self.copy_abilities[enemy] = ability + enemies_to_set.remove(enemy) # place remaining for enemy in enemies_to_set: self.copy_abilities[enemy] = self.random.choice(valid_abilities) @@ -283,6 +293,8 @@ class KDL3World(World): self.boss_butch_bosses = [True for _ in range(6)] else: self.boss_butch_bosses = [self.random.choice([True, False]) for _ in range(6)] + else: + self.boss_butch_bosses = [False for _ in range(6)] def generate_output(self, output_directory: str): rom_path = "" From fa233b25831a4a0ea0d7ca3dae5381e164783c30 Mon Sep 17 00:00:00 2001 From: Bryce Wilson Date: Thu, 14 Mar 2024 05:37:10 -0600 Subject: [PATCH 49/49] Pokemon Emerald: v2 Update (#2918) --- worlds/pokemon_emerald/CHANGELOG.md | 186 + worlds/pokemon_emerald/README.md | 57 +- worlds/pokemon_emerald/__init__.py | 821 ++-- worlds/pokemon_emerald/client.py | 536 ++- worlds/pokemon_emerald/data.py | 1463 ++++-- .../pokemon_emerald/data/base_patch.bsdiff4 | Bin 209743 -> 243175 bytes .../pokemon_emerald/data/extracted_data.json | 2 +- worlds/pokemon_emerald/data/items.json | 1016 +++-- worlds/pokemon_emerald/data/locations.json | 4057 ++++++++++++++++- .../data/regions/battle_frontier.json | 458 ++ .../pokemon_emerald/data/regions/cities.json | 1391 +++++- .../data/regions/dungeons.json | 1054 ++++- .../data/regions/{unused => }/islands.json | 120 +- .../pokemon_emerald/data/regions/routes.json | 1693 ++++++- .../data/regions/unused/battle_frontier.json | 368 +- .../data/regions/unused/dungeons.json | 50 +- .../data/regions/unused/routes.json | 82 - .../data/trade_pokemon_schema.json | 162 + .../docs/en_Pokemon Emerald.md | 26 +- .../{data/README.md => docs/region data.md} | 38 +- worlds/pokemon_emerald/docs/rom changes.md | 36 +- worlds/pokemon_emerald/docs/warps.md | 50 + worlds/pokemon_emerald/docs/wonder trades.md | 103 + worlds/pokemon_emerald/items.py | 6 +- worlds/pokemon_emerald/locations.py | 182 +- worlds/pokemon_emerald/opponents.py | 116 + worlds/pokemon_emerald/options.py | 415 +- worlds/pokemon_emerald/pokemon.py | 660 ++- worlds/pokemon_emerald/regions.py | 80 +- worlds/pokemon_emerald/rom.py | 725 ++- worlds/pokemon_emerald/rules.py | 1003 ++-- worlds/pokemon_emerald/sanity_check.py | 137 +- .../test/test_accessibility.py | 19 +- worlds/pokemon_emerald/util.py | 340 +- 34 files changed, 14212 insertions(+), 3240 deletions(-) create mode 100644 worlds/pokemon_emerald/CHANGELOG.md create mode 100644 worlds/pokemon_emerald/data/regions/battle_frontier.json rename worlds/pokemon_emerald/data/regions/{unused => }/islands.json (73%) delete mode 100644 worlds/pokemon_emerald/data/regions/unused/routes.json create mode 100644 worlds/pokemon_emerald/data/trade_pokemon_schema.json rename worlds/pokemon_emerald/{data/README.md => docs/region data.md} (74%) create mode 100644 worlds/pokemon_emerald/docs/warps.md create mode 100644 worlds/pokemon_emerald/docs/wonder trades.md create mode 100644 worlds/pokemon_emerald/opponents.py diff --git a/worlds/pokemon_emerald/CHANGELOG.md b/worlds/pokemon_emerald/CHANGELOG.md new file mode 100644 index 0000000000..dbc1123b77 --- /dev/null +++ b/worlds/pokemon_emerald/CHANGELOG.md @@ -0,0 +1,186 @@ +# 2.0.0 + +### Features +- Picking up items for other players will display the actual item name and receiving player in-game instead of +"ARCHIPELAGO ITEM". (This does have a limit, but you're unlikely to reach it in all but the largest multiworlds.) +- New goal `legendary_hunt`. Your goal is to catch/defeat some number of legendary encounters. That is, the static +encounters themselves, whatever species they may be. Legendary species found in the wild don't count. + - You can force the goal to require captures with `legendary_hunt_catch`. If you accidentally faint a legendary, you + can respawn it by beating the champion. + - The number of legendaries needed is controlled by the `legendary_hunt_count` option. + - The caves containing Kyogre and Groudon are fixed to one location per seed. You need to go to the weather + institute to trigger a permanent weather event at the corresponding locations. Only one weather event can be active + at a time. + - The move tutor for the move Sleep Talk has been changed to Dig and is unlimited use (for Sealed Chamber). + - Relicanth and Wailord are guaranteed to be reachable in the wild (for Sealed Chamber). Interacting with the Sealed + Chamber wall will give you dex info for Wailord and Relicanth. + - Event legendaries are included for this goal (see below for new ferry behavior and event tickets). + - The roamer is included in this count. It will _always_ be Latios no matter what your options are. Otherwise you + might not have any way of knowing which species is roaming to be able to track it. In legendary hunt, Latios will + never appear as a wild pokemon to make tracking it easier. The television broadcast that creates the roamer will + give you dex info for Latios. + - You can set which encounters are considered for this goal with the `allowed_legendary_hunt_encounters` option. +- New option `dexsanity`. Adds pokedex entries as locations. + - Added locations contribute either a Poke Ball, Great Ball, or Ultra Ball to the item pool, based on the evolution + stage. + - Logic uses only wild encounters for now. + - Defeating a gym leader awards "seen" info on 1/8th of the pokedex. +- New option `trainersanity`. Defeating a trainer awards a random item. + - Trainers no longer award money upon defeat. Instead they add a sellable item to the item pool. + - Missable trainers are prevented from disappearing when this is enabled. + - Gym trainers remain active after their leader is defeated. + - Does not include trainers in the Trick House. +- New option `berry_trees`. Adds berry trees as locations. + - All soil patches start with a fully grown berry tree that gives one item. + - There are 88 berry trees. + - Berries cannot be planted in soil with this option enabled. + - Soil that doesn't start with a tree on a fresh save contributes a Sitrus Berry to the item pool. +- New option `death_link`. Forgive me, Figment. +- Added Artisan Cave locations + - Requires Wailmer Pail and the ability to Surf to access. +- Added Trick House locations. The Trick Master is finally here! + - He will make new layouts only if you have the corresponding badge (or beat the game) and have completed the + previous layout (all vanilla behavior). + - If you neglect to pick up an item in a puzzle before completing it, the Trick Master will give the item to you + alongside the prize. + - Locations are enabled or disabled with their broader categories (npc gifts, overworld items, etc...) +- Added daily berry gift locations. There are a half dozen or so NPCs that give you one or two berries per day. + - All these locations are considered NPC gifts. + - The NPCs have been reworked to give this gift once permanently so they can be added as locations. +- New option `remote_items`. All randomized items are sent from the server instead of being patched into your game +(except for start inventory, which remains in the PC) + - As a side effect, when you pick up your own item, there will be a gap between the item disappearing from the + overworld and your game actually receiving it. It also causes gifts from NPCs which contain your own items to not + show up until after their text box closes. It can feel odd, but there should be no danger to it. + - If the seed is in race mode, this is forcibly enabled. + - Benefits include: + - Two players can play the same slot and both receive items that slot picks up for itself (as long as it was + randomized) + - You receive items you picked up for yourself if you lose progress on your save + - Competitive integrity; the patch file no longer has any knowledge of item placement +- New option `match_trainer_levels`. This is a sort of pseudo level cap for a randomizer context. + - When you start a trainer fight, all your pokemon have their levels temporarily set to the highest level in the + opponent's party. + - During the battle, all earned exp is set to 0 (EVs are still gained during battle as normal). When the outcome of + the battle is decided, your pokemon have their levels reset to what they were before the fight and exp is awarded as + it would have been without this option. Think of it as holding earned exp in reserve and awarding it at the end + instead, even giving it to fainted pokemon if they earned any before fainting. + - Exp gain is based on _your_ party's average level to moderate exp over the course of a seed. Wild battles are + entirely unchanged by this option. +- New option `match_trainer_levels_bonus`. A flat bonus to apply to your party's levels when using +`match_trainer_levels`. In case you want to give yourself a nerf or buff while still approximately matching your +opponent. +- New option `force_fully_evolved`. Define a level at which trainers will stop using pokemon that have further evolution +stages. +- New option `move_blacklist`. Define a list of moves that should not be given randomly to learnsets or TMs. Move names +are accurate to Gen 3 except for capitalization. +- New option `extra_bumpy_slope`. Adds a "bumpy slope" to Route 115 that lets you hop up the ledge with the Acro Bike. +- New option `modify_118`. Changes Route 118 so that it must be crossed with the Acro Bike, and cannot be crossed by +surfing. +- Changed `require_flash` option to a choice between none, only granite cave, only victory road, or both caves. +- Removed `static_encounters` option. +- New option `legendary_encounters`. Replaces `static_encounters`, but only concerns legendaries. +- New option `misc_pokemon`. Replaces `static_encounters`, but only concerns non-legendaries. +- Removed `fly_without_badge` option. (Don't worry) +- New option `hm_requirements`. Will eventually be able to give you more control over the badge requirements for all +HMs. For now, only includes the presets `vanilla` and `fly_without_badge`. +- Removed `allow_wild_legendaries`, `allow_starter_legendaries`, and `allow_trainer_legendaries` options. +- New options `wild_encounter_blacklist`, `starter_blacklist`, and `trainer_party_blacklist`. + - These take lists of species and prevent them from randomizing into the corresponding categories + - If adhering to your blacklist would make it impossible to choose a random species, your blacklist is ignored in + that case + - All three include a shorthand for excluding legendaries +- Removed `enable_ferry` option. + - The ferry is now always present. + - The S.S. Ticket item/location is now part of `key_items`. +- Added event tickets and islands. + - All event tickets are given to the player by Norman after defeating the Champion alongside the S.S. Ticket. + - As in vanilla, these tickets are only usable from Lilycove. Not Slateport or the Battle Frontier. +- New option `event_tickets`. Randomizes the above-mentioned tickets into the item pool. +- New option `enable_wonder_trading`. You can participate in Wonder Trading by interacting with the center receptionist +on the second floor of Pokemon Centers. + - Why is this an option instead of just being enabled? You might want to disable wonder trading in a meta yaml to + make sure certain rules can't be broken. Or you may want to turn it off for yourself to definitively prevent being + asked for help if you prefer to keep certain walls up between your game and others. Trades _do_ include items and + known moves, which means there is potential for an extra level of cooperation and even ways to go out of logic. But + that's not a boundary everyone wants broken down all the time. Please be respectful of someone's choice to not + participate if that's their preference. + - A lot of time was spent trying to make this all work without having to touch your client. Hopefully it goes + smoothly, but there's room for jank. Anything you decide to give to her you should consider gone forever, whether + because it was traded away or because something "went wrong in transit" and the pokemon's data got lost after being + removed from the server. + - Wonder Trading is _not_ resistant to save scumming in either direction. You _could_ abuse it to dupe pokemon, + because there's not realistically a way for me to prevent it, but I'd urge you to stick to the spirit of the design + unless everyone involved doesn't mind. + - The wonder trades you receive are stored in your save data even before you pick them up, so if you save after the + client tells you that you received a wonder trade, it's safe. You don't need to retrieve it from a poke center for + it to persist. However, if you reset your game to a point in time before your client popped the "Wonder trade + received" message, that pokemon is lost forever. +- New `easter_egg` passphrase system. + - All valid easter egg passphrases will be a phrase that it's possible to submit as a trendy phrase in Dewford Town. + Changing the trendy phrase does ***not*** trigger easter eggs. Only the phrase you put in your YAML can trigger an + easter egg. + - There may be other ways to learn more information. + - Phrases are case insensitive. Here are a couple examples of possible phrases: `"GET FOE"`, + `"HERE GOES GRANDMOTHER"`, `"late eh?"` (None of those do anything, but I'd love to hear what you think they would.) +- Added three new easter egg effects. +- Changed the original easter egg phrase to use the new system. +- Renamed `tm_moves` to `tm_tutor_moves`. Move tutors are also affected by this option (except the new Dig tutor). +- Renamed `tm_compatibility` to `tm_tutor_compatibility`. Move tutors are also affected by this option. +- Changed `tm_tutor_compatibility` to be a percent chance instead of a choice. Use `-1` for vanilla. +- Changed `hm_compatibility` to be a percent chance instead of a choice. Use `-1` for vanilla. +- New option `music`. Shuffles all looping music. Includes FRLG tracks and possibly some unused stuff. +- New option `fanfares`. Shuffles all fanfares. Includes FRLG tracks. When this is enabled, pressing B will interrupt +most fanfares. +- New option `purge_spinners`. Trainers that change which direction they face will do so predictably, and will no longer +turn to face you when you run. +- New option `normalize_encounter_rates`. Sets every encounter slot to (almost) equal probability. Does NOT make every +species equally likely to appear, but makes rare encounters less rare. +- Added `Trick House` location group. +- Removed `Postgame Locations` location group. + +### QoL + +- Can teach moves over HM moves. +- Fishing is much less random; pokemon will always bite if there's an encounter there. +- Mirage Island is now always present. +- Waking Rayquaza is no longer required. After releasing Kyogre, going to Sootopolis will immediately trigger the +Rayquaza cutscene. +- Renamed some locations to be more accurate. +- Most trainers will no longer ask to be registered in your Pokegear after battle. Also removed most step-based match +calls. +- Removed a ledge on Route 123. With careful routing, it's now possible to check every location without having to save +scum or go back around. +- Added "GO HOME" button on the start menu where "EXIT" used to be. Will teleport you to Littleroot. +- Some locations which are directly blocked by completing your goal are automatically excluded. + - For example, the S.S. Ticket and a Champion goal, or the Sludge Bomb TM and the Norman goal. + - Your particular options might still result in locations that can't be reached until after your goal. For example, + setting a Norman goal and setting your E4 requirement to 8 gyms means that post-Champion locations will not be + reachable before defeating Norman, but they are NOT excluded by this modification. That's one of the simpler + examples. It is extremely tedious to try to detect these sorts of situations, so I'll instead leave it to you to be + aware of your own options. +- Species in the pokedex are searchable by type even if you haven't caught that species yet + +### Fixes + +- Mt. Pyre summit state no longer changes when you finish the Sootopolis events, which would lock you out of one or two +locations. +- Whiting out under certain conditions no longer softlocks you by moving Mr. Briney to an inaccessible area. +- It's no longer possible to join a room using the wrong patch file, even if the slot names match. +- NPCs now stop moving while you're receiving an item. +- Creating a secret base no longer triggers sending the Secret Power TM location. +- Hopefully fix bug where receiving an item while walking over a trigger can skip that trigger (the Moving +Truck/Petalburg wrong warp) + +## Easter Eggs + +There are plenty among you who are capable of ~~cheating~~ finding information about the easter egg phrases by reading +source code, writing brute force scripts, and inspecting memory for clues and answers. By all means, go ahead, that can +be your version of this puzzle and I don't intend to stand in your way. **However**, I would ask that any information +you come up with by doing this, you keep entirely to yourself until the community as a whole has figured out what you +know. There was not previously a way to reasonably learn about or make guesses at the easter egg, but that has changed. +There are mechanisms by which solutions can be found or guessed over the course of multiple games by multiple people, +and I'd rather the fun not get spoiled immediately. + +Once a solution has been found I'd _still_ prefer discussion about hints and effects remain behind spoiler tags just in +case there are people who want to do the hunt on their own. Thank you all, and good luck. diff --git a/worlds/pokemon_emerald/README.md b/worlds/pokemon_emerald/README.md index 2c1e9e3560..8441afc56a 100644 --- a/worlds/pokemon_emerald/README.md +++ b/worlds/pokemon_emerald/README.md @@ -1,58 +1,3 @@ # Pokemon Emerald -Version 1.2.1 - -This README contains general info useful for understanding the world. Pretty much all the long lists of locations, -regions, and items are stored in `data/` and (mostly) loaded in by `data.py`. Access rules are in `rules.py`. Check -[data/README.md](data/README.md) for more detailed information on the JSON files holding most of the data. - -## Warps - -Quick note to start, you should not be defining or modifying encoded warps from this repository. They're encoded in the -source code repository for the mod, and then assigned to regions in `data/regions/`. All warps in the game already exist -within `extracted_data.json`, and all relevant warps are already placed in `data/regions/` (unless they were deleted -accidentally). - -Many warps are actually two or three events acting as one logical warp. Doorways, for example, are often 2 tiles wide -indoors but only 1 tile wide outdoors. Both indoor warps point to the outdoor warp, and the outdoor warp points to only -one of the indoor warps. We want to describe warps logically in a way that retains information about individual warp -events. That way a 2-tile-wide doorway doesnt look like a one-way warp next to an unrelated two-way warp, but if we want -to randomize the destinations of those warps, we can still get back each individual id of the multi-tile warp. - -This is how warps are encoded: - -`{source_map}:{source_warp_ids}/{dest_map}:{dest_warp_ids}[!]` - -- `source_map`: The map the warp events are located in -- `source_warp_ids`: The ids of all adjacent warp events in source_map which lead to the same destination (these must be -in ascending order) -- `dest_map`: The map of the warp event to which this one is connected -- `dest_warp_ids`: The ids of the warp events in dest_map -- `[!]`: If the warp expects to lead to a destination which doesnot lead back to it, add a ! to the end - -Example: `MAP_LAVARIDGE_TOWN_HOUSE:0,1/MAP_LAVARIDGE_TOWN:4` - -Example 2: `MAP_AQUA_HIDEOUT_B1F:14/MAP_AQUA_HIDEOUT_B1F:12!` - -Note: A warp must have its destination set to another warp event. However, that does not guarantee that the destination -warp event will warp back to the source. - -Note 2: Some warps _only_ act as destinations and cannot actually be interacted with by the player as sources. These are -usually places you fall from a hole above. At the time of writing, these are actually not accounted for, but there are -no instances where it changes logical access. - -Note 3: Some warp destinations go to the map `MAP_DYNAMIC` and have a special warp id. These edge cases are: - -- The Moving Truck -- Terra Cave -- Marine Cave -- The Department Store Elevator -- Secret Bases -- The Trade Center -- The Union Room -- The Record Corner -- 2P/4P Battle Colosseum - -Note 4: The trick house on Route 110 changes the warp destinations of its entrance and ending room as you progress -through the puzzles, but the source code only sets the trick house up for the first puzzle, and I assume the destination -gets overwritten at run time when certain flags are set. +Version 2.0.0 diff --git a/worlds/pokemon_emerald/__init__.py b/worlds/pokemon_emerald/__init__.py index 4d40dd1966..c17fd1bc19 100644 --- a/worlds/pokemon_emerald/__init__.py +++ b/worlds/pokemon_emerald/__init__.py @@ -5,7 +5,7 @@ from collections import Counter import copy import logging import os -from typing import Any, Set, List, Dict, Optional, Tuple, ClassVar +from typing import Any, Set, List, Dict, Optional, Tuple, ClassVar, TextIO, Union from BaseClasses import ItemClassification, MultiWorld, Tutorial, LocationProgressType from Fill import FillError, fill_restrictive @@ -14,21 +14,18 @@ import settings from worlds.AutoWorld import WebWorld, World from .client import PokemonEmeraldClient # Unused, but required to register with BizHawkClient -from .data import (SpeciesData, MapData, EncounterTableData, LearnsetMove, TrainerPokemonData, StaticEncounterData, - TrainerData, data as emerald_data) +from .data import LEGENDARY_POKEMON, MapData, SpeciesData, TrainerData, data as emerald_data from .items import (ITEM_GROUPS, PokemonEmeraldItem, create_item_label_to_code_map, get_item_classification, offset_item_value) from .locations import (LOCATION_GROUPS, PokemonEmeraldLocation, create_location_label_to_id_map, - create_locations_with_tags) -from .options import (Goal, ItemPoolType, RandomizeWildPokemon, RandomizeBadges, RandomizeTrainerParties, RandomizeHms, - RandomizeStarters, LevelUpMoves, RandomizeAbilities, RandomizeTypes, TmCompatibility, - HmCompatibility, RandomizeStaticEncounters, NormanRequirement, PokemonEmeraldOptions) -from .pokemon import get_random_species, get_random_move, get_random_damaging_move, get_random_type -from .regions import create_regions -from .rom import PokemonEmeraldDeltaPatch, generate_output, location_visited_event_to_id_map -from .rules import set_rules -from .sanity_check import validate_regions -from .util import int_to_bool_array, bool_array_to_int + create_locations_with_tags, 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) +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) +from .rom import PokemonEmeraldDeltaPatch, create_patch class PokemonEmeraldWebWorld(WebWorld): @@ -89,22 +86,46 @@ class PokemonEmeraldWorld(World): item_name_groups = ITEM_GROUPS location_name_groups = LOCATION_GROUPS - data_version = 1 + data_version = 2 required_client_version = (0, 4, 3) - badge_shuffle_info: Optional[List[Tuple[PokemonEmeraldLocation, PokemonEmeraldItem]]] = None - hm_shuffle_info: Optional[List[Tuple[PokemonEmeraldLocation, PokemonEmeraldItem]]] = None - free_fly_location_id: int = 0 + badge_shuffle_info: Optional[List[Tuple[PokemonEmeraldLocation, PokemonEmeraldItem]]] + hm_shuffle_info: Optional[List[Tuple[PokemonEmeraldLocation, PokemonEmeraldItem]]] + free_fly_location_id: int + blacklisted_moves: Set[int] + blacklisted_wilds: Set[int] + blacklisted_starters: Set[int] + blacklisted_opponent_pokemon: Set[int] + hm_requirements: Dict[str, Union[int, List[str]]] + auth: bytes - modified_species: List[Optional[SpeciesData]] - modified_maps: List[MapData] + modified_species: Dict[int, SpeciesData] + modified_maps: Dict[str, MapData] modified_tmhm_moves: List[int] - modified_static_encounters: List[int] + modified_legendary_encounters: List[int] modified_starters: Tuple[int, int, int] modified_trainers: List[TrainerData] + def __init__(self, multiworld, player): + super(PokemonEmeraldWorld, self).__init__(multiworld, player) + self.badge_shuffle_info = None + self.hm_shuffle_info = None + self.free_fly_location_id = 0 + self.blacklisted_moves = set() + self.blacklisted_wilds = set() + self.blacklisted_starters = set() + self.blacklisted_opponent_pokemon = set() + self.modified_maps = copy.deepcopy(emerald_data.maps) + self.modified_species = copy.deepcopy(emerald_data.species) + self.modified_tmhm_moves = [] + self.modified_starters = emerald_data.starters + self.modified_trainers = [] + self.modified_legendary_encounters = [] + @classmethod def stage_assert_generate(cls, multiworld: MultiWorld) -> None: + from .sanity_check import validate_regions + if not os.path.exists(cls.settings.rom_file): raise FileNotFoundError(cls.settings.rom_file) @@ -114,15 +135,83 @@ class PokemonEmeraldWorld(World): return "Great Ball" def generate_early(self) -> None: - # If badges or HMs are vanilla, Norman locks you from using Surf, which means you're not guaranteed to be - # able to reach Fortree Gym, Mossdeep Gym, or Sootopolis Gym. So we can't require reaching those gyms to - # challenge Norman or it creates a circular dependency. - # This is never a problem for completely random badges/hms because the algo will not place Surf/Balance Badge - # on Norman on its own. It's never a problem for shuffled badges/hms because there is no scenario where Cut or - # the Stone Badge can be a lynchpin for access to any gyms, so they can always be put on Norman in a worst case - # scenario. - # This will also be a problem in warp rando if direct access to Norman's room requires Surf or if access - # any gym leader in general requires Surf. We will probably have to force this to 0 in that case. + self.hm_requirements = { + "HM01 Cut": ["Stone Badge"], + "HM02 Fly": ["Feather Badge"], + "HM03 Surf": ["Balance Badge"], + "HM04 Strength": ["Heat Badge"], + "HM05 Flash": ["Knuckle Badge"], + "HM06 Rock Smash": ["Dynamo Badge"], + "HM07 Waterfall": ["Rain Badge"], + "HM08 Dive": ["Mind Badge"], + } + if self.options.hm_requirements == HmRequirements.option_fly_without_badge: + self.hm_requirements["HM02 Fly"] = 0 + + self.blacklisted_moves = {emerald_data.move_labels[label] for label in self.options.move_blacklist.value} + + self.blacklisted_wilds = { + get_species_id_by_label(species_name) + for species_name in self.options.wild_encounter_blacklist.value + if species_name != "_Legendaries" + } + if "_Legendaries" in self.options.wild_encounter_blacklist.value: + self.blacklisted_wilds |= LEGENDARY_POKEMON + + self.blacklisted_starters = { + get_species_id_by_label(species_name) + for species_name in self.options.starter_blacklist.value + if species_name != "_Legendaries" + } + if "_Legendaries" in self.options.starter_blacklist.value: + self.blacklisted_starters |= LEGENDARY_POKEMON + + self.blacklisted_opponent_pokemon = { + get_species_id_by_label(species_name) + for species_name in self.options.trainer_party_blacklist.value + if species_name != "_Legendaries" + } + if "_Legendaries" in self.options.starter_blacklist.value: + self.blacklisted_opponent_pokemon |= LEGENDARY_POKEMON + + # In race mode we don't patch any item location information into the ROM + if self.multiworld.is_race and not self.options.remote_items: + logging.warning("Pokemon Emerald: Forcing Player %s (%s) to use remote items due to race mode.", + self.player, self.multiworld.player_name[self.player]) + self.options.remote_items.value = Toggle.option_true + + if self.options.goal == Goal.option_legendary_hunt: + # Prevent turning off all legendary encounters + if len(self.options.allowed_legendary_hunt_encounters.value) == 0: + raise ValueError(f"Pokemon Emerald: Player {self.player} ({self.multiworld.player_name[self.player]}) " + "needs to allow at least one legendary encounter when goal is legendary hunt.") + + # Prevent setting the number of required legendaries higher than the number of enabled legendaries + if self.options.legendary_hunt_count.value > len(self.options.allowed_legendary_hunt_encounters.value): + logging.warning("Pokemon Emerald: Legendary hunt count for Player %s (%s) higher than number of allowed " + "legendary encounters. Reducing to number of allowed encounters.", self.player, + self.multiworld.player_name[self.player]) + self.options.legendary_hunt_count.value = len(self.options.allowed_legendary_hunt_encounters.value) + + # Require random wild encounters if dexsanity is enabled + if self.options.dexsanity and self.options.wild_pokemon == RandomizeWildPokemon.option_vanilla: + raise ValueError(f"Pokemon Emerald: Player {self.player} ({self.multiworld.player_name[self.player]}) must " + "not leave wild encounters vanilla if enabling dexsanity.") + + # If badges or HMs are vanilla, Norman locks you from using Surf, + # which means you're not guaranteed to be able to reach Fortree Gym, + # Mossdeep Gym, or Sootopolis Gym. So we can't require reaching those + # gyms to challenge Norman or it creates a circular dependency. + # + # This is never a problem for completely random badges/hms because the + # algo will not place Surf/Balance Badge on Norman on its own. It's + # never a problem for shuffled badges/hms because there is no scenario + # where Cut or the Stone Badge can be a lynchpin for access to any gyms, + # so they can always be put on Norman in a worst case scenario. + # + # This will also be a problem in warp rando if direct access to Norman's + # room requires Surf or if access any gym leader in general requires + # Surf. We will probably have to force this to 0 in that case. max_norman_count = 7 if self.options.badges == RandomizeBadges.option_vanilla: @@ -141,17 +230,22 @@ class PokemonEmeraldWorld(World): self.options.norman_count.value = max_norman_count def create_regions(self) -> None: + from .regions import create_regions regions = create_regions(self) - tags = {"Badge", "HM", "KeyItem", "Rod", "Bike"} + tags = {"Badge", "HM", "KeyItem", "Rod", "Bike", "EventTicket"} # Tags with progression items always included if self.options.overworld_items: tags.add("OverworldItem") if self.options.hidden_items: tags.add("HiddenItem") if self.options.npc_gifts: tags.add("NpcGift") - if self.options.enable_ferry: - tags.add("Ferry") + if self.options.berry_trees: + tags.add("BerryTree") + if self.options.dexsanity: + tags.add("Pokedex") + if self.options.trainersanity: + tags.add("Trainer") create_locations_with_tags(self, regions, tags) self.multiworld.regions.extend(regions.values()) @@ -166,18 +260,18 @@ class PokemonEmeraldWorld(World): continue # Location not in multiworld if self.options.goal == Goal.option_champion: - # Always required to beat champion before receiving this + # Always required to beat champion before receiving these exclude_locations([ - "Littleroot Town - S.S. Ticket from Norman" + "Littleroot Town - S.S. Ticket from Norman", + "Littleroot Town - Aurora Ticket from Norman", + "Littleroot Town - Eon Ticket from Norman", + "Littleroot Town - Mystic Ticket from Norman", + "Littleroot Town - Old Sea Map from Norman", + "Ever Grande City - Champion Wallace", + "Meteor Falls 1F - Rival Steven", + "Trick House Puzzle 8 - Item", ]) - # S.S. Ticket requires beating champion, so ferry is not accessible until after goal - if not self.options.enable_ferry: - exclude_locations([ - "SS Tidal - Hidden Item in Lower Deck Trash Can", - "SS Tidal - TM49 from Thief" - ]) - # Construction workers don't move until champion is defeated if "Safari Zone Construction Workers" not in self.options.remove_roadblocks.value: exclude_locations([ @@ -186,8 +280,12 @@ class PokemonEmeraldWorld(World): "Safari Zone NE - Item on Ledge", "Safari Zone SE - Hidden Item in South Grass 1", "Safari Zone SE - Hidden Item in South Grass 2", - "Safari Zone SE - Item in Grass" + "Safari Zone SE - Item in Grass", ]) + elif self.options.goal == Goal.option_steven: + exclude_locations([ + "Meteor Falls 1F - Rival Steven", + ]) elif self.options.goal == Goal.option_norman: # If the player sets their options such that Surf or the Balance # Badge is vanilla, a very large number of locations become @@ -207,7 +305,7 @@ class PokemonEmeraldWorld(World): "Petalburg City - HM03 from Wally's Uncle", "Dewford Town - TM36 from Sludge Bomb Man", "Mauville City - Basement Key from Wattson", - "Mauville City - TM24 from Wattson" + "Mauville City - TM24 from Wattson", ]) def create_items(self) -> None: @@ -217,8 +315,9 @@ class PokemonEmeraldWorld(World): if location.address is not None ] - # Filter progression items which shouldn't be shuffled into the itempool. Their locations - # still exist, but event items will be placed and locked at their vanilla locations instead. + # Filter progression items which shouldn't be shuffled into the itempool. + # Their locations will still exist, but event items will be placed and + # locked at their vanilla locations instead. filter_tags = set() if not self.options.key_items: @@ -227,12 +326,17 @@ class PokemonEmeraldWorld(World): filter_tags.add("Rod") if not self.options.bikes: filter_tags.add("Bike") + if not self.options.event_tickets: + filter_tags.add("EventTicket") if self.options.badges in {RandomizeBadges.option_vanilla, RandomizeBadges.option_shuffle}: filter_tags.add("Badge") if self.options.hms in {RandomizeHms.option_vanilla, RandomizeHms.option_shuffle}: filter_tags.add("HM") + # If Badges and HMs are set to the `shuffle` option, don't add them to + # the normal item pool, but do create their items and save them and + # their locations for use in `pre_fill` later. if self.options.badges == RandomizeBadges.option_shuffle: self.badge_shuffle_info = [ (location, self.create_item_by_code(location.default_item_code)) @@ -244,14 +348,18 @@ class PokemonEmeraldWorld(World): for location in [l for l in item_locations if "HM" in l.tags] ] + # Filter down locations to actual items that will be filled and create + # the itempool. item_locations = [location for location in item_locations if len(filter_tags & location.tags) == 0] default_itempool = [self.create_item_by_code(location.default_item_code) for location in item_locations] + # Take the itempool as-is if self.options.item_pool_type == ItemPoolType.option_shuffled: self.multiworld.itempool += default_itempool - elif self.options.item_pool_type in {ItemPoolType.option_diverse, ItemPoolType.option_diverse_balanced}: - item_categories = ["Ball", "Heal", "Vitamin", "EvoStone", "Money", "TM", "Held", "Misc"] + # Recreate the itempool from random items + elif self.options.item_pool_type in (ItemPoolType.option_diverse, ItemPoolType.option_diverse_balanced): + item_categories = ["Ball", "Heal", "Candy", "Vitamin", "EvoStone", "Money", "TM", "Held", "Misc", "Berry"] # Count occurrences of types of vanilla items in pool item_category_counter = Counter() @@ -306,38 +414,23 @@ class PokemonEmeraldWorld(World): self.multiworld.itempool.append(item) def set_rules(self) -> None: + from .rules import set_rules set_rules(self) def generate_basic(self) -> None: - locations: List[PokemonEmeraldLocation] = self.multiworld.get_locations(self.player) + # Create auth + # self.auth = self.random.randbytes(16) # Requires >=3.9 + self.auth = self.random.getrandbits(16 * 8).to_bytes(16, "little") - # Set our free fly location - # If not enabled, set it to Littleroot Town by default - fly_location_name = "EVENT_VISITED_LITTLEROOT_TOWN" - if self.options.free_fly_location: - fly_location_name = self.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" - ]) - - self.free_fly_location_id = location_visited_event_to_id_map[fly_location_name] - - free_fly_location_location = self.multiworld.get_location("FREE_FLY_LOCATION", self.player) - free_fly_location_location.item = None - free_fly_location_location.place_locked_item(self.create_event(fly_location_name)) + randomize_types(self) + randomize_wild_encounters(self) + set_free_fly(self) + set_legendary_cave_entrances(self) # Key items which are considered in access rules but not randomized are converted to events and placed # in their vanilla locations so that the player can have them in their inventory for logic. def convert_unrandomized_items_to_events(tag: str) -> None: - for location in locations: + for location in self.multiworld.get_locations(self.player): if location.tags is not None and tag in location.tags: location.place_locked_item(self.create_event(self.item_id_to_name[location.default_item_code])) location.progress_type = LocationProgressType.DEFAULT @@ -351,30 +444,36 @@ class PokemonEmeraldWorld(World): convert_unrandomized_items_to_events("Rod") if not self.options.bikes: convert_unrandomized_items_to_events("Bike") + if not self.options.event_tickets: + convert_unrandomized_items_to_events("EventTicket") if not self.options.key_items: convert_unrandomized_items_to_events("KeyItem") def pre_fill(self) -> None: - # Items which are shuffled between their own locations + # Badges and HMs that are set to shuffle need to be placed at + # their own subset of locations if self.options.badges == RandomizeBadges.option_shuffle: badge_locations: List[PokemonEmeraldLocation] badge_items: List[PokemonEmeraldItem] # Sort order makes `fill_restrictive` try to place important badges later, which # makes it less likely to have to swap at all, and more likely for swaps to work. - # In the case of vanilla HMs, navigating Granite Cave is required to access more than 2 gyms, - # so Knuckle Badge deserves highest priority if Flash is logically required. badge_locations, badge_items = [list(l) for l in zip(*self.badge_shuffle_info)] badge_priority = { - "Knuckle Badge": 0 if (self.options.hms == RandomizeHms.option_vanilla and self.options.require_flash) else 3, + "Knuckle Badge": 3, "Balance Badge": 1, "Dynamo Badge": 1, "Mind Badge": 2, "Heat Badge": 2, "Rain Badge": 3, "Stone Badge": 4, - "Feather Badge": 5 + "Feather Badge": 5, } + # In the case of vanilla HMs, navigating Granite Cave is required to access more than 2 gyms, + # so Knuckle Badge deserves highest priority if Flash is logically required. + if self.options.hms == RandomizeHms.option_vanilla and \ + self.options.require_flash in (DarkCavesRequireFlash.option_both, DarkCavesRequireFlash.option_only_granite_cave): + badge_priority["Knuckle Badge"] = 0 badge_items.sort(key=lambda item: badge_priority.get(item.name, 0)) # Un-exclude badge locations, since we need to put progression items on them @@ -384,6 +483,11 @@ class PokemonEmeraldWorld(World): else location.progress_type collection_state = self.multiworld.get_all_state(False) + + # If HM shuffle is on, HMs are not placed and not in the pool, so + # `get_all_state` did not contain them. Collect them manually for + # this fill. We know that they will be included in all state after + # this stage. if self.hm_shuffle_info is not None: for _, item in self.hm_shuffle_info: collection_state.collect(item) @@ -406,25 +510,29 @@ class PokemonEmeraldWorld(World): logging.debug(f"Failed to shuffle badges for player {self.player}. Retrying.") continue + # Badges are guaranteed to be either placed or in the multiworld's itempool now if self.options.hms == RandomizeHms.option_shuffle: hm_locations: List[PokemonEmeraldLocation] hm_items: List[PokemonEmeraldItem] # Sort order makes `fill_restrictive` try to place important HMs later, which # makes it less likely to have to swap at all, and more likely for swaps to work. - # In the case of vanilla badges, navigating Granite Cave is required to access more than 2 gyms, - # so Flash deserves highest priority if it's logically required. hm_locations, hm_items = [list(l) for l in zip(*self.hm_shuffle_info)] hm_priority = { - "HM05 Flash": 0 if (self.options.badges == RandomizeBadges.option_vanilla and self.options.require_flash) else 3, + "HM05 Flash": 3, "HM03 Surf": 1, "HM06 Rock Smash": 1, "HM08 Dive": 2, "HM04 Strength": 2, "HM07 Waterfall": 3, "HM01 Cut": 4, - "HM02 Fly": 5 + "HM02 Fly": 5, } + # In the case of vanilla badges, navigating Granite Cave is required to access more than 2 gyms, + # so Flash deserves highest priority if it's logically required. + if self.options.badges == RandomizeBadges.option_vanilla and \ + self.options.require_flash in (DarkCavesRequireFlash.option_both, DarkCavesRequireFlash.option_only_granite_cave): + hm_priority["HM05 Flash"] = 0 hm_items.sort(key=lambda item: hm_priority.get(item.name, 0)) # Un-exclude HM locations, since we need to put progression items on them @@ -454,465 +562,110 @@ class PokemonEmeraldWorld(World): continue def generate_output(self, output_directory: str) -> None: - def randomize_abilities() -> None: - # Creating list of potential abilities - ability_label_to_value = {ability.label.lower(): ability.ability_id for ability in emerald_data.abilities} + self.modified_trainers = copy.deepcopy(emerald_data.trainers) + self.modified_tmhm_moves = copy.deepcopy(emerald_data.tmhm_moves) + self.modified_legendary_encounters = copy.deepcopy(emerald_data.legendary_encounters) + self.modified_misc_pokemon = copy.deepcopy(emerald_data.misc_pokemon) + self.modified_starters = copy.deepcopy(emerald_data.starters) - ability_blacklist_labels = {"cacophony"} - option_ability_blacklist = self.options.ability_blacklist.value - if option_ability_blacklist is not None: - ability_blacklist_labels |= {ability_label.lower() for ability_label in option_ability_blacklist} + randomize_abilities(self) + randomize_learnsets(self) + randomize_tm_hm_compatibility(self) + randomize_legendary_encounters(self) + randomize_misc_pokemon(self) + randomize_opponent_parties(self) + randomize_starters(self) - ability_blacklist = {ability_label_to_value[label] for label in ability_blacklist_labels} - ability_whitelist = [a.ability_id for a in emerald_data.abilities if a.ability_id not in ability_blacklist] + # Modify catch rate + min_catch_rate = min(self.options.min_catch_rate.value, 255) + for species in self.modified_species.values(): + species.catch_rate = max(species.catch_rate, min_catch_rate) - if self.options.abilities == RandomizeAbilities.option_follow_evolutions: - already_modified: Set[int] = set() - - # Loops through species and only tries to modify abilities if the pokemon has no pre-evolution - # or if the pre-evolution has already been modified. Then tries to modify all species that evolve - # from this one which have the same abilities. - # The outer while loop only runs three times for vanilla ordering: Once for a first pass, once for - # Hitmonlee/Hitmonchan, and once to verify that there's nothing left to do. - while True: - had_clean_pass = True - for species in self.modified_species: - if species is None: - continue - if species.species_id in already_modified: - continue - if species.pre_evolution is not None and species.pre_evolution not in already_modified: - continue - - had_clean_pass = False - - old_abilities = species.abilities - new_abilities = ( - 0 if old_abilities[0] == 0 else self.random.choice(ability_whitelist), - 0 if old_abilities[1] == 0 else self.random.choice(ability_whitelist) - ) - - evolutions = [species] - while len(evolutions) > 0: - evolution = evolutions.pop() - if evolution.abilities == old_abilities: - evolution.abilities = new_abilities - already_modified.add(evolution.species_id) - evolutions += [ - self.modified_species[evolution.species_id] - for evolution in evolution.evolutions - if evolution.species_id not in already_modified - ] - - if had_clean_pass: - break - else: # Not following evolutions - for species in self.modified_species: - if species is None: - continue - - old_abilities = species.abilities - new_abilities = ( - 0 if old_abilities[0] == 0 else self.random.choice(ability_whitelist), - 0 if old_abilities[1] == 0 else self.random.choice(ability_whitelist) - ) - - species.abilities = new_abilities - - def randomize_types() -> None: - if self.options.types == RandomizeTypes.option_shuffle: - type_map = list(range(18)) - self.random.shuffle(type_map) - - # We never want to map to the ??? type, so swap whatever index maps to ??? with ??? - # So ??? will always map to itself, and there are no pokemon which have the ??? type - mystery_type_index = type_map.index(9) - type_map[mystery_type_index], type_map[9] = type_map[9], type_map[mystery_type_index] - - for species in self.modified_species: - if species is not None: - species.types = (type_map[species.types[0]], type_map[species.types[1]]) - elif self.options.types == RandomizeTypes.option_completely_random: - for species in self.modified_species: - if species is not None: - new_type_1 = get_random_type(self.random) - new_type_2 = new_type_1 - if species.types[0] != species.types[1]: - while new_type_1 == new_type_2: - new_type_2 = get_random_type(self.random) - - species.types = (new_type_1, new_type_2) - elif self.options.types == RandomizeTypes.option_follow_evolutions: - already_modified: Set[int] = set() - - # Similar to follow evolutions for abilities, but only needs to loop through once. - # For every pokemon without a pre-evolution, generates a random mapping from old types to new types - # and then walks through the evolution tree applying that map. This means that evolutions that share - # types will have those types mapped to the same new types, and evolutions with new or diverging types - # will still have new or diverging types. - # Consider: - # - Charmeleon (Fire/Fire) -> Charizard (Fire/Flying) - # - Onyx (Rock/Ground) -> Steelix (Steel/Ground) - # - Nincada (Bug/Ground) -> Ninjask (Bug/Flying) && Shedinja (Bug/Ghost) - # - Azurill (Normal/Normal) -> Marill (Water/Water) - for species in self.modified_species: - if species is None: - continue - if species.species_id in already_modified: - continue - if species.pre_evolution is not None and species.pre_evolution not in already_modified: - continue - - type_map = list(range(18)) - self.random.shuffle(type_map) - - # We never want to map to the ??? type, so swap whatever index maps to ??? with ??? - # So ??? will always map to itself, and there are no pokemon which have the ??? type - mystery_type_index = type_map.index(9) - type_map[mystery_type_index], type_map[9] = type_map[9], type_map[mystery_type_index] - - evolutions = [species] - while len(evolutions) > 0: - evolution = evolutions.pop() - evolution.types = (type_map[evolution.types[0]], type_map[evolution.types[1]]) - already_modified.add(evolution.species_id) - evolutions += [self.modified_species[evo.species_id] for evo in evolution.evolutions] - - def randomize_learnsets() -> None: - type_bias = self.options.move_match_type_bias.value - normal_bias = self.options.move_normal_type_bias.value - - for species in self.modified_species: - if species is None: - continue - - old_learnset = species.learnset - new_learnset: List[LearnsetMove] = [] - - i = 0 - # Replace filler MOVE_NONEs at start of list - while old_learnset[i].move_id == 0: - if self.options.level_up_moves == LevelUpMoves.option_start_with_four_moves: - new_move = get_random_move(self.random, {move.move_id for move in new_learnset}, type_bias, - normal_bias, species.types) - else: - new_move = 0 - new_learnset.append(LearnsetMove(old_learnset[i].level, new_move)) - i += 1 - - while i < len(old_learnset): - # Guarantees the starter has a good damaging move - if i == 3: - new_move = get_random_damaging_move(self.random, {move.move_id for move in new_learnset}) - else: - new_move = get_random_move(self.random, {move.move_id for move in new_learnset}, type_bias, - normal_bias, species.types) - new_learnset.append(LearnsetMove(old_learnset[i].level, new_move)) - i += 1 - - species.learnset = new_learnset - - def randomize_tm_hm_compatibility() -> None: - for species in self.modified_species: - if species is None: - continue - - combatibility_array = int_to_bool_array(species.tm_hm_compatibility) - - # TMs - for i in range(0, 50): - if self.options.tm_compatibility == TmCompatibility.option_fully_compatible: - combatibility_array[i] = True - elif self.options.tm_compatibility == TmCompatibility.option_completely_random: - combatibility_array[i] = self.random.choice([True, False]) - - # HMs - for i in range(50, 58): - if self.options.hm_compatibility == HmCompatibility.option_fully_compatible: - combatibility_array[i] = True - elif self.options.hm_compatibility == HmCompatibility.option_completely_random: - combatibility_array[i] = self.random.choice([True, False]) - - species.tm_hm_compatibility = bool_array_to_int(combatibility_array) - - def randomize_tm_moves() -> None: + # Modify TM moves + if self.options.tm_tutor_moves: new_moves: Set[int] = set() for i in range(50): - new_move = get_random_move(self.random, new_moves) + new_move = get_random_move(self.random, new_moves | self.blacklisted_moves) new_moves.add(new_move) self.modified_tmhm_moves[i] = new_move - def randomize_wild_encounters() -> None: - should_match_bst = self.options.wild_pokemon in { - RandomizeWildPokemon.option_match_base_stats, - RandomizeWildPokemon.option_match_base_stats_and_type + create_patch(self, output_directory) + + del self.modified_trainers + del self.modified_tmhm_moves + del self.modified_legendary_encounters + del self.modified_misc_pokemon + del self.modified_starters + del self.modified_species + + def write_spoiler(self, spoiler_handle: TextIO): + if self.options.dexsanity: + from collections import defaultdict + + spoiler_handle.write(f"\n\nWild Pokemon ({self.multiworld.player_name[self.player]}):\n\n") + + species_maps = defaultdict(set) + for map in self.modified_maps.values(): + if map.land_encounters is not None: + for encounter in map.land_encounters.slots: + species_maps[encounter].add(map.name[4:]) + + if map.water_encounters is not None: + for encounter in map.water_encounters.slots: + species_maps[encounter].add(map.name[4:]) + + if map.fishing_encounters is not None: + for encounter in map.fishing_encounters.slots: + species_maps[encounter].add(map.name[4:]) + + lines = [f"{emerald_data.species[species].label}: {', '.join(maps)}\n" + for species, maps in species_maps.items()] + lines.sort() + for line in lines: + spoiler_handle.write(line) + + del self.modified_maps + + def extend_hint_information(self, hint_data): + if self.options.dexsanity: + from collections import defaultdict + + slot_to_rod = { + 0: "_OLD_ROD", + 1: "_OLD_ROD", + 2: "_GOOD_ROD", + 3: "_GOOD_ROD", + 4: "_GOOD_ROD", + 5: "_SUPER_ROD", + 6: "_SUPER_ROD", + 7: "_SUPER_ROD", + 8: "_SUPER_ROD", + 9: "_SUPER_ROD", } - should_match_type = self.options.wild_pokemon in { - RandomizeWildPokemon.option_match_type, - RandomizeWildPokemon.option_match_base_stats_and_type + + species_maps = defaultdict(set) + for map in self.modified_maps.values(): + if map.land_encounters is not None: + for encounter in map.land_encounters.slots: + species_maps[encounter].add(map.name[4:] + "_GRASS") + + if map.water_encounters is not None: + for encounter in map.water_encounters.slots: + species_maps[encounter].add(map.name[4:] + "_WATER") + + if map.fishing_encounters is not None: + for slot, encounter in enumerate(map.fishing_encounters.slots): + species_maps[encounter].add(map.name[4:] + slot_to_rod[slot]) + + hint_data[self.player] = { + self.location_name_to_id[f"Pokedex - {emerald_data.species[species].label}"]: ", ".join(maps) + for species, maps in species_maps.items() } - should_allow_legendaries = self.options.allow_wild_legendaries == Toggle.option_true - for map_data in self.modified_maps: - new_encounters: List[Optional[EncounterTableData]] = [None, None, None] - old_encounters = [map_data.land_encounters, map_data.water_encounters, map_data.fishing_encounters] - - for i, table in enumerate(old_encounters): - if table is not None: - species_old_to_new_map: Dict[int, int] = {} - for species_id in table.slots: - if species_id not in species_old_to_new_map: - original_species = emerald_data.species[species_id] - target_bst = sum(original_species.base_stats) if should_match_bst else None - target_type = self.random.choice(original_species.types) if should_match_type else None - - species_old_to_new_map[species_id] = get_random_species( - self.random, - self.modified_species, - target_bst, - target_type, - should_allow_legendaries - ).species_id - - new_slots: List[int] = [] - for species_id in table.slots: - new_slots.append(species_old_to_new_map[species_id]) - - new_encounters[i] = EncounterTableData(new_slots, table.rom_address) - - map_data.land_encounters = new_encounters[0] - map_data.water_encounters = new_encounters[1] - map_data.fishing_encounters = new_encounters[2] - - def randomize_static_encounters() -> None: - if self.options.static_encounters == RandomizeStaticEncounters.option_shuffle: - shuffled_species = [encounter.species_id for encounter in emerald_data.static_encounters] - self.random.shuffle(shuffled_species) - - self.modified_static_encounters = [] - for i, encounter in enumerate(emerald_data.static_encounters): - self.modified_static_encounters.append(StaticEncounterData( - shuffled_species[i], - encounter.rom_address - )) - else: - should_match_bst = self.options.static_encounters in { - RandomizeStaticEncounters.option_match_base_stats, - RandomizeStaticEncounters.option_match_base_stats_and_type - } - should_match_type = self.options.static_encounters in { - RandomizeStaticEncounters.option_match_type, - RandomizeStaticEncounters.option_match_base_stats_and_type - } - - for encounter in emerald_data.static_encounters: - original_species = self.modified_species[encounter.species_id] - target_bst = sum(original_species.base_stats) if should_match_bst else None - target_type = self.random.choice(original_species.types) if should_match_type else None - - self.modified_static_encounters.append(StaticEncounterData( - get_random_species(self.random, self.modified_species, target_bst, target_type).species_id, - encounter.rom_address - )) - - def randomize_opponent_parties() -> None: - should_match_bst = self.options.trainer_parties in { - RandomizeTrainerParties.option_match_base_stats, - RandomizeTrainerParties.option_match_base_stats_and_type - } - should_match_type = self.options.trainer_parties in { - RandomizeTrainerParties.option_match_type, - RandomizeTrainerParties.option_match_base_stats_and_type - } - allow_legendaries = self.options.allow_trainer_legendaries == Toggle.option_true - - per_species_tmhm_moves: Dict[int, List[int]] = {} - - for trainer in self.modified_trainers: - new_party = [] - for pokemon in trainer.party.pokemon: - original_species = emerald_data.species[pokemon.species_id] - target_bst = sum(original_species.base_stats) if should_match_bst else None - target_type = self.random.choice(original_species.types) if should_match_type else None - - new_species = get_random_species( - self.random, - self.modified_species, - target_bst, - target_type, - allow_legendaries - ) - - if new_species.species_id not in per_species_tmhm_moves: - per_species_tmhm_moves[new_species.species_id] = list({ - self.modified_tmhm_moves[i] - for i, is_compatible in enumerate(int_to_bool_array(new_species.tm_hm_compatibility)) - if is_compatible - }) - - tm_hm_movepool = per_species_tmhm_moves[new_species.species_id] - level_up_movepool = list({ - move.move_id - for move in new_species.learnset - if move.move_id != 0 and move.level <= pokemon.level - }) - - new_moves = ( - self.random.choice(tm_hm_movepool if self.random.random() < 0.25 and len(tm_hm_movepool) > 0 else level_up_movepool), - self.random.choice(tm_hm_movepool if self.random.random() < 0.25 and len(tm_hm_movepool) > 0 else level_up_movepool), - self.random.choice(tm_hm_movepool if self.random.random() < 0.25 and len(tm_hm_movepool) > 0 else level_up_movepool), - self.random.choice(tm_hm_movepool if self.random.random() < 0.25 and len(tm_hm_movepool) > 0 else level_up_movepool) - ) - - new_party.append(TrainerPokemonData(new_species.species_id, pokemon.level, new_moves)) - - trainer.party.pokemon = new_party - - def randomize_starters() -> None: - match_bst = self.options.starters in { - RandomizeStarters.option_match_base_stats, - RandomizeStarters.option_match_base_stats_and_type - } - match_type = self.options.starters in { - RandomizeStarters.option_match_type, - RandomizeStarters.option_match_base_stats_and_type - } - allow_legendaries = self.options.allow_starter_legendaries == Toggle.option_true - - starter_bsts = ( - sum(emerald_data.species[emerald_data.starters[0]].base_stats) if match_bst else None, - sum(emerald_data.species[emerald_data.starters[1]].base_stats) if match_bst else None, - sum(emerald_data.species[emerald_data.starters[2]].base_stats) if match_bst else None - ) - - starter_types = ( - self.random.choice(emerald_data.species[emerald_data.starters[0]].types) if match_type else None, - self.random.choice(emerald_data.species[emerald_data.starters[1]].types) if match_type else None, - self.random.choice(emerald_data.species[emerald_data.starters[2]].types) if match_type else None - ) - - new_starters = ( - get_random_species(self.random, self.modified_species, - starter_bsts[0], starter_types[0], allow_legendaries), - get_random_species(self.random, self.modified_species, - starter_bsts[1], starter_types[1], allow_legendaries), - get_random_species(self.random, self.modified_species, - starter_bsts[2], starter_types[2], allow_legendaries) - ) - - egg_code = self.options.easter_egg.value - egg_check_1 = 0 - egg_check_2 = 0 - - for i in egg_code: - egg_check_1 += ord(i) - egg_check_2 += egg_check_1 * egg_check_1 - - egg = 96 + egg_check_2 - (egg_check_1 * 0x077C) - if egg_check_2 == 0x14E03A and egg < 411 and egg > 0 and egg not in range(252, 277): - self.modified_starters = (egg, egg, egg) - else: - self.modified_starters = ( - new_starters[0].species_id, - new_starters[1].species_id, - new_starters[2].species_id - ) - - # Putting the unchosen starter onto the rival's team - rival_teams: List[List[Tuple[str, int, bool]]] = [ - [ - ("TRAINER_BRENDAN_ROUTE_103_TREECKO", 0, False), - ("TRAINER_BRENDAN_RUSTBORO_TREECKO", 1, False), - ("TRAINER_BRENDAN_ROUTE_110_TREECKO", 2, True ), - ("TRAINER_BRENDAN_ROUTE_119_TREECKO", 2, True ), - ("TRAINER_BRENDAN_LILYCOVE_TREECKO", 3, True ), - ("TRAINER_MAY_ROUTE_103_TREECKO", 0, False), - ("TRAINER_MAY_RUSTBORO_TREECKO", 1, False), - ("TRAINER_MAY_ROUTE_110_TREECKO", 2, True ), - ("TRAINER_MAY_ROUTE_119_TREECKO", 2, True ), - ("TRAINER_MAY_LILYCOVE_TREECKO", 3, True ) - ], - [ - ("TRAINER_BRENDAN_ROUTE_103_TORCHIC", 0, False), - ("TRAINER_BRENDAN_RUSTBORO_TORCHIC", 1, False), - ("TRAINER_BRENDAN_ROUTE_110_TORCHIC", 2, True ), - ("TRAINER_BRENDAN_ROUTE_119_TORCHIC", 2, True ), - ("TRAINER_BRENDAN_LILYCOVE_TORCHIC", 3, True ), - ("TRAINER_MAY_ROUTE_103_TORCHIC", 0, False), - ("TRAINER_MAY_RUSTBORO_TORCHIC", 1, False), - ("TRAINER_MAY_ROUTE_110_TORCHIC", 2, True ), - ("TRAINER_MAY_ROUTE_119_TORCHIC", 2, True ), - ("TRAINER_MAY_LILYCOVE_TORCHIC", 3, True ) - ], - [ - ("TRAINER_BRENDAN_ROUTE_103_MUDKIP", 0, False), - ("TRAINER_BRENDAN_RUSTBORO_MUDKIP", 1, False), - ("TRAINER_BRENDAN_ROUTE_110_MUDKIP", 2, True ), - ("TRAINER_BRENDAN_ROUTE_119_MUDKIP", 2, True ), - ("TRAINER_BRENDAN_LILYCOVE_MUDKIP", 3, True ), - ("TRAINER_MAY_ROUTE_103_MUDKIP", 0, False), - ("TRAINER_MAY_RUSTBORO_MUDKIP", 1, False), - ("TRAINER_MAY_ROUTE_110_MUDKIP", 2, True ), - ("TRAINER_MAY_ROUTE_119_MUDKIP", 2, True ), - ("TRAINER_MAY_LILYCOVE_MUDKIP", 3, True ) - ] - ] - - for i, starter in enumerate([new_starters[1], new_starters[2], new_starters[0]]): - potential_evolutions = [evolution.species_id for evolution in starter.evolutions] - picked_evolution = starter.species_id - if len(potential_evolutions) > 0: - picked_evolution = self.random.choice(potential_evolutions) - - for trainer_name, starter_position, is_evolved in rival_teams[i]: - trainer_data = self.modified_trainers[emerald_data.constants[trainer_name]] - trainer_data.party.pokemon[starter_position].species_id = picked_evolution if is_evolved else starter.species_id - - self.modified_species = copy.deepcopy(emerald_data.species) - self.modified_trainers = copy.deepcopy(emerald_data.trainers) - self.modified_maps = copy.deepcopy(emerald_data.maps) - self.modified_tmhm_moves = copy.deepcopy(emerald_data.tmhm_moves) - self.modified_static_encounters = copy.deepcopy(emerald_data.static_encounters) - self.modified_starters = copy.deepcopy(emerald_data.starters) - - # Randomize species data - if self.options.abilities != RandomizeAbilities.option_vanilla: - randomize_abilities() - - if self.options.types != RandomizeTypes.option_vanilla: - randomize_types() - - if self.options.level_up_moves != LevelUpMoves.option_vanilla: - randomize_learnsets() - - randomize_tm_hm_compatibility() # Options are checked within this function - - min_catch_rate = min(self.options.min_catch_rate.value, 255) - for species in self.modified_species: - if species is not None: - species.catch_rate = max(species.catch_rate, min_catch_rate) - - if self.options.tm_moves: - randomize_tm_moves() - - # Randomize wild encounters - if self.options.wild_pokemon != RandomizeWildPokemon.option_vanilla: - randomize_wild_encounters() - - # Randomize static encounters - if self.options.static_encounters != RandomizeStaticEncounters.option_vanilla: - randomize_static_encounters() - - # Randomize opponents - if self.options.trainer_parties != RandomizeTrainerParties.option_vanilla: - randomize_opponent_parties() - - # Randomize starters - if self.options.starters != RandomizeStarters.option_vanilla: - randomize_starters() - - generate_output(self, output_directory) + def modify_multidata(self, multidata: Dict[str, Any]): + import base64 + multidata["connect_names"][base64.b64encode(self.auth).decode("ascii")] = multidata["connect_names"][self.multiworld.player_name[self.player]] def fill_slot_data(self) -> Dict[str, Any]: slot_data = self.options.as_dict( @@ -921,23 +674,33 @@ class PokemonEmeraldWorld(World): "hms", "key_items", "bikes", + "event_tickets", "rods", "overworld_items", "hidden_items", "npc_gifts", + "berry_trees", "require_itemfinder", "require_flash", - "enable_ferry", "elite_four_requirement", "elite_four_count", "norman_requirement", "norman_count", + "legendary_hunt_catch", + "legendary_hunt_count", "extra_boulders", "remove_roadblocks", + "allowed_legendary_hunt_encounters", + "extra_bumpy_slope", "free_fly_location", - "fly_without_badge", + "remote_items", + "dexsanity", + "trainersanity", + "modify_118", + "death_link", ) slot_data["free_fly_location_id"] = self.free_fly_location_id + slot_data["hm_requirements"] = self.hm_requirements return slot_data def create_item(self, name: str) -> PokemonEmeraldItem: diff --git a/worlds/pokemon_emerald/client.py b/worlds/pokemon_emerald/client.py index d8b4b8d587..0dccc1fe17 100644 --- a/worlds/pokemon_emerald/client.py +++ b/worlds/pokemon_emerald/client.py @@ -1,19 +1,28 @@ -from typing import TYPE_CHECKING, Dict, Set +import asyncio +import copy +import orjson +import random +import time +from typing import TYPE_CHECKING, Optional, Dict, Set, Tuple +import uuid from NetUtils import ClientStatus +from Options import Toggle +import Utils import worlds._bizhawk as bizhawk from worlds._bizhawk.client import BizHawkClient -from .data import BASE_OFFSET, data -from .options import Goal +from .data import BASE_OFFSET, POKEDEX_OFFSET, data +from .options import Goal, RemoteItems +from .util import pokemon_data_to_json, json_to_pokemon_data if TYPE_CHECKING: from worlds._bizhawk.context import BizHawkClientContext -EXPECTED_ROM_NAME = "pokemon emerald version / AP 2" +EXPECTED_ROM_NAME = "pokemon emerald version / AP 5" -IS_CHAMPION_FLAG = data.constants["FLAG_IS_CHAMPION"] +DEFEATED_WALLACE_FLAG = data.constants["TRAINER_FLAGS_START"] + data.constants["TRAINER_WALLACE"] DEFEATED_STEVEN_FLAG = data.constants["TRAINER_FLAGS_START"] + data.constants["TRAINER_STEVEN"] DEFEATED_NORMAN_FLAG = data.constants["TRAINER_FLAGS_START"] + data.constants["TRAINER_NORMAN_1"] @@ -31,7 +40,7 @@ TRACKER_EVENT_FLAGS = [ "FLAG_RECEIVED_POKENAV", # Talk to Mr. Stone "FLAG_DELIVERED_STEVEN_LETTER", "FLAG_DELIVERED_DEVON_GOODS", - "FLAG_HIDE_ROUTE_119_TEAM_AQUA", # Clear Weather Institute + "FLAG_HIDE_ROUTE_119_TEAM_AQUA_SHELLY", # Clear Weather Institute "FLAG_MET_ARCHIE_METEOR_FALLS", # Magma steals meteorite "FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT", # Clear Magma Hideout "FLAG_MET_TEAM_AQUA_HARBOR", # Aqua steals submarine @@ -41,19 +50,19 @@ TRACKER_EVENT_FLAGS = [ "FLAG_HIDE_SKY_PILLAR_TOP_RAYQUAZA", # Rayquaza departs for Sootopolis "FLAG_OMIT_DIVE_FROM_STEVEN_LETTER", # Steven gives Dive HM (clears seafloor cavern grunt) "FLAG_IS_CHAMPION", - "FLAG_PURCHASED_HARBOR_MAIL" + "FLAG_PURCHASED_HARBOR_MAIL", ] EVENT_FLAG_MAP = {data.constants[flag_name]: flag_name for flag_name in TRACKER_EVENT_FLAGS} KEY_LOCATION_FLAGS = [ - "NPC_GIFT_RECEIVED_HM01", - "NPC_GIFT_RECEIVED_HM02", - "NPC_GIFT_RECEIVED_HM03", - "NPC_GIFT_RECEIVED_HM04", - "NPC_GIFT_RECEIVED_HM05", - "NPC_GIFT_RECEIVED_HM06", - "NPC_GIFT_RECEIVED_HM07", - "NPC_GIFT_RECEIVED_HM08", + "NPC_GIFT_RECEIVED_HM_CUT", + "NPC_GIFT_RECEIVED_HM_FLY", + "NPC_GIFT_RECEIVED_HM_SURF", + "NPC_GIFT_RECEIVED_HM_STRENGTH", + "NPC_GIFT_RECEIVED_HM_FLASH", + "NPC_GIFT_RECEIVED_HM_ROCK_SMASH", + "NPC_GIFT_RECEIVED_HM_WATERFALL", + "NPC_GIFT_RECEIVED_HM_DIVE", "NPC_GIFT_RECEIVED_ACRO_BIKE", "NPC_GIFT_RECEIVED_WAILMER_PAIL", "NPC_GIFT_RECEIVED_DEVON_GOODS_RUSTURF_TUNNEL", @@ -70,7 +79,7 @@ KEY_LOCATION_FLAGS = [ "HIDDEN_ITEM_ABANDONED_SHIP_RM_1_KEY", "HIDDEN_ITEM_ABANDONED_SHIP_RM_4_KEY", "HIDDEN_ITEM_ABANDONED_SHIP_RM_6_KEY", - "ITEM_ABANDONED_SHIP_HIDDEN_FLOOR_ROOM_4_SCANNER", + "ITEM_ABANDONED_SHIP_HIDDEN_FLOOR_ROOM_2_SCANNER", "ITEM_ABANDONED_SHIP_CAPTAINS_OFFICE_STORAGE_KEY", "NPC_GIFT_RECEIVED_OLD_ROD", "NPC_GIFT_RECEIVED_GOOD_ROD", @@ -78,6 +87,24 @@ KEY_LOCATION_FLAGS = [ ] KEY_LOCATION_FLAG_MAP = {data.locations[location_name].flag: location_name for location_name in KEY_LOCATION_FLAGS} +LEGENDARY_NAMES = { + "Groudon": "GROUDON", + "Kyogre": "KYOGRE", + "Rayquaza": "RAYQUAZA", + "Latias": "LATIAS", + "Latios": "LATIOS", + "Regirock": "REGIROCK", + "Regice": "REGICE", + "Registeel": "REGISTEEL", + "Mew": "MEW", + "Deoxys": "DEOXYS", + "Ho-oh": "HO_OH", + "Lugia": "LUGIA", +} + +DEFEATED_LEGENDARY_FLAG_MAP = {data.constants[f"FLAG_DEFEATED_{name}"]: name for name in LEGENDARY_NAMES.values()} +CAUGHT_LEGENDARY_FLAG_MAP = {data.constants[f"FLAG_CAUGHT_{name}"]: name for name in LEGENDARY_NAMES.values()} + class PokemonEmeraldClient(BizHawkClient): game = "Pokemon Emerald" @@ -86,14 +113,31 @@ class PokemonEmeraldClient(BizHawkClient): local_checked_locations: Set[int] local_set_events: Dict[str, bool] local_found_key_items: Dict[str, bool] - goal_flag: int + local_defeated_legendaries: Dict[str, bool] + goal_flag: Optional[int] + + wonder_trade_update_event: asyncio.Event + latest_wonder_trade_reply: dict + wonder_trade_cooldown: int + wonder_trade_cooldown_timer: int + + death_counter: Optional[int] + previous_death_link: float + ignore_next_death_link: bool def __init__(self) -> None: super().__init__() self.local_checked_locations = set() self.local_set_events = {} self.local_found_key_items = {} - self.goal_flag = IS_CHAMPION_FLAG + self.local_defeated_legendaries = {} + self.goal_flag = None + self.wonder_trade_update_event = asyncio.Event() + self.wonder_trade_cooldown = 5000 + self.wonder_trade_cooldown_timer = 0 + self.death_counter = None + self.previous_death_link = 0 + self.ignore_next_death_link = False async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: from CommonClient import logger @@ -123,88 +167,103 @@ class PokemonEmeraldClient(BizHawkClient): ctx.want_slot_data = True ctx.watcher_timeout = 0.125 + self.death_counter = None + self.previous_death_link = 0 + self.ignore_next_death_link = False + return True async def set_auth(self, ctx: "BizHawkClientContext") -> None: - slot_name_bytes = (await bizhawk.read(ctx.bizhawk_ctx, [(data.rom_addresses["gArchipelagoInfo"], 64, "ROM")]))[0] - ctx.auth = bytes([byte for byte in slot_name_bytes if byte != 0]).decode("utf-8") + import base64 + auth_raw = (await bizhawk.read(ctx.bizhawk_ctx, [(data.rom_addresses["gArchipelagoInfo"], 16, "ROM")]))[0] + ctx.auth = base64.b64encode(auth_raw).decode("utf-8") async def game_watcher(self, ctx: "BizHawkClientContext") -> None: - if ctx.slot_data is not None: - if ctx.slot_data["goal"] == Goal.option_champion: - self.goal_flag = IS_CHAMPION_FLAG - elif ctx.slot_data["goal"] == Goal.option_steven: - self.goal_flag = DEFEATED_STEVEN_FLAG - elif ctx.slot_data["goal"] == Goal.option_norman: - self.goal_flag = DEFEATED_NORMAN_FLAG + if ctx.server is None or ctx.server.socket.closed or ctx.slot_data is None: + return + + if ctx.slot_data["goal"] == Goal.option_champion: + self.goal_flag = DEFEATED_WALLACE_FLAG + elif ctx.slot_data["goal"] == Goal.option_steven: + self.goal_flag = DEFEATED_STEVEN_FLAG + elif ctx.slot_data["goal"] == Goal.option_norman: + self.goal_flag = DEFEATED_NORMAN_FLAG + elif ctx.slot_data["goal"] == Goal.option_legendary_hunt: + self.goal_flag = None + + if ctx.slot_data["remote_items"] == RemoteItems.option_true and not ctx.items_handling & 0b010: + ctx.items_handling = 0b011 + Utils.async_start(ctx.send_msgs([{ + "cmd": "ConnectUpdate", + "items_handling": ctx.items_handling + }])) try: + guards: Dict[str, Tuple[int, bytes, str]] = {} + # Checks that the player is in the overworld - overworld_guard = (data.ram_addresses["gMain"] + 4, (data.ram_addresses["CB2_Overworld"] + 1).to_bytes(4, "little"), "System Bus") - - # Read save block address - read_result = await bizhawk.guarded_read( - ctx.bizhawk_ctx, - [(data.ram_addresses["gSaveBlock1Ptr"], 4, "System Bus")], - [overworld_guard] + guards["IN OVERWORLD"] = ( + data.ram_addresses["gMain"] + 4, + (data.ram_addresses["CB2_Overworld"] + 1).to_bytes(4, "little"), + "System Bus" ) - if read_result is None: # Not in overworld - return - # Checks that the save block hasn't moved - save_block_address_guard = (data.ram_addresses["gSaveBlock1Ptr"], read_result[0], "System Bus") - - save_block_address = int.from_bytes(read_result[0], "little") - - # Handle giving the player items - read_result = await bizhawk.guarded_read( + # Read save block addresses + read_result = await bizhawk.read( ctx.bizhawk_ctx, [ - (save_block_address + 0x3778, 2, "System Bus"), # Number of received items - (data.ram_addresses["gArchipelagoReceivedItem"] + 4, 1, "System Bus") # Received item struct full? - ], - [overworld_guard, save_block_address_guard] + (data.ram_addresses["gSaveBlock1Ptr"], 4, "System Bus"), + (data.ram_addresses["gSaveBlock2Ptr"], 4, "System Bus"), + ] ) - if read_result is None: # Not in overworld, or save block moved - return - num_received_items = int.from_bytes(read_result[0], "little") - received_item_is_empty = read_result[1][0] == 0 + # Checks that the save data hasn't moved + guards["SAVE BLOCK 1"] = (data.ram_addresses["gSaveBlock1Ptr"], read_result[0], "System Bus") + guards["SAVE BLOCK 2"] = (data.ram_addresses["gSaveBlock2Ptr"], read_result[1], "System Bus") - # If the game hasn't received all items yet and the received item struct doesn't contain an item, then - # fill it with the next item - if num_received_items < len(ctx.items_received) and received_item_is_empty: - next_item = ctx.items_received[num_received_items] - await bizhawk.write(ctx.bizhawk_ctx, [ - (data.ram_addresses["gArchipelagoReceivedItem"] + 0, (next_item.item - BASE_OFFSET).to_bytes(2, "little"), "System Bus"), - (data.ram_addresses["gArchipelagoReceivedItem"] + 2, (num_received_items + 1).to_bytes(2, "little"), "System Bus"), - (data.ram_addresses["gArchipelagoReceivedItem"] + 4, [1], "System Bus"), # Mark struct full - (data.ram_addresses["gArchipelagoReceivedItem"] + 5, [next_item.flags & 1], "System Bus"), - ]) + sb1_address = int.from_bytes(guards["SAVE BLOCK 1"][1], "little") + sb2_address = int.from_bytes(guards["SAVE BLOCK 2"][1], "little") + + await self.handle_death_link(ctx, guards) + await self.handle_received_items(ctx, guards) + await self.handle_wonder_trade(ctx, guards) # Read flags in 2 chunks read_result = await bizhawk.guarded_read( ctx.bizhawk_ctx, - [(save_block_address + 0x1450, 0x96, "System Bus")], # Flags - [overworld_guard, save_block_address_guard] + [(sb1_address + 0x1450, 0x96, "System Bus")], # Flags + [guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]] ) if read_result is None: # Not in overworld, or save block moved return - flag_bytes = read_result[0] read_result = await bizhawk.guarded_read( ctx.bizhawk_ctx, - [(save_block_address + 0x14E6, 0x96, "System Bus")], # Flags - [overworld_guard, save_block_address_guard] + [(sb1_address + 0x14E6, 0x96, "System Bus")], # Flags continued + [guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]] ) if read_result is not None: flag_bytes += read_result[0] + # Read pokedex flags + pokedex_caught_bytes = bytes(0) + if ctx.slot_data["dexsanity"] == Toggle.option_true: + # Read pokedex flags + read_result = await bizhawk.guarded_read( + ctx.bizhawk_ctx, + [(sb2_address + 0x28, 0x34, "System Bus")], + [guards["IN OVERWORLD"], guards["SAVE BLOCK 2"]] + ) + if read_result is not None: + pokedex_caught_bytes = read_result[0] + game_clear = False local_checked_locations = 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()} + caught_legendaries = {legendary_name: False for legendary_name in LEGENDARY_NAMES.values()} # Check set flags for byte_i, byte in enumerate(flag_bytes): @@ -219,12 +278,45 @@ class PokemonEmeraldClient(BizHawkClient): if flag_id == self.goal_flag: game_clear = True + if flag_id in DEFEATED_LEGENDARY_FLAG_MAP: + defeated_legendaries[DEFEATED_LEGENDARY_FLAG_MAP[flag_id]] = True + + if flag_id in CAUGHT_LEGENDARY_FLAG_MAP: + caught_legendaries[CAUGHT_LEGENDARY_FLAG_MAP[flag_id]] = True + if flag_id in EVENT_FLAG_MAP: local_set_events[EVENT_FLAG_MAP[flag_id]] = True if flag_id in KEY_LOCATION_FLAG_MAP: local_found_key_items[KEY_LOCATION_FLAG_MAP[flag_id]] = True + # Check pokedex + if ctx.slot_data["dexsanity"] == Toggle.option_true: + for byte_i, byte in enumerate(pokedex_caught_bytes): + for i in range(8): + if byte & (1 << i) != 0: + dex_number = (byte_i * 8 + i) + 1 + + location_id = dex_number + BASE_OFFSET + POKEDEX_OFFSET + if location_id in ctx.server_locations: + local_checked_locations.add(location_id) + + # Count legendary hunt flags + if ctx.slot_data["goal"] == Goal.option_legendary_hunt: + # If legendary hunt doesn't require catching, add defeated legendaries to caught_legendaries + if ctx.slot_data["legendary_hunt_catch"] == Toggle.option_false: + for legendary, is_defeated in defeated_legendaries.items(): + if is_defeated: + caught_legendaries[legendary] = True + + num_caught = 0 + for legendary, is_caught in caught_legendaries.items(): + if is_caught and legendary in [LEGENDARY_NAMES[name] for name in ctx.slot_data["allowed_legendary_hunt_encounters"]]: + num_caught += 1 + + if num_caught >= ctx.slot_data["legendary_hunt_count"]: + game_clear = True + # Send locations if local_checked_locations != self.local_checked_locations: self.local_checked_locations = local_checked_locations @@ -232,14 +324,14 @@ class PokemonEmeraldClient(BizHawkClient): if local_checked_locations is not None: await ctx.send_msgs([{ "cmd": "LocationChecks", - "locations": list(local_checked_locations) + "locations": list(local_checked_locations), }]) # Send game clear if not ctx.finished_game and game_clear: await ctx.send_msgs([{ "cmd": "StatusUpdate", - "status": ClientStatus.CLIENT_GOAL + "status": ClientStatus.CLIENT_GOAL, }]) # Send tracker event flags @@ -254,7 +346,7 @@ class PokemonEmeraldClient(BizHawkClient): "key": f"pokemon_emerald_events_{ctx.team}_{ctx.slot}", "default": 0, "want_reply": False, - "operations": [{"operation": "or", "value": event_bitfield}] + "operations": [{"operation": "or", "value": event_bitfield}], }]) self.local_set_events = local_set_events @@ -269,9 +361,313 @@ class PokemonEmeraldClient(BizHawkClient): "key": f"pokemon_emerald_keys_{ctx.team}_{ctx.slot}", "default": 0, "want_reply": False, - "operations": [{"operation": "or", "value": key_bitfield}] + "operations": [{"operation": "or", "value": key_bitfield}], }]) self.local_found_key_items = local_found_key_items + + if ctx.slot_data["goal"] == Goal.option_legendary_hunt: + if caught_legendaries != self.local_defeated_legendaries and ctx.slot is not None: + legendary_bitfield = 0 + for i, legendary_name in enumerate(LEGENDARY_NAMES.values()): + if caught_legendaries[legendary_name]: + legendary_bitfield |= 1 << i + + await ctx.send_msgs([{ + "cmd": "Set", + "key": f"pokemon_emerald_legendaries_{ctx.team}_{ctx.slot}", + "default": 0, + "want_reply": False, + "operations": [{"operation": "or", "value": legendary_bitfield}], + }]) + self.local_defeated_legendaries = caught_legendaries except bizhawk.RequestFailedError: # Exit handler and return to main loop to reconnect pass + + async def handle_death_link(self, ctx: "BizHawkClientContext", guards: Dict[str, Tuple[int, bytes, str]]) -> None: + """ + Checks whether the player has died while connected and sends a death link if so. Queues a death link in the game + if a new one has been received. + """ + if ctx.slot_data.get("death_link", Toggle.option_false) == Toggle.option_true: + if "DeathLink" not in ctx.tags: + await ctx.update_death_link(True) + self.previous_death_link = ctx.last_death_link + + sb1_address = int.from_bytes(guards["SAVE BLOCK 1"][1], "little") + sb2_address = int.from_bytes(guards["SAVE BLOCK 2"][1], "little") + + read_result = await bizhawk.guarded_read( + ctx.bizhawk_ctx, [ + (sb1_address + 0x177C + (52 * 4), 4, "System Bus"), # White out stat + (sb1_address + 0x177C + (22 * 4), 4, "System Bus"), # Canary stat + (sb2_address + 0xAC, 4, "System Bus"), # Encryption key + ], + [guards["SAVE BLOCK 1"], guards["SAVE BLOCK 2"]] + ) + if read_result is None: # Save block moved + return + + encryption_key = int.from_bytes(read_result[2], "little") + times_whited_out = int.from_bytes(read_result[0], "little") ^ encryption_key + + # Canary is an unused stat that will always be 0. There is a low chance that we've done this read on + # a frame where the user has just entered a battle and the encryption key has been changed, but the data + # has not yet been encrypted with the new key. If `canary` is 0, `times_whited_out` is correct. + canary = int.from_bytes(read_result[1], "little") ^ encryption_key + + # Skip all deathlink code if save is not yet loaded (encryption key is zero) or white out stat not yet + # initialized (starts at 100 as a safety for subtracting values from an unsigned int). + if canary == 0 and encryption_key != 0 and times_whited_out >= 100: + if self.previous_death_link != ctx.last_death_link: + self.previous_death_link = ctx.last_death_link + if self.ignore_next_death_link: + self.ignore_next_death_link = False + else: + await bizhawk.write( + ctx.bizhawk_ctx, + [(data.ram_addresses["gArchipelagoDeathLinkQueued"], [1], "System Bus")] + ) + + if self.death_counter is None: + self.death_counter = times_whited_out + elif times_whited_out > self.death_counter: + await ctx.send_death(f"{ctx.player_names[ctx.slot]} is out of usable POKéMON! " + f"{ctx.player_names[ctx.slot]} whited out!") + self.ignore_next_death_link = True + self.death_counter = times_whited_out + + async def handle_received_items(self, ctx: "BizHawkClientContext", guards: Dict[str, Tuple[int, bytes, str]]) -> None: + """ + Checks the index of the most recently received item and whether the item queue is full. Writes the next item + into the game if necessary. + """ + received_item_address = data.ram_addresses["gArchipelagoReceivedItem"] + + sb1_address = int.from_bytes(guards["SAVE BLOCK 1"][1], "little") + + read_result = await bizhawk.guarded_read( + ctx.bizhawk_ctx, + [ + (sb1_address + 0x3778, 2, "System Bus"), # Number of received items + (received_item_address + 4, 1, "System Bus") # Received item struct full? + ], + [guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]] + ) + if read_result is None: # Not in overworld, or save block moved + return + + num_received_items = int.from_bytes(read_result[0], "little") + received_item_is_empty = read_result[1][0] == 0 + + # If the game hasn't received all items yet and the received item struct doesn't contain an item, then + # fill it with the next item + if num_received_items < len(ctx.items_received) and received_item_is_empty: + next_item = ctx.items_received[num_received_items] + should_display = 1 if next_item.flags & 1 or next_item.player == ctx.slot else 0 + await bizhawk.write(ctx.bizhawk_ctx, [ + (received_item_address + 0, (next_item.item - BASE_OFFSET).to_bytes(2, "little"), "System Bus"), + (received_item_address + 2, (num_received_items + 1).to_bytes(2, "little"), "System Bus"), + (received_item_address + 4, [1], "System Bus"), + (received_item_address + 5, [should_display], "System Bus"), + ]) + + async def handle_wonder_trade(self, ctx: "BizHawkClientContext", guards: Dict[str, Tuple[int, bytes, str]]) -> None: + """ + Read wonder trade status from save data and either send a queued pokemon to data storage or attempt to retrieve + one from data storage and write it into the save. + """ + from CommonClient import logger + + sb1_address = int.from_bytes(guards["SAVE BLOCK 1"][1], "little") + + read_result = await bizhawk.guarded_read( + ctx.bizhawk_ctx, + [ + (sb1_address + 0x377C, 0x50, "System Bus"), # Wonder trade data + (sb1_address + 0x37CC, 1, "System Bus"), # Is wonder trade sent + ], + [guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]] + ) + + if read_result is not None: + wonder_trade_pokemon_data = read_result[0] + trade_is_sent = read_result[1][0] + + if trade_is_sent == 0 and wonder_trade_pokemon_data[19] == 2: + # Game has wonder trade data to send. Send it to data storage, remove it from the game's memory, + # and mark that the game is waiting on receiving a trade + Utils.async_start(self.wonder_trade_send(ctx, pokemon_data_to_json(wonder_trade_pokemon_data))) + await bizhawk.write(ctx.bizhawk_ctx, [ + (sb1_address + 0x377C, bytes(0x50), "System Bus"), + (sb1_address + 0x37CC, [1], "System Bus"), + ]) + elif trade_is_sent != 0 and wonder_trade_pokemon_data[19] != 2: + # Game is waiting on receiving a trade. See if there are any available trades that were not + # sent by this player, and if so, try to receive one. + if self.wonder_trade_cooldown_timer <= 0 and f"pokemon_wonder_trades_{ctx.team}" in ctx.stored_data: + if any(item[0] != ctx.slot + for key, item in ctx.stored_data.get(f"pokemon_wonder_trades_{ctx.team}", {}).items() + if key != "_lock" and orjson.loads(item[1])["species"] <= 386): + received_trade = await self.wonder_trade_receive(ctx) + if received_trade is None: + self.wonder_trade_cooldown_timer = self.wonder_trade_cooldown + self.wonder_trade_cooldown *= 2 + self.wonder_trade_cooldown += random.randrange(0, 500) + else: + await bizhawk.write(ctx.bizhawk_ctx, [ + (sb1_address + 0x377C, json_to_pokemon_data(received_trade), "System Bus"), + ]) + logger.info("Wonder trade received!") + self.wonder_trade_cooldown = 5000 + + else: + # Very approximate "time since last loop", but extra delay is fine for this + self.wonder_trade_cooldown_timer -= int(ctx.watcher_timeout * 1000) + + async def wonder_trade_acquire(self, ctx: "BizHawkClientContext", keep_trying: bool = False) -> Optional[dict]: + """ + Acquires a lock on the `pokemon_wonder_trades_{ctx.team}` key in + datastorage. Locking the key means you have exclusive access + to modifying the value until you unlock it or the key expires (5 + seconds). + + If `keep_trying` is `True`, it will keep trying to acquire the lock + until successful. Otherwise it will return `None` if it fails to + acquire the lock. + """ + while not ctx.exit_event.is_set(): + lock = int(time.time_ns() / 1000000) + message_uuid = str(uuid.uuid4()) + await ctx.send_msgs([{ + "cmd": "Set", + "key": f"pokemon_wonder_trades_{ctx.team}", + "default": {"_lock": 0}, + "want_reply": True, + "operations": [{"operation": "update", "value": {"_lock": lock}}], + "uuid": message_uuid, + }]) + + self.wonder_trade_update_event.clear() + try: + await asyncio.wait_for(self.wonder_trade_update_event.wait(), 5) + except asyncio.TimeoutError: + if not keep_trying: + return None + continue + + reply = copy.deepcopy(self.latest_wonder_trade_reply) + + # Make sure the most recently received update was triggered by our lock attempt + if reply.get("uuid", None) != message_uuid: + if not keep_trying: + return None + await asyncio.sleep(self.wonder_trade_cooldown) + continue + + # Make sure the current value of the lock is what we set it to + # (I think this should theoretically never run) + if reply["value"]["_lock"] != lock: + if not keep_trying: + return None + await asyncio.sleep(self.wonder_trade_cooldown) + continue + + # Make sure that the lock value we replaced is at least 5 seconds old + # If it was unlocked before our change, its value was 0 and it will look decades old + if lock - reply["original_value"]["_lock"] < 5000: + # Multiple clients trying to lock the key may get stuck in a loop of checking the lock + # by trying to set it, which will extend its expiration. So if we see that the lock was + # too new when we replaced it, we should wait for increasingly longer periods so that + # eventually the lock will expire and a client will acquire it. + self.wonder_trade_cooldown *= 2 + self.wonder_trade_cooldown += random.randrange(0, 500) + + if not keep_trying: + self.wonder_trade_cooldown_timer = self.wonder_trade_cooldown + return None + await asyncio.sleep(self.wonder_trade_cooldown) + continue + + # We have the lock, reset the cooldown and return + self.wonder_trade_cooldown = 5000 + return reply + + async def wonder_trade_send(self, ctx: "BizHawkClientContext", data: str) -> None: + """ + Sends a wonder trade pokemon to data storage + """ + from CommonClient import logger + + reply = await self.wonder_trade_acquire(ctx, True) + + wonder_trade_slot = 0 + while str(wonder_trade_slot) in reply["value"]: + wonder_trade_slot += 1 + + await ctx.send_msgs([{ + "cmd": "Set", + "key": f"pokemon_wonder_trades_{ctx.team}", + "default": {"_lock": 0}, + "operations": [{"operation": "update", "value": { + "_lock": 0, + str(wonder_trade_slot): (ctx.slot, data), + }}], + }]) + + logger.info("Wonder trade sent! We'll notify you here when a trade has been found.") + + async def wonder_trade_receive(self, ctx: "BizHawkClientContext") -> Optional[str]: + """ + Tries to pop a pokemon out of the wonder trades. Returns `None` if + for some reason it can't immediately remove a compatible pokemon. + """ + reply = await self.wonder_trade_acquire(ctx) + + if reply is None: + return None + + candidate_slots = [ + int(slot) + for slot in reply["value"] + if slot != "_lock" \ + and reply["value"][slot][0] != ctx.slot \ + and orjson.loads(reply["value"][slot][1])["species"] <= 386 + ] + + if len(candidate_slots) == 0: + await ctx.send_msgs([{ + "cmd": "Set", + "key": f"pokemon_wonder_trades_{ctx.team}", + "default": {"_lock": 0}, + "operations": [{"operation": "update", "value": {"_lock": 0}}], + }]) + return None + + wonder_trade_slot = max(candidate_slots) + + await ctx.send_msgs([{ + "cmd": "Set", + "key": f"pokemon_wonder_trades_{ctx.team}", + "default": {"_lock": 0}, + "operations": [ + {"operation": "update", "value": {"_lock": 0}}, + {"operation": "pop", "value": str(wonder_trade_slot)}, + ] + }]) + + return reply["value"][str(wonder_trade_slot)][1] + + def on_package(self, ctx: "BizHawkClientContext", cmd: str, args: dict) -> None: + if cmd == "Connected": + Utils.async_start(ctx.send_msgs([{ + "cmd": "SetNotify", + "keys": [f"pokemon_wonder_trades_{ctx.team}"], + }, { + "cmd": "Get", + "keys": [f"pokemon_wonder_trades_{ctx.team}"], + }])) + elif cmd == "SetReply": + if args.get("key", "") == f"pokemon_wonder_trades_{ctx.team}": + self.latest_wonder_trade_reply = args + self.wonder_trade_update_event.set() diff --git a/worlds/pokemon_emerald/data.py b/worlds/pokemon_emerald/data.py index bc51d84963..c4f7d7711c 100644 --- a/worlds/pokemon_emerald/data.py +++ b/worlds/pokemon_emerald/data.py @@ -5,7 +5,6 @@ defined data (like location labels or usable pokemon species), some cleanup and sorting, and Warp methods. """ from dataclasses import dataclass -import copy from enum import IntEnum import orjson from typing import Dict, List, NamedTuple, Optional, Set, FrozenSet, Tuple, Any, Union @@ -16,6 +15,25 @@ from BaseClasses import ItemClassification BASE_OFFSET = 3860000 +POKEDEX_OFFSET = 10000 + +IGNORABLE_MAPS = { + "MAP_ALTERING_CAVE", + "MAP_CAVE_OF_ORIGIN_UNUSED_RUBY_SAPPHIRE_MAP1", + "MAP_CAVE_OF_ORIGIN_UNUSED_RUBY_SAPPHIRE_MAP2", + "MAP_CAVE_OF_ORIGIN_UNUSED_RUBY_SAPPHIRE_MAP3", +} +"""These maps exist but don't show up in the rando or are unused, and so should be discarded""" + +POSTGAME_MAPS = { + "MAP_DESERT_UNDERPASS", + "MAP_SAFARI_ZONE_NORTHEAST", + "MAP_SAFARI_ZONE_SOUTHEAST", + "MAP_METEOR_FALLS_STEVENS_CAVE", +} +"""These maps have encounters and are locked behind beating the champion. Those encounter slots should be ignored for logical access to a species.""" + +NUM_REAL_SPECIES = 386 class Warp: @@ -55,14 +73,14 @@ class Warp: return f"{self.source_map}:{source_ids_string}/{self.dest_map}:{dest_ids_string}{'!' if self.is_one_way else ''}" - def connects_to(self, other: 'Warp') -> bool: + def connects_to(self, other: "Warp") -> bool: """ Returns true if this warp sends the player to `other` """ return self.dest_map == other.source_map and set(self.dest_ids) <= set(other.source_ids) @staticmethod - def decode(encoded_string: str) -> 'Warp': + def decode(encoded_string: str) -> "Warp": """ Create a Warp object from an encoded string """ @@ -87,6 +105,7 @@ class Warp: class ItemData(NamedTuple): label: str item_id: int + modern_id: Optional[int] classification: ItemClassification tags: FrozenSet[str] @@ -96,11 +115,25 @@ class LocationData(NamedTuple): label: str parent_region: str default_item: int - rom_address: int + address: Union[int, List[int]] flag: int tags: FrozenSet[str] +class EncounterTableData(NamedTuple): + slots: List[int] + address: int + + +@dataclass +class MapData: + name: str + header_address: int + land_encounters: Optional[EncounterTableData] + water_encounters: Optional[EncounterTableData] + fishing_encounters: Optional[EncounterTableData] + + class EventData(NamedTuple): name: str parent_region: str @@ -108,13 +141,21 @@ class EventData(NamedTuple): class RegionData: name: str + parent_map: MapData + has_grass: bool + has_water: bool + has_fishing: bool exits: List[str] warps: List[str] locations: List[str] events: List[EventData] - def __init__(self, name: str): + def __init__(self, name: str, parent_map: MapData, has_grass: bool, has_water: bool, has_fishing: bool): self.name = name + self.parent_map = parent_map + self.has_grass = has_grass + self.has_water = has_water + self.has_fishing = has_fishing self.exits = [] self.warps = [] self.locations = [] @@ -181,9 +222,9 @@ class EvolutionData(NamedTuple): species_id: int -class StaticEncounterData(NamedTuple): +class MiscPokemonData(NamedTuple): species_id: int - rom_address: int + address: int @dataclass @@ -191,16 +232,18 @@ class SpeciesData: name: str label: str species_id: int + national_dex_number: int base_stats: BaseStats types: Tuple[int, int] abilities: Tuple[int, int] evolutions: List[EvolutionData] pre_evolution: Optional[int] catch_rate: int + friendship: int learnset: List[LearnsetMove] tm_hm_compatibility: int - learnset_rom_address: int - rom_address: int + learnset_address: int + address: int class AbilityData(NamedTuple): @@ -208,19 +251,6 @@ class AbilityData(NamedTuple): label: str -class EncounterTableData(NamedTuple): - slots: List[int] - rom_address: int - - -@dataclass -class MapData: - name: str - land_encounters: Optional[EncounterTableData] - water_encounters: Optional[EncounterTableData] - fishing_encounters: Optional[EncounterTableData] - - class TrainerPokemonDataTypeEnum(IntEnum): NO_ITEM_DEFAULT_MOVES = 0 ITEM_DEFAULT_MOVES = 1 @@ -250,15 +280,15 @@ class TrainerPokemonData: class TrainerPartyData: pokemon: List[TrainerPokemonData] pokemon_data_type: TrainerPokemonDataTypeEnum - rom_address: int + address: int @dataclass class TrainerData: trainer_id: int party: TrainerPartyData - rom_address: int - battle_script_rom_address: int + address: int + script_address: int class PokemonEmeraldData: @@ -269,11 +299,13 @@ class PokemonEmeraldData: regions: Dict[str, RegionData] locations: Dict[str, LocationData] items: Dict[int, ItemData] - species: List[Optional[SpeciesData]] - static_encounters: List[StaticEncounterData] + species: Dict[int, SpeciesData] + legendary_encounters: List[MiscPokemonData] + misc_pokemon: List[MiscPokemonData] tmhm_moves: List[int] abilities: List[AbilityData] - maps: List[MapData] + move_labels: Dict[str, int] + maps: Dict[str, MapData] warps: Dict[str, Warp] warp_map: Dict[str, Optional[str]] trainers: List[TrainerData] @@ -286,29 +318,20 @@ class PokemonEmeraldData: self.regions = {} self.locations = {} self.items = {} - self.species = [] - self.static_encounters = [] + self.species = {} + self.legendary_encounters = [] + self.misc_pokemon = [] self.tmhm_moves = [] self.abilities = [] - self.maps = [] + self.move_labels = {} + self.maps = {} self.warps = {} self.warp_map = {} self.trainers = [] def load_json_data(data_name: str) -> Union[List[Any], Dict[str, Any]]: - return orjson.loads(pkgutil.get_data(__name__, "data/" + data_name).decode('utf-8-sig')) - - -data = PokemonEmeraldData() - -def create_data_copy() -> PokemonEmeraldData: - new_copy = PokemonEmeraldData() - new_copy.species = copy.deepcopy(data.species) - new_copy.tmhm_moves = copy.deepcopy(data.tmhm_moves) - new_copy.maps = copy.deepcopy(data.maps) - new_copy.static_encounters = copy.deepcopy(data.static_encounters) - new_copy.trainers = copy.deepcopy(data.trainers) + return orjson.loads(pkgutil.get_data(__name__, "data/" + data_name).decode("utf-8-sig")) def _init() -> None: @@ -319,6 +342,39 @@ def _init() -> None: location_attributes_json = load_json_data("locations.json") + # Create map data + for map_name, map_json in extracted_data["maps"].items(): + if map_name in IGNORABLE_MAPS: + continue + + land_encounters = None + water_encounters = None + fishing_encounters = None + + if "land_encounters" in map_json: + land_encounters = EncounterTableData( + map_json["land_encounters"]["slots"], + map_json["land_encounters"]["address"] + ) + if "water_encounters" in map_json: + water_encounters = EncounterTableData( + map_json["water_encounters"]["slots"], + map_json["water_encounters"]["address"] + ) + if "fishing_encounters" in map_json: + fishing_encounters = EncounterTableData( + map_json["fishing_encounters"]["slots"], + map_json["fishing_encounters"]["address"] + ) + + data.maps[map_name] = MapData( + map_name, + map_json["header_address"], + land_encounters, + water_encounters, + fishing_encounters + ) + # Load/merge region json files region_json_list = [] for file in pkg_resources.resource_listdir(__name__, "data/regions"): @@ -338,7 +394,13 @@ def _init() -> None: data.regions = {} for region_name, region_json in regions_json.items(): - new_region = RegionData(region_name) + new_region = RegionData( + region_name, + data.maps[region_json["parent_map"]], + region_json["has_grass"], + region_json["has_water"], + region_json["has_fishing"] + ) # Locations for location_name in region_json["locations"]: @@ -346,15 +408,35 @@ def _init() -> None: raise AssertionError(f"Location [{location_name}] was claimed by multiple regions") location_json = extracted_data["locations"][location_name] - new_location = LocationData( - location_name, - location_attributes_json[location_name]["label"], - region_name, - location_json["default_item"], - location_json["rom_address"], - location_json["flag"], - frozenset(location_attributes_json[location_name]["tags"]) - ) + if location_name.startswith("TRAINER_BRENDAN_") or location_name.startswith("TRAINER_MAY_"): + import re + locale = re.match("TRAINER_BRENDAN_([A-Z0-9_]+)_MUDKIP_REWARD", location_name).group(1) + alternate_rival_jsons = [extracted_data["locations"][alternate] for alternate in [ + f"TRAINER_BRENDAN_{locale}_TORCHIC_REWARD", + f"TRAINER_BRENDAN_{locale}_TREECKO_REWARD", + f"TRAINER_MAY_{locale}_MUDKIP_REWARD", + f"TRAINER_MAY_{locale}_TORCHIC_REWARD", + f"TRAINER_MAY_{locale}_TREECKO_REWARD", + ]] + new_location = LocationData( + location_name, + location_attributes_json[location_name]["label"], + region_name, + location_json["default_item"], + [location_json["address"]] + [j["address"] for j in alternate_rival_jsons], + location_json["flag"], + frozenset(location_attributes_json[location_name]["tags"]) + ) + else: + new_location = LocationData( + location_name, + location_attributes_json[location_name]["label"], + region_name, + location_json["default_item"], + location_json["address"], + location_json["flag"], + frozenset(location_attributes_json[location_name]["tags"]) + ) new_region.locations.append(location_name) data.locations[location_name] = new_location claimed_locations.add(location_name) @@ -401,6 +483,7 @@ def _init() -> None: data.items[data.constants[item_constant_name]] = ItemData( attributes["label"], data.constants[item_constant_name], + attributes["modern_id"], item_classification, frozenset(attributes["tags"]) ) @@ -408,408 +491,408 @@ def _init() -> None: # Create species data # Excludes extras like copies of Unown and special species values like SPECIES_EGG. - all_species: List[Tuple[str, str]] = [ - ("SPECIES_BULBASAUR", "Bulbasaur"), - ("SPECIES_IVYSAUR", "Ivysaur"), - ("SPECIES_VENUSAUR", "Venusaur"), - ("SPECIES_CHARMANDER", "Charmander"), - ("SPECIES_CHARMELEON", "Charmeleon"), - ("SPECIES_CHARIZARD", "Charizard"), - ("SPECIES_SQUIRTLE", "Squirtle"), - ("SPECIES_WARTORTLE", "Wartortle"), - ("SPECIES_BLASTOISE", "Blastoise"), - ("SPECIES_CATERPIE", "Caterpie"), - ("SPECIES_METAPOD", "Metapod"), - ("SPECIES_BUTTERFREE", "Butterfree"), - ("SPECIES_WEEDLE", "Weedle"), - ("SPECIES_KAKUNA", "Kakuna"), - ("SPECIES_BEEDRILL", "Beedrill"), - ("SPECIES_PIDGEY", "Pidgey"), - ("SPECIES_PIDGEOTTO", "Pidgeotto"), - ("SPECIES_PIDGEOT", "Pidgeot"), - ("SPECIES_RATTATA", "Rattata"), - ("SPECIES_RATICATE", "Raticate"), - ("SPECIES_SPEAROW", "Spearow"), - ("SPECIES_FEAROW", "Fearow"), - ("SPECIES_EKANS", "Ekans"), - ("SPECIES_ARBOK", "Arbok"), - ("SPECIES_PIKACHU", "Pikachu"), - ("SPECIES_RAICHU", "Raichu"), - ("SPECIES_SANDSHREW", "Sandshrew"), - ("SPECIES_SANDSLASH", "Sandslash"), - ("SPECIES_NIDORAN_F", "Nidoran Female"), - ("SPECIES_NIDORINA", "Nidorina"), - ("SPECIES_NIDOQUEEN", "Nidoqueen"), - ("SPECIES_NIDORAN_M", "Nidoran Male"), - ("SPECIES_NIDORINO", "Nidorino"), - ("SPECIES_NIDOKING", "Nidoking"), - ("SPECIES_CLEFAIRY", "Clefairy"), - ("SPECIES_CLEFABLE", "Clefable"), - ("SPECIES_VULPIX", "Vulpix"), - ("SPECIES_NINETALES", "Ninetales"), - ("SPECIES_JIGGLYPUFF", "Jigglypuff"), - ("SPECIES_WIGGLYTUFF", "Wigglytuff"), - ("SPECIES_ZUBAT", "Zubat"), - ("SPECIES_GOLBAT", "Golbat"), - ("SPECIES_ODDISH", "Oddish"), - ("SPECIES_GLOOM", "Gloom"), - ("SPECIES_VILEPLUME", "Vileplume"), - ("SPECIES_PARAS", "Paras"), - ("SPECIES_PARASECT", "Parasect"), - ("SPECIES_VENONAT", "Venonat"), - ("SPECIES_VENOMOTH", "Venomoth"), - ("SPECIES_DIGLETT", "Diglett"), - ("SPECIES_DUGTRIO", "Dugtrio"), - ("SPECIES_MEOWTH", "Meowth"), - ("SPECIES_PERSIAN", "Persian"), - ("SPECIES_PSYDUCK", "Psyduck"), - ("SPECIES_GOLDUCK", "Golduck"), - ("SPECIES_MANKEY", "Mankey"), - ("SPECIES_PRIMEAPE", "Primeape"), - ("SPECIES_GROWLITHE", "Growlithe"), - ("SPECIES_ARCANINE", "Arcanine"), - ("SPECIES_POLIWAG", "Poliwag"), - ("SPECIES_POLIWHIRL", "Poliwhirl"), - ("SPECIES_POLIWRATH", "Poliwrath"), - ("SPECIES_ABRA", "Abra"), - ("SPECIES_KADABRA", "Kadabra"), - ("SPECIES_ALAKAZAM", "Alakazam"), - ("SPECIES_MACHOP", "Machop"), - ("SPECIES_MACHOKE", "Machoke"), - ("SPECIES_MACHAMP", "Machamp"), - ("SPECIES_BELLSPROUT", "Bellsprout"), - ("SPECIES_WEEPINBELL", "Weepinbell"), - ("SPECIES_VICTREEBEL", "Victreebel"), - ("SPECIES_TENTACOOL", "Tentacool"), - ("SPECIES_TENTACRUEL", "Tentacruel"), - ("SPECIES_GEODUDE", "Geodude"), - ("SPECIES_GRAVELER", "Graveler"), - ("SPECIES_GOLEM", "Golem"), - ("SPECIES_PONYTA", "Ponyta"), - ("SPECIES_RAPIDASH", "Rapidash"), - ("SPECIES_SLOWPOKE", "Slowpoke"), - ("SPECIES_SLOWBRO", "Slowbro"), - ("SPECIES_MAGNEMITE", "Magnemite"), - ("SPECIES_MAGNETON", "Magneton"), - ("SPECIES_FARFETCHD", "Farfetch'd"), - ("SPECIES_DODUO", "Doduo"), - ("SPECIES_DODRIO", "Dodrio"), - ("SPECIES_SEEL", "Seel"), - ("SPECIES_DEWGONG", "Dewgong"), - ("SPECIES_GRIMER", "Grimer"), - ("SPECIES_MUK", "Muk"), - ("SPECIES_SHELLDER", "Shellder"), - ("SPECIES_CLOYSTER", "Cloyster"), - ("SPECIES_GASTLY", "Gastly"), - ("SPECIES_HAUNTER", "Haunter"), - ("SPECIES_GENGAR", "Gengar"), - ("SPECIES_ONIX", "Onix"), - ("SPECIES_DROWZEE", "Drowzee"), - ("SPECIES_HYPNO", "Hypno"), - ("SPECIES_KRABBY", "Krabby"), - ("SPECIES_KINGLER", "Kingler"), - ("SPECIES_VOLTORB", "Voltorb"), - ("SPECIES_ELECTRODE", "Electrode"), - ("SPECIES_EXEGGCUTE", "Exeggcute"), - ("SPECIES_EXEGGUTOR", "Exeggutor"), - ("SPECIES_CUBONE", "Cubone"), - ("SPECIES_MAROWAK", "Marowak"), - ("SPECIES_HITMONLEE", "Hitmonlee"), - ("SPECIES_HITMONCHAN", "Hitmonchan"), - ("SPECIES_LICKITUNG", "Lickitung"), - ("SPECIES_KOFFING", "Koffing"), - ("SPECIES_WEEZING", "Weezing"), - ("SPECIES_RHYHORN", "Rhyhorn"), - ("SPECIES_RHYDON", "Rhydon"), - ("SPECIES_CHANSEY", "Chansey"), - ("SPECIES_TANGELA", "Tangela"), - ("SPECIES_KANGASKHAN", "Kangaskhan"), - ("SPECIES_HORSEA", "Horsea"), - ("SPECIES_SEADRA", "Seadra"), - ("SPECIES_GOLDEEN", "Goldeen"), - ("SPECIES_SEAKING", "Seaking"), - ("SPECIES_STARYU", "Staryu"), - ("SPECIES_STARMIE", "Starmie"), - ("SPECIES_MR_MIME", "Mr. Mime"), - ("SPECIES_SCYTHER", "Scyther"), - ("SPECIES_JYNX", "Jynx"), - ("SPECIES_ELECTABUZZ", "Electabuzz"), - ("SPECIES_MAGMAR", "Magmar"), - ("SPECIES_PINSIR", "Pinsir"), - ("SPECIES_TAUROS", "Tauros"), - ("SPECIES_MAGIKARP", "Magikarp"), - ("SPECIES_GYARADOS", "Gyarados"), - ("SPECIES_LAPRAS", "Lapras"), - ("SPECIES_DITTO", "Ditto"), - ("SPECIES_EEVEE", "Eevee"), - ("SPECIES_VAPOREON", "Vaporeon"), - ("SPECIES_JOLTEON", "Jolteon"), - ("SPECIES_FLAREON", "Flareon"), - ("SPECIES_PORYGON", "Porygon"), - ("SPECIES_OMANYTE", "Omanyte"), - ("SPECIES_OMASTAR", "Omastar"), - ("SPECIES_KABUTO", "Kabuto"), - ("SPECIES_KABUTOPS", "Kabutops"), - ("SPECIES_AERODACTYL", "Aerodactyl"), - ("SPECIES_SNORLAX", "Snorlax"), - ("SPECIES_ARTICUNO", "Articuno"), - ("SPECIES_ZAPDOS", "Zapdos"), - ("SPECIES_MOLTRES", "Moltres"), - ("SPECIES_DRATINI", "Dratini"), - ("SPECIES_DRAGONAIR", "Dragonair"), - ("SPECIES_DRAGONITE", "Dragonite"), - ("SPECIES_MEWTWO", "Mewtwo"), - ("SPECIES_MEW", "Mew"), - ("SPECIES_CHIKORITA", "Chikorita"), - ("SPECIES_BAYLEEF", "Bayleaf"), - ("SPECIES_MEGANIUM", "Meganium"), - ("SPECIES_CYNDAQUIL", "Cindaquil"), - ("SPECIES_QUILAVA", "Quilava"), - ("SPECIES_TYPHLOSION", "Typhlosion"), - ("SPECIES_TOTODILE", "Totodile"), - ("SPECIES_CROCONAW", "Croconaw"), - ("SPECIES_FERALIGATR", "Feraligatr"), - ("SPECIES_SENTRET", "Sentret"), - ("SPECIES_FURRET", "Furret"), - ("SPECIES_HOOTHOOT", "Hoothoot"), - ("SPECIES_NOCTOWL", "Noctowl"), - ("SPECIES_LEDYBA", "Ledyba"), - ("SPECIES_LEDIAN", "Ledian"), - ("SPECIES_SPINARAK", "Spinarak"), - ("SPECIES_ARIADOS", "Ariados"), - ("SPECIES_CROBAT", "Crobat"), - ("SPECIES_CHINCHOU", "Chinchou"), - ("SPECIES_LANTURN", "Lanturn"), - ("SPECIES_PICHU", "Pichu"), - ("SPECIES_CLEFFA", "Cleffa"), - ("SPECIES_IGGLYBUFF", "Igglybuff"), - ("SPECIES_TOGEPI", "Togepi"), - ("SPECIES_TOGETIC", "Togetic"), - ("SPECIES_NATU", "Natu"), - ("SPECIES_XATU", "Xatu"), - ("SPECIES_MAREEP", "Mareep"), - ("SPECIES_FLAAFFY", "Flaafy"), - ("SPECIES_AMPHAROS", "Ampharos"), - ("SPECIES_BELLOSSOM", "Bellossom"), - ("SPECIES_MARILL", "Marill"), - ("SPECIES_AZUMARILL", "Azumarill"), - ("SPECIES_SUDOWOODO", "Sudowoodo"), - ("SPECIES_POLITOED", "Politoed"), - ("SPECIES_HOPPIP", "Hoppip"), - ("SPECIES_SKIPLOOM", "Skiploom"), - ("SPECIES_JUMPLUFF", "Jumpluff"), - ("SPECIES_AIPOM", "Aipom"), - ("SPECIES_SUNKERN", "Sunkern"), - ("SPECIES_SUNFLORA", "Sunflora"), - ("SPECIES_YANMA", "Yanma"), - ("SPECIES_WOOPER", "Wooper"), - ("SPECIES_QUAGSIRE", "Quagsire"), - ("SPECIES_ESPEON", "Espeon"), - ("SPECIES_UMBREON", "Umbreon"), - ("SPECIES_MURKROW", "Murkrow"), - ("SPECIES_SLOWKING", "Slowking"), - ("SPECIES_MISDREAVUS", "Misdreavus"), - ("SPECIES_UNOWN", "Unown"), - ("SPECIES_WOBBUFFET", "Wobbuffet"), - ("SPECIES_GIRAFARIG", "Girafarig"), - ("SPECIES_PINECO", "Pineco"), - ("SPECIES_FORRETRESS", "Forretress"), - ("SPECIES_DUNSPARCE", "Dunsparce"), - ("SPECIES_GLIGAR", "Gligar"), - ("SPECIES_STEELIX", "Steelix"), - ("SPECIES_SNUBBULL", "Snubbull"), - ("SPECIES_GRANBULL", "Granbull"), - ("SPECIES_QWILFISH", "Qwilfish"), - ("SPECIES_SCIZOR", "Scizor"), - ("SPECIES_SHUCKLE", "Shuckle"), - ("SPECIES_HERACROSS", "Heracross"), - ("SPECIES_SNEASEL", "Sneasel"), - ("SPECIES_TEDDIURSA", "Teddiursa"), - ("SPECIES_URSARING", "Ursaring"), - ("SPECIES_SLUGMA", "Slugma"), - ("SPECIES_MAGCARGO", "Magcargo"), - ("SPECIES_SWINUB", "Swinub"), - ("SPECIES_PILOSWINE", "Piloswine"), - ("SPECIES_CORSOLA", "Corsola"), - ("SPECIES_REMORAID", "Remoraid"), - ("SPECIES_OCTILLERY", "Octillery"), - ("SPECIES_DELIBIRD", "Delibird"), - ("SPECIES_MANTINE", "Mantine"), - ("SPECIES_SKARMORY", "Skarmory"), - ("SPECIES_HOUNDOUR", "Houndour"), - ("SPECIES_HOUNDOOM", "Houndoom"), - ("SPECIES_KINGDRA", "Kingdra"), - ("SPECIES_PHANPY", "Phanpy"), - ("SPECIES_DONPHAN", "Donphan"), - ("SPECIES_PORYGON2", "Porygon2"), - ("SPECIES_STANTLER", "Stantler"), - ("SPECIES_SMEARGLE", "Smeargle"), - ("SPECIES_TYROGUE", "Tyrogue"), - ("SPECIES_HITMONTOP", "Hitmontop"), - ("SPECIES_SMOOCHUM", "Smoochum"), - ("SPECIES_ELEKID", "Elekid"), - ("SPECIES_MAGBY", "Magby"), - ("SPECIES_MILTANK", "Miltank"), - ("SPECIES_BLISSEY", "Blissey"), - ("SPECIES_RAIKOU", "Raikou"), - ("SPECIES_ENTEI", "Entei"), - ("SPECIES_SUICUNE", "Suicune"), - ("SPECIES_LARVITAR", "Larvitar"), - ("SPECIES_PUPITAR", "Pupitar"), - ("SPECIES_TYRANITAR", "Tyranitar"), - ("SPECIES_LUGIA", "Lugia"), - ("SPECIES_HO_OH", "Ho-oh"), - ("SPECIES_CELEBI", "Celebi"), - ("SPECIES_TREECKO", "Treecko"), - ("SPECIES_GROVYLE", "Grovyle"), - ("SPECIES_SCEPTILE", "Sceptile"), - ("SPECIES_TORCHIC", "Torchic"), - ("SPECIES_COMBUSKEN", "Combusken"), - ("SPECIES_BLAZIKEN", "Blaziken"), - ("SPECIES_MUDKIP", "Mudkip"), - ("SPECIES_MARSHTOMP", "Marshtomp"), - ("SPECIES_SWAMPERT", "Swampert"), - ("SPECIES_POOCHYENA", "Poochyena"), - ("SPECIES_MIGHTYENA", "Mightyena"), - ("SPECIES_ZIGZAGOON", "Zigzagoon"), - ("SPECIES_LINOONE", "Linoon"), - ("SPECIES_WURMPLE", "Wurmple"), - ("SPECIES_SILCOON", "Silcoon"), - ("SPECIES_BEAUTIFLY", "Beautifly"), - ("SPECIES_CASCOON", "Cascoon"), - ("SPECIES_DUSTOX", "Dustox"), - ("SPECIES_LOTAD", "Lotad"), - ("SPECIES_LOMBRE", "Lombre"), - ("SPECIES_LUDICOLO", "Ludicolo"), - ("SPECIES_SEEDOT", "Seedot"), - ("SPECIES_NUZLEAF", "Nuzleaf"), - ("SPECIES_SHIFTRY", "Shiftry"), - ("SPECIES_NINCADA", "Nincada"), - ("SPECIES_NINJASK", "Ninjask"), - ("SPECIES_SHEDINJA", "Shedinja"), - ("SPECIES_TAILLOW", "Taillow"), - ("SPECIES_SWELLOW", "Swellow"), - ("SPECIES_SHROOMISH", "Shroomish"), - ("SPECIES_BRELOOM", "Breloom"), - ("SPECIES_SPINDA", "Spinda"), - ("SPECIES_WINGULL", "Wingull"), - ("SPECIES_PELIPPER", "Pelipper"), - ("SPECIES_SURSKIT", "Surskit"), - ("SPECIES_MASQUERAIN", "Masquerain"), - ("SPECIES_WAILMER", "Wailmer"), - ("SPECIES_WAILORD", "Wailord"), - ("SPECIES_SKITTY", "Skitty"), - ("SPECIES_DELCATTY", "Delcatty"), - ("SPECIES_KECLEON", "Kecleon"), - ("SPECIES_BALTOY", "Baltoy"), - ("SPECIES_CLAYDOL", "Claydol"), - ("SPECIES_NOSEPASS", "Nosepass"), - ("SPECIES_TORKOAL", "Torkoal"), - ("SPECIES_SABLEYE", "Sableye"), - ("SPECIES_BARBOACH", "Barboach"), - ("SPECIES_WHISCASH", "Whiscash"), - ("SPECIES_LUVDISC", "Luvdisc"), - ("SPECIES_CORPHISH", "Corphish"), - ("SPECIES_CRAWDAUNT", "Crawdaunt"), - ("SPECIES_FEEBAS", "Feebas"), - ("SPECIES_MILOTIC", "Milotic"), - ("SPECIES_CARVANHA", "Carvanha"), - ("SPECIES_SHARPEDO", "Sharpedo"), - ("SPECIES_TRAPINCH", "Trapinch"), - ("SPECIES_VIBRAVA", "Vibrava"), - ("SPECIES_FLYGON", "Flygon"), - ("SPECIES_MAKUHITA", "Makuhita"), - ("SPECIES_HARIYAMA", "Hariyama"), - ("SPECIES_ELECTRIKE", "Electrike"), - ("SPECIES_MANECTRIC", "Manectric"), - ("SPECIES_NUMEL", "Numel"), - ("SPECIES_CAMERUPT", "Camerupt"), - ("SPECIES_SPHEAL", "Spheal"), - ("SPECIES_SEALEO", "Sealeo"), - ("SPECIES_WALREIN", "Walrein"), - ("SPECIES_CACNEA", "Cacnea"), - ("SPECIES_CACTURNE", "Cacturne"), - ("SPECIES_SNORUNT", "Snorunt"), - ("SPECIES_GLALIE", "Glalie"), - ("SPECIES_LUNATONE", "Lunatone"), - ("SPECIES_SOLROCK", "Solrock"), - ("SPECIES_AZURILL", "Azurill"), - ("SPECIES_SPOINK", "Spoink"), - ("SPECIES_GRUMPIG", "Grumpig"), - ("SPECIES_PLUSLE", "Plusle"), - ("SPECIES_MINUN", "Minun"), - ("SPECIES_MAWILE", "Mawile"), - ("SPECIES_MEDITITE", "Meditite"), - ("SPECIES_MEDICHAM", "Medicham"), - ("SPECIES_SWABLU", "Swablu"), - ("SPECIES_ALTARIA", "Altaria"), - ("SPECIES_WYNAUT", "Wynaut"), - ("SPECIES_DUSKULL", "Duskull"), - ("SPECIES_DUSCLOPS", "Dusclops"), - ("SPECIES_ROSELIA", "Roselia"), - ("SPECIES_SLAKOTH", "Slakoth"), - ("SPECIES_VIGOROTH", "Vigoroth"), - ("SPECIES_SLAKING", "Slaking"), - ("SPECIES_GULPIN", "Gulpin"), - ("SPECIES_SWALOT", "Swalot"), - ("SPECIES_TROPIUS", "Tropius"), - ("SPECIES_WHISMUR", "Whismur"), - ("SPECIES_LOUDRED", "Loudred"), - ("SPECIES_EXPLOUD", "Exploud"), - ("SPECIES_CLAMPERL", "Clamperl"), - ("SPECIES_HUNTAIL", "Huntail"), - ("SPECIES_GOREBYSS", "Gorebyss"), - ("SPECIES_ABSOL", "Absol"), - ("SPECIES_SHUPPET", "Shuppet"), - ("SPECIES_BANETTE", "Banette"), - ("SPECIES_SEVIPER", "Seviper"), - ("SPECIES_ZANGOOSE", "Zangoose"), - ("SPECIES_RELICANTH", "Relicanth"), - ("SPECIES_ARON", "Aron"), - ("SPECIES_LAIRON", "Lairon"), - ("SPECIES_AGGRON", "Aggron"), - ("SPECIES_CASTFORM", "Castform"), - ("SPECIES_VOLBEAT", "Volbeat"), - ("SPECIES_ILLUMISE", "Illumise"), - ("SPECIES_LILEEP", "Lileep"), - ("SPECIES_CRADILY", "Cradily"), - ("SPECIES_ANORITH", "Anorith"), - ("SPECIES_ARMALDO", "Armaldo"), - ("SPECIES_RALTS", "Ralts"), - ("SPECIES_KIRLIA", "Kirlia"), - ("SPECIES_GARDEVOIR", "Gardevoir"), - ("SPECIES_BAGON", "Bagon"), - ("SPECIES_SHELGON", "Shelgon"), - ("SPECIES_SALAMENCE", "Salamence"), - ("SPECIES_BELDUM", "Beldum"), - ("SPECIES_METANG", "Metang"), - ("SPECIES_METAGROSS", "Metagross"), - ("SPECIES_REGIROCK", "Regirock"), - ("SPECIES_REGICE", "Regice"), - ("SPECIES_REGISTEEL", "Registeel"), - ("SPECIES_KYOGRE", "Kyogre"), - ("SPECIES_GROUDON", "Groudon"), - ("SPECIES_RAYQUAZA", "Rayquaza"), - ("SPECIES_LATIAS", "Latias"), - ("SPECIES_LATIOS", "Latios"), - ("SPECIES_JIRACHI", "Jirachi"), - ("SPECIES_DEOXYS", "Deoxys"), - ("SPECIES_CHIMECHO", "Chimecho") + all_species: List[Tuple[str, str, int]] = [ + ("SPECIES_BULBASAUR", "Bulbasaur", 1), + ("SPECIES_IVYSAUR", "Ivysaur", 2), + ("SPECIES_VENUSAUR", "Venusaur", 3), + ("SPECIES_CHARMANDER", "Charmander", 4), + ("SPECIES_CHARMELEON", "Charmeleon", 5), + ("SPECIES_CHARIZARD", "Charizard", 6), + ("SPECIES_SQUIRTLE", "Squirtle", 7), + ("SPECIES_WARTORTLE", "Wartortle", 8), + ("SPECIES_BLASTOISE", "Blastoise", 9), + ("SPECIES_CATERPIE", "Caterpie", 10), + ("SPECIES_METAPOD", "Metapod", 11), + ("SPECIES_BUTTERFREE", "Butterfree", 12), + ("SPECIES_WEEDLE", "Weedle", 13), + ("SPECIES_KAKUNA", "Kakuna", 14), + ("SPECIES_BEEDRILL", "Beedrill", 15), + ("SPECIES_PIDGEY", "Pidgey", 16), + ("SPECIES_PIDGEOTTO", "Pidgeotto", 17), + ("SPECIES_PIDGEOT", "Pidgeot", 18), + ("SPECIES_RATTATA", "Rattata", 19), + ("SPECIES_RATICATE", "Raticate", 20), + ("SPECIES_SPEAROW", "Spearow", 21), + ("SPECIES_FEAROW", "Fearow", 22), + ("SPECIES_EKANS", "Ekans", 23), + ("SPECIES_ARBOK", "Arbok", 24), + ("SPECIES_PIKACHU", "Pikachu", 25), + ("SPECIES_RAICHU", "Raichu", 26), + ("SPECIES_SANDSHREW", "Sandshrew", 27), + ("SPECIES_SANDSLASH", "Sandslash", 28), + ("SPECIES_NIDORAN_F", "Nidoran Female", 29), + ("SPECIES_NIDORINA", "Nidorina", 30), + ("SPECIES_NIDOQUEEN", "Nidoqueen", 31), + ("SPECIES_NIDORAN_M", "Nidoran Male", 32), + ("SPECIES_NIDORINO", "Nidorino", 33), + ("SPECIES_NIDOKING", "Nidoking", 34), + ("SPECIES_CLEFAIRY", "Clefairy", 35), + ("SPECIES_CLEFABLE", "Clefable", 36), + ("SPECIES_VULPIX", "Vulpix", 37), + ("SPECIES_NINETALES", "Ninetales", 38), + ("SPECIES_JIGGLYPUFF", "Jigglypuff", 39), + ("SPECIES_WIGGLYTUFF", "Wigglytuff", 40), + ("SPECIES_ZUBAT", "Zubat", 41), + ("SPECIES_GOLBAT", "Golbat", 42), + ("SPECIES_ODDISH", "Oddish", 43), + ("SPECIES_GLOOM", "Gloom", 44), + ("SPECIES_VILEPLUME", "Vileplume", 45), + ("SPECIES_PARAS", "Paras", 46), + ("SPECIES_PARASECT", "Parasect", 47), + ("SPECIES_VENONAT", "Venonat", 48), + ("SPECIES_VENOMOTH", "Venomoth", 49), + ("SPECIES_DIGLETT", "Diglett", 50), + ("SPECIES_DUGTRIO", "Dugtrio", 51), + ("SPECIES_MEOWTH", "Meowth", 52), + ("SPECIES_PERSIAN", "Persian", 53), + ("SPECIES_PSYDUCK", "Psyduck", 54), + ("SPECIES_GOLDUCK", "Golduck", 55), + ("SPECIES_MANKEY", "Mankey", 56), + ("SPECIES_PRIMEAPE", "Primeape", 57), + ("SPECIES_GROWLITHE", "Growlithe", 58), + ("SPECIES_ARCANINE", "Arcanine", 59), + ("SPECIES_POLIWAG", "Poliwag", 60), + ("SPECIES_POLIWHIRL", "Poliwhirl", 61), + ("SPECIES_POLIWRATH", "Poliwrath", 62), + ("SPECIES_ABRA", "Abra", 63), + ("SPECIES_KADABRA", "Kadabra", 64), + ("SPECIES_ALAKAZAM", "Alakazam", 65), + ("SPECIES_MACHOP", "Machop", 66), + ("SPECIES_MACHOKE", "Machoke", 67), + ("SPECIES_MACHAMP", "Machamp", 68), + ("SPECIES_BELLSPROUT", "Bellsprout", 69), + ("SPECIES_WEEPINBELL", "Weepinbell", 70), + ("SPECIES_VICTREEBEL", "Victreebel", 71), + ("SPECIES_TENTACOOL", "Tentacool", 72), + ("SPECIES_TENTACRUEL", "Tentacruel", 73), + ("SPECIES_GEODUDE", "Geodude", 74), + ("SPECIES_GRAVELER", "Graveler", 75), + ("SPECIES_GOLEM", "Golem", 76), + ("SPECIES_PONYTA", "Ponyta", 77), + ("SPECIES_RAPIDASH", "Rapidash", 78), + ("SPECIES_SLOWPOKE", "Slowpoke", 79), + ("SPECIES_SLOWBRO", "Slowbro", 80), + ("SPECIES_MAGNEMITE", "Magnemite", 81), + ("SPECIES_MAGNETON", "Magneton", 82), + ("SPECIES_FARFETCHD", "Farfetch'd", 83), + ("SPECIES_DODUO", "Doduo", 84), + ("SPECIES_DODRIO", "Dodrio", 85), + ("SPECIES_SEEL", "Seel", 86), + ("SPECIES_DEWGONG", "Dewgong", 87), + ("SPECIES_GRIMER", "Grimer", 88), + ("SPECIES_MUK", "Muk", 89), + ("SPECIES_SHELLDER", "Shellder", 90), + ("SPECIES_CLOYSTER", "Cloyster", 91), + ("SPECIES_GASTLY", "Gastly", 92), + ("SPECIES_HAUNTER", "Haunter", 93), + ("SPECIES_GENGAR", "Gengar", 94), + ("SPECIES_ONIX", "Onix", 95), + ("SPECIES_DROWZEE", "Drowzee", 96), + ("SPECIES_HYPNO", "Hypno", 97), + ("SPECIES_KRABBY", "Krabby", 98), + ("SPECIES_KINGLER", "Kingler", 99), + ("SPECIES_VOLTORB", "Voltorb", 100), + ("SPECIES_ELECTRODE", "Electrode", 101), + ("SPECIES_EXEGGCUTE", "Exeggcute", 102), + ("SPECIES_EXEGGUTOR", "Exeggutor", 103), + ("SPECIES_CUBONE", "Cubone", 104), + ("SPECIES_MAROWAK", "Marowak", 105), + ("SPECIES_HITMONLEE", "Hitmonlee", 106), + ("SPECIES_HITMONCHAN", "Hitmonchan", 107), + ("SPECIES_LICKITUNG", "Lickitung", 108), + ("SPECIES_KOFFING", "Koffing", 109), + ("SPECIES_WEEZING", "Weezing", 110), + ("SPECIES_RHYHORN", "Rhyhorn", 111), + ("SPECIES_RHYDON", "Rhydon", 112), + ("SPECIES_CHANSEY", "Chansey", 113), + ("SPECIES_TANGELA", "Tangela", 114), + ("SPECIES_KANGASKHAN", "Kangaskhan", 115), + ("SPECIES_HORSEA", "Horsea", 116), + ("SPECIES_SEADRA", "Seadra", 117), + ("SPECIES_GOLDEEN", "Goldeen", 118), + ("SPECIES_SEAKING", "Seaking", 119), + ("SPECIES_STARYU", "Staryu", 120), + ("SPECIES_STARMIE", "Starmie", 121), + ("SPECIES_MR_MIME", "Mr. Mime", 122), + ("SPECIES_SCYTHER", "Scyther", 123), + ("SPECIES_JYNX", "Jynx", 124), + ("SPECIES_ELECTABUZZ", "Electabuzz", 125), + ("SPECIES_MAGMAR", "Magmar", 126), + ("SPECIES_PINSIR", "Pinsir", 127), + ("SPECIES_TAUROS", "Tauros", 128), + ("SPECIES_MAGIKARP", "Magikarp", 129), + ("SPECIES_GYARADOS", "Gyarados", 130), + ("SPECIES_LAPRAS", "Lapras", 131), + ("SPECIES_DITTO", "Ditto", 132), + ("SPECIES_EEVEE", "Eevee", 133), + ("SPECIES_VAPOREON", "Vaporeon", 134), + ("SPECIES_JOLTEON", "Jolteon", 135), + ("SPECIES_FLAREON", "Flareon", 136), + ("SPECIES_PORYGON", "Porygon", 137), + ("SPECIES_OMANYTE", "Omanyte", 138), + ("SPECIES_OMASTAR", "Omastar", 139), + ("SPECIES_KABUTO", "Kabuto", 140), + ("SPECIES_KABUTOPS", "Kabutops", 141), + ("SPECIES_AERODACTYL", "Aerodactyl", 142), + ("SPECIES_SNORLAX", "Snorlax", 143), + ("SPECIES_ARTICUNO", "Articuno", 144), + ("SPECIES_ZAPDOS", "Zapdos", 145), + ("SPECIES_MOLTRES", "Moltres", 146), + ("SPECIES_DRATINI", "Dratini", 147), + ("SPECIES_DRAGONAIR", "Dragonair", 148), + ("SPECIES_DRAGONITE", "Dragonite", 149), + ("SPECIES_MEWTWO", "Mewtwo", 150), + ("SPECIES_MEW", "Mew", 151), + ("SPECIES_CHIKORITA", "Chikorita", 152), + ("SPECIES_BAYLEEF", "Bayleef", 153), + ("SPECIES_MEGANIUM", "Meganium", 154), + ("SPECIES_CYNDAQUIL", "Cindaquil", 155), + ("SPECIES_QUILAVA", "Quilava", 156), + ("SPECIES_TYPHLOSION", "Typhlosion", 157), + ("SPECIES_TOTODILE", "Totodile", 158), + ("SPECIES_CROCONAW", "Croconaw", 159), + ("SPECIES_FERALIGATR", "Feraligatr", 160), + ("SPECIES_SENTRET", "Sentret", 161), + ("SPECIES_FURRET", "Furret", 162), + ("SPECIES_HOOTHOOT", "Hoothoot", 163), + ("SPECIES_NOCTOWL", "Noctowl", 164), + ("SPECIES_LEDYBA", "Ledyba", 165), + ("SPECIES_LEDIAN", "Ledian", 166), + ("SPECIES_SPINARAK", "Spinarak", 167), + ("SPECIES_ARIADOS", "Ariados", 168), + ("SPECIES_CROBAT", "Crobat", 169), + ("SPECIES_CHINCHOU", "Chinchou", 170), + ("SPECIES_LANTURN", "Lanturn", 171), + ("SPECIES_PICHU", "Pichu", 172), + ("SPECIES_CLEFFA", "Cleffa", 173), + ("SPECIES_IGGLYBUFF", "Igglybuff", 174), + ("SPECIES_TOGEPI", "Togepi", 175), + ("SPECIES_TOGETIC", "Togetic", 176), + ("SPECIES_NATU", "Natu", 177), + ("SPECIES_XATU", "Xatu", 178), + ("SPECIES_MAREEP", "Mareep", 179), + ("SPECIES_FLAAFFY", "Flaaffy", 180), + ("SPECIES_AMPHAROS", "Ampharos", 181), + ("SPECIES_BELLOSSOM", "Bellossom", 182), + ("SPECIES_MARILL", "Marill", 183), + ("SPECIES_AZUMARILL", "Azumarill", 184), + ("SPECIES_SUDOWOODO", "Sudowoodo", 185), + ("SPECIES_POLITOED", "Politoed", 186), + ("SPECIES_HOPPIP", "Hoppip", 187), + ("SPECIES_SKIPLOOM", "Skiploom", 188), + ("SPECIES_JUMPLUFF", "Jumpluff", 189), + ("SPECIES_AIPOM", "Aipom", 190), + ("SPECIES_SUNKERN", "Sunkern", 191), + ("SPECIES_SUNFLORA", "Sunflora", 192), + ("SPECIES_YANMA", "Yanma", 193), + ("SPECIES_WOOPER", "Wooper", 194), + ("SPECIES_QUAGSIRE", "Quagsire", 195), + ("SPECIES_ESPEON", "Espeon", 196), + ("SPECIES_UMBREON", "Umbreon", 197), + ("SPECIES_MURKROW", "Murkrow", 198), + ("SPECIES_SLOWKING", "Slowking", 199), + ("SPECIES_MISDREAVUS", "Misdreavus", 200), + ("SPECIES_UNOWN", "Unown", 201), + ("SPECIES_WOBBUFFET", "Wobbuffet", 202), + ("SPECIES_GIRAFARIG", "Girafarig", 203), + ("SPECIES_PINECO", "Pineco", 204), + ("SPECIES_FORRETRESS", "Forretress", 205), + ("SPECIES_DUNSPARCE", "Dunsparce", 206), + ("SPECIES_GLIGAR", "Gligar", 207), + ("SPECIES_STEELIX", "Steelix", 208), + ("SPECIES_SNUBBULL", "Snubbull", 209), + ("SPECIES_GRANBULL", "Granbull", 210), + ("SPECIES_QWILFISH", "Qwilfish", 211), + ("SPECIES_SCIZOR", "Scizor", 212), + ("SPECIES_SHUCKLE", "Shuckle", 213), + ("SPECIES_HERACROSS", "Heracross", 214), + ("SPECIES_SNEASEL", "Sneasel", 215), + ("SPECIES_TEDDIURSA", "Teddiursa", 216), + ("SPECIES_URSARING", "Ursaring", 217), + ("SPECIES_SLUGMA", "Slugma", 218), + ("SPECIES_MAGCARGO", "Magcargo", 219), + ("SPECIES_SWINUB", "Swinub", 220), + ("SPECIES_PILOSWINE", "Piloswine", 221), + ("SPECIES_CORSOLA", "Corsola", 222), + ("SPECIES_REMORAID", "Remoraid", 223), + ("SPECIES_OCTILLERY", "Octillery", 224), + ("SPECIES_DELIBIRD", "Delibird", 225), + ("SPECIES_MANTINE", "Mantine", 226), + ("SPECIES_SKARMORY", "Skarmory", 227), + ("SPECIES_HOUNDOUR", "Houndour", 228), + ("SPECIES_HOUNDOOM", "Houndoom", 229), + ("SPECIES_KINGDRA", "Kingdra", 230), + ("SPECIES_PHANPY", "Phanpy", 231), + ("SPECIES_DONPHAN", "Donphan", 232), + ("SPECIES_PORYGON2", "Porygon2", 233), + ("SPECIES_STANTLER", "Stantler", 234), + ("SPECIES_SMEARGLE", "Smeargle", 235), + ("SPECIES_TYROGUE", "Tyrogue", 236), + ("SPECIES_HITMONTOP", "Hitmontop", 237), + ("SPECIES_SMOOCHUM", "Smoochum", 238), + ("SPECIES_ELEKID", "Elekid", 239), + ("SPECIES_MAGBY", "Magby", 240), + ("SPECIES_MILTANK", "Miltank", 241), + ("SPECIES_BLISSEY", "Blissey", 242), + ("SPECIES_RAIKOU", "Raikou", 243), + ("SPECIES_ENTEI", "Entei", 244), + ("SPECIES_SUICUNE", "Suicune", 245), + ("SPECIES_LARVITAR", "Larvitar", 246), + ("SPECIES_PUPITAR", "Pupitar", 247), + ("SPECIES_TYRANITAR", "Tyranitar", 248), + ("SPECIES_LUGIA", "Lugia", 249), + ("SPECIES_HO_OH", "Ho-oh", 250), + ("SPECIES_CELEBI", "Celebi", 251), + ("SPECIES_TREECKO", "Treecko", 252), + ("SPECIES_GROVYLE", "Grovyle", 253), + ("SPECIES_SCEPTILE", "Sceptile", 254), + ("SPECIES_TORCHIC", "Torchic", 255), + ("SPECIES_COMBUSKEN", "Combusken", 256), + ("SPECIES_BLAZIKEN", "Blaziken", 257), + ("SPECIES_MUDKIP", "Mudkip", 258), + ("SPECIES_MARSHTOMP", "Marshtomp", 259), + ("SPECIES_SWAMPERT", "Swampert", 260), + ("SPECIES_POOCHYENA", "Poochyena", 261), + ("SPECIES_MIGHTYENA", "Mightyena", 262), + ("SPECIES_ZIGZAGOON", "Zigzagoon", 263), + ("SPECIES_LINOONE", "Linoone", 264), + ("SPECIES_WURMPLE", "Wurmple", 265), + ("SPECIES_SILCOON", "Silcoon", 266), + ("SPECIES_BEAUTIFLY", "Beautifly", 267), + ("SPECIES_CASCOON", "Cascoon", 268), + ("SPECIES_DUSTOX", "Dustox", 269), + ("SPECIES_LOTAD", "Lotad", 270), + ("SPECIES_LOMBRE", "Lombre", 271), + ("SPECIES_LUDICOLO", "Ludicolo", 272), + ("SPECIES_SEEDOT", "Seedot", 273), + ("SPECIES_NUZLEAF", "Nuzleaf", 274), + ("SPECIES_SHIFTRY", "Shiftry", 275), + ("SPECIES_NINCADA", "Nincada", 290), + ("SPECIES_NINJASK", "Ninjask", 291), + ("SPECIES_SHEDINJA", "Shedinja", 292), + ("SPECIES_TAILLOW", "Taillow", 276), + ("SPECIES_SWELLOW", "Swellow", 277), + ("SPECIES_SHROOMISH", "Shroomish", 285), + ("SPECIES_BRELOOM", "Breloom", 286), + ("SPECIES_SPINDA", "Spinda", 327), + ("SPECIES_WINGULL", "Wingull", 278), + ("SPECIES_PELIPPER", "Pelipper", 279), + ("SPECIES_SURSKIT", "Surskit", 283), + ("SPECIES_MASQUERAIN", "Masquerain", 284), + ("SPECIES_WAILMER", "Wailmer", 320), + ("SPECIES_WAILORD", "Wailord", 321), + ("SPECIES_SKITTY", "Skitty", 300), + ("SPECIES_DELCATTY", "Delcatty", 301), + ("SPECIES_KECLEON", "Kecleon", 352), + ("SPECIES_BALTOY", "Baltoy", 343), + ("SPECIES_CLAYDOL", "Claydol", 344), + ("SPECIES_NOSEPASS", "Nosepass", 299), + ("SPECIES_TORKOAL", "Torkoal", 324), + ("SPECIES_SABLEYE", "Sableye", 302), + ("SPECIES_BARBOACH", "Barboach", 339), + ("SPECIES_WHISCASH", "Whiscash", 340), + ("SPECIES_LUVDISC", "Luvdisc", 370), + ("SPECIES_CORPHISH", "Corphish", 341), + ("SPECIES_CRAWDAUNT", "Crawdaunt", 342), + ("SPECIES_FEEBAS", "Feebas", 349), + ("SPECIES_MILOTIC", "Milotic", 350), + ("SPECIES_CARVANHA", "Carvanha", 318), + ("SPECIES_SHARPEDO", "Sharpedo", 319), + ("SPECIES_TRAPINCH", "Trapinch", 328), + ("SPECIES_VIBRAVA", "Vibrava", 329), + ("SPECIES_FLYGON", "Flygon", 330), + ("SPECIES_MAKUHITA", "Makuhita", 296), + ("SPECIES_HARIYAMA", "Hariyama", 297), + ("SPECIES_ELECTRIKE", "Electrike", 309), + ("SPECIES_MANECTRIC", "Manectric", 310), + ("SPECIES_NUMEL", "Numel", 322), + ("SPECIES_CAMERUPT", "Camerupt", 323), + ("SPECIES_SPHEAL", "Spheal", 363), + ("SPECIES_SEALEO", "Sealeo", 364), + ("SPECIES_WALREIN", "Walrein", 365), + ("SPECIES_CACNEA", "Cacnea", 331), + ("SPECIES_CACTURNE", "Cacturne", 332), + ("SPECIES_SNORUNT", "Snorunt", 361), + ("SPECIES_GLALIE", "Glalie", 362), + ("SPECIES_LUNATONE", "Lunatone", 337), + ("SPECIES_SOLROCK", "Solrock", 338), + ("SPECIES_AZURILL", "Azurill", 298), + ("SPECIES_SPOINK", "Spoink", 325), + ("SPECIES_GRUMPIG", "Grumpig", 326), + ("SPECIES_PLUSLE", "Plusle", 311), + ("SPECIES_MINUN", "Minun", 312), + ("SPECIES_MAWILE", "Mawile", 303), + ("SPECIES_MEDITITE", "Meditite", 307), + ("SPECIES_MEDICHAM", "Medicham", 308), + ("SPECIES_SWABLU", "Swablu", 333), + ("SPECIES_ALTARIA", "Altaria", 334), + ("SPECIES_WYNAUT", "Wynaut", 360), + ("SPECIES_DUSKULL", "Duskull", 355), + ("SPECIES_DUSCLOPS", "Dusclops", 356), + ("SPECIES_ROSELIA", "Roselia", 315), + ("SPECIES_SLAKOTH", "Slakoth", 287), + ("SPECIES_VIGOROTH", "Vigoroth", 288), + ("SPECIES_SLAKING", "Slaking", 289), + ("SPECIES_GULPIN", "Gulpin", 316), + ("SPECIES_SWALOT", "Swalot", 317), + ("SPECIES_TROPIUS", "Tropius", 357), + ("SPECIES_WHISMUR", "Whismur", 293), + ("SPECIES_LOUDRED", "Loudred", 294), + ("SPECIES_EXPLOUD", "Exploud", 295), + ("SPECIES_CLAMPERL", "Clamperl", 366), + ("SPECIES_HUNTAIL", "Huntail", 367), + ("SPECIES_GOREBYSS", "Gorebyss", 368), + ("SPECIES_ABSOL", "Absol", 359), + ("SPECIES_SHUPPET", "Shuppet", 353), + ("SPECIES_BANETTE", "Banette", 354), + ("SPECIES_SEVIPER", "Seviper", 336), + ("SPECIES_ZANGOOSE", "Zangoose", 335), + ("SPECIES_RELICANTH", "Relicanth", 369), + ("SPECIES_ARON", "Aron", 304), + ("SPECIES_LAIRON", "Lairon", 305), + ("SPECIES_AGGRON", "Aggron", 306), + ("SPECIES_CASTFORM", "Castform", 351), + ("SPECIES_VOLBEAT", "Volbeat", 313), + ("SPECIES_ILLUMISE", "Illumise", 314), + ("SPECIES_LILEEP", "Lileep", 345), + ("SPECIES_CRADILY", "Cradily", 346), + ("SPECIES_ANORITH", "Anorith", 347), + ("SPECIES_ARMALDO", "Armaldo", 348), + ("SPECIES_RALTS", "Ralts", 280), + ("SPECIES_KIRLIA", "Kirlia", 281), + ("SPECIES_GARDEVOIR", "Gardevoir", 282), + ("SPECIES_BAGON", "Bagon", 371), + ("SPECIES_SHELGON", "Shelgon", 372), + ("SPECIES_SALAMENCE", "Salamence", 373), + ("SPECIES_BELDUM", "Beldum", 374), + ("SPECIES_METANG", "Metang", 375), + ("SPECIES_METAGROSS", "Metagross", 376), + ("SPECIES_REGIROCK", "Regirock", 377), + ("SPECIES_REGICE", "Regice", 378), + ("SPECIES_REGISTEEL", "Registeel", 379), + ("SPECIES_KYOGRE", "Kyogre", 382), + ("SPECIES_GROUDON", "Groudon", 383), + ("SPECIES_RAYQUAZA", "Rayquaza", 384), + ("SPECIES_LATIAS", "Latias", 380), + ("SPECIES_LATIOS", "Latios", 381), + ("SPECIES_JIRACHI", "Jirachi", 385), + ("SPECIES_DEOXYS", "Deoxys", 386), + ("SPECIES_CHIMECHO", "Chimecho", 358), ] - species_list: List[SpeciesData] = [] max_species_id = 0 - for species_name, species_label in all_species: + for species_name, species_label, species_dex_number in all_species: species_id = data.constants[species_name] max_species_id = max(species_id, max_species_id) species_data = extracted_data["species"][species_id] learnset = [LearnsetMove(item["level"], item["move_id"]) for item in species_data["learnset"]["moves"]] - species_list.append(SpeciesData( + data.species[species_id] = SpeciesData( species_name, species_label, species_id, + species_dex_number, BaseStats( species_data["base_stats"][0], species_data["base_stats"][1], @@ -827,27 +910,52 @@ def _init() -> None: ) for evolution_json in species_data["evolutions"]], None, species_data["catch_rate"], + species_data["friendship"], learnset, int(species_data["tmhm_learnset"], 16), - species_data["learnset"]["rom_address"], - species_data["rom_address"] + species_data["learnset"]["address"], + species_data["address"] + ) + + for species in data.species.values(): + for evolution in species.evolutions: + data.species[evolution.species_id].pre_evolution = species.species_id + + # Replace default item for dex entry locations based on evo stage of species + evo_stage_to_ball_map = { + 0: data.constants["ITEM_POKE_BALL"], + 1: data.constants["ITEM_GREAT_BALL"], + 2: data.constants["ITEM_ULTRA_BALL"], + } + for species in data.species.values(): + evo_stage = 0 + pre_evolution = species.pre_evolution + while pre_evolution is not None: + evo_stage += 1 + pre_evolution = data.species[pre_evolution].pre_evolution + + dex_location_name = f"POKEDEX_REWARD_{str(species.national_dex_number).zfill(3)}" + data.locations[dex_location_name] = LocationData( + data.locations[dex_location_name].name, + data.locations[dex_location_name].label, + data.locations[dex_location_name].parent_region, + evo_stage_to_ball_map[evo_stage], + data.locations[dex_location_name].address, + data.locations[dex_location_name].flag, + data.locations[dex_location_name].tags + ) + + # Create legendary encounter data + for legendary_encounter_json in extracted_data["legendary_encounters"]: + data.legendary_encounters.append(MiscPokemonData( + legendary_encounter_json["species"], + legendary_encounter_json["address"] )) - data.species = [None for i in range(max_species_id + 1)] - - for species_data in species_list: - data.species[species_data.species_id] = species_data - - for species in data.species: - if species is not None: - for evolution in species.evolutions: - data.species[evolution.species_id].pre_evolution = species.species_id - - # Create static encounter data - for static_encounter_json in extracted_data["static_encounters"]: - data.static_encounters.append(StaticEncounterData( - static_encounter_json["species"], - static_encounter_json["rom_address"] + for misc_pokemon_json in extracted_data["misc_pokemon"]: + data.misc_pokemon.append(MiscPokemonData( + misc_pokemon_json["species"], + misc_pokemon_json["address"] )) # TM moves @@ -868,7 +976,7 @@ def _init() -> None: ("ABILITY_WATER_ABSORB", "Water Absorb"), ("ABILITY_OBLIVIOUS", "Oblivious"), ("ABILITY_CLOUD_NINE", "Cloud Nine"), - ("ABILITY_COMPOUND_EYES", "Compound Eyes"), + ("ABILITY_COMPOUND_EYES", "Compoundeyes"), ("ABILITY_INSOMNIA", "Insomnia"), ("ABILITY_COLOR_CHANGE", "Color Change"), ("ABILITY_IMMUNITY", "Immunity"), @@ -885,7 +993,7 @@ def _init() -> None: ("ABILITY_SYNCHRONIZE", "Synchronize"), ("ABILITY_CLEAR_BODY", "Clear Body"), ("ABILITY_NATURAL_CURE", "Natural Cure"), - ("ABILITY_LIGHTNING_ROD", "Lightning Rod"), + ("ABILITY_LIGHTNING_ROD", "Lightningrod"), ("ABILITY_SERENE_GRACE", "Serene Grace"), ("ABILITY_SWIFT_SWIM", "Swift Swim"), ("ABILITY_CHLOROPHYLL", "Chlorophyll"), @@ -934,36 +1042,362 @@ def _init() -> None: ("ABILITY_AIR_LOCK", "Air Lock") ]] - # Create map data - for map_name, map_json in extracted_data["maps"].items(): - land_encounters = None - water_encounters = None - fishing_encounters = None - - if map_json["land_encounters"] is not None: - land_encounters = EncounterTableData( - map_json["land_encounters"]["encounter_slots"], - map_json["land_encounters"]["rom_address"] - ) - if map_json["water_encounters"] is not None: - water_encounters = EncounterTableData( - map_json["water_encounters"]["encounter_slots"], - map_json["water_encounters"]["rom_address"] - ) - if map_json["fishing_encounters"] is not None: - fishing_encounters = EncounterTableData( - map_json["fishing_encounters"]["encounter_slots"], - map_json["fishing_encounters"]["rom_address"] - ) - - data.maps.append(MapData( - map_name, - land_encounters, - water_encounters, - fishing_encounters - )) - - data.maps.sort(key=lambda map: map.name) + # Move labels + data.move_labels = {r: data.constants[l] for l, r in [ + ("MOVE_POUND", "Pound"), + ("MOVE_KARATE_CHOP", "Karate Chop"), + ("MOVE_DOUBLE_SLAP", "Doubleslap"), + ("MOVE_COMET_PUNCH", "Comet Punch"), + ("MOVE_MEGA_PUNCH", "Mega Punch"), + ("MOVE_PAY_DAY", "Pay Day"), + ("MOVE_FIRE_PUNCH", "Fire Punch"), + ("MOVE_ICE_PUNCH", "Ice Punch"), + ("MOVE_THUNDER_PUNCH", "Thunderpunch"), + ("MOVE_SCRATCH", "Scratch"), + ("MOVE_VICE_GRIP", "Vicegrip"), + ("MOVE_GUILLOTINE", "Guillotine"), + ("MOVE_RAZOR_WIND", "Razor Wind"), + ("MOVE_SWORDS_DANCE", "Swords Dance"), + ("MOVE_CUT", "Cut"), + ("MOVE_GUST", "Gust"), + ("MOVE_WING_ATTACK", "Wing Attack"), + ("MOVE_WHIRLWIND", "Whirlwind"), + ("MOVE_FLY", "Fly"), + ("MOVE_BIND", "Bind"), + ("MOVE_SLAM", "Slam"), + ("MOVE_VINE_WHIP", "Vine Whip"), + ("MOVE_STOMP", "Stomp"), + ("MOVE_DOUBLE_KICK", "Double Kick"), + ("MOVE_MEGA_KICK", "Mega Kick"), + ("MOVE_JUMP_KICK", "Jump Kick"), + ("MOVE_ROLLING_KICK", "Rolling Kick"), + ("MOVE_SAND_ATTACK", "Sand-Attack"), + ("MOVE_HEADBUTT", "Headbutt"), + ("MOVE_HORN_ATTACK", "Horn Attack"), + ("MOVE_FURY_ATTACK", "Fury Attack"), + ("MOVE_HORN_DRILL", "Horn Drill"), + ("MOVE_TACKLE", "Tackle"), + ("MOVE_BODY_SLAM", "Body Slam"), + ("MOVE_WRAP", "Wrap"), + ("MOVE_TAKE_DOWN", "Take Down"), + ("MOVE_THRASH", "Thrash"), + ("MOVE_DOUBLE_EDGE", "Double-Edge"), + ("MOVE_TAIL_WHIP", "Tail Whip"), + ("MOVE_POISON_STING", "Poison Sting"), + ("MOVE_TWINEEDLE", "Twineedle"), + ("MOVE_PIN_MISSILE", "Pin Missile"), + ("MOVE_LEER", "Leer"), + ("MOVE_BITE", "Bite"), + ("MOVE_GROWL", "Growl"), + ("MOVE_ROAR", "Roar"), + ("MOVE_SING", "Sing"), + ("MOVE_SUPERSONIC", "Supersonic"), + ("MOVE_SONIC_BOOM", "Sonicboom"), + ("MOVE_DISABLE", "Disable"), + ("MOVE_ACID", "Acid"), + ("MOVE_EMBER", "Ember"), + ("MOVE_FLAMETHROWER", "Flamethrower"), + ("MOVE_MIST", "Mist"), + ("MOVE_WATER_GUN", "Water Gun"), + ("MOVE_HYDRO_PUMP", "Hydro Pump"), + ("MOVE_SURF", "Surf"), + ("MOVE_ICE_BEAM", "Ice Beam"), + ("MOVE_BLIZZARD", "Blizzard"), + ("MOVE_PSYBEAM", "Psybeam"), + ("MOVE_BUBBLE_BEAM", "Bubblebeam"), + ("MOVE_AURORA_BEAM", "Aurora Beam"), + ("MOVE_HYPER_BEAM", "Hyper Beam"), + ("MOVE_PECK", "Peck"), + ("MOVE_DRILL_PECK", "Drill Peck"), + ("MOVE_SUBMISSION", "Submission"), + ("MOVE_LOW_KICK", "Low Kick"), + ("MOVE_COUNTER", "Counter"), + ("MOVE_SEISMIC_TOSS", "Seismic Toss"), + ("MOVE_STRENGTH", "Strength"), + ("MOVE_ABSORB", "Absorb"), + ("MOVE_MEGA_DRAIN", "Mega Drain"), + ("MOVE_LEECH_SEED", "Leech Seed"), + ("MOVE_GROWTH", "Growth"), + ("MOVE_RAZOR_LEAF", "Razor Leaf"), + ("MOVE_SOLAR_BEAM", "Solarbeam"), + ("MOVE_POISON_POWDER", "Poisonpowder"), + ("MOVE_STUN_SPORE", "Stun Spore"), + ("MOVE_SLEEP_POWDER", "Sleep Powder"), + ("MOVE_PETAL_DANCE", "Petal Dance"), + ("MOVE_STRING_SHOT", "String Shot"), + ("MOVE_DRAGON_RAGE", "Dragon Rage"), + ("MOVE_FIRE_SPIN", "Fire Spin"), + ("MOVE_THUNDER_SHOCK", "Thundershock"), + ("MOVE_THUNDERBOLT", "Thunderbolt"), + ("MOVE_THUNDER_WAVE", "Thunder Wave"), + ("MOVE_THUNDER", "Thunder"), + ("MOVE_ROCK_THROW", "Rock Throw"), + ("MOVE_EARTHQUAKE", "Earthquake"), + ("MOVE_FISSURE", "Fissure"), + ("MOVE_DIG", "Dig"), + ("MOVE_TOXIC", "Toxic"), + ("MOVE_CONFUSION", "Confusion"), + ("MOVE_PSYCHIC", "Psychic"), + ("MOVE_HYPNOSIS", "Hypnosis"), + ("MOVE_MEDITATE", "Meditate"), + ("MOVE_AGILITY", "Agility"), + ("MOVE_QUICK_ATTACK", "Quick Attack"), + ("MOVE_RAGE", "Rage"), + ("MOVE_TELEPORT", "Teleport"), + ("MOVE_NIGHT_SHADE", "Night Shade"), + ("MOVE_MIMIC", "Mimic"), + ("MOVE_SCREECH", "Screech"), + ("MOVE_DOUBLE_TEAM", "Double Team"), + ("MOVE_RECOVER", "Recover"), + ("MOVE_HARDEN", "Harden"), + ("MOVE_MINIMIZE", "Minimize"), + ("MOVE_SMOKESCREEN", "Smokescreen"), + ("MOVE_CONFUSE_RAY", "Confuse Ray"), + ("MOVE_WITHDRAW", "Withdraw"), + ("MOVE_DEFENSE_CURL", "Defense Curl"), + ("MOVE_BARRIER", "Barrier"), + ("MOVE_LIGHT_SCREEN", "Light Screen"), + ("MOVE_HAZE", "Haze"), + ("MOVE_REFLECT", "Reflect"), + ("MOVE_FOCUS_ENERGY", "Focus Energy"), + ("MOVE_BIDE", "Bide"), + ("MOVE_METRONOME", "Metronome"), + ("MOVE_MIRROR_MOVE", "Mirror Move"), + ("MOVE_SELF_DESTRUCT", "Selfdestruct"), + ("MOVE_EGG_BOMB", "Egg Bomb"), + ("MOVE_LICK", "Lick"), + ("MOVE_SMOG", "Smog"), + ("MOVE_SLUDGE", "Sludge"), + ("MOVE_BONE_CLUB", "Bone Club"), + ("MOVE_FIRE_BLAST", "Fire Blast"), + ("MOVE_WATERFALL", "Waterfall"), + ("MOVE_CLAMP", "Clamp"), + ("MOVE_SWIFT", "Swift"), + ("MOVE_SKULL_BASH", "Skull Bash"), + ("MOVE_SPIKE_CANNON", "Spike Cannon"), + ("MOVE_CONSTRICT", "Constrict"), + ("MOVE_AMNESIA", "Amnesia"), + ("MOVE_KINESIS", "Kinesis"), + ("MOVE_SOFT_BOILED", "Softboiled"), + ("MOVE_HI_JUMP_KICK", "Hi Jump Kick"), + ("MOVE_GLARE", "Glare"), + ("MOVE_DREAM_EATER", "Dream Eater"), + ("MOVE_POISON_GAS", "Poison Gas"), + ("MOVE_BARRAGE", "Barrage"), + ("MOVE_LEECH_LIFE", "Leech Life"), + ("MOVE_LOVELY_KISS", "Lovely Kiss"), + ("MOVE_SKY_ATTACK", "Sky Attack"), + ("MOVE_TRANSFORM", "Transform"), + ("MOVE_BUBBLE", "Bubble"), + ("MOVE_DIZZY_PUNCH", "Dizzy Punch"), + ("MOVE_SPORE", "Spore"), + ("MOVE_FLASH", "Flash"), + ("MOVE_PSYWAVE", "Psywave"), + ("MOVE_SPLASH", "Splash"), + ("MOVE_ACID_ARMOR", "Acid Armor"), + ("MOVE_CRABHAMMER", "Crabhammer"), + ("MOVE_EXPLOSION", "Explosion"), + ("MOVE_FURY_SWIPES", "Fury Swipes"), + ("MOVE_BONEMERANG", "Bonemerang"), + ("MOVE_REST", "Rest"), + ("MOVE_ROCK_SLIDE", "Rock Slide"), + ("MOVE_HYPER_FANG", "Hyper Fang"), + ("MOVE_SHARPEN", "Sharpen"), + ("MOVE_CONVERSION", "Conversion"), + ("MOVE_TRI_ATTACK", "Tri Attack"), + ("MOVE_SUPER_FANG", "Super Fang"), + ("MOVE_SLASH", "Slash"), + ("MOVE_SUBSTITUTE", "Substitute"), + ("MOVE_SKETCH", "Sketch"), + ("MOVE_TRIPLE_KICK", "Triple Kick"), + ("MOVE_THIEF", "Thief"), + ("MOVE_SPIDER_WEB", "Spider Web"), + ("MOVE_MIND_READER", "Mind Reader"), + ("MOVE_NIGHTMARE", "Nightmare"), + ("MOVE_FLAME_WHEEL", "Flame Wheel"), + ("MOVE_SNORE", "Snore"), + ("MOVE_CURSE", "Curse"), + ("MOVE_FLAIL", "Flail"), + ("MOVE_CONVERSION_2", "Conversion 2"), + ("MOVE_AEROBLAST", "Aeroblast"), + ("MOVE_COTTON_SPORE", "Cotton Spore"), + ("MOVE_REVERSAL", "Reversal"), + ("MOVE_SPITE", "Spite"), + ("MOVE_POWDER_SNOW", "Powder Snow"), + ("MOVE_PROTECT", "Protect"), + ("MOVE_MACH_PUNCH", "Mach Punch"), + ("MOVE_SCARY_FACE", "Scary Face"), + ("MOVE_FAINT_ATTACK", "Faint Attack"), + ("MOVE_SWEET_KISS", "Sweet Kiss"), + ("MOVE_BELLY_DRUM", "Belly Drum"), + ("MOVE_SLUDGE_BOMB", "Sludge Bomb"), + ("MOVE_MUD_SLAP", "Mud-Slap"), + ("MOVE_OCTAZOOKA", "Octazooka"), + ("MOVE_SPIKES", "Spikes"), + ("MOVE_ZAP_CANNON", "Zap Cannon"), + ("MOVE_FORESIGHT", "Foresight"), + ("MOVE_DESTINY_BOND", "Destiny Bond"), + ("MOVE_PERISH_SONG", "Perish Song"), + ("MOVE_ICY_WIND", "Icy Wind"), + ("MOVE_DETECT", "Detect"), + ("MOVE_BONE_RUSH", "Bone Rush"), + ("MOVE_LOCK_ON", "Lock-On"), + ("MOVE_OUTRAGE", "Outrage"), + ("MOVE_SANDSTORM", "Sandstorm"), + ("MOVE_GIGA_DRAIN", "Giga Drain"), + ("MOVE_ENDURE", "Endure"), + ("MOVE_CHARM", "Charm"), + ("MOVE_ROLLOUT", "Rollout"), + ("MOVE_FALSE_SWIPE", "False Swipe"), + ("MOVE_SWAGGER", "Swagger"), + ("MOVE_MILK_DRINK", "Milk Drink"), + ("MOVE_SPARK", "Spark"), + ("MOVE_FURY_CUTTER", "Fury Cutter"), + ("MOVE_STEEL_WING", "Steel Wing"), + ("MOVE_MEAN_LOOK", "Mean Look"), + ("MOVE_ATTRACT", "Attract"), + ("MOVE_SLEEP_TALK", "Sleep Talk"), + ("MOVE_HEAL_BELL", "Heal Bell"), + ("MOVE_RETURN", "Return"), + ("MOVE_PRESENT", "Present"), + ("MOVE_FRUSTRATION", "Frustration"), + ("MOVE_SAFEGUARD", "Safeguard"), + ("MOVE_PAIN_SPLIT", "Pain Split"), + ("MOVE_SACRED_FIRE", "Sacred Fire"), + ("MOVE_MAGNITUDE", "Magnitude"), + ("MOVE_DYNAMIC_PUNCH", "Dynamicpunch"), + ("MOVE_MEGAHORN", "Megahorn"), + ("MOVE_DRAGON_BREATH", "Dragonbreath"), + ("MOVE_BATON_PASS", "Baton Pass"), + ("MOVE_ENCORE", "Encore"), + ("MOVE_PURSUIT", "Pursuit"), + ("MOVE_RAPID_SPIN", "Rapid Spin"), + ("MOVE_SWEET_SCENT", "Sweet Scent"), + ("MOVE_IRON_TAIL", "Iron Tail"), + ("MOVE_METAL_CLAW", "Metal Claw"), + ("MOVE_VITAL_THROW", "Vital Throw"), + ("MOVE_MORNING_SUN", "Morning Sun"), + ("MOVE_SYNTHESIS", "Synthesis"), + ("MOVE_MOONLIGHT", "Moonlight"), + ("MOVE_HIDDEN_POWER", "Hidden Power"), + ("MOVE_CROSS_CHOP", "Cross Chop"), + ("MOVE_TWISTER", "Twister"), + ("MOVE_RAIN_DANCE", "Rain Dance"), + ("MOVE_SUNNY_DAY", "Sunny Day"), + ("MOVE_CRUNCH", "Crunch"), + ("MOVE_MIRROR_COAT", "Mirror Coat"), + ("MOVE_PSYCH_UP", "Psych Up"), + ("MOVE_EXTREME_SPEED", "Extremespeed"), + ("MOVE_ANCIENT_POWER", "Ancientpower"), + ("MOVE_SHADOW_BALL", "Shadow Ball"), + ("MOVE_FUTURE_SIGHT", "Future Sight"), + ("MOVE_ROCK_SMASH", "Rock Smash"), + ("MOVE_WHIRLPOOL", "Whirlpool"), + ("MOVE_BEAT_UP", "Beat Up"), + ("MOVE_FAKE_OUT", "Fake Out"), + ("MOVE_UPROAR", "Uproar"), + ("MOVE_STOCKPILE", "Stockpile"), + ("MOVE_SPIT_UP", "Spit Up"), + ("MOVE_SWALLOW", "Swallow"), + ("MOVE_HEAT_WAVE", "Heat Wave"), + ("MOVE_HAIL", "Hail"), + ("MOVE_TORMENT", "Torment"), + ("MOVE_FLATTER", "Flatter"), + ("MOVE_WILL_O_WISP", "Will-O-Wisp"), + ("MOVE_MEMENTO", "Memento"), + ("MOVE_FACADE", "Facade"), + ("MOVE_FOCUS_PUNCH", "Focus Punch"), + ("MOVE_SMELLING_SALT", "Smellingsalt"), + ("MOVE_FOLLOW_ME", "Follow Me"), + ("MOVE_NATURE_POWER", "Nature Power"), + ("MOVE_CHARGE", "Charge"), + ("MOVE_TAUNT", "Taunt"), + ("MOVE_HELPING_HAND", "Helping Hand"), + ("MOVE_TRICK", "Trick"), + ("MOVE_ROLE_PLAY", "Role Play"), + ("MOVE_WISH", "Wish"), + ("MOVE_ASSIST", "Assist"), + ("MOVE_INGRAIN", "Ingrain"), + ("MOVE_SUPERPOWER", "Superpower"), + ("MOVE_MAGIC_COAT", "Magic Coat"), + ("MOVE_RECYCLE", "Recycle"), + ("MOVE_REVENGE", "Revenge"), + ("MOVE_BRICK_BREAK", "Brick Break"), + ("MOVE_YAWN", "Yawn"), + ("MOVE_KNOCK_OFF", "Knock Off"), + ("MOVE_ENDEAVOR", "Endeavor"), + ("MOVE_ERUPTION", "Eruption"), + ("MOVE_SKILL_SWAP", "Skill Swap"), + ("MOVE_IMPRISON", "Imprison"), + ("MOVE_REFRESH", "Refresh"), + ("MOVE_GRUDGE", "Grudge"), + ("MOVE_SNATCH", "Snatch"), + ("MOVE_SECRET_POWER", "Secret Power"), + ("MOVE_DIVE", "Dive"), + ("MOVE_ARM_THRUST", "Arm Thrust"), + ("MOVE_CAMOUFLAGE", "Camouflage"), + ("MOVE_TAIL_GLOW", "Tail Glow"), + ("MOVE_LUSTER_PURGE", "Luster Purge"), + ("MOVE_MIST_BALL", "Mist Ball"), + ("MOVE_FEATHER_DANCE", "Featherdance"), + ("MOVE_TEETER_DANCE", "Teeter Dance"), + ("MOVE_BLAZE_KICK", "Blaze Kick"), + ("MOVE_MUD_SPORT", "Mud Sport"), + ("MOVE_ICE_BALL", "Ice Ball"), + ("MOVE_NEEDLE_ARM", "Needle Arm"), + ("MOVE_SLACK_OFF", "Slack Off"), + ("MOVE_HYPER_VOICE", "Hyper Voice"), + ("MOVE_POISON_FANG", "Poison Fang"), + ("MOVE_CRUSH_CLAW", "Crush Claw"), + ("MOVE_BLAST_BURN", "Blast Burn"), + ("MOVE_HYDRO_CANNON", "Hydro Cannon"), + ("MOVE_METEOR_MASH", "Meteor Mash"), + ("MOVE_ASTONISH", "Astonish"), + ("MOVE_WEATHER_BALL", "Weather Ball"), + ("MOVE_AROMATHERAPY", "Aromatherapy"), + ("MOVE_FAKE_TEARS", "Fake Tears"), + ("MOVE_AIR_CUTTER", "Air Cutter"), + ("MOVE_OVERHEAT", "Overheat"), + ("MOVE_ODOR_SLEUTH", "Odor Sleuth"), + ("MOVE_ROCK_TOMB", "Rock Tomb"), + ("MOVE_SILVER_WIND", "Silver Wind"), + ("MOVE_METAL_SOUND", "Metal Sound"), + ("MOVE_GRASS_WHISTLE", "Grasswhistle"), + ("MOVE_TICKLE", "Tickle"), + ("MOVE_COSMIC_POWER", "Cosmic Power"), + ("MOVE_WATER_SPOUT", "Water Spout"), + ("MOVE_SIGNAL_BEAM", "Signal Beam"), + ("MOVE_SHADOW_PUNCH", "Shadow Punch"), + ("MOVE_EXTRASENSORY", "Extrasensory"), + ("MOVE_SKY_UPPERCUT", "Sky Uppercut"), + ("MOVE_SAND_TOMB", "Sand Tomb"), + ("MOVE_SHEER_COLD", "Sheer Cold"), + ("MOVE_MUDDY_WATER", "Muddy Water"), + ("MOVE_BULLET_SEED", "Bullet Seed"), + ("MOVE_AERIAL_ACE", "Aerial Ace"), + ("MOVE_ICICLE_SPEAR", "Icicle Spear"), + ("MOVE_IRON_DEFENSE", "Iron Defense"), + ("MOVE_BLOCK", "Block"), + ("MOVE_HOWL", "Howl"), + ("MOVE_DRAGON_CLAW", "Dragon Claw"), + ("MOVE_FRENZY_PLANT", "Frenzy Plant"), + ("MOVE_BULK_UP", "Bulk Up"), + ("MOVE_BOUNCE", "Bounce"), + ("MOVE_MUD_SHOT", "Mud Shot"), + ("MOVE_POISON_TAIL", "Poison Tail"), + ("MOVE_COVET", "Covet"), + ("MOVE_VOLT_TACKLE", "Volt Tackle"), + ("MOVE_MAGICAL_LEAF", "Magical Leaf"), + ("MOVE_WATER_SPORT", "Water Sport"), + ("MOVE_CALM_MIND", "Calm Mind"), + ("MOVE_LEAF_BLADE", "Leaf Blade"), + ("MOVE_DRAGON_DANCE", "Dragon Dance"), + ("MOVE_ROCK_BLAST", "Rock Blast"), + ("MOVE_SHOCK_WAVE", "Shock Wave"), + ("MOVE_WATER_PULSE", "Water Pulse"), + ("MOVE_DOOM_DESIRE", "Doom Desire"), + ("MOVE_PSYCHO_BOOST", "Psycho Boost"), + ]} # Create warp map for warp, destination in extracted_data["warps"].items(): @@ -975,21 +1409,56 @@ def _init() -> None: # Create trainer data for i, trainer_json in enumerate(extracted_data["trainers"]): party_json = trainer_json["party"] - pokemon_data_type = _str_to_pokemon_data_type(trainer_json["pokemon_data_type"]) + pokemon_data_type = _str_to_pokemon_data_type(trainer_json["data_type"]) data.trainers.append(TrainerData( i, TrainerPartyData( [TrainerPokemonData( p["species"], p["level"], - (p["moves"][0], p["moves"][1], p["moves"][2], p["moves"][3]) + (p["moves"][0], p["moves"][1], p["moves"][2], p["moves"][3]) if "moves" in p else None ) for p in party_json], pokemon_data_type, - trainer_json["party_rom_address"] + trainer_json["party_address"] ), - trainer_json["rom_address"], - trainer_json["battle_script_rom_address"] + trainer_json["address"], + trainer_json["script_address"] )) +data = PokemonEmeraldData() _init() + +LEGENDARY_POKEMON = frozenset([data.constants[species] for species in [ + "SPECIES_ARTICUNO", + "SPECIES_ZAPDOS", + "SPECIES_MOLTRES", + "SPECIES_MEWTWO", + "SPECIES_MEW", + "SPECIES_RAIKOU", + "SPECIES_ENTEI", + "SPECIES_SUICUNE", + "SPECIES_LUGIA", + "SPECIES_HO_OH", + "SPECIES_CELEBI", + "SPECIES_REGIROCK", + "SPECIES_REGICE", + "SPECIES_REGISTEEL", + "SPECIES_LATIAS", + "SPECIES_LATIOS", + "SPECIES_KYOGRE", + "SPECIES_GROUDON", + "SPECIES_RAYQUAZA", + "SPECIES_JIRACHI", + "SPECIES_DEOXYS", +]]) +"""Species IDs of legendary pokemon""" + +UNEVOLVED_POKEMON = frozenset({ + species.species_id + for species in data.species.values() + if len(species.evolutions) > 0 +}) +"""Species IDs of pokemon which have further evolution stages in the vanilla game""" + +NATIONAL_ID_TO_SPECIES_ID = {species.national_dex_number: i for i, species in data.species.items()} diff --git a/worlds/pokemon_emerald/data/base_patch.bsdiff4 b/worlds/pokemon_emerald/data/base_patch.bsdiff4 index c1843904a9caa81d52b766eb7056bf6e1bbc6546..0da226f617f6fd7d235c98c85b47767240514ccf 100644 GIT binary patch literal 243175 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%0DUCS6yUV%C+ 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

9ejY2o zb_cZ8`Ax=PHocqqj}Ot^eN6OCC1Qd5dr!<@MU=K%k7<^?fh{V~Y`DTVLa$fa z^pSvT&McO>YiKC%_@&Br!Q?Nc$i$;+zeDx#rizM8=Zgd=tA`BLmQz!kuR1=i-!x zvd|zs69U}l6Mbb8dgv%bSTK++n1T&sfN&?vLfzw_VBtAp(!@NoAM-K-rj_Jm9`jmOKk9cB11*@Y`*)NzlnoqnUKFMb*l zcZSSwrf3o_!ON|4SA(_1|9>Z`{9Rn(nmni+qhmE#9@G=liP@LTlA4wns>1+HBO24n@QYZa=I7S)noueC*%IWvia`!;* z^^jD=26yMO_5WtL2Z&p;qTMoiiDczscNA_I3iKVS{6xQ!zqL-IbsVOGrbA8$7m5!d zhf~W?I_3(7D>5Kuy7F3rg;U2X+b5?h=)vxw-+7%m%{v(p@F8HiEy=A*TBV0iH9DuG zr3og2XS#Tq4iAXT*rXUh)QKSTpqd~Cq!V{ah5IlM1BFVT79bd+{OGDKNGc}g6uYpg zRaKy(sjjuU^`%2cPb!Z@>wKL(pbq&rCma~1UIqke4TakzMIxxDrFciVmp(J`y6IHbqI!gN=Usk zVH2-!(kMlin2Pn2Jl``Yi!36NF|Voh^lzOCCJzJy`#wAy__=S#H!4q~o=nR=HlGJ7 z68$!Mdvtpe9;D5 zfmJgO+8=r5aNcBbaISXsuhD-ifwN?^$rtf4loAI*B6%9Rz75B9i!__9AED5~#~NYG zhAjQYEO?exb-zZ{56_FK1ZSs51dbpXrg58YS-&nDrbU83Qz|o|BC0Qt&rN}qps7+w zM2GHa6O0IqOOi0;IZxk3dH()98B}kIDrD`)xs}4a)<-jCx9USEecd+4vrbM9jmIIC zI1}k;)gZ&pg}8dX?QiTr2W#8byY!k)S0c8O``5F_=s(P_Ou_>;B)gb~Y;|v|Mq|N& zjYgaXpU~r*8soI%k_A@$ozznyPmX|QFge%-T&cinj4;*#-uj5xB4`N{4*;$P-W1bc zozDj8G5>oc7x<{PZQ~=K|Ln>0|(`KM)3<(rE3lTpd0x9VFwwag3 zYsAxCDAjz`Kdt-h{E7Cz131CU0KYmBKa~P|sd?lNVh-3tqXavMhy4*a5JBovNQGg|2Z__b7!L-B1=?JmF|ua79EDsR6iUV|>`Xk~ZIu=g zxnd2=8}}Nk=g_y$NPEXv=5c%K`dV1m{d*FO#6?(3Ij-Hot`Dm|p#~i0fv00(l5 zCT&_PVvU@7dUto+8Vy)JtX<6p7Sp$8)dLg-{9Z{)@@79iu7Rv~d@DRIzK#zI9{WzK zi?5UgEk*|QC5;WcuhX#WtaCesaOA3S;v5^yrHBL2A)1*4TWVn8q}99?+iPN`+!9%( znnCb=Ob-GO1Ak>{eXu>jMOmP?*b4hbf?bd{~(#5%k#luc{QaQT2BTg72>kDPJ!E{wE*}zCz z?f6tRRjNS|D~4m5037OWE29n=O9{58wrD}W+Vu2(^*3NUh`$vGm9K8zKFrr&qMhEW z>gaj)(F2a8leHO=VFL;%WK})u8hDwYZK9;^xhc>PH7IAhi>6Q%1qvC+^BDS==~oyP z-MSPr9f|@NAgAdb2E%2XiZmGaOkrEq|4OyqF{P+GhD0--23t3g=0?O9W>pm*-YX@g4L>R&^(x6Ojy11Cb8S9WcNBQ*Q?Q z?(Fh!1TYMM{MJw@E{lqxL0AF4ys1$j5BOqZ)^2Jba32mbWn!tb!7yyAANFn^Q5ZoiFlbEGV#dEPE zI~zuoIxS6OWAi(nwf(;5f5+W9*nO=R94JT+0wR(Kyh0fuhO_~sWM$BwHeHiwXWyc1 zLAtvblAhFlmFu;^pivP!3%JCU4b)~p`ukD9AAHcnQ41*PNiUAZI|I{Ve9ZjvgQ?RA zRyD6urUvD7UNe3wQrGq4z-}zm9+LH8nRC4i$9AtZntn`qr&m*Z7|y2{-t06kV+lm{ zG;dhlTy2Y?9{K-=|7s2+`q3U?slZV}nwYTAnVo;ez+a<}_S!e2gtCwL?y6?TfS;}wT zFR<%k(4yM1Fzr#TTNSdjzk#^VFHq)AJcY58+gyrk+p^oNEylo91?0qm`cM13FDdNf zY=5e&w{9-Hr6d-yfM!HR#abe9=}mD*aRqKq$Vf#Kiw|}oo7m(O9FIeg>l-bULNB%P*k&c5M^FJFCVU71f_EIkN8Azd< zLDauJ;wZn?_$d%+1ZTsLi|Iv_Z{)fMVjQZeY;4H+Ax+(baz3F5{=BeB`Mg`6xo$J? zwX<@eiiJRa>+1$7{PuvE=(rmfLcUE>wA5OKYar|Yd$rGgXXPg4XQ-m14`$6+WA5=X z6v-a;M$HX%7d3K5YI3MYwPM95mV-t;O~#eSSy@Nnkkc|)I5sN_0lCAtSqj!Z6t{&W z@}*^k6wb)4xMx$zfhf1})9RvGN~{tJVzdY&Lr1&Mxh16{3*2lM7obz@PRooV5dLsP zBBt1e4f7>NH+T=ETA0$F|LSi;>4ucDL>H5@7j{%juR79^r>>5sOb@SjE;=BM{R%v2 zp4JNMfALR7Ba0nP@sEvi+N2CHH=S1V0+=*Rpq*3XKaIYFHBwMWXhsG;_bQV*X-!CP z=b0AKb#V9`%e5vEyps(p8dFvwHUsoYsCJ9_q(-3$YvQ8GZSN$VSvRh zND+%82kf~i!V=0p}mH-<7)d?uoI8Zll*6k4X+brw{`~P zr{HYoHJLlbRUaoCxbAgYZSnc2_~ty-3${DQ<-7|_d09l2`GQ!_9y{6Nm5twHTc&?U zD0>)qqgmOEi$zQz2%*RmaPg`;vD4(d!U?Mt?>EI{i!Pwe63`te2LFk5cD<>?;caZ| z>2c|x<8LGB+q_}f@8I`;xK$A#qMbaxA;wk}I)6b@xm*4P%;s^e{D`0!vg_^Z)#>^% z>%};eZyCb1KvQmbjz?b99*K$dP@H{3>mL#8Y6GTa6`0(yR5-?Caib7=rUzyy9(>25 zgS!?pLKk0?88e!FWp1F6Ikh;C)zbC)#$GRjtEZo116piKoZS}Z-0H+Rb7v)I-|1RK zQ~QtxqA%pZ$snJ_fdk>f_@oa$bs_z?bM7?%4*oUxFhk0SZ~PiZYJT5!LT}-@x#f4g zJ|8C#SL9Idp}!!cdI(YMPqQ!}`sKG&bMbz(GH~Ln-|Kq~C*6^P=ivT6zox<-ho{%Y zf>IA(8HQ_Zr(06~PccAY4s>to#!O4DS5h@GDm3hSK8@{((TT&jjqhzx!!IYmkWt z%~$^aR$*tl^u9`6Nv{zOrHL}v=2%EzH|{gFkajq zFBY6p+W%cA5A5pM4<0CgItF>biX2aOG`hVR!=3z?fHY=XhzM^9jx3K$t9;262T;-9 zoVXw{1w*`OXG7?AmS;z5GxQUu{VeJ*(rlS(d{d8%q43c~YqHb))pZq8)e6hvHrUji z-ru^lK)Y%5?Jqo2=&r}~uAr+x-2H3h+Nvnq$=gYx4m^zwnggjV5%~7absVU~Ec(@5vy*LZcU0&l%UTJs z^$+e_>|oN=c)zgS&0582QbI3zvVg@8`-Oo&W?MwTQe z^goi!U^n5P@cUBT{AcdrzpGuF9ohTaVk%V4uLN}HyZkLD4HWA|ewU2P6#r2q2&NeT zEtwDkVUYflx?y33cC5G@75bd1FrGZtl{C7lQM_{OztT8Tc1Uj0_s8 zKc&ZA`Zx(_pdEuG(J|8X^D5&oz83dkE*ivxASvAAW-=3{F<_7LI37@K@rx?M#CId`Cd~ZWlteR(8F@bdG57APxW}ew8Cho zr3=@M$&zq2H+bf|pUC%9%Je8)Q%f@xj-+i*hOcVPb`-X{H8Yw>^DUzXISusi(j~@< zk)F<9;qz9Nul*^8%05N|!fM-#w~C+aeE2_YUsf`7_+4hB|Lk@i$e`IY>@u|-mhmiZ zdwT6FjwJgm7MZNcwOtu@vLLfN1JZ}3kh7EDK5|2532ojZ3L;p@h%8|TtjbfDx7vuh z@DB1DL-uTKe!{=fVp5RqQ?B9Wt~4&vP3<&KF~2r)?Pvo!m~@yTx0gbtmDi1ch-Oi$ zrgFytN!W1^fJHY`;4#A`~T%#-Cxk=dD>@75zT^+eGl<^zjI_#Tu5 z4(@38#W#DkhDWE3~d+>@D2H1#B6pNA_hG(!XW{e@sKhJ=Pw%`)B`z!09s=GO#3X$ zR|X-HGNdRYs}V9m67L$(u219MJ#|RtPV` zg+HhIJQPFYNAka+h(GGV+<`w1QTZ~5`zP~Yf!2Vi@1VN761bJdnXjU+uP)+)eF^FX zA2`f?HuCwEQ5^XgT?l{Xs8VCnv=w+j_XzWyKcr&`Lm1> z-hLZ*GLc1lKUs(5e_?*!dr#s%#Q!t)s>GBeg60u4_lo^Qf*qqNMowKq<{DB6!J1`z zvL@cYZIN+#iPg_o^WS!UMSV$joph#4QTCx|YtdZ@BH z-&~4#`Mg^$8#Rh#+mzZB`P65;T&RiN@a!C)D+k<9G@K*j$)Z1R9a_deZyCKfQr{~r zz0KONlO#9SrlbypKlJZFNlW+#>6%bR~{zpK>u_AxqpN5xWJYVciW?>3%U9< zuDhy_=QTINI|?GhGJ)x$YbYNIIef(t7uqr(35#Y!7Pl2R(Zny4mbA+QTeNts_2~9< zWG^V$Z?5vmR=hQq7FmA^IzW-t+(WBrw#~P2-^n9F-z_7lm5GO z=FReQ9(uk77+MQqY`G^iNQogW`u&$U(Iy1S{cF_2&cOE>Xju5yidSpkIg#F8#A&6w zH28n8<&|ryv{*ZR$5>z6{iT0F)#|Pjnt9eU54(2_Jdf0{LT}l@`|nmZMp+H?ND$qu&h*RyGY zzld zFbHWGy7{n$0w2S10c5P0RVp!U^tASrmgmn1ZtYnQtSLS)ENjW&XiKfVk`6lXgIZaZ zmBHun??V5_lm9L+^Ljgld;lloXLR*z{-rxjN6mJgkI9K<6viNlH!Wec6;^KFw}*L7 zTGe4?`Y^;p{%tE$f>xyE@2c2kpgC5@7eISCc|mUtLbCr{v#jz zB!mdNh6lqQ-}G2tv~1l$r1W9bn&%iN7~|QDZ~gKz$Ok{gCy_KuZ6qsM?;(WtcIl8_AlgbpwMFYaaMgjJ@zgJ^+Tpm zsytYR_Sb)k?37cY2hgfaxpr#FAIQH^7U@M;9p`6cs(d6ZiM?O zQ00Z`lwXG^KCGad zRDz$Gs_G{@SB$JKDLS2flTs;^`bb}Fufck5P}-Jf*z5dt`|l4dSD%$P72wP9s;8j+ zBidn|_3~NPXhr_oj4EhXAVD2_>|imc2qKhl4y0qs-*yEka4!o56~0s&yTPf|;8l0s zde+rD4to$QyON`K;hJm^o}BDw@wlAE1y2H|O;Eb-LD%U@HutcAd6Wlg)XwI|F%$CT zGB-kZqkrOJbKB#p9F9-5#Rtrgf4qR}hxfl9A05dJdGd?XDa|X!UWiAR6b8{$4DeG8 ztkT%x&v{9ke_Pu%BBgy*|6KbpA?g`)A2G(i%}*JQx$GC|#y(`89K_CHjY49k3XZuN zW#DQ9#TxI}U*+@EzKO@OVzVGYM`;y)selJb=xhLx`Tdg<&nWICf=K`*CNgp6AanGa zPH;}raSxPZ^jXDB7=hVOyrO(&Lz_9kwo?c{mVB;U1%na}sfavXB$HxmDMv2SKu#zS zt>gAZ!J;xxE-C(1@2DY8o9l>(3jQPV8>=aktKHk6MuFu?BukASOB1eu&4-D?W$YUU zoLyBaT zvfch9SkSbn{&{0Y{dw?j@H3WAoMZt?{Yax~mnCpYFlI(%G2`DyRzdkY&uyZGe1N&s z_{?BEQc{zGCbige`upewNXSv8jYQhQUBj$k%+3j!l1&WXB0;u%aD0rIWES*suK$V5 z5pqPue}_4F2GP~(`}@8{dynDFk!OiSDBDl}+12@N^`yP-t^^YxO_^z(Wll=~(qcNK zq=>JKfG-9k!YR5-O%>m+2IXo7y3*B1AFo(Z@afe zftLPX#!#ZeiSGy}j{tz=P<$Tm4Yub^yV53HfE!=X+oK~{MV*sD_&>Z|@2Hgz3WUyJ zWDo6cCztB)b!Sb^`!wCLufi)q?{h1+rZ;kACE+mh&AdDINi{8=N>@~d2OrJaTRHEV z@r!bo4rqIMld<34fc}q>aaW2(n?G&1bl@h-^c$B?Iu_kk^!Bsqp>vJkv?}cQ!&0>fP?Zy@(9U`Z#gJhuc$*tli6^ z6<<4iwfMiKQF>spHMX@MRPE+>3m}TVd6(4nc+EkbNB4#U%unp9gEPt!Q|lf5`kDdr zXup>I_n+u*A6Wda8TdFqnA!gUIB-`8Lh2FWM$rU6+aEXY=>+#tMetw=jvqcInLZg* za5Xqy6~p6d*MA3>j5f1eaUpfNb`+Qy^N>Q}i6%w1aEys2vwQ<;fTGP`O@0~uS&pQ_ z>pfmZ2hP40JtC9$x%FYlf4J+clk?@B2F-rApPld^Pcfm0D0AT8sgC`08Q{&j6q}i~ zGmFKcb9X&-hxL;$M*Tm;^sZbl^>N#@>W2@d)pfVnmoVDUu?7^pe8g{={|}2>c=%w9 zq}gUFutUlV|5Gq%R$ZVNGS@qx*f3u16x871UsStEcu`2qPcV=ZjY%puAe_(WX_fGq zZZkqg&sB;>WwDqmf}55&A9YEtWgFH~U^ah8r~SYDzAf5xL{$pQY~HUOg_5Pw0M;`x zz(7HoR=Az|kT@slJvLV+*Y95TS{FxE8wVud7+dvjew`?*$;#^A92?B{hxD~P_G;kV zYL!pJ3)}kYg-shz+Q5*uW(+%fD{SV=VQwUGeFIq6Vp*iHi~yq`S^q%VPu+y9k$6F{ zxH@Q~_q*A@pObZll81(hiZ3;V-?>9*E0+)=ApTenD2PS|xMvKs9_v+AoBE!kjgwr{ zkHzgjZEtmN?s(}4eX9=0(qT>JJ;Q55Od|THeq?aedXGjc)N%)OE+U8qU%EfI6ksc| z&qHv47&-4$8nY^&T?)w{ar|r$yCwjEh?pdHVe6YB3aEtyEkExV_{JuCZadI|@gz}7 zoeOJ;pc?>4`rep$9#xWAK~5|nUDT5U)GXgjuWtdD=lt@vBrl%Y^V^Gsp=J97bZj?y zVti$HvGqSSZ8Ivt5KV^0v@yEPCWF`ENWrcOzdgB^P>q*oNeGIQFllcd5vgyZ&{{)JN+0z2;hYS*i_hX^;9n^lK+YG3Aj#UWfvucNCF>kuH-b&O&ILuz@p{WgE1Si)2J|Wgq=txaVpIfp5a8pY=m!2MX~8`B zrdT3zBCghcHj9Nj`LQ-{nn&U_I{nku>)=P%Hz%$f-*YXIS^TxePS?EMym&jzvdYU1%>d<4R~MvI^M%BOTCD5j+Gn^E!NnMq!Xvh%qM0Y$|9gT<7DpbV1Imp+q}T9`>y|7Z8A)AQq=3kd&sGhe5fH%#Br$Kac;4^Pn+(j&7M$g zie`$G*ZaT0VY(MiU0T?=eXV}};Pl#%*+TWMrp`jRLE>c|QU@ZQ9(vPg*FTooRZW=y zJn>g0uHU#8gQ&>?f-~uOSYox#MFX_j2V>@LZfC1SQxRaZ;p6h}ezrkvrED29LB)qb zmabX3#%4A}BijA&U&h71oq_S9i`arb6cjdb`a5|238|@{g)ZOZ4OnN4q$hxXej)~Y zwRs9Si~*m@lo(zUN{ktpO@(|{)k7A5-S{&H?O?tWqsh+*GIkW3eZw3C0 z|E32&V`muu%!Q_%Ys@s2YB$LtQv9YTNT4Ag!N90ZAcA()U>-^qtW*X9ZvU-I2TBP+ zx{}|R3Tb2nt`LSWyv$#h!Dl6s5vI75n4pLV%!r9<I$@e(A_NY1l z_;o8%t+B%Qe2z)E`F| z7DmKI^dWPZRqFUs9jzL%_ci){IGmqLWd=Qx`@I#ht!q$ZtHwi?P;x<2o!X-KVH{Sq zvO-mT?pt4S533g}5WW;VGAH0jf$`*DgD3fLy%41+d^x>nL`e^;Sp*m`3k<p zfo#}1Q(BKt-cO2+DO?BTJMiAkPXa779}Aa${Tr{apGPKV_^(A64bE;iK7E}FEhVm7 zZR)y-esVNF+3M_zR{1%<^4-$)tnr$)Rt@w{wtx7fY_a^*>G!DP@3nn+jxM}BC8MSi z*;1iEi-XOLdjo|YS>tsgX>fQ^IbZdWBNuYk?i9RR9)uIB8n$ z)F19&4i$>pALC2yVe&t>-us=7zw!Avy{Zsnf0LOHi5ghZ^zD#H=9s;~L74IndT?MM z$7_<3=A{9~w2}lZI{x3QN*^0qgbxBZhEiY^dsPJuqA>D;OvPZI218G1g0Xm@+$UymBoHz7z`1l8V zao3)u*!qbf&pp4T{q_NMmI9-Q@{tv4X(BSFzpa)_?EwH(nKX6(E4c^Fa$h60p7AmBDSrG0=lA|pI&s`;m+Yz``jC7a=cs-- zgA1!|NezB+i#yMt_*E&-;nIz5h`&+@_A-{p`IG)-xme0n|I5Fu<%&)yIZ8;q{uloz zo!@vj`^@J`eiM-e^3o(Q??s#|R^L(>&W-GUET|9VI558>d+c7(wN52w+__q>EsJOI zS+nuuMhnkPSkC%Q$vPIz@9xuqw*`9H7`5%x9@4KQuzh2d|9G!CLT3h+u8aw2icxoj z#6HY5?d4z4oxO=`K14zDe{S|)RzzqLx4!m*{C`tPEv{96|<9KG?`hRnWSyL{#Dt4q%R4yFAjg5#F;6wa4c3c^;6);Ax6T)3o@j6P*Ze-j= zp?|VYZhYCVu;=bnpw%sNz`Z&+OC>wD_OFz-#umg?s?I8HT|@}7YNDQov|cfRjIJL)W-Gj`lfhjQq^gj2&4&0Td1+wN9l zTv>EJoA@`(ZQfFl#J>XUKnLqk#G3% z`}=V~Yz%%wA{NE(F8*W>WH~42bx~-@bwBmX`hV4rgvQ1S0eZ*r{a?_7>8<<+DE1G8 zU~`_m;CRac$36}`;GTvhdYX1}Jdc0e&im~7xAC7kf928p-D7;;H1kq5w)texQCUJ5#kDUd7InnSWL*J~J{zWe<_T+UTN23q9BhsV# z%MG|hKut0RL*)*gA?wm7Z#_C+BZ?*3rd#0ET8&sziqwMqBCm%t0JiRk21C}rNGq=h zN3TW*m;A{SPkvz({JD&r+ewwnmmq|~D~62WE-ry#QnPcB>2RTpEPJyAS@L;r0bSzB zs<#V0av}pG2YqaT5Rjb0p_=XhpG;Lj5W@o@m&P)%&tCCpTAG%rb*|vyNWrN#u9Nk=_sWb4Fr>GEJP~4jT`|DmwT8J-z$?rL zBb++gRYv9xb$|e!1@#3e03?WK*jno%a1dfyA)TBsUcOmyNE{x&0u(93gvfEr&vp#> zPwpMu$??7y@ZT*G1%U=d^l>$XOYD$?7Kp z-xnU>8gT0m@i@m`RWd8kUKF@DxQ@C)kSzNJn}aGojkFTwh$CivG~BAty%d8b#qnSc zD$}LpY$uHqd?)}cXzbZV?4(`aafNyqt4^~DC>C&3wFXx6lv#zTe6 zu)gdF_v;I@b8EZr=3kCe`VwPU`kg7iN}!1fw2I)evonHzhV$F8qee~kYz1c8)|hoC z&*DjsgYY#UgH`1W`K^zWi=%na%ua->V}}En{P-4lla8S`!1$R`RjropmV8+A2VB_2 zK!-neA7HnLxGm-|DDxoPwT2G4f!60wAS6 z`4jlQH&XThs>i_!))nLmxYg_so16At@Hu>cij{M6Xl zv;>K(Vv!k<rAGxtC5esf_BjiNFaqS9<96heK@h^=2=WF9K#~nWPU6O!T4T%yGsc^BW-YU^ zNqp>vJ1&so#nyJh#p7e6Ce)#B#Yps`;5TzxHl4O5L2h?}_dyLf=#XRu<@1a`4Suu> zP|?l0=57Tnnx1o4wDMsHKn^*`%cDB+tD0=L#Db=Y%vQV02I^1z>KHXA}hzxZlSc&jj_L6 zgc?YBcyB3l;+ayB6(n8z__OEo7oc!75q(9V(xCOwHyG(*6^30uKjkQS`cFZZ#z4_f zLIuA6SwnrMJA`(eT4q8qvSS?crIIQ$L9rr=^d+E(P%*&f_va{A%!wY7z*{hL(Rm-j zm17PpRRSlBN(Nb5T@;Wi5RgDZgTq2ZEffGto|lgDMCMnMX<$M|`a)zdjtRq(hHfAg zXae~nJ(f}kw2Urz`6vV_817Brq!c3=7o2469Rn+d3nQl$BnkWIshnekU@m7l9`VyK z1v4O6wl^E7u@>f~Na_V#z>I#5A^-$C&LZ^Znuf;RIba@K=GAs*t+`Fn=j5bwz}$j( zk>5Zw#NtB;oiYpSz~sexk$c#u4j!}~9KIT{46#Fh1lru7;m&LWlM&y++k*6_S;>F~ zh@o^}P8a8-3~&e7f#CWSAY_0!AOY|sL#hSofqby3xRF=Zl~diwi{U{~>cLYi6+kjY zPyq+?AfJ2SSgU+8cqd_7ff`p51n}q+y9yOAz|Ovnd=~1qrbhpQ?ZJEJ;%(yBz>fZ9 z1*GNhqriLOVFafrXS@>?2$4T~DTy;EdY+l`c1zORHlh|~TM&;_$V{Y;6#!lEO9TwC z#vRDT#-l1Yp-n&zC2_$$o{LNA{n?0+;DCWZSO6Ts+eZWRqH=zAHQ9=!qU4W*_O?8x{8m~r7nOgvXwANMRkG} zxS!?BTlziC)tCePL;ojDIsM<>4ff_9HtUVp#fG+hj5P4YSy0sy=~jZs10sNbJqS*i zP>Td)i5M)MuU{*kI|75JfF$U4YOY} zMSxRPT?%BQC?N%gXtO`?;3+^ORVMA9H*@}tKqMf73jM-b@u=EBQ5zxCb?-MY9ZabI zckchqyCeE~E9J9>b|C8ifBuH#3FR1S#Dc{$A77F#fT1V$&4S?kqd-C;@f zw0z&Z_?vrp{^o2)#oeK5ASu7@C=op9ANIfy-BBV7>CW>e_YXK{>qnne+VZ!Zk0p|8 zSowZc@?l4Lo(dlUsgBogf#+jv=jPb&c3QG9*V!G$DHC&bkdExUu}jK#p!JtIjFdij z@yAv#rR=fH_WL8Be+FFP7yy)n`@u;7ju zd7+8OhZ$@4yI$5;J9mwvl|l;)ZEKh6-QtJ_IBMzg_*54Q=P#^_{Cg%0_R%x#Ue$g+ zv`tKM`hDK|#f_MFBt1*G@&*LaaAt?wfFpgZA(&-9>8&g*<^{p@atUuk7*@t98I%~( zMi-S!XUKS-61k^f zYvpw@@Ju8#uc9@x($G;D`h%jL$XxoYLGMJ*DElJbGa?Yjk(=!5idk1_@b!iBs8796 z0?x(=;Nxfv%hNGxPOl0sE>nKiNY9ZgBk5Ohvgk)iJVXb|?@fyvE(s9hw-`##mN$N& zi8iFN{O%NK08c=$zw}~BWN-C;M+#LiA!tpg9TB|Kfwv5nO#OZukclBFsi&3)jqhZu zU%i*ix#3SR^>p@i$CatFIU5OU)k0bPbPcF2vP1s{2IK?>&C`;8e1t8(P5u8XXRma9 z^yL98BVe|7wms}@9FhgVy&9hzZFS)q)xZ%uPv z0?)SsUPTIX4jesf%)Bc}rNn=gB@Iqu;|+0=5qtWn7#WH{Cr2jk524r3*=HR7XY5C! z!riA)sSfvT%wUh}S(`ykXG5bCu<020+|%i`Q%|$UuS5 z`ym~Sq3HY61zg?kCM`@moqSDnXBYQOoxiOEvAuhqIWFB>LBxI|_LgT^OhOd49`I!3 z5*ito-KAsU4v!b#%cSV}67aX+vXL(L1Z43yu~mi0k&FbTfLak+4q@-SrJ-VGRh}N* z$gO0&HpPL85DXZiznHdqem3s;@r*GB6qKZI@ZhB2q2DXlbA5~S!Hh~ERjIp~S8KmZ z4)3={`{DtLO^c94_!(alD08!MKO-8&^Q&OUEeJCDu<97{IkR$A&&!Q{dcrj_P-lv3 zZsOJIb9Z|Eur(@MguNH&THbtDeJ=jqD8O)LUV(8LOIXjXfu*VC(pe+@9r-LZ$B4z7yFos} z-5r*&YICrhr}ViTEn)?0Hvb1SMD{r_Z|#+>e0~eAdZ%+%_U1c+MmE%@;Wx#?`Wt#f zorURQ*S*Bq()0FH$Gi8KrNbOM`JTP-_Q#KBimoZ{&loCa5}lmcqtF%UJ+oyG@4Phz zjP4KY*R5PzNqTwkxA_3(+>E8S{0uonKxQlI&}n9-a{<*9>Z@0r>kG~9X?r-;S2fnD zwxEsNas*}p3P)bd?1dKY*4GP>R@8~(D<{R(%w5hsX8Cxljq2CQ6;;TCmw)v>uZb=- z2fq9sgqhp$W0_p(5(|}O7X~Zw@W6hV_1@tDbUx1!e zD=*{Xjho+<@uqii>L5`NuGk$r?U{jlb~+fh2QL}lJ;;ZI>UF*y znJa5GCR%uNsbt}zsdZ6^oL3_1mFv7~{mzs)SRE*IKL(^dZjFn;#cLkEb$_>tIeG zMtsJ$Xsc_p?#;DI6%YmN4$MSp%a~#o%6Jc5<-A+Ng!L^6_tf_9X9Jxk47yP|o8LPR z8v%^?7AQuQ10BhH|ETs9=o!^nx5Ii3kz4w=6A2M-v*hC1ii_GjMy%h@JqVO-K!YA` zHhp02Zhy;5OjKoD2R5|pPQ9q>d)TU|ggV?a#$ywV=6d+Fbi`;fv8q<< zNu0;h*@-#cE@ar3&++EvN}*XC#JVLS`_+$!Ib0F|@T^hZzxYTXe$fUYc71sxNACom;QP-Ii7D5+wZo$ z@BfLu<9O+TV&tWKZ(3@u^_uZrhlefRIfb_U`5$A5ESJ^1;wW)9wk-E}EAAl89JY|r zjc4QtUg(TkF?hGMJh8s#ao~KV=`lUr9F7mCpOL+f-oDCyvjWYda&5&LG~GkxvAo3d7Dq?#prpubHrsV0R11)iWCh76u43SWCGkn9OF`GZSuMUj6TeH#+G9~w@OGa4Z(zq>9Z z-_G{ziWpuYFDz!~2>?w$E^IL604O~~x}as|;rdotp+cEa!?h#WRb8+4d0Qedo(r%x zAi*u>YAZ88ei5^n#8!NC5Rzb`nGmqG?A7tW)OyeaFpPlH;AdRB<=cYb$qwK^L?dD@ zKH9g6VZB-@aonic@HIoVC|TX4FQ>=_B*+Nw10n-V5TB6-S(g5o(;zZH$p!A5#IdFY zyOk5Ck-)*oYi9b!45HD)@NL5ZdMw*5GsF2J&1c2{!^n%hGKNDJ$K>^MA@$~K(azrL z>U{c0%f*u%s=!-N9J1ZU-YpvvBiEl@_w5KUbvyfu0vF3_kyz4(pirA2V2kbtwNE}>mtJU* zRlMs_>Fm86;oH;V%6keJnfK%AMB$>W7?&UE*6a{n-_Yp zsmvVg8!}|)Lp;f3P}mTQ00tz6#OCCrBwuk|*@;SQVXaGkg22Yi$lo8*bOxrQ z{rl`&7nZiddbU(kuEeL(yEM2F~^%y`@6++E#Hy7$r`Fpc_Rr zM81wMZqUA+i2+(q#p%!CD@DpsE@?fZKXJ0J#rz(Jkrvn+>K7WFkb=*Fw%Z^^z@5^N z=1S$KGNj22sKl+zZ@*h*bBGbxd?H8*e@iOO;kmM9hAd zV+;GONW_m!Kzi|l6=%o@UkQowC$yJC1!s`9P+DD9-zobOWj$HjdEYOmHTcEf9z9qb zXJy@k6uUS&cKL9+3^tK*sabUT-0ET+T4*PRhLQl0S4LhEc~u-t+Vq;YnC`^64(B~P zsSu!5ydP`{dcN;Bim5h`{nO^)M6pEq3XN=X8n;4v&x-(1(#Sb>#O0RC=0e!+WoE6? z?Yh-^nm zCKGK=cBTHx*eCi}`yH+#*cABIbnQBAhto;k14-@-r-triwg2} zxB?eCA7^>OzAIO=c-)wcaNmOM?{im%xU))K^h^oYm*~H3JZ1=Q4x+koi6^mq&0}V8E;d00O|-5)~vHyE9q@auDb#O@11>NTga^y#kiAlBX})y zB|wi#V2L*9PhDK`~EHSyscXknC+J$=%@nO!r(v;CaLOGbs zwVG|x!1`994LX$7s_h0L9&^V0HWQ^62Hke6xy^2|=|e;Z+NB#Oi+J}6BrgO=GxeUy zX}k+U{}Y+D9m)+cH#>M@_PRos2O(<|Z(&h6y7a7cmWbUAHA`i|SJZ{8(a{HxXoNhkxhy#fx z7F}g;p=oNrhaJ<_ijBH5j7iAczo!ow=;>_|-je~01nb$A4u2LEOl|}&Oa_M`zV79$ zH3df8jZ${a8MEUXRVd4MrvRg`4&3goTf4ZK)=z3PSr~oO+RTBQ3sJr0`mW1FA2D(8 z*#eMnLY{opJMq89(uA%zKc7Q#EK|2R>(~L@9yE3aR6I^3b;xper~f$Lt<0Lzn0J)x_2g<^*rQWJYY$64#KEH)+E&~BTgGo!8}wJg7`R>b zYTiSnC^(48w#YaDAW)sCyD`c-1eaGS_-kePfAWYta~dwg@_AbP@BVV=Suj{1Q&-N0 ze14G+p0AD~sxp``4;7>ahbfOJzGuJhF8Fl8nDx!@gnzigzTzOR!{zOdf#wthFMRfai^qzvS!lHF%>t$M<-B&IZ_M zYVC)(ybkY`maye=w)x)SW=lk8FpGg%)XJ+YWlNDF>487A}hggVc;FS%e z3@umhw#G4DpkP+kF-O2NzxQoMFT98XOFKx=R<*s>fKA}<%?I5Y`m3~0$YpT3dFp5=fGQ?L2Q}#Tea?LB|8FK+8pYce$F(enXygf_OhxFDUe27YLL!0c zKfLw1IxWMtk+*h&;dRm|N?O-KF~+8o2cyK_dy_dFZS?9KB?LC+6EXN)@u|-Br;ZqI zJm4DX&)^1H_Wn&H8B@RRhyox0hZsl#IT3U4W(>9Q1em5WGc88BG>XZQ5D8HLJ98#^ z?x8;hIe=V@WS!tU{&q!pI_&7aY~#ihC2z{lA5=p=&Fza77sL^0PWU4~+OgUl{9K+t zCxP@c5Z9&XCy1aC=w9)MAdL82#Bcute@xb}u<^Mmzkzr%F-r50vTtva8X~2k)VD~6 z4B_eGbU@I&@*nJEFTw*Gldz6YAxdlIIxk2+B!J96G{E9%kqI=13*lN9i0J0TgCWQq zB~8y9DU0+dZ+RM(_z%m9CG1vVY&-;SMEF>j(b${J+A+Rxn&*o5o>6@Py%-MpOph}u z__MhxJU~R~hya>IBLedb2;26;0K%R_Iw73eq(lzP@+B1m;rzfY3(%MaYMrQ4W?hrZ z$bc)p_d|CEw|k4e9gu7OKJ^=($~S*nXANGzADQ6rZSQFyRfsix9h@jSY>^Dc$XQ!` z!J-Ssd6Pyq&%d#el8yOqHjWdy__)#iRsMG5P6-*G3(0SV;mAZ5wNaDUN?)?_HT!YB zy)A7DA1kdA3F<=b@i>KouUm>98?i;r&PYBSg9o}frYB?x+!fXeG%Q^c~^ayHWS3-1h0AsYmMhc!^z8qp`7yfz*?g4hblntK^r@}adJ0z zI6nWn-^}l=#_`t+{fX#KADI|W?nIN~r&w(8 zS!UFs7h{j9+x1QaT8JkY8M^Uo7TkCXu0y9-d7a#^bAemumdM=PFLAD9Q6Ny-+bG2f z{OQQ}tg)w{DG?}uEA8z$f&MPU8eXdx_ckxQX+s_+@>g%r{~zDJ$`m} zlMq;+Mag?t9}t5Qhe4VP+18Zbug$+HWFyKF&|_ z$_Roi7y=mv>_{28;>-y-#8Y3Gb^k*8dvEwQv|&F^77lmX{7?J8CscC0{TBb-@p%I% z_|Qcu)Yk(%LcA#FNO=5vV@a(~iH_*+zJA??eT`dHjPO1bxUWX~{ea$2gB~vbzn9*~ zg#&v*^q|)nSh^x;k*W(q&2gej@b~o{$(wPEQWTn{eV~Jc$f)`QvV>*(NRLUV)3^ZN667Xol9 zQL}-J^^=_P)_1rzp%_83U|SREVbg>dvevc-n=2y8T% zXJI*!3ug9I-iuJYwe|dsLgZTJ;^TVwccx)Hy}yn7%E^V3i*HKJAx~Qj4H);h^s;X0 zTf$nyg7+I`eVBKLslJ?^9Zwz4R%HB+%^VrJ9R4$Nj`wn=@}v^g@-niHmV;Tczweii zgYNOJd0E`by?@cushf?>a9q1ecM5APT^kr_-P%XTH=j58E%Vif?DxJ`Pm5~@0CL9% z3j+VyQD5Ls*fjCe>M?ecTt;|&OVRf62eE;~<9VzkMgH#doxU~nW-%_re(#;~cM-u4 zQ@V}5G1=#*yO#j3Ah3rqw%5mt!s2YPcNcZecbDq=_ICVh>-BLTF8@ON2cZH)sDAdR zMo?RKk}v4OWe6HIEOYaY3i;Mg;`&VrynYOf2@uDZDd=|E;x`;|d6{v?Z;M{Xtxjft zH@|y7N?_-HFOUOT9H)l@osO#r&q!ZkFL7Al%?{yyB+)dXr7;p-xCvEoeZpt=4Nc!waddn@%-4EGp{l`%;>-tYPQXR z*Q-cfxc!ZH-}p0OzSS8nPv6PH$mYk_)~)75ld%CXZzrp@Ckyie0-3ahSUD>EEM zmxFx*ZLNH60-~%Rbv8HSv2Vc_jq*8;`DgfeKFwcsXgECQp^Pb*0+Sd#e1B4-{?8{Y zceu+@p&7rYP4^n{YK*_Hwb)}O4V~Ur`+{@(jqqXOqXPu^+;_Ec@O@vEsO@bhH!ok) z=gXa9`ciY_Q1AL37;`k5*~e>L^X+?`e4hJy6FnM_rD-p|{j^>B-Ptu6&4!L`NE`+4 zzOFXap7YqXJ|){e)rERi_e?!EO#>ZSrWLrj7XKPubqHt9btl6FIzjV~oFU-?c6~5c0RI*V)+e8Q)IA!O3?GHYRd)Cq#w&Su(F6 z^Jq?4P$t#v^C^!qK783ctslnrI0G_-Y@aHJhtj@&AA{&km%XXHe`m|b@%xo{_mr3V zS@EDMk?lcCk(c~`qv8LbS5x8oo5}bey?cYnXudj-$?76D7U$R0?{hy>wTzwqw&#D= zx{37#ls<=vm|1V2TO$)lc(Fu^1S!`#c69(jXSioJawA# z`B0=O2&bcNny}8mR)5w^8@St6v zFDxC=Br{|mkHZ%Ig~j7-Bn3AOwyDASV>Fu3p_no+CHWZVVzv8X@0c$Ik8pYIjPJJv z!-<{orWR3xutJcVTQ4`d<{#DC;dtk?Uf)des z8+?xrm0yu*d%TxLPhx2}wk6D(#{NH`=p0P-sGo+|y7HuaIVOYLb*pk0K zho){9k5&?&JL6t~y$J*ImSfXANUN_i*Ih{aoKU}AXHU5X)afEr38ibVdY>uj2ROlB z7$GdcmSS_r@!x}{s8JeNMxgp1W)e~KT~!BGWaq4}qLetaL^zR{hk%Di$aAEP4(Dy{ z?$58-_xJ8~^zGdAysPx(gY!=kHRIsg zxc@55e(yJ}AI0*nZH7Q}7%ria7uX@>XAboH$_sLSWSgbeWd2PL?!XO*=wG&gA)5XZ zb?~nz-a$S`emwr=44*GDtr3{rXzrP}z{ZK+KU>pOx+{Gca0i*@>zW_@snM+dWKR65&BU8r+y|w-NRdXVE)2%DeoYg&lYw{5_qf)m5i-CJnnz7nS2tr-O!cxWbzA( zM|;47>hvi7cdlC#eR?}%fTQ5H)lrkLjOtOd-MCAE_W>d1s@MrygOcZY`&U; z=~&lFJi}UcKM-eZFW4Gmo@QozT(X<3Sh%K}LdguGlrvlnk9VbxxllFa4jGsO*S@(H z4U5X+?6AQRao4}hrq)vwn`L%K;fYEFH!$Cw-R1H@kdfODUXq10ayQnt;{GNh*4Wz> z0wTphCmULDIoz*0C)S7%BRXgqP?4F>VI<@m#DWt{x&Y_D@;4&8oVykJ_=ytT)pJwq zqBG^Pg4ans4VJBM)?2Ij0t5@6=dT_>fpcf6BuZp_VrQ_(Scgbx{GuNxrvm(B_Pc12 zOZMQ!91<}cuNdUsg2g;K<^h>bPEf!;NLE4vAKgCPPUaVl3%DHaVqcRXKkXIy^>hpj zFk`!CXTl;t%Fn-xv#tzlW#*wWZwQ3?&s&(bXt~-#0g=QP!?dyXMbikzbzX;Lgqx6f z98?XGXse$O%t86I#WUm!yHxOem38lO84)qX04Zhe<=ALGo7QwJ)9YnO9G~mx^vCt< zboxc<17FwrpE*Kq_vh|Z7GvWH)c8Ct{c@s2{mM{K5E2Noyw&1qN5=Nb)Glji0~q#J zNRj2WtFsIN&^@C73;iSw0t2UqgSJhmi$}rh(S>7w$f-s|k`!iE^Xf}hCH;-S*1r}04?>U~ zSns(`F$?MNtb?%*B6qZKYYqJCa|bt>nxLRiVT25BL5yLVS{%&17bG?>rWpDaa|)4Q z*eeEG%&@4+@@(OZJ~$+-p~|p_vEpOigjD1_DPLzQomS)469&NOe(tM{-( z-+P0+z&3#JpTJS9&Z^EE?C>?TtO7h6GVe#_M8xO${`!FV9o~gT)&=ExS^hq+6Sl_p zg)p;ePQTo~zn(?7Lt)06jv^2-v9;6^q*!WZVY|zijh*~F{~w(+iKeJkzhL_ElLcIbXwc)j+`7Ww-St}SD5RUEC^!dc8- zvKN_qA&mqVk9;J?4(E^rXs=-A&@qO zDcpEUtbEao9AUG*ES~+!>tG!$&~ZWnHw2rrdG&}2SYYMUAb?y0ARiF22wp9by$Lc2 za+9t*$cxV6>n%1w^r)DX-i@u~$(^1q-!QRtFfd5g&|2)|SUGd%^LGTI!`^K7QOMj% zPk@9Rny#|Ise zyxf51I)n+@Qnd4cWaauV5>#Xus{qfESM4f!{$|_-w&Y6AoH`MKD&;W(#X7*RAO^7o z(!2?*Em7+^l~Y$>c~$glh?zR41QWa$Z|STVj5xn1lFqNs_@AMJ>FjgZ>(vI1pU4&3 zgs|euy(J92nFMqA+BUVuK`&h9QoN$2xN3|k(}7j zl!$OpGmH!TpgJi7T=J-NVY;k+j%$mCi-sp{&e)I(r??n2-;ldQYUN6fiZ(!>@kC4S z&Dsb^gQY^C1peu$O$--Pdz)7Ek&M?=a4hN$l%Xg9fG}eN12P_4=o^gE6sppw!AQYA z$FTnd$DZHpRy@bZJ2s5`LCuf^c>!$-oS6>FGdYt^Lm3)pVZfUZ1&dOi0B9Ky5DbWg zMn(XWn>JGbPLPb(5N2jG47k0N5Ty=&Tqx;9EEo6f&phlr=)tPUwTG21e;-OM#H3yxNs}9GTG+tzvE{n+?v8*B@$wGn z8!<*SY>C$$CyoqHTM%+vl2jb$VliJgpP6(k-p;)Kyyv3{DA=tw+#!d3iZ|aq1?YZ) zGOpBe1{!5_qR*SzZ#$4QOuX#mMi$%0wqy z93b{YwPQlc(F^>F4&Gl$?sco=7mb)&TsRTnbvi;hSuy}-<7N%!L#vR*#z1D;3G=?n zsW#l52=yB>*8~=83tgFlyyXk30PdYvz1Owp>Gc#LiaIFZ02LF zv>|YeaI(=2wnmg;7a}%565NU@?Hb0TLF@&I;TZ_=8pqCUBA$(!V&1hUob|G|dTRCN$-t z_jubYF{FN0ueEXijI6Ep`(?UsY=$PR029hR%c`^tWL2!5agfZlm92`m3dPv>E^4qv zo4r78M5uR?py{j`UlKJx8@068iMn?t)Wl2*W>TXU9s1psP{Lx2Kik4WRT=rlKuL? zWf;OS8XL^&+_jZPO-S}$6PSeFRY*2jaXgC7QY|hKjd=(P!4cM=~AtCtQaaLsz0hGnG-0Jr~d+7!s&o+?6*8W!MuF zC#|^UNnv)Ut0F4y$#qEu5;84}PMk=Sx6LxajU34hcYL;bA2$c;ZtXnzf|6n}^rFSp z=j`|Q`odi&@7|A~{6BTo{0yRDi_2(^eXG}THgF~J@at=<8a zp$WCbSGQs9dADxd;nJcY5Z^+go!R*N^eQRrOyEh2lFx@qXAd&V)Yhn%qM^eIpkBzZ-Q|1d+uP~Cj^sWJORKFr8grZPujArbbUNs*bGH}PSV(5nPZuR|Y}UiM zI98KQgjr{Y+*lI_Cn7cUTga?C1pqUAXpfii#SzE)@@@dvG&y8 z(L*_=k2di++r9fTW-qSCVhm_#$A*Xvb<&Snxw!J`Wv8yU9k)*!-9ZL)iV~T< zizPe#elLyjuWepO!gf4J>!XlkH_wW+H!vkL8@9XV5@DJawf&Sj!MKw{T!n6M*0}%2 zUJZ5s@7HhQet*PIndrcjKcTXU$DEcytV zW2HZ_g~Q=qaVjK)BOnJv$bkUwhmQ__KHq40_UqqdRV}%&<)49!W}-;u&g%8hMs{fV z0N`h5Kn7=6+D{0O8!(eZG*!Ed%H2iB=p`OMVz9|spLVyKgknFC07|_zi~w}CUZ3J#1kg1d$PZ%;3If(GCm``idv;|G<=M;pfjK{+GU!ceU` zP~58mo|a}VLEeg47;?2UtzEb1R#d(%a_JxqudsZj&|GDJ=9<6efI6P~9N^eu@jQ~65)n}z@v$|O2R|Wc^pPHv-YU^u{V%ku zt-og4suQbimOt>Q-zg&)MZcpC+)D`Y;%C~2v@}mN8&TU+?-SfEI`dY6;+di|C#jal{P~2>~H+Oua#wn zJ|yezF=akX{$pI!`p0XLm$879*=hnMFh*sZA6^^=rAqp>)iIS@B>zF~MZZ@}v~hWF z1^BxrT>o>{?6Om4M8u3MjI&AfqH_{W@b>zJAZzrFkD)j|CmWZhqcfOmB?dDS4`X=`Zi-mPj`Y4vKy+gN9r6`+YMbk#JM_8O zJ!2M_T@)7EWza^U_hV5Ry%))3E8OCEE`9&XQFKygDJEg72e6dT!2Sc%LF;pr8o*xN z=Q|Vu3nzE%Co#-g@=k_(b2XNB}3G39)(myw;wr?^R9Jx?-_8>!PpCP=b`YHV! zUcdND0%4A)B%220Hyc*f?ItvP@L%=kz1+3;zq6_~tFl!g2!f~9G(Hw*lNtreq zKwiQ=s?zH!iT_E60cMdhb!Ey6=nNPy;DUi2Pd_Za9|CxlcY3@O6&M1Y#2q&v$o81W zfK5wp#q-_s8^W_Y00t!8dLbm~pv{i*6LAnb`IMBS2su_BCxXbRq&WUtP-&n!!9t$I z-(P-r=5ZN%l{fTsr^TNH^R)M5NiO)k63L}fC~^!qul?PBNiqiM<&52C1h z4s#lq`JXDkAHCpseYNoUxR~nL*DvbFz|a9A#=Z8LfjTOI&posNYA{WKgwoU{0f|!p zzgMyx56t`>+J%>morHX~0f^d{^vfQ9V_M(AWK$xdFIP6AGinw1|CfiV?@%0GAofB7 zbsVUD2KIU?2R?u{vlYkwnP2l@QZ?lw0h|OZvJM*3Q~5Vo2@pE%e~{bAIXcX{kJpC$ z9aU9Y$I-pDD^1)U<&5oeHf+yY?)+QVyDx&lJy2J*ZPwne}2Y(Z-(A zhx0f46E<7RVj15Uu)+i``UA$n(lNrs;ZTK7uE440prwC-0DifEno^stlgq*pjJzS+ z99u9$EXF%to9afMjVg)S1wv0+@6_4}uWYQLw^RXt5LdAj)f zIkB`QwAtCScv0E-{hhPg?@uF74H^cG~$;2kU6@ZqRel z_M%A$h9(dLE#vAhTgz_cBLIds?!mHQbU?#hLGzHPw;zQXLh(cyw<6!ILI*EaqSWKH z$W&;T)@tUVT;rhykm?Y>%c_^&uL_9~474 zArrxw_b%VTJ81=*|6HKzo4UY40-)VztW-VhQpfq$vH zVD0MBtEWVAIk#i@ab=C~J?*H(Vvkz&Ywl_lI5x{+9ZSCPV>LdjnjGfniusmy-dT_M z65v`M<@JROzQrs|8H$aj(?Az9Jw8;}{Lp5GMVl06_mIujRb-Fz`0j-(z6>tGtYlNU z$nZ3R5e<{}ji2ryL2NphZEk24FukLGH0UBk)DY{fGA8P3;5M|#9I7m(X!9o^G;J@P z#HlgoCm~qMl;!6BO${F~`>pbP z?(JCZ;LDY*G~AF|++A1ckwX?3QyqAxM?w&*#u1>2(lG zr5t5Th9q~V?`y2|DHCd}+Vz)TfVi=VIdPY>sM|3Oh9~e%%=q^DVyR(KP=hp5CMO@r|(t z=6a2<9X?XQ_aSUo!I!Z-ic}YBPh~pCtGX)S%^RuzCE7!sTBhU{iY3MMR> zVVNLEEan#&qq{ar698*{s9z{vm)kR^cwS+gs+d-sh*N>TG1kji?A@pNC^U zZLM~R>(Z3{m#4q!^w!T#HfX`MyVI?lJDlA}kmEV>n<=g=5`c@}k~XcHmI=o`JE~ zr}5|`5(Y`eI4d+02Bq?`SzKP3M7tXgO%LF-RAL}GMT-LkG*gh!q+(Ps<>o!fP2)U- zC;&;Kh_261LoO{510xod)n&!vKM2Hm%QFNJqF`WXwAZ7U&s)-)8r>)g3Ncv2Fa;a< zka-_(UN;K&B0S|p;3hO!=uZWS?eS5>_{ zZo_wrf{^Xm4lM1}$H|5>@-{&CIeqU%owhh;yK2=~WH9PREry{SZcYOqkUs@>+b=2T zpehQN#mMpD)`0=obE8zhgVAMkniI_If=VrZY@TG;YIu=CVH|(SG=|_S`ZqyK{nT-7BFS4=PPd{}zkD{~` zNcCz&mcC(#sX)V~<%O!W@nMM4oI!Yus2G!t=Xrmaz)`^Sd6_s{_va)9=}?&MIiDJ6*ON zC)Hyrhv#b%!8S?NIUA(V8D4KxL&te(2Eykg1?@#d7X7w-+}{2$u_Nnw_k zmmp*xyoSQV8xi~pRvBaS6MbrWS?N9O!J{v^@@Pj6!6}AL7=2_>N&-yPQ1P19Wr8*r z%EVd427{so1>xdFJ>y5G#(H%5j!`LC$Li1cJxtAc^l&AAtL0PXd2U%yo9Mc@wa43+ z8h6b_*P1YO;o>eNFM}V2OQR4+zYLWlAtZG&k{4^2xBM=9<|vNb`B&3JM_as|+3lk} z#Jjl3de}vpDo&#wx7D#q#wER@wMr#|AQu{Xr`M?&^bJZMn${n8-|MKcs9LL%fRhL# zhO!HFM7H|x$%L#0*(#?pl#7a+iFW`mzTt$1^rpiM*+FOnzf!<^ZZY$;@bgU|XmWvZ_=w+x(Zp4hdF~W*8N(PzD6G*W1?Jo(0Ya+ z$u%C_a`F&cce@t0oy^J?^xc!uoR#EEs3bs#NuFuHlCM(BQWs!_E%P*G;_sNtSrF{A zFZW<$_F3d%e&k7cucUq^+QhHcv6+2Nty84gDzx5=C|7q`d6sA7!*4dBtcmYL8M5oq zIV?AFC>FW5_)Rk#p(B4aOIwkmwXE-Mb%){JjbH%G2O%9va$$vic&Z+>{%_1E+ zCp}pQHw^)X`VFGOnTjnf>rqt=8T@9Mk@Ou9AdBp^Lq24rg9R`@m$0YARslN8aC5Mh zPE3TF?D*;{o6n)Zabe@0TsP@F_W5o`42*3%``e8i`zbudV!cUtbUY+UAE zgk??^+;4S5xY!dLwzj{i!^0eV9oh!TCuZYi{{l6gWN$oI`Ak*3-;X16 zJp!FctqfT(Xus*6EB3s!GU^x1wM|e`uz?y9XiSL&@ z>hFASPJROq&DgsdPMSA!ICxI~2k&h3?rfM6;aE?4W(*jSI{Bz)8oC7;KStx*>`5^r zvsfWm4$uab&`CV&EDt|sjG+KO`DBXYk5UG$s2)W)w%7myFGs? zv!7?}{FU8?j{YTOuN)o}_|5Z@1t`diB|J)w<>|Rn*U8VC&GYaB?6x4*g?WKj)P&(Q z48fSO1aI+j)(CsqdqOj9s!Kx;6?Q4W0ds*t70#Pt*9}vmF9-%-S}r2#?tXsFm(}>2 zd+S8*>eFwK=ZpsIHyHRuV9)Mx|7y4yzZ2d0SbLSUklsH&p@(WtwW6eR3+A*u;`lgQ z50yp^uZ+ZMf`+Nv=4bIUi?6bGwWG>y0|K1S(t0V635>F$jE-gl%v^~W1LQ^DV?=R_ zF7ZG#`re8VGk>XK4+i%49+)~Qg)*@9W^-|hrMO+&m+>F0BaZCClvZ2rOcR@JW5z8g8af}zFv z3I6uvsCai!ah&V$T);&7#ifBhW{dWOlNK}>dx zgepRbg)|1A5$-UWWAB5Ihg0NpC~<}!q_Qj*S4#B!KL!@S!0=`vQ)JMHq!pB_)$e!N zEvaGMvSDgBqLSCom@E*8xQ~yPJ*G;yMa;hd`!6+lxLH8Ok|*H(e*Z@0uHqew>G1Db z?{lI(!{U~$xbNnBeh%`DJWp1w^JA`B>{ZKmfo)O z%U>d?u@hk6+Gwlf<8*nP;GX8S*`NvzrJq2+0sOFHL$bh(@7+MUb)myp4e5%WK5ziYVcrR=xxtF23j zJBW(59evvsG2uH|kDEz_yza^Y)S8{Y^!Mzm7PSQ8#eVTZ+3}zbEQngRtzl}Tf0>DR z|HNq6hrd}M?DeEn7nY^Xhh`nOy{MRZ?!t(2$|Q9c?}Y2#lo;z#KScX?j?;bp3DdmZ zCS&MF!ER?eS(F}({|23Rw8KfwZhLRR?4S>z3e#__<4=Uw{^?^=1xmLb1mX?fCJ5U$R`=BYh4e7$v0o6Q$C zj2Cw(1PufTZo#1qZoyp}AUL5E*A{mPB)Ge~6n%;pcb682Vuezm-nYN`zJK5M%!JFJ?hNhL@!vNEnHNU)efzP;DV??2EqA z`qk58{U6`h(jC4Ezp*-hO|eBO5_;ugA4c8brA9#=M<4i9`|tNe;z_Z*Nz^-Y5v-J- zfB*0D@qea2BiQ3V2a80oTLiddrSPB^y1P8v5<0^vVTD7u_#d|hv$DqSNRhm%wocC-|L9B@PoaUZ@Ly=4e zVsEqzF&cv2^Bk#3@FbigmREREXlEg!6-Ct@C4p!+QP%3RV60^$ntSei<&`*8ax#Hh z9)Mk3e-z6FaxcC@kU~@fS>Te-G^}vJ!m$(K#=;w<`Pcrp1uQif?EmlmPs0|$f~naYxxUrJCVKgu`s&K+VP8?B&eKKhR+k1>isIEP)ud8;cXqc;ifCCkM) zSGG7^E4E^bH0}xVAj^O>BR$P{2=2-PVu7+EgZDg2@mvpzl|v@>&j%bhQKUWOUI7aW z@IQb4Z3d1vI*0>z`KRExhO^-Q1ZDLSGU~wdymG2YO_&Sa0`te}%o3;pB&P8x$pk~H zA|;Z%f^@J2gDAUvPCQM~*61Zmj`)pjTEHT_Jdi4|I-<{N#HOE@wq}B1BLk-4625_( z(8Xyqaw6JIHdn}$jMFw*D#p8ca7(&rIkasNBRc}`+Gdg{Cw5N550rn>N1-*OZEhp9 zpH6$xeE^jWRKzFEmDJtJR55fj*dq@NK8@HC@9f@7Z}iXCtcY@jm^KFBm$&8~2g3fU;o& zA2*!^eriX7GLZfvLQNoD+@c~&OG`_ew_#JFUrH5`fkt#yY_=oTI5mwcxj=c4wjyc2 z#k^d7ZZdaq2k$!*#SelCRB`dC0to#c$Re4FAQ(I>cqso#Q%hWkV+u-<8AW%Qhi6~T_lwdvT z1HsL>qf)SOgRu0j(0fN#YDs3RT>MG)mWIdp8%~}`2WT0vXKy!w=@o&LbM!SoL*SJo zsb}wGj4~$Ut><-z^xWQ*P-SWn;;Klf@Ku2@?8_;lx3kxxhY~d?ZC11)I4FOEQ^H># z6Ri)iL8mJhjWP3152o%WSPSs=r8wzkdiKCF`qUBDcP8HX(Q#t31(WsmD={_6Je9^`a>ygozYQyc57q*Z+*N|+XUNgr$8+1$Y_%^gDj z8AwfG7DuLpBMLw`El{|Pl+~OXc9hM!Y03@KdFv(xRzS-;zqj4$p}@;&vKgP9+~(M+ zoip*&QPR5Gkd%Y0q;9t|M#Cg8mnX^>9w5k9IFI`N)T$;pCU*D-y#kI`YD?8JoE?LU z@CZhc17uSZNJ8e)M-?^gdsmUFlCgi_T}PKfd=jc27fTzexjP@f%F29&Z|Hknw&#N~ zq~^6-lVW6M(iAfGXrc~~!G~Rs%=DE7$PD}Viqa@_?G~1X;5e2I$4E<#pR9uuQTHqH zSKQRCTAG}`ce^`CpQJX&GOAst;NT}R8RczU(%s|Z!;HR5`POee$k%r0I$9YNy>1n> znDNGxeH1~?tto1(Qu4Q`?i!o9*6sEk=g2_XL-$DLW}=G9VeYM?5ny2sO$S3`?~w^L zH4J69U5AGlQ+0_LCAPztU3XH(Vf=@v8W>exeHC*=T`eQ8^{QxOZ=ZnBiZq=7i3dE0 z>74qHaI(NoOr4*8lrz9*RM=oD-Sa|#fHLGMUzJdh^}l(X7}e~Ii>cRR$pO(a{; zD6MB=^4n=G&)S;=OKdytQxAFFExsCOXG3BQNnu<)AY#ciI>lb9Dx9+4%J3zK*P0YQ< zXCgMp?m(PCRj7b!yM1KJX^lo#o3b~(mI}|7s5{V4wxF^|H^}yCwWNTrU9zFg1#Pqn z{sJHj+QvHLu?uEhe6NkM4g4o{(_Ece)gqeQD6+@F-IV<^XnB8|wz&t13fwViHE z_BK5l@v7GBeXl7;s$Y*&uOQ4#^Y0vVYh z3ta9BF?Y-g zLH4$BkXfT$HocwAJ5m^qXQ)YZH^q~rFE5GS;#cA&B&bqm`1lSK_L>{oR>^qM#o8y! z!*tuG$_)@%)a$ZRvIRDPSpTT@9UWy~O;5BguSh%wEhQMmP-~kZIjL#q71QeAo;O)! ze>L{VX zLSF|58o=3#ytu?t2DLCXHK(aF+FH-vkgpy-V&RiA3Nx@vcIT?MEHchG+tycJ(rBcn z5UMV_%wzD@N|c#6SSM-{6>ZoB#xUO!u0%g-&Fj=2(@qx6X{DN6 zpZ;dR*!3VSXJE;*F72!gSSGeuI8b8|mU4El ze{2q@UF)0es&W-$y2NtxntrlgbMQ7`yo&?vVQgT&3J|f9_wP1v)0#vAq7WTOph1#B z9cU|YT(oQjNe4h}NeEr!XT#`FOO`zog7if~^;v}VBR+JAV+^a_Z}|<}j;->_#<~^( zZ)Gf#ROz$~EBQLO_&TDL$Z(C3iBW(xzLK@p#{C9zr5ak=L`Y3XN4-XbF|ypHGub7j z0huTnWuQf^lP6iWB~e3)&rp$@oQ~$^ggK?hf=XMa7!d#oTe(c`6eV{iOYW-3$Q%w0 z!jiX=$&!OBSD51&>vcy71|c(zGKeazOAGC61&50f`y%CJE^i*p5qQ{ieE{TCtWG@- zhgI8b!cjm07m)QCF@eiMJYx$yxeJORY)zuyreE4vrBhY$P%-6`pf#7w$QgpDA+i+49n&ClHV-(+%~Fbh_M;!=Mhb<^S?)D}}}7sbygH^{AtUnCF&2;_5E z4%-7I9l1-As5A`PkV=a7xT+=GuGAS|@W!AQGD=X!+S4vE# zP2l=BLdziP(qaxVXibcw%|w-yiCTi%@Dqn>#XOh*;MSUQ6>ecVTO7p-s?x>x0NPIa4&XW*hkDnEVp#fv~^rC951}-aZHH{r6bgc$u9p+nO6`g>^hP;}tu?8!b zu9~%!4p;VMmkPrefLf-jVFY8M5)wFqQh;n6X57l)8LMzAF~iNM%HvCAx$Tf z^Xbc06_IL!CEG5bt+Es(ZAC)MIB1kqY*@nq*-4yIvyDeWs{^FbB*ZFJVkiEGBbq2< zpGg5wj~XN!(nC;F$_9wma+fkm0TZ%39Re)L3{63SuGTJC2BKmMGo~6}j+g`_j!*N` zXr*Ar$`V9r7jsE0Ap}|}HOYCC1RN>!5Jdc_6@CJTAQJ-^k~1zLf`Y}`af27jB)BEf zYRNDORYl06rizsV{bCXz*}#%R)FL4nlgmD(VgbqLB1*E$ci|9C;ui798mmcw5F|=O zx4z`utyyeMp>>t;Gud?mbut0QI%bmq0uFADtw;w0DmNVux3bP8m(Fr4z^XoyTPp`x zm1QcfGQQEKCIEwgMS1fq6H@Fo1WGF7mrTl?+_uEpENWY+dBrrtH^xO!s`1Iu2&gz0 zfEbCN^zYS;JDDCllN_HV8U=DAq9cM(X8_B%Ja{#+3|&=RX44ZB$aqt<@P;@8w^qBF zzwJdZsHW?xC9v02Q@yg5OMH{9b25+y4{`x5U>_Xmlh-8T#OcNu({ig|soAM|;ECYl zn==x61Gez54)w>jmnwhq>pv!NRqAKZyI{3pPr}*A*xl69aeY2`M5-G?jM$;1FFi-{ z7^GSU%GS9*}xG|A=UGXL}KyjgC*hjYyN-L zpR|6VqiOM|mmXYg$7H}R;S<(G9Eu$J354wN#M3hBBju^Tx6?mFNX3(~Q?d6DqEP9G zMaIQA(ig1}^eI-;v8`{Mcz*rx=N^UJQhI;{cFQqus`so#PX4d}e)BwOD1MZ9NB{Wys_4yv87;3?Bp4HpkC%A<{)OrU z0X9A^wF>rdRMp4~9Af>qfrUxwGm3mp?rHN|JHI4LZ9n-vN169nF6=W!-z(ULqDxeE z^uKqq^8Nkqz)rxE)XkNUg)?!{SSB-VRD^LJSRZ5#Ahb)trD-sWrX{HKI|KucY39nr zH9SyghjHctLTWh&{8z$tYj@NhsUqC@sR6|WR#<>Rv!zG zUc#R)$y7@I;efE-jOpn0@%T9#E9WJkBm`wl&lchLHE*0-V#8n}qBop_7+p)&sjq*; zq#XL;EGuwqQL^VdbRO!&+;8&k)UI`(4&htv*-Wv^Vg^1d#s0M{6917=q2+(AC$ z9^Fjmw72SS(6eOYacQ}Hu7^8~|K0EaI`dL&W)Rs-s#v%+D2Da%$?uc4Y~Mo;!uL^u zKrs_-r@$Zc`NJhfv?WsVh9y+vmZmz9%My3G!JLJqJw-xNT2_PaBl2Y zzLfnl(pIXb>dFSPP+XQpV#5wy9Lbii7jAoRh;oW;6w3C$u1L~=L-X+WNPcvwxHx53FhXvHRc#|>@W z-yK8O4%SDGe);^tU{45{#`z%5hCr&mIwl)yUH)Z8>i^|D^2?tZTjTSZ?b}u*7pb=S z$MJKLfaf=JuLF?KwSNecsRN(eUrsfp9s-%X74P}9sP37tS#lNmT@@n}k1m=+WS&6n zIErt{2$EF7OEl@Bv=1F$H`Bdjo*8Jej;#N}Sy}v&^HJ2+kB2dFt^sSAe=>$zRYHvK z@p-~+C$Z6SP)uVd`Ad&VIO74q>6>ig!92`oLFW_8^)UO&ccw-YphiwB=7tZM_3=a3 zyi=8NY1yf64ezKb_qG^VlHkTo+b4hR3`+ZUm8UTi&EOr=4fKZfp?I`UKEoP?qGk^u zCzZyB&SZP`Vni_BUyR#QS21r#fWiuAryyl4N?QFlZ~528{$y@b-UwL*i9vgzOYE1y zO>DQnq(v=dZ+dp*8jQzf+c(<qT+$O&)e+yoqtiFQ$_aSY>>Ix=C zC6OvbiA`u`Skoqp&rqw5>sL$go7ukuoC43KK&glK2pk0|+o@mjzbjn}0-}U_S(1E| zKXZO7G+;0kCH!^1DuBm+Gr7@4@>!CXn-6I9G7o6_dgb%=+=owv_U`NQ;`+PRT>P4B zKWExuO0N`&(w5^c2J2tGI=4i5iM!#8HfaqEYy2nxahO(__3Z4oa(vcflvXC}w7;-T zB71!LCS+29`^D*k_@+Ra!$Vt}OL7Ay)JTVDlMHb>-o!I-#+D=ldc!06TGzY!*D$PE zYg*|vxQjn#*F$OwQk!Gm@M62%h1l!h7|)eBzi^GM(Z<6}SMH}n$mf*LU2OikStIqn zk+Yfx6uJwGaneiFn`=!VBh20dmr0uNk14rlFf>-=rP{0iuAD}{m#tn~7^?CA4BE3K z4-0w8QrdA@ILOW2&7Zlpj8UVuQ-|*n%l*}2wF>npb(^n?3p|>nZ|wasU+#mezxpl0 znsW}WalMtfB5=nqRlSurJ!fJ=uagFSlRUcq*HS_#NGssdu!uW+=c<<`?BTD`c;4AS zXZQ52GW93JZchKPsg_q~X3bBw>}@*Nm1|1=0z#}hmRDQ+Nd9GpVTNM6h1SpvYy}_m z6hik7Kb|$Nk)Ar00=KMBi-AUl-VZcC`b&}npk?N;#lql@1Ni%ccWW6j2gs}byRajK zknmMs6uU3e+Ww*d`2j9RnYlK!0}vYgkYDAQm4>&|vuV3$q3_P4vs9dL_z;lWNar_q zoqO{dWMu15Rc+7MHQc9DH0x&_1Zd9=HtWKvv$2|g|8=bO+n)V1o&Kq5tzY9OO`1*fJ<;4MM zVnZtIv?ORGYZKnPUCd?q-n3>6owrEpMKvN0&dOALW9)X6Klk~sDELHCv`2=Mci_f2 z26a5{lutIAO%esT%Np(7!}{M#edOdKF`<0+`$=L*{)_nTXTa(f z!!jIxr+t-o+m#+T487;(c69E5+s0&wFb-JXwUh1v+63%ZvU^Di11l@Jp`=^*1YR-PXV6lm!)@KRuO>iSif` zo4&x=UcIY>_4&_UG`3eqXN0a@%T$p>u%-*%``%`q(s&z6r%5V|W0QLLS8mxn6@2rd zg)kiYj)}KDokNL4jot}Z`%d!W>B)^W>Pe`E{5$I;q5fcvhwxWP(IP6k{`WK~&Qmbo zh4strOVH>(BR({3j%iTpZLAB-C+7W<)=J@NB~+@`9R1EIg?se@bx>8&4Q5(7=n6fS zy2@i7ytbV^3V?`vj@)x=GswC@~m;K+&GA7-6tZLpujyVJbCTLM&x5bk&8ErS; zPO-EEqmhsG6S!d&S5{WAE=Pn_KY+hFgE3C7A4Hi%uLN=d`Cn=)ff@@h8s#aZJsFZ7 zBd=eudow<@xUBo6u|S(X_lfa}bLpW($)AokSt2O(2RRc#`~s8hy^3A(FT20f08Mrk z3z+ROw2PLeTU{uH#J@hs!^KkLJ1mH{0#v%fx?d>kjc1@!(R-3e@`}oIjGXG%O!p{_ zPNv5EnZri0^^as%TqEW>m3Z)XihE=)S+b0FdULTTO*B`|dHi7dGDqMi@%X2_W4jBt z)Gt@1T{L}*Rf{Ycv|P`hNdM!~`d!(GHPUmWKo6V0ZmjX~xU|6eHnl>*lgV4wP@13_ zFtM%OUZnQ#u;5NBQE%EO6uRLF8O z{4+nAi>EM>wYPw}%8$+%Koc961jp-Pih>CYARaughS8@wTS!&c?D6T;FYD>=sYO_bf>s4`M}|lxztLl67mj%l7U2c zCoHxL%S6zkQb>;7a~{}W@$=3My*T?+9Sy5=pMe@dO>c0u)&698$W>|6UN3ACk)ov< zvUHa)CMGbyit&hIE*5h0Gp#vl3g#VKqf+yRBgNE1#Tl>bK6+!iVmX z9+Vg!kr1T)$wzwwnBjcp&n7Z*Y(>#CV_$t3t!`Yc5yn7D#D5J**g{*{s?sVD1D2;E zB^0gk%ur@Wo6nW?qGD9Y0d@sOxaJY)NkiLjzH$27)vVEDVvO#5$^&=j#xeJMU1u%~ ztVM@JMid#9N!&frpQJIr*88SsykndQ^71yc{NhT=5=Y_nxPw=FKsidx4b#`E2Fp@e zft<;`V>wWs#ec^3_(mYS=r|4;7V8m&Bt&!mNW!q=nlpYmf$OS7Z0|O2A^2QRl=$mX z@2@Ld+d0pB4K_`756TSRnWB0kB9yRFk>t^rz@A%!0na#p=bYrO-GK^!iHP@#57&g` zM7xf9tKCG~p7Z4@rMq^LsY;U?YPldRSCc1Lmi!5f z*ncQ_w9%OpUfna&L5(H*PE6$vHsTgcl_TQF4PhWb>DnVfIHB6$zZzGYl34LR;stRk zPAH)Szvm7_pWbgC-d~S_5*0N;YEPp~O6!3U{(!AZvePP732EGH^#JD$BlbKx4fqU0 zM01;ZVCm1oVG6!z)(4)z43v;<-MI`&7uq?$P$;b`s4h$$CjrWyflcfh56_`wq>5Cj z58QJ7-aBDl`I;>pOxulN!gWMRul@T7O z?6TB@o_j(1vGJ{^Ls#ngR{^zms`~I~N?(@F?fQ{Vx;yo~zv?6G1_rmFM<(v=IM8}_ z^6-FhChpjc#2b#B=vXlsJ${0N7pKlQ20#tym-`HwwB>q`v8)P(??s;+S@4Eu`^*F- zP~$!7mpZ1Jo(t+SVJ!y3?!}LkTgtR7I3&mrg?2fZP&(_iZOl7PUG9N2L$&*o$KGFV zYxd0%IHg4?bO)%AF{&4TGCVRg`n|L(L2q}AkMC$xGR(5BmK3@G;}NbKJs)b~`i^`5 z2`A=F7JMx$0k}}lEA7Q|-39i`Q1lPPn<8G4yk#J{w0iuWpT#K>{+BN9c!@CBgSTgm zvlkT>px{Io>zgUM6Df}J!@gXv3$J)f}y$K!M^s7Sg5_K0-n*(?4OI9Akk%u7fl<30_nb{gN zh1rS0Ik5Ui%AnS9E9+Fqas}o0ceAqpvdcDE&OXg@D_ypKofqDsIpgot z+L)qN@mL#{GX1u0^OvvwT=OXMs$TWyck|~>js+okAp#cCU2S)6vL}E3{Fty+TI(!$ zwrsgU(VCIpElJWe%7?gnmwjN8^8&48yX+Z@exuEsp(L(tPFkHiLW-y1w z0$ilc@jDD(af_mk(vT_;C?lJRk+ay$B5XW3oj_+8#Lv_)wng2aHO-{rrx>L|(5=1IN>BHiGg(?cs0*&B4b@2&e;m0E7?vr^I3haa+C|un5z%YfU>z} z;wU7qUvvk5sdB`Xh*x|$K2x|^w3AlID8h};Litm6)N*hEO)l3+I%VLAMv`Npr#MNJ z45#oX10<&rX6^9CCL5~(6^~VO0jACNqYp}}jS5zCr|tOaek%8m2I*MbgQk}x{P)%@ zqc$@x*6men5YZX9BW^bfK*Odw){v@cE^#WSI+Y1$S zP$yaea9hpSv1&VPtH>V> zBkPmIUAW;_=dz9LH?(QuOYYxnTl!lTvVNLzz%wp8q62@rlOAURn~_cBJQA-15La^d zZ+l|?IB*B1E)9hoxAOgdQBZEvZXwE5M#cNZZz4AC?>irJ*$T4TcT8prZ>4Km8lVIu zV-Hr}``5*+g}QP}@K=(5FE_q*@l4Z-4N1fNfR~iE?>rf3UC!a@)cMY4yt126BCX2m zIPfFM-SuAcp!XS4?~104L8_?`Z*+dqep?pzB-i}z4ZC?2{iW;trY$-w;rLZi;Q`=# zP#Vj{E%`5_H}tA?ZmO%kB_0aGskH+?-+m7%HUfQ+m9trBmIUpsiKD;TZ0QxFO2~k? zp+>&?&rnfkqNpg_QR=r=Oaw#4Pj?nJ0(@ga0yR9NAJ8({rAy*BRmeYNu^i~D-dM}h ztjAu3E}^zDZlUX91C&q(s~m;vdc}WspMWJp%Txn`bqwcIdd)}r8MAp=N&~pzN4tJV zqE5$17H!-%#4+_t2K;5AB^VCD@65}4R5#+dN0xPhkC@t4eX-k4TGUa~GsC$CapO^XB`vj8L6)5mPlkNZx{v_`4PRESvW@VaT`c@W5SmiPmd%R@)!xeI+5C3SMnL*oB4o# z#{#vZtn|`_ZY6E|+COo5YKR~}ED1?5o6_>uU-x~R4=ZB5J zW*k+Ep@dN;5F~_WlJ`7~B9Wf)sz)^0D!nqp&N(evWA}HFYq& zXJ-g%cBx9rNQOKh7MhYr?cpcfiQbAU{3V=F<>PK9Vom;BwMk1K8*>X#65+VX@#lM| z<-$s*pJKZ#FWK_!gDQN0xY)*Fx_=Jrh}?4hzme5w{!aDx%8yBC8)tHg0W^QE@45sJi{pI853jagODod3Y#= zvkl6;jOPI&`NW29>3heqHG>@mTyCeRXl-j8`fMK$Ub-;CLLG%HYovE(tVJqcykiL%XmuzCDL zr+K}}Zy|X1!+Ok+Z7c%5W2@yi;Vby?Av@Me+!?ibS(kYRSl2jj1l!5}(4>$Ew}0y| zN;|bcB^4Wsai*JVAD0Vk8hESb^wpfcm6@^FCRLqgG{C*4=b2M|2i5pHO7>e+S$JCu z+s+;-{Y&MR@pt;B;0D_wRVU!VsjC>k;##q3pt%iT9k2&^gs12x7+yEW5Mlq1Tou{J3w@~xtx(({GcXI`#_s^N~mR?yV^PtC8{N@unM|=>zd6joTE+-0P*cN$oAv zT}x$H@nEk~Yy*|&-F+Fn!_l!z*t*h6mM$`)iWb~P7KEiDI#@#CZ~m8E`u~(Y$UEF4 z@R_i)B2>Zu>iTYZvo2QK;X})5SbP{678dRXcK^+f0E&SYmY$EEKQCQd?>GBoA8xL@ zu1NKo*}}R*NkSCPCHMxm%j(y6@0!~$t3C$=SQuWo2i@;HZnyVYWkIgDFM4vhN4Bd4 zo!5Fz4KC`}cb;85OWoGh3y{CQTab#6q{MSqFfiI>QSF;$zxH?2<2mtMuXrrZnYoPySX<|d*I%RNf z?9vDT0VfoI6RaaDAx>kE$4x_37hD{@@>|b{a9D4}wF*6jgaG%9^o*v0i;NIDXzn~c zqs1siCEib1YEdd*APW#2mr-10P1GbHpBrCqOrg~1>(_;4mB~)lShVIb&nGms&e@7< zTN-33SlReDWcB$XcAi^tU9e7ckNbr{s3E(>I0h*0FmLh8h3FnNVWRlA_J@{-8$!H~f=u&d z7n)qYgMz#M?=M7baY6jmM4_*Y|Aw8>O0tV;x&*h(D;M1 zRT`se$bST;J+5TL0d>SyJf5GxuEx!@HwzxxfLufPr&0@??_!z+_fplwiVWZuz7&tV zk|8B;)9Rnj2S3Gt9i6H#VrRl0So#VRe&KzG=kkR*Z=`QQ@+r0q!z0Q7Nc)X=J3^_D=cIB^(wxqi zkXdvnF44dj_)?B-{RwK+ zVL>tRJf$`3MoWl~Ia|}mH}CppU#$w)|8{nU{TaZnyO=|;ns*y$noaYHW~Wr`!1DD6 z_aWF0RY#^TZ}zNW0%esQcT_)$q!2nNw1KLHV41*y^fOc|5KyKbZ)6unW=EVh;=L`d zu)dd%#u;U9i;_3noKpOIpsy3Q@S&6NV|V{Z$w56#YLUpK+K)kMAXTq-eVXsQdV%hg4r8>y+)F-FpKG+bT2!i(m^85Nmea}@4D}J{eQ9U(MYd|9VB#=1 zFGp(aZJ~UnUuqitnv>gSo5qaeqT+z?+oD%T4oD=9>yeqz4q;D#&saE8|B?e4&3^?=1b{ZrNNub zcf6Xo-XpOGjA9%B;ppSz+?4=fkrxoYL6LSmih=mGp%QOb(c|1vh-Ni+Z-ARU!=pZ< zZ7h9yaZ|i9K=?K5soB+ED+QbX*4^75-ZW;qR`|{;zx0nJizYbGNI8+a^d-!Va@@u( z`*?YhY8b3T&mQ}UoF7^$wT7~1122X|QJ%rC6n(%n_8!Qtjd9U?OSYHOJNkiaP6dJO zy2sz`>88sxJZz}^a4uhMxf(bFtudRX{D~?{*NmQWG*INaGcQ>b31#PJ&&eFAuZ(0N z|BY7KmC=aYrlO$VVUH}OQ}+c=me-9lEoAJ9%oOoPm;@UufvsuawJ2d?C(RsA3Vry( z+$$B__=@aR=jSs_6W&#)fnQ2RrixVftUd$p6O=@rv^-P9qJ^(+GRLbO{FMkMkbk^z ztn_G4;YC8iUZgc0N%p^QjCE#-&h6_hTHtL!UNgYm^|9HvfS#pI@A%|+ z(WyU8L@_~*Ma2vEP*?Yu8?2gq>o?MmDsnQyQuRJ6RbGON(he{bp?5o5z0vdk>(ld$%FVm zHn5Yf_b4&V>_R<(Ki@`!(hd8$(!%O{2f|Wle4m)eo)^Y$l771}@X?GHkNw+r{F1bF z+oklwD!-fY%1qW%52u#UK7^vfypTYay7gg@>y_WufCcZLY@4d)pr<^_`9=Fvz?7)j z;n>H^>|Z-{Sqz>Dd<9SO_XLF%x@NtO9Y~B1KV8W%DdGHi&*bXOr9byrvV7F#a(}q} z-0|Z(A_^9S(C8v1n{IS*S@#ZLG%r>~e%;ACRLQC@LCUhyE;|Y|sbpn57B2f|%zh00 zYAhX{RV8-s1QxGS&A=(cNpRt??}(mrqXU>ed5=?n(oEU_-`rsND(H@{)%G8lNOD|n zeo`$gOP#&H@5*=k_pa;^%)>%$Snd93=H1s90aMg0&*fvxNGFDTiKK{kNfJooKY0=- zJLIX_zPYh63P=ILi!J}WpJ*DNshpeq)eMj}<0t2t8cdW~k!q>~Uw+rRDE4x0`UH5# zwUsC_X8&1ei}W}qeKe%h!6!GzpQ+Dk;MdH-4r7(N^cPRff!pEZ=D%cf+tu&4O&&x% z|5WdcxHrzX-8Dac2=W%X0@*@(lZyw6^Zy(8>Q?Cafv6DhZR5qi0!U>mw_m@~ooD83 zd^~pfIK|$#bYHMDCVD2QU0dVag-Pc>gSh7*aA~F|-fi5X>naumA6uM94nlPvy}y;$ z$4%cH8#jLBDJDE)BWMMNhhsR*2A^rOrPjlYp zTHk+R{n2L=zm7;_TD_6}$k{e?RszR-8C*Vq&z`pb8hcsTtdq1a)KPXP!Y}2v_u&a& z2Qy~8wH7kYnyjQ#`HHMe_>M@jep(^5q=yJ;6q$^UQtDe>uJ=vYAFjBH20KfV$7UWnJsN#ih2tf40r5TK=NQob5~@>Egy- z&!P7&e3DG``|J!M8!{w)CTzU>^X`e2Pfn=wq!Q`0noMq2`XHprRdX@{>M!BTyf+S0+s7B1eaGW?8lxb&ZFLUG3*m`^*BG@Rg6Fw(!G82Q~-$;eNn zVhV0RRuausGx;?nC1Iz@Mkygx_Dz>jA!}W4GL}n|&F5*wXVasfZs#eEc}lmI9ZYJ> zhEm)o%-%ib%$bEB?2pL#@lK|*N5rDdbai2>PbGIBacf)l?xd}Ir>-T|_Lb(30uItG zhiIb+q#_9z$Qj$XaJm57TSV>sdD=D|ew2iPvd>sUf({lw*~E*op)FEzhkL%;ubd zSUQpkU^zmrU|Kg6UM(r^6LcC}lShi&bgPSixU6SlzU+_RM+VVxx~s5HfOQ93(SIMo zUab;W-(I)D`-miI&S!4sdg~^cQQz@;L(7>U00MEwCa_fv33U{OtjmySTcU_HNfpd_Lin~ijcLpwYEns)sS#qahz)itQaNU4_v zjS$#GQenG_jgSX-ouqW6K=P?SF#{LHWH?qgyztKy-4j&*b~K8enEF3VzocWmxLeG7LDE(iiUG)qFtT11cZN z1LB1yv$>qUEyj^p6cqaTiW9p)L0#RyszRF3At5!k?p3fKF<6nnd*VIZh_v|GiQ2&# zi3TU})&pt9&0yr~(5u1ugbGkdyl>G|Kr5##@u*H}GziJ9ncOSMouU6kA7wuKKL6?K za0zhuI_IF!!p6lVrY6Ds0pQePB16z$sO;P{oka(fT*8xtHSTM$e63L`#bR%35g>K> zwDK#*299ijiKPcv`MWy zDxw;o_o)JB6ZVqkaV4pE1v^u=wRIX)q~oQ7%7m7^ak!>?e1$o5=LJvylWr`DvMLm5 zP*&^Nts+v6HfIk9Y=q0iVYoz~4V+d;JH%&v$S6V6B(D-4H6Bvl++gCeSaovKBr{9; zDw?{_pn|_wUrBBta;u1h;Z7rWP85f|d{I6ngK0GA?*G3ymMJ`{}=HCOg}hCB=}V)U_3(t;FcaL#oY2;^|2oShJe!>BU>DASn} z#q^jlz^w3=d3=(nK}Z?iUVy@jjNUw);kKKxlZfc}^`~!|N(3l<8s9T!836FaiXESh zow4`uZNHJYg{p2Y=b<>^G4!CwBrpLvVYG@0J-um*+|O^FWCZaiJKPPzMz~$}4aq^J zcK`Kb@wHTk8QZvy-SVDsfkWwQy` zr$;@RxJtf$o*PhWEWOwBi(33>4Te1txCW5Zf%U~eXuw*`Wykc2)M$)_vSI+KvWS+e zc)JJ`rB9FyP@!g_0l^9Zpt+odYA`0lP){v@2$ah~=qw%pt17I3;ez1_z~y1eMJg>~ zEp|#R4LT4Zu?9QBfD2@Zjgyh5k_Dxmp}{kNE`-matDRigYxYN^g_KC^jRN2ZWqLt_ z41t7N4BkE+yC#AYU9q4aTooll`46S)ss?u_N069ugU9*ZbU9QKRz*n@=;)Np ztGwe82Pp)6={dmULb03xaSh6w!7R{V6U#;2bFi14+~wuMb?4cAJ01Ykj1tk2WI z0!pXPFSuAKIl3lJig)BKN|@ev#SZ9syR|8^==GiqtfsLNn#I}T!a@{20RhOOhp|J_mr~4+JH7aaj{?8 z7^ba&S%b5WmK)qNV`-7bYpWII`}Nf`Xq??)nW|kK{6QZ~@e;lro;J zY>5G5y|P(W?R+~oUx!by0990ysJQjY%d2pbEV!!QoIq8V2%6LAwbK4zW(z6N<$fvq z{PXpH*{ZDN>p*7KKW|J=)?ODry0W7&`TAUq<+P69kMrGRKVBzB5(Sd~Dct;im#%mI zjy=HZhy4UXxqrAwD@IZxu(~7gmyf6ld1%sS+}s$%UBIH4I47LU+KC{IOE^jLw!>ZP$j~UKM zAvD+!n38dX&Jw(^Ab>&ojAI%_st{z@U)a@SI!v6%DHbt(C;UX_Wy45b=lA#bKW}}} z{9n+qK9A+sY5f+Qe|PRp@l_xAb`j`w%;A}+Ca{#Q71^g|gZAabrA8T_zHLgiTfa9h zB8xJMnYm$JomEXG3xbBLXg%}n1KagHu?<*gMC`9&xV-!a7I)brX}pj1KRD4T1@NQS zy*H1{_0*%Kfa&%Wuz9GQ{NT_)&T`Crc4S(ejj1#W7z}B&D0@aFA)!#fnSmxaf*K*V zh-_kpC};>^L_rN9wGAQ|n@S=E!L%iiVGK#O(oLq+n4ggXlL4@72@FIq`Es6VgxVN} zA+#}~O+!fy$Y4Vo8wSC#v`Qc%ArTOf455gUXl*uyCIKe6$g7*?INDhJ@3Yc+JGCJ~ z^7yCqT^*e!+#T|x(s66l;ZE71&739LIj!(5Lwc-j*Y58az0JOc{_%4N7j&s`_+f^W zDh;t0$3FY$@Map_9ez&x_zHum{bA7za5|eK#DUp)ZE+0gP%$|tW@v=~O3~_Lo{k?o z(I>49l}`3J{BT@=)TT2@w!GK!qtGD|)u%-JhKLYmAKhA#Cu9`JQ4q6LiV_hM#F$kT z3?acf{dRl`0#b1KlXi=Bq^BSGZDNqufOB+rjRR`Du+_`tQa_mdjM6YOZ*=-d ztZuuJ=2P$2>9)L69R`Y|U#g=KQE@QZI2%@8nuloLd6{mM&;6yn>Vqbgf*Tvsw5ctecxVEt*{>+k*i8D0MV-ol7iscOQxlhC`jS+gGSlwL}^tHSwFn z#s~$Mvx`s$Nlp;c5_*G4ZN9o)`Xd@2$Yb$6nbH3gtw)9lQj5%OHmM`)#@hE zh0o8a;z^`A;S0uUKh&HUlOPSizyqgu&rE0Vus|!eR#R_I|9@paJ8Dt^E0TB@bnVe0o&{=x$Qd4A~ z@ANB^_+TCKeQz3dH_St%S@d^f06Z~`srZFBK0}(Q#n7pVf7_uDgnKqKhaZUem|zh= z#y~GM9tKbNa7&lJ5eVL2QXrGozp;U3r6Y5 z?JG30=nNtA+*_lOq|4uZUei5i`HXZX+i39;m8bh97r49bJkfx(hL)CbWWJ6HzvOmB z|3S7Zlg=t#m)GP4VI)jJY#y(<>*1>jp6ALmK6W1$*ZE+3b$>;^FK0RM7;6POI7SP6 zFV($1?~U>J*c5UPq7c!2Gw@5Ud~^`&-NNpr8m7Tqxcv9FQBg$FLQ`EVlfV4Q(kxf ziVXj$w?p>f@^96d`0MHR2Duh{bpH4Z%uVNnDe~0{WLPGTKm<+D3`0NzLc=&epF8Vf z-giLXac8-&hb?^g_gf?QM1bqr_rCp2LEh0nn6S%gu?phl?~tDa95g{f4-+&yR^K8U3^1nrpXXG6v7+Fw4pU`pwYF9`YUl0Z;(I*7w47#(O!N85l zLBYjw=(tQjf!4||(xr_uJld;-7Zi5%x$AGC!d|tT&K=9%!xWp|_ho7YV9GB@03aX+ zXLreZ-nc$O*cprPRm{1Zby|wpxCEnmh#Pt5%`g!}0Kaw)-Mul+A>rS<00lq{1Av90 zgfo`Ge~j0`{~nTcDaD2C(Uw*g$e`f}0}C$&HN0{H!e@V)i7`*0^-ZTTQSta%v5w2- zJDMzS6%zAGlLh}xb?hOg$u<~DA&L!=XbRwjj!H$Y;OlU4*mwMmpH3h zi55<4SgAW5TMkv29Zr!c`gH1IcfT67OBqfT=}cw2N{29)zr}FA?&GoT>3nT1Q>E+M zT9Z_2$%EvhM2o=kA>jMmK(9sWJZ=Rt2MPdz1rJVuco}mi+waP-@bVq=o0qU!+ObmN zg+t2Q6Rnyl9m~n!2q6NL)?Hw`&+CtY@Ps2!Py#}V*zI-uU)#eW-oUnZX~sN&BkY?; zYlI#u62p4m(cbKGJOyaOb*gOIy6QAh^UmyXjUE+hR%2qUTfkdLJowd* z1iu%BfP*>}`Op$3hQEdMhD#JfhcbSNv~OeliKpPIpknq4OYYU|JVq(ZtoLP z+f{ybT%~^oF=ts&xs6YKix_5%W0^8w%QcfGam*?uDcP@I*r{I4V*N8pn19Wp z{R<{67s{_)2P>!s6}C+pIkam%k6(P2MV*|(o4v&uT&R_kZ`$jscWyC>X?OyeFri_* z#vt!czEEOrG&>Z!r&e6;xD$u$vINT2x&cFtQunU2m{IG{UgM~`AdnLsRj{%(l~jl9 zdKBa{uiX7)SOYT7pLq&atZ8lmFT8+4jjb^V1E6(q(e?Ismi#ngMU_Xq7zYwW8DYGG z5ycU==_uT;a+lxC*m6Gaqvm&dO=Ze*-+H?Jwx_2S+eS=;!^a>$G=%~H^Key$a6?*4 z{v>@fYdzr!lBtXWv$FtXXu?pmkmBzJtT&TS$HSJM%jy| znu(5rMC!l&+ej#C%U%CN81@`X5vXM*pE3gzxm5D0?8L@Uop2$Ka*NihN~bx|$HdCq zufHB=8)?yRf3$b){q#ok$_P1kME1dD{MFIO*?WzQPXVQiR_C4ozz%dnY&&4I1q%X# zk2Vl{4(@0YFwkrwC>Xud{nlpq9Em*EtA4YikmtHZ2TWx+b zST9aMu0hR~ECjUSK_KkD7Be3IuR3z`%ktbcOzNceUD%01ka|o;aZR2pS?&Ap8DTEw zalQ|HW4~FuA9dhvZ)O1t!*xqN_2<@CKm4}Pk4+Qr9=IR3UGn46^Ovi^*l+lGIYy0V zcHR4)^%aDz$*-k>x!*UY{|MGm#mdq_(zTA@TyI!QcOz&gXm_l-tf{ae|4koCidUx6 zoAsu+m-5my&El=Qs!$*o`de|p|(>u;J{Pwdxi{B8JMpH;N?XPvY` ze@kH7_3rijl#8}s%l%#Dc%1$Xtu;EmCzY4cysS*y`I>{6c{9xdTX##p6!g?BSx3Xf z=V!W5Io`B|SEg!GVvbHSP6lcg9x+ZlhJsH9DsmGNKTjirrO#)*Z9VkEtNZ)w>1gZu zxoi7ZT-*7LCG@qu{L8OVWzE&|r#gFuuAN@qQMtFay>&l1eJJLYn-@;1Ev=`m?XFj{ zt+chGsaa;%M@K5XhOKj~ZrxRL&4)uD3l+YfA5&e8i_gfo$=2NZyZFj$FIn-fnAj{F z3!RRl`)kNDZ;EuMOCG_g3D!x}coI^bei8CH-5Le$_qNuj&AxA(MuWP{afyh0nf{)$ zTlnyV>?cyBSZ&|F)y-W{=xW1NH+phZF^`*kr01eEFYDcNR13TT}d!`%~vvb^BKT zWY5E?-TrfWHJN|1&nNW5_q_Tk*v$8WHo=v?ACjlj=$X5g{N_BZwEoYYi>X56!L0Q7 zZ6mzwJUO^NW=xpj+SOp`v-Mwj)K1V*vI#3&V$&UtZC6=CxF6bWY&wUp*Tq!RQL=36 zh}xI)Dd$J2y3j{LNXJ;%SVi1NUclJM$7h?lxNO$CzN%Wq#f_bljTVioix%zbTUV@U zS6@XtQsTM8YC3BA_RDB%XJ+e~u4^+d14SgYeFbiTbn6MG3@;qoTve`e;;PQpuGZzt zi?$AI7Ap2Qgm5w*uGQPZ*E=dfM)p=v*SWGl6_(vNYgXel9BV0ZGEm7z8pVQ8G{YvA!S{> zkywY$IJ1O2qrdnYM7t`7$C~(|`XS#_?*-XqF>pZIZ3@?9U`y@&AIb0Qz|xKMo6EC} zWTb2cW5iqh(l-5eL8T9V@fpf6$?%18{^56LUk`v;)J`d|Ihguvf@16ARIwOn$K@Tb zxX?^sJ~5fvGWk<>T$gz&bUX-ub4*Sh%8$c=+fC5-G)eH4K^IChqDs!Qy#4}CTmF}d zWB@uxLrJ^*0Tt*d1G?S=v%CHjFESEcIwWF1gsPwjtZ$mw(}%q=3MHq(tS|C8nPvO0 zvT-;46xY+%CXZVr;}=@Or{=-a)~4Wu;+O*S+aF`q#7PYcRtR-!*f;2%gHd32{fA__ zZcGM&m(*Aw?uR&t>Lyt`(itnm|McDK!eB^t++`l5C!80zz&@T~-XH=ogSjw;4RHDY zmZGgbQ0sD7Xw`W!yU5$H`Hd4pZ#McjLTpPzfxT^fjrWJS^zNpR>04T1>O8&|q<{ct z>7~6gD`?P5kT*;eckLEK(DM_YqSj}SX1Wfav0pFwWmH70?ombSmCw{$yY)G&X-1G@ z7(MQ(qCdsUg9{SCNZbdY|0PqL$9`tUp;d{QXDo!#uhu`mC1=|^R4SAe5GP(x9A)PF zi_~Ny@fZu#kVHG<k6?}cgx0AtZLdmvENvs zh8mwzA5XD!OeK1Wuu9Yk2ewD3c};12G5Oqx27k3`k2GL=%K!oy;1v$M8XRCavefGW zaz;X4t%*EH)UHlPrG|&s6H%XNI2$G3)zyp_&rI-8I*(8BQUw7AgloZI5g04RoA4iO zgN}XjE|Fa3yq|ssDP}S6B{k}5caVKC-*f~&?wHFZ(P@trn#{m7B)y!8XPAnm1}WW@ zrAy_>3~9sze4rmZAsz9##vz2+czb+!I^?$S$W)9;zk&f-BVsjm#5f(!^t@<^hTlbd z^KrL(yAS)i^lMj^=J$uAPRc6BGaJjeon;859QnAjB)I!JEM|Cm}F@<6WHA( zx$G0s0pd=30I~E;f#zE!%y1^)EZ0Mt`mu&7`BT?k&az*!g zjm3YpS2Jjy>YqK)b53aczX-f^g`K16} zPS3F|Qsbo|*Kf@gAchHPp>%j{AOL2 zay~z$<}_2zdmF03Y4v#LB_GzJk)4)gB2tGa_RO`CAOav!K^Ao@2~C9=+?8$luAI}M z;})dVIYTfQ1HlkiHp$SJMXz+SLR|)G>E;ym7uz%d=AT&#Y#84}dYHL$)(Pc{8E=s;g#c(D{My?w`+XXWK$GJpU& zj@FD(ZpWV}vBltg-*eQzPa^6x{|&)x(nPGJif?=o@Kwscire-DMyS6mK=DIeu#L!K z#?7tWn?xGDlZ5Hpgd)mqoc_RTXwVmR+;9$2QCK^~NnOGp1i8IWA-Og#EphY%`wdT6 z9b~)RkpMK|;ajNDM618dX*B*M)V~{~U_B#PFNtA0l4rq~ikF-Qn*-!vUsv)2(-KJm zzlfBmjY}GBt;D*Qe=pY)F*MZ)PI8oU`$^n`%3oK0$22^Ix4&D0r=biq~ ztnaPPuTG3^k_dmlq^Z{RiiJ1dbsIp4BK&+0oQ#M;cczZ&65|TlPm90Vcy2U#exG`; z7pVU57mkjde{aiOy1HP}7l>wHwRCOG_t9uuJ6zLKeOo{+4MhuM{ktuN7Szp)TsChZ zE-wd{^6gI0H_XRY<>KMFxqO~F8PIpxn}~kV8hwW?5OB_s*p+{!kQPxzGY|-ar6JM= zmG6b(p~dLWqMc54;7>#3<;S^4s5wxCh?#6NeM%kOEhJ zfsH@)oU%}*xv=-TcbOn(K8sRTHCi7t#^;YZ)CPHjX{IeJT@p{+^0oEs`&b>$qr%j2 zT$Xb=Ytz!$vu^obmgg>zY1q8xx>mQ!dlzQAedg1XlJPre)^gEPW3!NpxwP*CpBORe zT((=TUXdCbUSNucPm!%wun>J3XV8Kdc%sWa{~xcB_gIx^!2th6R{qwGgOktzg_^;= z)cVo@pp+#QvJ!waK2thSe?L@0(}3?9EiQ;ZB8-_%96 z^!d~;RY6hXo|0OPFb&T_(K=vSoB$1)2q#HS#?l@Qu{USy=sAox8H~zX^tvlLr>(Oc zmX--@Zas`g3GGpBg#`_U(4R8rxJgV4Pg&#YcZ3D(nRxw4~vK6fYz(0U^ zhk$n+Z`HlDP;jakQrICtu546|!li1^a!XFn zZOeHbI~L$(X}~((1Bw4{&2D%h%wxa;(j+Y+>6UKk`KSW;qp%&%@yq@D3a4}6wS$=F zK{?%wxL+}ts0eFW0DvL8ZI2P53+rcF_>ZPOQxQ)IQN`E>IDj{fb=;x{-$4UJgk2KW z)AcgDpF30V_Ok~ zW-&YC5)I6MP7w?kHqQIXAA?9O@Y_ll3zkXmL9D=Lu?da5E|na4sgMwW{=`i3%*-aO z2NV5y>(bC>RYzLtq`SBkxW#enfg@^nhsihf4PH++_>3E`gLPfOCqCWC~`#Dki6Z86v@-nTyBcJ@I$b`rN;&1mb zhIMl8%aj)kNVSKw?p4Kma?Y?JhBF35ET2nOZNEdyMccHj!+Po6A3}%eQzsdbJP_NH zk_R5MrU(FFpI`vB=rR4%(;o&ZNHn2EtCf>VpAC}dfy7noQuosc8A0v|N6o@-dXd8p zHQE5kht)~FQOaJ_DS-Q|8NUt$Ms6Nx;8Bhsbp`k3zteJM!Mny5^;0XlgkQJE*HRcmx#yp#s+(uPx$#V;YyDvtk!f_B<{02;A#RwA!zHi0gYpJQ59_Un^WTi6bv;=?L3(9UmBy%m7+(<$G@U_`)IxzF&kAjR&Iw0V87Z^Qv}!rR#WMg6XV^&iL>aoMP#W0PN4IEUO>! zxU&H{r(Hus9R>dAr&EUA@|?2IXiaW4)n$1_=vcWam~yN%bGmJX@xw>#0J{OFZD){$4=DQ<2wW zbN`FW`b*tm???=>js`OqIV-B1EBND!^la-^@teYM)Gu47Yi4Zy92|W-QH?a+S-JN8 zbp3qQnj1G=m56Tv&jU7oXFcavE|fVn1POi?lJ$^vw%?Eonk`B%+&q}xC>>jcSc-G! zOl!By&DL4|_YwE0yXy3z6X2lbcz%8f%yqefu3A9=#w>us=y^dIl9fVTiQW*vO5u*m zOKH7(hriWD3Iw6L#&rr5S*qHfOp5cutVobjd^t34r|>;=-4X#r92?qTN2_{37;*k1 zfChO)hsR1#f_A*q<<%*wKzTlL-F+6{Z>ecRIl5n{waZ0cO$w!u3&f-k;;7dm6U$62 zpwtOS1*8B!qX-HWZ;LaRJ4gD87(Tb%b1P%1=*ject;`OrGC=HKk{MZF&UUOS8!ZN^ zz7iJ`d|wkC(C8PV{`&Xd)0r7|;XD0li=z`nEQlKF+Q3N&BbS@drcTpg4{*bYNm(+@ zYfQF~i2h%%%F@5eip0maeG>E-_ospoe>5}jrkIG(FUUT*({h_YhJ7x6f(@i%1(amO zTF>v+UnN0o6j<9@j*--lQe=27|C!5|H~{*Xg$Bq^%Nu@$46}?YiJJWlUGm2{zr*Ey%%NxPlWH#3M(KFCTpvP&8^D@?!+>v2eLlH(446F`J;=Xnx+NOeS$a z=N)al&)QRQV{t4x=B(c~fps$^?54BXyyqRLw7#GGxQ{C|NwrD#dbLm{T$YaY>2vYk z5(MJ+?YvJcQpew)<2~#8x-BL$ujQ=1$Jrn^vEBbv2r@lJ&)T6wJCb|YU~}Y#9yH7( z(+$9`KS2*3mQp4bSCP6vP!#NVf+a|WNbo>f8Dem;56g$=xm6`r)QD+&Urki*)4^_e zJWP=SFka0jQN^6gtX~z8=(iaS&5dqzeDmhk+%cxc)h|{gHrU2Bz|LL1vl3)9D(dwQ zZP3r$Y)&i1$ee3`lBo~`aKtWV(V3R&{6fKqeg5XO3%9gr26-eRo-b*jc_GcP+_nTi zqqk+1y%M$37zEuk8@cY|*m=LMFBWEks~F$k@4W>_sTH|)AYtP?K}0fxKDqr`*vHoW zLN06T=0o9zj8aOvsZ%HCp@$YXM^=A1b?(WyDgk z8Z8n-Vh+u)&oo&_F1|Dbzcr&#U-hSPxs@-|&u;TdXj=(DRPR$rT7@+Eb_n%;de7#V zF2)#N5%FF3$*X2m2&l08K2M%V95tGORQ3k^j8lia27WZE zUhq!YSpISOh7jSOxdM&#Bm8oib#zqvamgx15*c2?BSt$3vH{_Mnnnlv?<6P+gG&Ni z2W*lFl@c&6WKMps_r>2v$TcXXc$D<%T8qTvx2nc5D#qg>OI(@Xi{3FiQ*D?#vLOg@ z)()2@$^~50h=PsN*sIBC`||2{_4^dLmh)$H=h&4-o-z}ERB?}$j;=hsF?9$-kn5cc2 z>^_!z-=e#QFs?#E0KTT9tTwxY;`tkn>S*Q8JZjvI=mz&?)?L^wz`d6?{;giyQDNqC z$!a4AFlIl%h@zPCiDh?KSaL$kX5PE)uREC6k@A06a-hJdvMv+zB(?EyEwqtxe#0pa zMzGaYPJN6OOwWaa^^HvZ|8_F@ICI-qY^h^yX_Al9y}P1jz7g3Q>cm0y)WIXd?H=#+ z8l(y|njHL0wG*@`COhk1L4r5&NFf?Uqa{71r<<@nPpM9461V^nBp&oFM|l3cC>h<+x5<9kb6qtJHFIIu7NF&N6P;_>_cEKvjTH z%@70l$gy{sc-)#>m?-n{9C(Er%id&9+0>S?iVBzh7v6 zCQ~lJs&s_nVY`-KZG-?l0_baw46^c=o4m`UJr({O)&Ao+=GVg^Sl(OC$V-eOU1?9= z7jL6@zmPt{|!kLF%PlImo3Oo94BtsucKCJFhtl^76>`n zXAX;cPo+$)pHoz|Kd!djufuzZY6=x)y8!*0`e3c9s^aLL)Gro1X#$j?rJ2ppm9 zB~0^OI$r}r3$Z}k1NtPS^U7mW_>aR%H(HuQnNg4cT@i>n?rp<5WE{29=P)}j<41*0 zP6U#`8FtLyXBk!y`upZvJ^zJ3*4lqfwKO^$!A>R9()}aemhM~`a;QMpxVRqXd*Qp0 z?puHJ9aiJ$2pJ-9ldNvBoRPwQm>JAK=Wg%&~J zD@2IID$!rwR;CULG({zWCdPD@S9NUnAD%uXLC5w?qFIW$C%c}&twI=u_>_R%@w1n! zHmtOvfD{<8NC3ufz9=RjL1gy0u-|v6SoP5RJ9AW8Bk9hY%a_!R<_6ZTe|X0AdV3xU z4_`wZ-_58N*PJ&p zcj~Q=f9Jt6q*;+hTHagI=o|VXb=M{|z86}b z)^H9VoYBM$$I5x*3-ELZ0vp-I1w6Q{jAY`B>38tS8L?$2FS75AP--U;hmIHwlQCrx zkGNT1LMs!HQZtmJ7=RcIPNBpwKDHdgf=$uHg;ueMulylYMYc0@>5stb$fy9TDIQIj zZ%gXOAqmsO0DfbVQ;Yb{8(@_Vj7+5T>~fgzMQHadPJ@RX&1e%yM20sv0xAwC5 zOIG{?gXiuS6bRAti$nlFI`IQz!dD3$ zqG^6Gw6QocX8szEt|vxB@O#tyniMdj!!2CE#IJ~4jmE&#?>A9#ahrio(VogKGPbbfo+`qq*+v@exKYit!gh@HKPs6 zBpEhPbLT04K;3gT&Am_3PLVwSPy0(S6%B~BJIb48qyEkwpN0LeZINsUTNvsv@UOd#Pov_wNQC) zaX>-j3|=bTtMrKB$={NKQTP1JJbJgLl!wEM?7riwjS*0iXKX;C9me4wnE{}=_CMRL zHaQ%H3z4CR)v|b9m#72Kt-wv5Fw*{Nh}5VzCo2rm9K`6#_B|3M;2_tRWA=37Sz>J8 z52p;y3v0nof<0gD?Wm&p{D9ZDYAsqlvg#aAK|jInSF8N(eWcI-nh@Nzu_hK+yc72x)pZM9rGY<>&@p_DtAjzTT%{X&f-`g{InZQ~2DvE9B>w_1*+ zfI%C}KRRjib?eqjG4gf3)3eKQTe)}4cn52{vgXdStQ#x8e4bH)>+${i0DQmf(d%1j zuk{La*W%9Na%i7=jPcn=A@0NubsYWJ( z5JC&)JwSR)=ww*I4MC-IAA{Q3w|43NMdx}jC6m*|ZPYd@6X`*}O6NI;Wi;t2hceT} zG?tIG8m_NF&Fx4D05g6`{jEF66_Ic^LwG*>9!e~-x@6lA^{m42)L7|a(}j^0h!%u= zBqez_Z43rbCh|w=bH?pm$Nfw9l+<6@S1sWw(Zu`nTh;6Rx0tnv3MzNZLcV0Lr;O6k zlX*Xg{e>Z>0EpNo!wf*)_v`o(eMP+XOocfZ*nRPwqi_ljb==7!=q~AsrWkT`NK zZR1Je7zRp1rf4>7P7LtOK`x_Qj(#@QA6Buij1DwXqhbnP;{+@O;w_6SmKPw96f8IBtI3@5vj%n6$iijoba79;6=Y$iZHCqrHU~?D3R!I^Fe1F z88;{k5oDndBBeAA0EnO2sA+aj@li-}oU_!@`QPESpri-{+Co9#w2=)61?#@QOBmLB zz9lSQU#X&;Fy!k^N_=d#+|BKLbw2MBVtos2o6&3ay;rJ>K5`qQqpwMSXTtToMOM>c zRo(1NdF`_>{eJ1X_Z@~)hVP8qa#>?Pro?ST!=|0VEwTpkQSe(XH$n*ZP}aXPirXw- z`SS8wvKS3_QyG3}8Uq2wR8^QAXMa;e=FSfW-4hU%tp;h{`|jQECC~g{t=ogz$NQJ7 zq#$fQD3loySJuyUlIwXr4FA!(*?RrYukUy6q^rA`z)@j$J1mYOVc)phl-3f8V*2ir zdH*wZZZI7#8x)*nyWE=|O_pAxZD&@9Ih5%Ym{2tu@dB}08U@k_L_1A&AtPgBa66x< zXXvP4^)5YX_lHHSk8k=+k4=Tr>lx2o(VV|3P{Zi=7|kDtNi_9w5pa*O{Qe3_GHh=< znpSl>t*X#LF}8}Z?dkp8yjvxrUxPwiCL)tzUbaT}jQDvA*~Ht*bDNi8oCxG~&ph#< z)f=?ZghbOBXv)t0zb$XH zIOm|v$DZU$>fS%A0-IXd5Bn0}8x2LJ)v9A7*?Ygw72_AtJBj>Svx#1Ff#H!b^8Jl-q>2&o^05OBGXB*N;hCgVola yX2!o?_u1$(XR7=JO3vxa{DuJrKR(Omvk5^86M_&fdDzK+_`8xR!i0cD34&