From 355223b8f0af1ee729ffa8b53eb717aa5bf283a4 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Fri, 22 Mar 2024 15:35:00 -0500 Subject: [PATCH] Yoshi's Island: Implement New Game (#2141) Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com> Co-authored-by: Alchav <59858495+Alchav@users.noreply.github.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --- README.md | 1 + docs/CODEOWNERS | 3 + inno_setup.iss | 5 + worlds/yoshisisland/Client.py | 144 ++ worlds/yoshisisland/Items.py | 122 ++ worlds/yoshisisland/Locations.py | 355 +++++ worlds/yoshisisland/Options.py | 296 ++++ worlds/yoshisisland/Regions.py | 248 ++++ worlds/yoshisisland/Rom.py | 1230 +++++++++++++++++ worlds/yoshisisland/Rules.py | 612 ++++++++ worlds/yoshisisland/__init__.py | 388 ++++++ worlds/yoshisisland/docs/en_Yoshi's Island.md | 71 + worlds/yoshisisland/docs/setup_en.md | 123 ++ worlds/yoshisisland/level_logic.py | 482 +++++++ worlds/yoshisisland/setup_bosses.py | 19 + worlds/yoshisisland/setup_game.py | 460 ++++++ 16 files changed, 4559 insertions(+) create mode 100644 worlds/yoshisisland/Client.py create mode 100644 worlds/yoshisisland/Items.py create mode 100644 worlds/yoshisisland/Locations.py create mode 100644 worlds/yoshisisland/Options.py create mode 100644 worlds/yoshisisland/Regions.py create mode 100644 worlds/yoshisisland/Rom.py create mode 100644 worlds/yoshisisland/Rules.py create mode 100644 worlds/yoshisisland/__init__.py create mode 100644 worlds/yoshisisland/docs/en_Yoshi's Island.md create mode 100644 worlds/yoshisisland/docs/setup_en.md create mode 100644 worlds/yoshisisland/level_logic.py create mode 100644 worlds/yoshisisland/setup_bosses.py create mode 100644 worlds/yoshisisland/setup_game.py diff --git a/README.md b/README.md index 18b1651bb039..905c731b643a 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Currently, the following games are supported: * Zork Grand Inquisitor * Castlevania 64 * A Short Hike +* Yoshi's Island For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/). Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index a67d5883007e..dc814aee2fa2 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -191,6 +191,9 @@ # The Witness /worlds/witness/ @NewSoupVi @blastron +# Yoshi's Island +/worlds/yoshisisland/ @PinkSwitch + # Zillion /worlds/zillion/ @beauxq diff --git a/inno_setup.iss b/inno_setup.iss index 9f4c9d1678ef..05bb27beca15 100644 --- a/inno_setup.iss +++ b/inno_setup.iss @@ -189,6 +189,11 @@ Root: HKCR; Subkey: "{#MyAppName}advnpatch"; ValueData: "Arc Root: HKCR; Subkey: "{#MyAppName}advnpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoAdventureClient.exe,0"; ValueType: string; ValueName: ""; Root: HKCR; Subkey: "{#MyAppName}advnpatch\shell\open\command"; ValueData: """{app}\ArchipelagoAdventureClient.exe"" ""%1"""; ValueType: string; ValueName: ""; +Root: HKCR; Subkey: ".apyi"; ValueData: "{#MyAppName}yipatch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; +Root: HKCR; Subkey: "{#MyAppName}yipatch"; ValueData: "Archipelago Yoshi's Island Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; +Root: HKCR; Subkey: "{#MyAppName}yipatch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; +Root: HKCR; Subkey: "{#MyAppName}yipatch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; + Root: HKCR; Subkey: ".archipelago"; ValueData: "{#MyAppName}multidata"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Root: HKCR; Subkey: "{#MyAppName}multidata"; ValueData: "Archipelago Server Data"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Root: HKCR; Subkey: "{#MyAppName}multidata\DefaultIcon"; ValueData: "{app}\ArchipelagoServer.exe,0"; ValueType: string; ValueName: ""; diff --git a/worlds/yoshisisland/Client.py b/worlds/yoshisisland/Client.py new file mode 100644 index 000000000000..c512a8316ab5 --- /dev/null +++ b/worlds/yoshisisland/Client.py @@ -0,0 +1,144 @@ +import logging +import struct +import typing +import time +from struct import pack + +from NetUtils import ClientStatus, color +from worlds.AutoSNIClient import SNIClient + +if typing.TYPE_CHECKING: + from SNIClient import SNIContext + +snes_logger = logging.getLogger("SNES") + +ROM_START = 0x000000 +WRAM_START = 0xF50000 +WRAM_SIZE = 0x20000 +SRAM_START = 0xE00000 + +YOSHISISLAND_ROMHASH_START = 0x007FC0 +ROMHASH_SIZE = 0x15 + +ITEMQUEUE_HIGH = WRAM_START + 0x1465 +ITEM_RECEIVED = WRAM_START + 0x1467 +DEATH_RECEIVED = WRAM_START + 0x7E23B0 +GAME_MODE = WRAM_START + 0x0118 +YOSHI_STATE = SRAM_START + 0x00AC +DEATHLINK_ADDR = ROM_START + 0x06FC8C +DEATHMUSIC_FLAG = WRAM_START + 0x004F +DEATHFLAG = WRAM_START + 0x00DB +DEATHLINKRECV = WRAM_START + 0x00E0 +GOALFLAG = WRAM_START + 0x14B6 + +VALID_GAME_STATES = [0x0F, 0x10, 0x2C] + + +class YoshisIslandSNIClient(SNIClient): + game = "Yoshi's Island" + + async def deathlink_kill_player(self, ctx: "SNIContext") -> None: + from SNIClient import DeathState, snes_buffered_write, snes_flush_writes, snes_read + game_state = await snes_read(ctx, GAME_MODE, 0x1) + if game_state[0] != 0x0F: + return + + yoshi_state = await snes_read(ctx, YOSHI_STATE, 0x1) + if yoshi_state[0] != 0x00: + return + + snes_buffered_write(ctx, WRAM_START + 0x026A, bytes([0x01])) + snes_buffered_write(ctx, WRAM_START + 0x00E0, bytes([0x01])) + await snes_flush_writes(ctx) + ctx.death_state = DeathState.dead + ctx.last_death_link = time.time() + + async def validate_rom(self, ctx: "SNIContext") -> bool: + from SNIClient import snes_read + + rom_name = await snes_read(ctx, YOSHISISLAND_ROMHASH_START, ROMHASH_SIZE) + if rom_name is None or rom_name[:7] != b"YOSHIAP": + return False + + ctx.game = self.game + ctx.items_handling = 0b111 # remote items + ctx.rom = rom_name + + death_link = await snes_read(ctx, DEATHLINK_ADDR, 1) + if death_link: + await ctx.update_death_link(bool(death_link[0] & 0b1)) + return True + + async def game_watcher(self, ctx: "SNIContext") -> None: + from SNIClient import snes_buffered_write, snes_flush_writes, snes_read + + game_mode = await snes_read(ctx, GAME_MODE, 0x1) + item_received = await snes_read(ctx, ITEM_RECEIVED, 0x1) + game_music = await snes_read(ctx, DEATHMUSIC_FLAG, 0x1) + goal_flag = await snes_read(ctx, GOALFLAG, 0x1) + + if "DeathLink" in ctx.tags and ctx.last_death_link + 1 < time.time(): + death_flag = await snes_read(ctx, DEATHFLAG, 0x1) + deathlink_death = await snes_read(ctx, DEATHLINKRECV, 0x1) + currently_dead = (game_music[0] == 0x07 or game_mode[0] == 0x12 or + (death_flag[0] == 0x00 and game_mode[0] == 0x11)) and deathlink_death[0] == 0x00 + await ctx.handle_deathlink_state(currently_dead) + + if game_mode is None: + return + elif goal_flag[0] != 0x00: + await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) + ctx.finished_game = True + elif game_mode[0] not in VALID_GAME_STATES: + return + elif item_received[0] > 0x00: + return + + from .Rom import item_values + rom = await snes_read(ctx, YOSHISISLAND_ROMHASH_START, ROMHASH_SIZE) + if rom != ctx.rom: + ctx.rom = None + return + + new_checks = [] + from .Rom import location_table + + location_ram_data = await snes_read(ctx, WRAM_START + 0x1440, 0x80) + for loc_id, loc_data in location_table.items(): + if loc_id not in ctx.locations_checked: + data = location_ram_data[loc_data[0] - 0x1440] + masked_data = data & (1 << loc_data[1]) + bit_set = masked_data != 0 + invert_bit = ((len(loc_data) >= 3) and loc_data[2]) + if bit_set != invert_bit: + new_checks.append(loc_id) + + for new_check_id in new_checks: + ctx.locations_checked.add(new_check_id) + location = ctx.location_names[new_check_id] + total_locations = len(ctx.missing_locations) + len(ctx.checked_locations) + snes_logger.info(f"New Check: {location} ({len(ctx.locations_checked)}/{total_locations})") + await ctx.send_msgs([{"cmd": "LocationChecks", "locations": [new_check_id]}]) + + recv_count = await snes_read(ctx, ITEMQUEUE_HIGH, 2) + recv_index = struct.unpack("H", recv_count)[0] + if recv_index < len(ctx.items_received): + item = ctx.items_received[recv_index] + recv_index += 1 + logging.info("Received %s from %s (%s) (%d/%d in list)" % ( + color(ctx.item_names[item.item], "red", "bold"), + color(ctx.player_names[item.player], "yellow"), + ctx.location_names[item.location], recv_index, len(ctx.items_received))) + + snes_buffered_write(ctx, ITEMQUEUE_HIGH, pack("H", recv_index)) + if item.item in item_values: + item_count = await snes_read(ctx, WRAM_START + item_values[item.item][0], 0x1) + increment = item_values[item.item][1] + new_item_count = item_count[0] + if increment > 1: + new_item_count = increment + else: + new_item_count += increment + + snes_buffered_write(ctx, WRAM_START + item_values[item.item][0], bytes([new_item_count])) + await snes_flush_writes(ctx) diff --git a/worlds/yoshisisland/Items.py b/worlds/yoshisisland/Items.py new file mode 100644 index 000000000000..c97678ed4ed4 --- /dev/null +++ b/worlds/yoshisisland/Items.py @@ -0,0 +1,122 @@ +from typing import Dict, Set, Tuple, NamedTuple, Optional +from BaseClasses import ItemClassification + +class ItemData(NamedTuple): + category: str + code: Optional[int] + classification: ItemClassification + amount: Optional[int] = 1 + +item_table: Dict[str, ItemData] = { + "! Switch": ItemData("Items", 0x302050, ItemClassification.progression), + "Dashed Platform": ItemData("Items", 0x302051, ItemClassification.progression), + "Dashed Stairs": ItemData("Items", 0x302052, ItemClassification.progression), + "Beanstalk": ItemData("Items", 0x302053, ItemClassification.progression), + "Helicopter Morph": ItemData("Morphs", 0x302054, ItemClassification.progression), + "Spring Ball": ItemData("Items", 0x302055, ItemClassification.progression), + "Large Spring Ball": ItemData("Items", 0x302056, ItemClassification.progression), + "Arrow Wheel": ItemData("Items", 0x302057, ItemClassification.progression), + "Vanishing Arrow Wheel": ItemData("Items", 0x302058, ItemClassification.progression), + "Mole Tank Morph": ItemData("Morphs", 0x302059, ItemClassification.progression), + "Watermelon": ItemData("Items", 0x30205A, ItemClassification.progression), + "Ice Melon": ItemData("Items", 0x30205B, ItemClassification.progression), + "Fire Melon": ItemData("Items", 0x30205C, ItemClassification.progression), + "Super Star": ItemData("Items", 0x30205D, ItemClassification.progression), + "Car Morph": ItemData("Morphs", 0x30205E, ItemClassification.progression), + "Flashing Eggs": ItemData("Items", 0x30205F, ItemClassification.progression), + "Giant Eggs": ItemData("Items", 0x302060, ItemClassification.progression), + "Egg Launcher": ItemData("Items", 0x302061, ItemClassification.progression), + "Egg Plant": ItemData("Items", 0x302062, ItemClassification.progression), + "Submarine Morph": ItemData("Morphs", 0x302063, ItemClassification.progression), + "Chomp Rock": ItemData("Items", 0x302064, ItemClassification.progression), + "Poochy": ItemData("Items", 0x302065, ItemClassification.progression), + "Platform Ghost": ItemData("Items", 0x302066, ItemClassification.progression), + "Skis": ItemData("Items", 0x302067, ItemClassification.progression), + "Train Morph": ItemData("Morphs", 0x302068, ItemClassification.progression), + "Key": ItemData("Items", 0x302069, ItemClassification.progression), + "Middle Ring": ItemData("Items", 0x30206A, ItemClassification.progression), + "Bucket": ItemData("Items", 0x30206B, ItemClassification.progression), + "Tulip": ItemData("Items", 0x30206C, ItemClassification.progression), + "Egg Capacity Upgrade": ItemData("Items", 0x30206D, ItemClassification.progression, 5), + "Secret Lens": ItemData("Items", 0x302081, ItemClassification.progression), + + "World 1 Gate": ItemData("Gates", 0x30206E, ItemClassification.progression), + "World 2 Gate": ItemData("Gates", 0x30206F, ItemClassification.progression), + "World 3 Gate": ItemData("Gates", 0x302070, ItemClassification.progression), + "World 4 Gate": ItemData("Gates", 0x302071, ItemClassification.progression), + "World 5 Gate": ItemData("Gates", 0x302072, ItemClassification.progression), + "World 6 Gate": ItemData("Gates", 0x302073, ItemClassification.progression), + + "Extra 1": ItemData("Panels", 0x302074, ItemClassification.progression), + "Extra 2": ItemData("Panels", 0x302075, ItemClassification.progression), + "Extra 3": ItemData("Panels", 0x302076, ItemClassification.progression), + "Extra 4": ItemData("Panels", 0x302077, ItemClassification.progression), + "Extra 5": ItemData("Panels", 0x302078, ItemClassification.progression), + "Extra 6": ItemData("Panels", 0x302079, ItemClassification.progression), + "Extra Panels": ItemData("Panels", 0x30207A, ItemClassification.progression), + + "Bonus 1": ItemData("Panels", 0x30207B, ItemClassification.progression), + "Bonus 2": ItemData("Panels", 0x30207C, ItemClassification.progression), + "Bonus 3": ItemData("Panels", 0x30207D, ItemClassification.progression), + "Bonus 4": ItemData("Panels", 0x30207E, ItemClassification.progression), + "Bonus 5": ItemData("Panels", 0x30207F, ItemClassification.progression), + "Bonus 6": ItemData("Panels", 0x302080, ItemClassification.progression), + "Bonus Panels": ItemData("Panels", 0x302082, ItemClassification.progression), + + "Anytime Egg": ItemData("Consumable", 0x302083, ItemClassification.useful, 0), + "Anywhere Pow": ItemData("Consumable", 0x302084, ItemClassification.filler, 0), + "Winged Cloud Maker": ItemData("Consumable", 0x302085, ItemClassification.filler, 0), + "Pocket Melon": ItemData("Consumable", 0x302086, ItemClassification.filler, 0), + "Pocket Fire Melon": ItemData("Consumable", 0x302087, ItemClassification.filler, 0), + "Pocket Ice Melon": ItemData("Consumable", 0x302088, ItemClassification.filler, 0), + "Magnifying Glass": ItemData("Consumable", 0x302089, ItemClassification.filler, 0), + "+10 Stars": ItemData("Consumable", 0x30208A, ItemClassification.useful, 0), + "+20 Stars": ItemData("Consumable", 0x30208B, ItemClassification.useful, 0), + "1-Up": ItemData("Lives", 0x30208C, ItemClassification.filler, 0), + "2-Up": ItemData("Lives", 0x30208D, ItemClassification.filler, 0), + "3-Up": ItemData("Lives", 0x30208E, ItemClassification.filler, 0), + "10-Up": ItemData("Lives", 0x30208F, ItemClassification.filler, 5), + "Bonus Consumables": ItemData("Events", None, ItemClassification.progression, 0), + "Bandit Consumables": ItemData("Events", None, ItemClassification.progression, 0), + "Bandit Watermelons": ItemData("Events", None, ItemClassification.progression, 0), + + "Fuzzy Trap": ItemData("Traps", 0x302090, ItemClassification.trap, 0), + "Reversal Trap": ItemData("Traps", 0x302091, ItemClassification.trap, 0), + "Darkness Trap": ItemData("Traps", 0x302092, ItemClassification.trap, 0), + "Freeze Trap": ItemData("Traps", 0x302093, ItemClassification.trap, 0), + + "Boss Clear": ItemData("Events", None, ItemClassification.progression, 0), + "Piece of Luigi": ItemData("Items", 0x302095, ItemClassification.progression, 0), + "Saved Baby Luigi": ItemData("Events", None, ItemClassification.progression, 0) +} + +filler_items: Tuple[str, ...] = ( + "Anytime Egg", + "Anywhere Pow", + "Winged Cloud Maker", + "Pocket Melon", + "Pocket Fire Melon", + "Pocket Ice Melon", + "Magnifying Glass", + "+10 Stars", + "+20 Stars", + "1-Up", + "2-Up", + "3-Up" +) + +trap_items: Tuple[str, ...] = ( + "Fuzzy Trap", + "Reversal Trap", + "Darkness Trap", + "Freeze Trap" +) + +def get_item_names_per_category() -> Dict[str, Set[str]]: + categories: Dict[str, Set[str]] = {} + + for name, data in item_table.items(): + if data.category != "Events": + categories.setdefault(data.category, set()).add(name) + + return categories diff --git a/worlds/yoshisisland/Locations.py b/worlds/yoshisisland/Locations.py new file mode 100644 index 000000000000..bc0855260eb4 --- /dev/null +++ b/worlds/yoshisisland/Locations.py @@ -0,0 +1,355 @@ +from typing import List, Optional, NamedTuple, TYPE_CHECKING + +from .Options import PlayerGoal, MinigameChecks +from worlds.generic.Rules import CollectionRule + +if TYPE_CHECKING: + from . import YoshisIslandWorld +from .level_logic import YoshiLogic + + +class LocationData(NamedTuple): + region: str + name: str + code: Optional[int] + LevelID: int + rule: CollectionRule = lambda state: True + + +def get_locations(world: Optional["YoshisIslandWorld"]) -> List[LocationData]: + if world: + logic = YoshiLogic(world) + + location_table: List[LocationData] = [ + LocationData("1-1", "Make Eggs, Throw Eggs: Red Coins", 0x305020, 0x00), + LocationData("1-1", "Make Eggs, Throw Eggs: Flowers", 0x305021, 0x00), + LocationData("1-1", "Make Eggs, Throw Eggs: Stars", 0x305022, 0x00), + LocationData("1-1", "Make Eggs, Throw Eggs: Level Clear", 0x305023, 0x00), + + LocationData("1-2", "Watch Out Below!: Red Coins", 0x305024, 0x01), + LocationData("1-2", "Watch Out Below!: Flowers", 0x305025, 0x01), + LocationData("1-2", "Watch Out Below!: Stars", 0x305026, 0x01), + LocationData("1-2", "Watch Out Below!: Level Clear", 0x305027, 0x01), + + LocationData("1-3", "The Cave Of Chomp Rock: Red Coins", 0x305028, 0x02), + LocationData("1-3", "The Cave Of Chomp Rock: Flowers", 0x305029, 0x02), + LocationData("1-3", "The Cave Of Chomp Rock: Stars", 0x30502A, 0x02), + LocationData("1-3", "The Cave Of Chomp Rock: Level Clear", 0x30502B, 0x02), + + LocationData("1-4", "Burt The Bashful's Fort: Red Coins", 0x30502C, 0x03), + LocationData("1-4", "Burt The Bashful's Fort: Flowers", 0x30502D, 0x03), + LocationData("1-4", "Burt The Bashful's Fort: Stars", 0x30502E, 0x03), + LocationData("1-4", "Burt The Bashful's Fort: Level Clear", 0x30502F, 0x03, lambda state: logic._14CanFightBoss(state)), + LocationData("Burt The Bashful's Boss Room", "Burt The Bashful's Boss Room", None, 0x03, lambda state: logic._14Boss(state)), + + LocationData("1-5", "Hop! Hop! Donut Lifts: Red Coins", 0x305031, 0x04), + LocationData("1-5", "Hop! Hop! Donut Lifts: Flowers", 0x305032, 0x04), + LocationData("1-5", "Hop! Hop! Donut Lifts: Stars", 0x305033, 0x04), + LocationData("1-5", "Hop! Hop! Donut Lifts: Level Clear", 0x305034, 0x04), + + LocationData("1-6", "Shy-Guys On Stilts: Red Coins", 0x305035, 0x05), + LocationData("1-6", "Shy-Guys On Stilts: Flowers", 0x305036, 0x05), + LocationData("1-6", "Shy-Guys On Stilts: Stars", 0x305037, 0x05), + LocationData("1-6", "Shy-Guys On Stilts: Level Clear", 0x305038, 0x05), + + LocationData("1-7", "Touch Fuzzy Get Dizzy: Red Coins", 0x305039, 0x06), + LocationData("1-7", "Touch Fuzzy Get Dizzy: Flowers", 0x30503A, 0x06), + LocationData("1-7", "Touch Fuzzy Get Dizzy: Stars", 0x30503B, 0x06), + LocationData("1-7", "Touch Fuzzy Get Dizzy: Level Clear", 0x30503C, 0x06), + LocationData("1-7", "Touch Fuzzy Get Dizzy: Gather Coins", None, 0x06, lambda state: logic._17Game(state)), + + LocationData("1-8", "Salvo The Slime's Castle: Red Coins", 0x30503D, 0x07), + LocationData("1-8", "Salvo The Slime's Castle: Flowers", 0x30503E, 0x07), + LocationData("1-8", "Salvo The Slime's Castle: Stars", 0x30503F, 0x07), + LocationData("1-8", "Salvo The Slime's Castle: Level Clear", 0x305040, 0x07, lambda state: logic._18CanFightBoss(state)), + LocationData("Salvo The Slime's Boss Room", "Salvo The Slime's Boss Room", None, 0x07, lambda state: logic._18Boss(state)), + + LocationData("1-Bonus", "Flip Cards", None, 0x09), + ############################################################################################ + LocationData("2-1", "Visit Koopa And Para-Koopa: Red Coins", 0x305041, 0x0C), + LocationData("2-1", "Visit Koopa And Para-Koopa: Flowers", 0x305042, 0x0C), + LocationData("2-1", "Visit Koopa And Para-Koopa: Stars", 0x305043, 0x0C), + LocationData("2-1", "Visit Koopa And Para-Koopa: Level Clear", 0x305044, 0x0C), + + LocationData("2-2", "The Baseball Boys: Red Coins", 0x305045, 0x0D), + LocationData("2-2", "The Baseball Boys: Flowers", 0x305046, 0x0D), + LocationData("2-2", "The Baseball Boys: Stars", 0x305047, 0x0D), + LocationData("2-2", "The Baseball Boys: Level Clear", 0x305048, 0x0D), + + LocationData("2-3", "What's Gusty Taste Like?: Red Coins", 0x305049, 0x0E), + LocationData("2-3", "What's Gusty Taste Like?: Flowers", 0x30504A, 0x0E), + LocationData("2-3", "What's Gusty Taste Like?: Stars", 0x30504B, 0x0E), + LocationData("2-3", "What's Gusty Taste Like?: Level Clear", 0x30504C, 0x0E), + + LocationData("2-4", "Bigger Boo's Fort: Red Coins", 0x30504D, 0x0F), + LocationData("2-4", "Bigger Boo's Fort: Flowers", 0x30504E, 0x0F), + LocationData("2-4", "Bigger Boo's Fort: Stars", 0x30504F, 0x0F), + LocationData("2-4", "Bigger Boo's Fort: Level Clear", 0x305050, 0x0F, lambda state: logic._24CanFightBoss(state)), + LocationData("Bigger Boo's Boss Room", "Bigger Boo's Boss Room", None, 0x0F, lambda state: logic._24Boss(state)), + + LocationData("2-5", "Watch Out For Lakitu: Red Coins", 0x305051, 0x10), + LocationData("2-5", "Watch Out For Lakitu: Flowers", 0x305052, 0x10), + LocationData("2-5", "Watch Out For Lakitu: Stars", 0x305053, 0x10), + LocationData("2-5", "Watch Out For Lakitu: Level Clear", 0x305054, 0x10), + + LocationData("2-6", "The Cave Of The Mystery Maze: Red Coins", 0x305055, 0x11), + LocationData("2-6", "The Cave Of The Mystery Maze: Flowers", 0x305056, 0x11), + LocationData("2-6", "The Cave Of The Mystery Maze: Stars", 0x305057, 0x11), + LocationData("2-6", "The Cave Of The Mystery Maze: Level Clear", 0x305058, 0x11), + LocationData("2-6", "The Cave Of the Mystery Maze: Seed Spitting Contest", None, 0x11, lambda state: logic._26Game(state)), + + LocationData("2-7", "Lakitu's Wall: Red Coins", 0x305059, 0x12), + LocationData("2-7", "Lakitu's Wall: Flowers", 0x30505A, 0x12), + LocationData("2-7", "Lakitu's Wall: Stars", 0x30505B, 0x12), + LocationData("2-7", "Lakitu's Wall: Level Clear", 0x30505C, 0x12), + LocationData("2-7", "Lakitu's Wall: Gather Coins", None, 0x12, lambda state: logic._27Game(state)), + + LocationData("2-8", "The Potted Ghost's Castle: Red Coins", 0x30505D, 0x13), + LocationData("2-8", "The Potted Ghost's Castle: Flowers", 0x30505E, 0x13), + LocationData("2-8", "The Potted Ghost's Castle: Stars", 0x30505F, 0x13), + LocationData("2-8", "The Potted Ghost's Castle: Level Clear", 0x305060, 0x13, lambda state: logic._28CanFightBoss(state)), + LocationData("Roger The Ghost's Boss Room", "Roger The Ghost's Boss Room", None, 0x13, lambda state: logic._28Boss(state)), + ############################################################################################### + LocationData("3-1", "Welcome To Monkey World!: Red Coins", 0x305061, 0x18), + LocationData("3-1", "Welcome To Monkey World!: Flowers", 0x305062, 0x18), + LocationData("3-1", "Welcome To Monkey World!: Stars", 0x305063, 0x18), + LocationData("3-1", "Welcome To Monkey World!: Level Clear", 0x305064, 0x18), + + LocationData("3-2", "Jungle Rhythm...: Red Coins", 0x305065, 0x19), + LocationData("3-2", "Jungle Rhythm...: Flowers", 0x305066, 0x19), + LocationData("3-2", "Jungle Rhythm...: Stars", 0x305067, 0x19), + LocationData("3-2", "Jungle Rhythm...: Level Clear", 0x305068, 0x19), + + LocationData("3-3", "Nep-Enuts' Domain: Red Coins", 0x305069, 0x1A), + LocationData("3-3", "Nep-Enuts' Domain: Flowers", 0x30506A, 0x1A), + LocationData("3-3", "Nep-Enuts' Domain: Stars", 0x30506B, 0x1A), + LocationData("3-3", "Nep-Enuts' Domain: Level Clear", 0x30506C, 0x1A), + + LocationData("3-4", "Prince Froggy's Fort: Red Coins", 0x30506D, 0x1B), + LocationData("3-4", "Prince Froggy's Fort: Flowers", 0x30506E, 0x1B), + LocationData("3-4", "Prince Froggy's Fort: Stars", 0x30506F, 0x1B), + LocationData("3-4", "Prince Froggy's Fort: Level Clear", 0x305070, 0x1B, lambda state: logic._34CanFightBoss(state)), + LocationData("Prince Froggy's Boss Room", "Prince Froggy's Boss Room", None, 0x1B, lambda state: logic._34Boss(state)), + + LocationData("3-5", "Jammin' Through The Trees: Red Coins", 0x305071, 0x1C), + LocationData("3-5", "Jammin' Through The Trees: Flowers", 0x305072, 0x1C), + LocationData("3-5", "Jammin' Through The Trees: Stars", 0x305073, 0x1C), + LocationData("3-5", "Jammin' Through The Trees: Level Clear", 0x305074, 0x1C), + + LocationData("3-6", "The Cave Of Harry Hedgehog: Red Coins", 0x305075, 0x1D), + LocationData("3-6", "The Cave Of Harry Hedgehog: Flowers", 0x305076, 0x1D), + LocationData("3-6", "The Cave Of Harry Hedgehog: Stars", 0x305077, 0x1D), + LocationData("3-6", "The Cave Of Harry Hedgehog: Level Clear", 0x305078, 0x1D), + + LocationData("3-7", "Monkeys' Favorite Lake: Red Coins", 0x305079, 0x1E), + LocationData("3-7", "Monkeys' Favorite Lake: Flowers", 0x30507A, 0x1E), + LocationData("3-7", "Monkeys' Favorite Lake: Stars", 0x30507B, 0x1E), + LocationData("3-7", "Monkeys' Favorite Lake: Level Clear", 0x30507C, 0x1E), + + LocationData("3-8", "Naval Piranha's Castle: Red Coins", 0x30507D, 0x1F), + LocationData("3-8", "Naval Piranha's Castle: Flowers", 0x30507E, 0x1F), + LocationData("3-8", "Naval Piranha's Castle: Stars", 0x30507F, 0x1F), + LocationData("3-8", "Naval Piranha's Castle: Level Clear", 0x305080, 0x1F, lambda state: logic._38CanFightBoss(state)), + LocationData("Naval Piranha's Boss Room", "Naval Piranha's Boss Room", None, 0x1F, lambda state: logic._38Boss(state)), + + LocationData("3-Bonus", "Drawing Lots", None, 0x21), + ############################################################################################## + LocationData("4-1", "GO! GO! MARIO!!: Red Coins", 0x305081, 0x24), + LocationData("4-1", "GO! GO! MARIO!!: Flowers", 0x305082, 0x24), + LocationData("4-1", "GO! GO! MARIO!!: Stars", 0x305083, 0x24), + LocationData("4-1", "GO! GO! MARIO!!: Level Clear", 0x305084, 0x24), + + LocationData("4-2", "The Cave Of The Lakitus: Red Coins", 0x305085, 0x25), + LocationData("4-2", "The Cave Of The Lakitus: Flowers", 0x305086, 0x25), + LocationData("4-2", "The Cave Of The Lakitus: Stars", 0x305087, 0x25), + LocationData("4-2", "The Cave Of The Lakitus: Level Clear", 0x305088, 0x25), + + LocationData("4-3", "Don't Look Back!: Red Coins", 0x305089, 0x26), + LocationData("4-3", "Don't Look Back!: Flowers", 0x30508A, 0x26), + LocationData("4-3", "Don't Look Back!: Stars", 0x30508B, 0x26), + LocationData("4-3", "Don't Look Back!: Level Clear", 0x30508C, 0x26), + + LocationData("4-4", "Marching Milde's Fort: Red Coins", 0x30508D, 0x27), + LocationData("4-4", "Marching Milde's Fort: Flowers", 0x30508E, 0x27), + LocationData("4-4", "Marching Milde's Fort: Stars", 0x30508F, 0x27), + LocationData("4-4", "Marching Milde's Fort: Level Clear", 0x305090, 0x27, lambda state: logic._44CanFightBoss(state)), + LocationData("Marching Milde's Boss Room", "Marching Milde's Boss Room", None, 0x27, lambda state: logic._44Boss(state)), + + LocationData("4-5", "Chomp Rock Zone: Red Coins", 0x305091, 0x28), + LocationData("4-5", "Chomp Rock Zone: Flowers", 0x305092, 0x28), + LocationData("4-5", "Chomp Rock Zone: Stars", 0x305093, 0x28), + LocationData("4-5", "Chomp Rock Zone: Level Clear", 0x305094, 0x28), + + LocationData("4-6", "Lake Shore Paradise: Red Coins", 0x305095, 0x29), + LocationData("4-6", "Lake Shore Paradise: Flowers", 0x305096, 0x29), + LocationData("4-6", "Lake Shore Paradise: Stars", 0x305097, 0x29), + LocationData("4-6", "Lake Shore Paradise: Level Clear", 0x305098, 0x29), + + LocationData("4-7", "Ride Like The Wind: Red Coins", 0x305099, 0x2A), + LocationData("4-7", "Ride Like The Wind: Flowers", 0x30509A, 0x2A), + LocationData("4-7", "Ride Like The Wind: Stars", 0x30509B, 0x2A), + LocationData("4-7", "Ride Like The Wind: Level Clear", 0x30509C, 0x2A), + LocationData("4-7", "Ride Like The Wind: Gather Coins", None, 0x2A, lambda state: logic._47Game(state)), + + LocationData("4-8", "Hookbill The Koopa's Castle: Red Coins", 0x30509D, 0x2B), + LocationData("4-8", "Hookbill The Koopa's Castle: Flowers", 0x30509E, 0x2B), + LocationData("4-8", "Hookbill The Koopa's Castle: Stars", 0x30509F, 0x2B), + LocationData("4-8", "Hookbill The Koopa's Castle: Level Clear", 0x3050A0, 0x2B, lambda state: logic._48CanFightBoss(state)), + LocationData("Hookbill The Koopa's Boss Room", "Hookbill The Koopa's Boss Room", None, 0x2B, lambda state: logic._48Boss(state)), + + LocationData("4-Bonus", "Match Cards", None, 0x2D), + ###################################################################################################### + LocationData("5-1", "BLIZZARD!!!: Red Coins", 0x3050A1, 0x30), + LocationData("5-1", "BLIZZARD!!!: Flowers", 0x3050A2, 0x30), + LocationData("5-1", "BLIZZARD!!!: Stars", 0x3050A3, 0x30), + LocationData("5-1", "BLIZZARD!!!: Level Clear", 0x3050A4, 0x30), + + LocationData("5-2", "Ride The Ski Lifts: Red Coins", 0x3050A5, 0x31), + LocationData("5-2", "Ride The Ski Lifts: Flowers", 0x3050A6, 0x31), + LocationData("5-2", "Ride The Ski Lifts: Stars", 0x3050A7, 0x31), + LocationData("5-2", "Ride The Ski Lifts: Level Clear", 0x3050A8, 0x31), + + LocationData("5-3", "Danger - Icy Conditions Ahead: Red Coins", 0x3050A9, 0x32), + LocationData("5-3", "Danger - Icy Conditions Ahead: Flowers", 0x3050AA, 0x32), + LocationData("5-3", "Danger - Icy Conditions Ahead: Stars", 0x3050AB, 0x32), + LocationData("5-3", "Danger - Icy Conditions Ahead: Level Clear", 0x3050AC, 0x32), + + LocationData("5-4", "Sluggy The Unshaven's Fort: Red Coins", 0x3050AD, 0x33), + LocationData("5-4", "Sluggy The Unshaven's Fort: Flowers", 0x3050AE, 0x33), + LocationData("5-4", "Sluggy The Unshaven's Fort: Stars", 0x3050AF, 0x33), + LocationData("5-4", "Sluggy The Unshaven's Fort: Level Clear", 0x3050B0, 0x33, lambda state: logic._54CanFightBoss(state)), + LocationData("Sluggy The Unshaven's Boss Room", "Sluggy The Unshaven's Boss Room", None, 0x33, lambda state: logic._54Boss(state)), + + LocationData("5-5", "Goonie Rides!: Red Coins", 0x3050B1, 0x34), + LocationData("5-5", "Goonie Rides!: Flowers", 0x3050B2, 0x34), + LocationData("5-5", "Goonie Rides!: Stars", 0x3050B3, 0x34), + LocationData("5-5", "Goonie Rides!: Level Clear", 0x3050B4, 0x34), + + LocationData("5-6", "Welcome To Cloud World: Red Coins", 0x3050B5, 0x35), + LocationData("5-6", "Welcome To Cloud World: Flowers", 0x3050B6, 0x35), + LocationData("5-6", "Welcome To Cloud World: Stars", 0x3050B7, 0x35), + LocationData("5-6", "Welcome To Cloud World: Level Clear", 0x3050B8, 0x35), + + LocationData("5-7", "Shifting Platforms Ahead: Red Coins", 0x3050B9, 0x36), + LocationData("5-7", "Shifting Platforms Ahead: Flowers", 0x3050BA, 0x36), + LocationData("5-7", "Shifting Platforms Ahead: Stars", 0x3050BB, 0x36), + LocationData("5-7", "Shifting Platforms Ahead: Level Clear", 0x3050BC, 0x36), + + LocationData("5-8", "Raphael The Raven's Castle: Red Coins", 0x3050BD, 0x37), + LocationData("5-8", "Raphael The Raven's Castle: Flowers", 0x3050BE, 0x37), + LocationData("5-8", "Raphael The Raven's Castle: Stars", 0x3050BF, 0x37), + LocationData("5-8", "Raphael The Raven's Castle: Level Clear", 0x3050C0, 0x37, lambda state: logic._58CanFightBoss(state)), + LocationData("Raphael The Raven's Boss Room", "Raphael The Raven's Boss Room", None, 0x37, lambda state: logic._58Boss(state)), + ###################################################################################################### + + LocationData("6-1", "Scary Skeleton Goonies!: Red Coins", 0x3050C1, 0x3C), + LocationData("6-1", "Scary Skeleton Goonies!: Flowers", 0x3050C2, 0x3C), + LocationData("6-1", "Scary Skeleton Goonies!: Stars", 0x3050C3, 0x3C), + LocationData("6-1", "Scary Skeleton Goonies!: Level Clear", 0x3050C4, 0x3C), + + LocationData("6-2", "The Cave Of The Bandits: Red Coins", 0x3050C5, 0x3D), + LocationData("6-2", "The Cave Of The Bandits: Flowers", 0x3050C6, 0x3D), + LocationData("6-2", "The Cave Of The Bandits: Stars", 0x3050C7, 0x3D), + LocationData("6-2", "The Cave Of The Bandits: Level Clear", 0x3050C8, 0x3D), + + LocationData("6-3", "Beware The Spinning Logs: Red Coins", 0x3050C9, 0x3E), + LocationData("6-3", "Beware The Spinning Logs: Flowers", 0x3050CA, 0x3E), + LocationData("6-3", "Beware The Spinning Logs: Stars", 0x3050CB, 0x3E), + LocationData("6-3", "Beware The Spinning Logs: Level Clear", 0x3050CC, 0x3E), + + LocationData("6-4", "Tap-Tap The Red Nose's Fort: Red Coins", 0x3050CD, 0x3F), + LocationData("6-4", "Tap-Tap The Red Nose's Fort: Flowers", 0x3050CE, 0x3F), + LocationData("6-4", "Tap-Tap The Red Nose's Fort: Stars", 0x3050CF, 0x3F), + LocationData("6-4", "Tap-Tap The Red Nose's Fort: Level Clear", 0x3050D0, 0x3F, lambda state: logic._64CanFightBoss(state)), + LocationData("Tap-Tap The Red Nose's Boss Room", "Tap-Tap The Red Nose's Boss Room", None, 0x3F, lambda state: logic._64Boss(state)), + + LocationData("6-5", "The Very Loooooong Cave: Red Coins", 0x3050D1, 0x40), + LocationData("6-5", "The Very Loooooong Cave: Flowers", 0x3050D2, 0x40), + LocationData("6-5", "The Very Loooooong Cave: Stars", 0x3050D3, 0x40), + LocationData("6-5", "The Very Loooooong Cave: Level Clear", 0x3050D4, 0x40), + + LocationData("6-6", "The Deep, Underground Maze: Red Coins", 0x3050D5, 0x41), + LocationData("6-6", "The Deep, Underground Maze: Flowers", 0x3050D6, 0x41), + LocationData("6-6", "The Deep, Underground Maze: Stars", 0x3050D7, 0x41), + LocationData("6-6", "The Deep, Underground Maze: Level Clear", 0x3050D8, 0x41), + + LocationData("6-7", "KEEP MOVING!!!!: Red Coins", 0x3050D9, 0x42), + LocationData("6-7", "KEEP MOVING!!!!: Flowers", 0x3050DA, 0x42), + LocationData("6-7", "KEEP MOVING!!!!: Stars", 0x3050DB, 0x42), + LocationData("6-7", "KEEP MOVING!!!!: Level Clear", 0x3050DC, 0x42), + + LocationData("6-8", "King Bowser's Castle: Red Coins", 0x3050DD, 0x43), + LocationData("6-8", "King Bowser's Castle: Flowers", 0x3050DE, 0x43), + LocationData("6-8", "King Bowser's Castle: Stars", 0x3050DF, 0x43) + ] + + if not world or world.options.extras_enabled: + location_table += [ + LocationData("1-Extra", "Poochy Ain't Stupid: Red Coins", 0x3050E0, 0x08), + LocationData("1-Extra", "Poochy Ain't Stupid: Flowers", 0x3050E1, 0x08), + LocationData("1-Extra", "Poochy Ain't Stupid: Stars", 0x3050E2, 0x08), + LocationData("1-Extra", "Poochy Ain't Stupid: Level Clear", 0x3050E3, 0x08), + + LocationData("2-Extra", "Hit That Switch!!: Red Coins", 0x3050E4, 0x14), + LocationData("2-Extra", "Hit That Switch!!: Flowers", 0x3050E5, 0x14), + LocationData("2-Extra", "Hit That Switch!!: Stars", 0x3050E6, 0x14), + LocationData("2-Extra", "Hit That Switch!!: Level Clear", 0x3050E7, 0x14), + + LocationData("3-Extra", "More Monkey Madness: Red Coins", 0x3050E8, 0x20), + LocationData("3-Extra", "More Monkey Madness: Flowers", 0x3050E9, 0x20), + LocationData("3-Extra", "More Monkey Madness: Stars", 0x3050EA, 0x20), + LocationData("3-Extra", "More Monkey Madness: Level Clear", 0x3050EB, 0x20), + + LocationData("4-Extra", "The Impossible? Maze: Red Coins", 0x3050EC, 0x2C), + LocationData("4-Extra", "The Impossible? Maze: Flowers", 0x3050ED, 0x2C), + LocationData("4-Extra", "The Impossible? Maze: Stars", 0x3050EE, 0x2C), + LocationData("4-Extra", "The Impossible? Maze: Level Clear", 0x3050EF, 0x2C), + + LocationData("5-Extra", "Kamek's Revenge: Red Coins", 0x3050F0, 0x38), + LocationData("5-Extra", "Kamek's Revenge: Flowers", 0x3050F1, 0x38), + LocationData("5-Extra", "Kamek's Revenge: Stars", 0x3050F2, 0x38), + LocationData("5-Extra", "Kamek's Revenge: Level Clear", 0x3050F3, 0x38), + + LocationData("6-Extra", "Castles - Masterpiece Set: Red Coins", 0x3050F4, 0x44), + LocationData("6-Extra", "Castles - Masterpiece Set: Flowers", 0x3050F5, 0x44), + LocationData("6-Extra", "Castles - Masterpiece Set: Stars", 0x3050F6, 0x44), + LocationData("6-Extra", "Castles - Masterpiece Set: Level Clear", 0x3050F7, 0x44), + ] + + if not world or world.options.minigame_checks in {MinigameChecks.option_bandit_games, MinigameChecks.option_both}: + location_table += [ + LocationData("1-3", "The Cave Of Chomp Rock: Bandit Game", 0x3050F8, 0x02, lambda state: logic._13Game(state)), + LocationData("1-7", "Touch Fuzzy Get Dizzy: Bandit Game", 0x3050F9, 0x06, lambda state: logic._17Game(state)), + LocationData("2-1", "Visit Koopa And Para-Koopa: Bandit Game", 0x3050FA, 0x0C, lambda state: logic._21Game(state)), + LocationData("2-3", "What's Gusty Taste Like?: Bandit Game", 0x3050FB, 0x0E, lambda state: logic._23Game(state)), + LocationData("2-6", "The Cave Of The Mystery Maze: Bandit Game", 0x3050FC, 0x11, lambda state: logic._26Game(state)), + LocationData("2-7", "Lakitu's Wall: Bandit Game", 0x3050FD, 0x12, lambda state: logic._27Game(state)), + LocationData("3-2", "Jungle Rhythm...: Bandit Game", 0x3050FE, 0x19, lambda state: logic._32Game(state)), + LocationData("3-7", "Monkeys' Favorite Lake: Bandit Game", 0x3050FF, 0x1E, lambda state: logic._37Game(state)), + LocationData("4-2", "The Cave Of The Lakitus: Bandit Game", 0x305100, 0x25, lambda state: logic._42Game(state)), + LocationData("4-6", "Lake Shore Paradise: Bandit Game", 0x305101, 0x29, lambda state: logic._46Game(state)), + LocationData("4-7", "Ride Like The Wind: Bandit Game", 0x305102, 0x2A, lambda state: logic._47Game(state)), + LocationData("5-1", "BLIZZARD!!!: Bandit Game", 0x305103, 0x30, lambda state: logic._51Game(state)), + LocationData("6-1", "Scary Skeleton Goonies!: Bandit Game", 0x305104, 0x3C, lambda state: logic._61Game(state)), + LocationData("6-7", "KEEP MOVING!!!!: Bandit Game", 0x305105, 0x42, lambda state: logic._67Game(state)), + ] + + if not world or world.options.minigame_checks in {MinigameChecks.option_bonus_games, MinigameChecks.option_both}: + location_table += [ + LocationData("1-Bonus", "Flip Cards: Victory", 0x305106, 0x09), + LocationData("2-Bonus", "Scratch And Match: Victory", 0x305107, 0x15), + LocationData("3-Bonus", "Drawing Lots: Victory", 0x305108, 0x21), + LocationData("4-Bonus", "Match Cards: Victory", 0x305109, 0x2D), + LocationData("5-Bonus", "Roulette: Victory", 0x30510A, 0x39), + LocationData("6-Bonus", "Slot Machine: Victory", 0x30510B, 0x45), + ] + if not world or world.options.goal == PlayerGoal.option_luigi_hunt: + location_table += [ + LocationData("Overworld", "Reconstituted Luigi", None, 0x00, lambda state: logic.reconstitute_luigi(state)), + ] + if not world or world.options.goal == PlayerGoal.option_bowser: + location_table += [ + LocationData("Bowser's Room", "King Bowser's Castle: Level Clear", None, 0x43, lambda state: logic._68Clear(state)), + ] + + return location_table diff --git a/worlds/yoshisisland/Options.py b/worlds/yoshisisland/Options.py new file mode 100644 index 000000000000..d02999309f61 --- /dev/null +++ b/worlds/yoshisisland/Options.py @@ -0,0 +1,296 @@ +from dataclasses import dataclass +from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, PerGameCommonOptions + + +class ExtrasEnabled(Toggle): + """If enabled, the more difficult Extra stages will be added into logic. Otherwise, they will be inaccessible.""" + display_name = "Include Extra Stages" + + +class SplitExtras(Toggle): + """If enabled, Extra stages will be unlocked individually. Otherwise, there will be a single 'Extra Panels' item that unlocks all of them.""" + display_name = "Split Extra Stages" + + +class SplitBonus(Toggle): + """If enabled, Bonus Games will be unlocked individually. Otherwise, there will be a single 'Bonus Panels' item that unlocks all of them.""" + display_name = "Split Bonus Games" + + +class ObjectVis(Choice): + """This will determine the default visibility of objects revealed by the Magnifying Glass. + Strict Logic will expect the Secret Lens or a Magnifying Glass to interact with hidden clouds containing stars if they are not set to visible by default.""" + display_name = "Hidden Object Visibility" + option_none = 0 + option_coins_only = 1 + option_clouds_only = 2 + option_full = 3 + default = 1 + + +class SoftlockPrevention(DefaultOnToggle): + """If enabled, hold R + X to warp to the last used Middle Ring, or the start of the level if none have been activated.""" + display_name = "Softlock Prevention Code" + + +class StageLogic(Choice): + """This determines what logic mode the stages will use. + Strict: Best for casual players or those new to playing Yoshi's Island in AP. Level requirements won't expect anything too difficult of the player. + Loose: Recommended for veterans of the original game. Won't expect anything too difficult, but may expect unusual platforming or egg throws. + Expert: Logic may expect advanced knowledge or memorization of level layouts, as well as jumps the player may only have one chance to make without restarting.""" + display_name = "Stage Logic" + option_strict = 0 + option_loose = 1 + option_expert = 2 + # option_glitched = 3 + default = 0 + + +class ShuffleMiddleRings(Toggle): + """If enabled, Middle Rings will be added to the item pool.""" + display_name = "Shuffle Middle Rings" + + +class ShuffleSecretLens(Toggle): + """If enabled, the Secret Lens will be added to the item pool. + The Secret Lens will act as a permanent Magnifying Glass.""" + display_name = "Add Secret Lens" + + +class DisableAutoScrollers(Toggle): + """If enabled, will disable autoscrolling during levels, except during levels which cannot function otherwise.""" + display_name = "Disable Autoscrolling" + + +class ItemLogic(Toggle): + """This will enable logic to expect consumables to be used from the inventory in place of some major items. + Logic will expect you to have access to an Overworld bonus game, or a bandit game to get the necessary items. + Logic will NOT expect grinding end-of-level bonus games, or any inventory consumables received from checks. + Casual logic will only expect consumables from Overworld games; Loose and Expert may expect them from bandit games.""" + display_name = "Consumable Logic" + + +class MinigameChecks(Choice): + """This will set minigame victories to give Archipelago checks. + This will not randomize minigames amongst themselves, and is compatible with item logic. + Bonus games will be expected to be cleared from the Overworld, not the end of levels. + Additionally, 1-Up bonus games will accept any profit as a victory.""" + display_name = "Minigame Reward Checks" + option_none = 0 + option_bandit_games = 1 + option_bonus_games = 2 + option_both = 3 + default = 0 + + +class StartingWorld(Choice): + """This sets which world you start in. Other worlds can be accessed by receiving a Gate respective to that world.""" + display_name = "Starting World" + option_world_1 = 0 + option_world_2 = 1 + option_world_3 = 2 + option_world_4 = 3 + option_world_5 = 4 + option_world_6 = 5 + default = 0 + + +class StartingLives(Range): + """This sets the amount of lives Yoshi will have upon loading the game.""" + display_name = "Starting Life Count" + range_start = 1 + range_end = 999 + default = 3 + + +class PlayerGoal(Choice): + """This sets the goal. Bowser goal requires defeating Bowser at the end of 6-8, while Luigi Hunt requires collecting all required Luigi Pieces.""" + display_name = "Goal" + option_bowser = 0 + option_luigi_hunt = 1 + default = 0 + + +class LuigiPiecesReq(Range): + """This will set how many Luigi Pieces are required to trigger a victory.""" + display_name = "Luigi Pieces Required" + range_start = 1 + range_end = 100 + default = 25 + + +class LuigiPiecesAmt(Range): + """This will set how many Luigi Pieces are in the item pool. + If the number in the pool is lower than the number required, + the amount in the pool will be randomized, with the minimum being the amount required.""" + display_name = "Amount of Luigi Pieces" + range_start = 1 + range_end = 100 + default = 50 + + +class FinalLevelBosses(Range): + """This sets how many bosses need to be defeated to access 6-8. + You can check this in-game by pressing SELECT while in any level.""" + display_name = "Bosses Required for 6-8 Unlock" + range_start = 0 + range_end = 11 + default = 5 + + +class FinalBossBosses(Range): + """This sets how many bosses need to be defeated to access the boss of 6-8. + You can check this in-game by pressing SELECT while in any level.""" + display_name = "Bosses Required for 6-8 Clear" + range_start = 0 + range_end = 11 + default = 0 + + +class BowserDoor(Choice): + """This will set which route you take through 6-8. + Manual: You go through the door that you hit with an egg, as normal. + Doors: Route will be forced to be the door chosen here, regardless of which door you hit. + Gauntlet: You will be forced to go through all 4 routes in order before the final hallway.""" + display_name = "Bowser's Castle Doors" + option_manual = 0 + option_door_1 = 1 + option_door_2 = 2 + option_door_3 = 3 + option_door_4 = 4 + option_gauntlet = 5 + default = 0 + + +class BossShuffle(Toggle): + """This whill shuffle which boss each boss door will lead to. Each boss can only appear once, and Baby Bowser is left alone.""" + display_name = "Boss Shuffle" + + +class LevelShuffle(Choice): + """Disabled: All levels will appear in their normal location. + Bosses Guranteed: All worlds will have a boss on -4 and -8. + Full: Worlds may have more than 2 or no bosses in them. + Regardless of the setting, 6-8 and Extra stages are not shuffled.""" + display_name = "Level Shuffle" + option_disabled = 0 + option_bosses_guranteed = 1 + option_full = 2 + default = 0 + + +class YoshiColors(Choice): + """Sets the Yoshi color for each level. + Normal will use the vanilla colors. + Random order will generate a random order of colors that will be used in each level. The stage 1 color will be used for Extra stages, and 6-8. + Random color will generate a random color for each stage. + Singularity will use a single color defined under 'Singularity Yoshi Color' for use in all stages.""" + display_name = "Yoshi Colors" + option_normal = 0 + option_random_order = 1 + option_random_color = 2 + option_singularity = 3 + default = 0 + + +class SinguColor(Choice): + """Sets which color Yoshi will be if Yoshi Colors is set to singularity.""" + display_name = "Singularity Yoshi Color" + option_green = 0 + option_pink = 1 + option_cyan = 3 + option_yellow = 2 + option_purple = 4 + option_brown = 5 + option_red = 6 + option_blue = 7 + default = 0 + + +class BabySound(Choice): + """Change the sound that Baby Mario makes when not on Yoshi.""" + display_name = "Mario Sound Effect" + option_normal = 0 + option_disabled = 1 + option_random_sound_effect = 2 + default = 0 + + +class TrapsEnabled(Toggle): + """Will place traps into the item pool. + Traps have a variety of negative effects, and will only replace filler items.""" + display_name = "Traps Enabled" + + +class TrapPercent(Range): + """Percentage of the item pool that becomes replaced with traps.""" + display_name = "Trap Chance" + range_start = 0 + range_end = 100 + default = 10 + +# class EnableScrets(Range): + # """This sets the amount of lives Yoshi will have upon loading the game.""" + # display_name = "Starting Life Count" + # range_start = 1 + # range_end = 255 + # default = 3 + +# class BackgroundColors(Range): + # """This sets the amount of lives Yoshi will have upon loading the game.""" + # display_name = "Starting Life Count" + # range_start = 1 + # range_end = 255 + # default = 3 + +# class Foreground Colors(Range): + # """This sets the amount of lives Yoshi will have upon loading the game.""" + # display_name = "Starting Life Count" + # range_start = 1 + # range_end = 255 + # default = 3 + +# class Music Shuffle(Range): + # """This sets the amount of lives Yoshi will have upon loading the game.""" + # display_name = "Starting Life Count" + # range_start = 1 + # range_end = 255 + # default = 3 + +# class Star Loss Rate(Range): + # """This sets the amount of lives Yoshi will have upon loading the game.""" + # display_name = "Starting Life Count" + # range_start = 1 + # range_end = 255 + # default = 3 + + +@dataclass +class YoshisIslandOptions(PerGameCommonOptions): + starting_world: StartingWorld + starting_lives: StartingLives + goal: PlayerGoal + luigi_pieces_required: LuigiPiecesReq + luigi_pieces_in_pool: LuigiPiecesAmt + extras_enabled: ExtrasEnabled + minigame_checks: MinigameChecks + split_extras: SplitExtras + split_bonus: SplitBonus + hidden_object_visibility: ObjectVis + add_secretlens: ShuffleSecretLens + shuffle_midrings: ShuffleMiddleRings + stage_logic: StageLogic + item_logic: ItemLogic + disable_autoscroll: DisableAutoScrollers + softlock_prevention: SoftlockPrevention + castle_open_condition: FinalLevelBosses + castle_clear_condition: FinalBossBosses + bowser_door_mode: BowserDoor + level_shuffle: LevelShuffle + boss_shuffle: BossShuffle + yoshi_colors: YoshiColors + yoshi_singularity_color: SinguColor + baby_mario_sound: BabySound + traps_enabled: TrapsEnabled + trap_percent: TrapPercent + death_link: DeathLink diff --git a/worlds/yoshisisland/Regions.py b/worlds/yoshisisland/Regions.py new file mode 100644 index 000000000000..59e93cfe7979 --- /dev/null +++ b/worlds/yoshisisland/Regions.py @@ -0,0 +1,248 @@ +from typing import List, Dict, TYPE_CHECKING +from BaseClasses import Region, Location +from .Locations import LocationData +from .Options import MinigameChecks +from .level_logic import YoshiLogic +from .setup_bosses import BossReqs +if TYPE_CHECKING: + from . import YoshisIslandWorld + + +class YoshisIslandLocation(Location): + game: str = "Yoshi's Island" + level_id: int + + def __init__(self, player: int, name: str = " ", address: int = None, parent=None, level_id: int = None): + super().__init__(player, name, address, parent) + self.level_id = level_id + + +def init_areas(world: "YoshisIslandWorld", locations: List[LocationData]) -> None: + multiworld = world.multiworld + player = world.player + logic = YoshiLogic(world) + + locations_per_region = get_locations_per_region(locations) + + regions = [ + create_region(world, player, locations_per_region, "Menu"), + create_region(world, player, locations_per_region, "Overworld"), + create_region(world, player, locations_per_region, "World 1"), + create_region(world, player, locations_per_region, "World 2"), + create_region(world, player, locations_per_region, "World 3"), + create_region(world, player, locations_per_region, "World 4"), + create_region(world, player, locations_per_region, "World 5"), + create_region(world, player, locations_per_region, "World 6"), + + create_region(world, player, locations_per_region, "1-1"), + create_region(world, player, locations_per_region, "1-2"), + create_region(world, player, locations_per_region, "1-3"), + create_region(world, player, locations_per_region, "1-4"), + create_region(world, player, locations_per_region, "Burt The Bashful's Boss Room"), + create_region(world, player, locations_per_region, "1-5"), + create_region(world, player, locations_per_region, "1-6"), + create_region(world, player, locations_per_region, "1-7"), + create_region(world, player, locations_per_region, "1-8"), + create_region(world, player, locations_per_region, "Salvo The Slime's Boss Room"), + + create_region(world, player, locations_per_region, "2-1"), + create_region(world, player, locations_per_region, "2-2"), + create_region(world, player, locations_per_region, "2-3"), + create_region(world, player, locations_per_region, "2-4"), + create_region(world, player, locations_per_region, "Bigger Boo's Boss Room"), + create_region(world, player, locations_per_region, "2-5"), + create_region(world, player, locations_per_region, "2-6"), + create_region(world, player, locations_per_region, "2-7"), + create_region(world, player, locations_per_region, "2-8"), + create_region(world, player, locations_per_region, "Roger The Ghost's Boss Room"), + + create_region(world, player, locations_per_region, "3-1"), + create_region(world, player, locations_per_region, "3-2"), + create_region(world, player, locations_per_region, "3-3"), + create_region(world, player, locations_per_region, "3-4"), + create_region(world, player, locations_per_region, "Prince Froggy's Boss Room"), + create_region(world, player, locations_per_region, "3-5"), + create_region(world, player, locations_per_region, "3-6"), + create_region(world, player, locations_per_region, "3-7"), + create_region(world, player, locations_per_region, "3-8"), + create_region(world, player, locations_per_region, "Naval Piranha's Boss Room"), + + create_region(world, player, locations_per_region, "4-1"), + create_region(world, player, locations_per_region, "4-2"), + create_region(world, player, locations_per_region, "4-3"), + create_region(world, player, locations_per_region, "4-4"), + create_region(world, player, locations_per_region, "Marching Milde's Boss Room"), + create_region(world, player, locations_per_region, "4-5"), + create_region(world, player, locations_per_region, "4-6"), + create_region(world, player, locations_per_region, "4-7"), + create_region(world, player, locations_per_region, "4-8"), + create_region(world, player, locations_per_region, "Hookbill The Koopa's Boss Room"), + + create_region(world, player, locations_per_region, "5-1"), + create_region(world, player, locations_per_region, "5-2"), + create_region(world, player, locations_per_region, "5-3"), + create_region(world, player, locations_per_region, "5-4"), + create_region(world, player, locations_per_region, "Sluggy The Unshaven's Boss Room"), + create_region(world, player, locations_per_region, "5-5"), + create_region(world, player, locations_per_region, "5-6"), + create_region(world, player, locations_per_region, "5-7"), + create_region(world, player, locations_per_region, "5-8"), + create_region(world, player, locations_per_region, "Raphael The Raven's Boss Room"), + + create_region(world, player, locations_per_region, "6-1"), + create_region(world, player, locations_per_region, "6-2"), + create_region(world, player, locations_per_region, "6-3"), + create_region(world, player, locations_per_region, "6-4"), + create_region(world, player, locations_per_region, "Tap-Tap The Red Nose's Boss Room"), + create_region(world, player, locations_per_region, "6-5"), + create_region(world, player, locations_per_region, "6-6"), + create_region(world, player, locations_per_region, "6-7"), + create_region(world, player, locations_per_region, "6-8"), + create_region(world, player, locations_per_region, "Bowser's Room"), + ] + + if world.options.extras_enabled: + regions.insert(68, create_region(world, player, locations_per_region, "6-Extra")) + regions.insert(58, create_region(world, player, locations_per_region, "5-Extra")) + regions.insert(48, create_region(world, player, locations_per_region, "4-Extra")) + regions.insert(38, create_region(world, player, locations_per_region, "3-Extra")) + regions.insert(28, create_region(world, player, locations_per_region, "2-Extra")) + regions.insert(18, create_region(world, player, locations_per_region, "1-Extra")) + + if world.options.minigame_checks in {MinigameChecks.option_bonus_games, MinigameChecks.option_both}: + regions.insert(74, create_region(world, player, locations_per_region, "6-Bonus")) + regions.insert(63, create_region(world, player, locations_per_region, "5-Bonus")) + regions.insert(52, create_region(world, player, locations_per_region, "4-Bonus")) + regions.insert(41, create_region(world, player, locations_per_region, "3-Bonus")) + regions.insert(29, create_region(world, player, locations_per_region, "2-Bonus")) + regions.insert(19, create_region(world, player, locations_per_region, "1-Bonus")) + + multiworld.regions += regions + + connect_starting_region(world) + + bosses = BossReqs(world) + + multiworld.get_region("Overworld", player).add_exits( + ["World 1", "World 2", "World 3", "World 4", "World 5", "World 6"], + { + "World 1": lambda state: state.has("World 1 Gate", player), + "World 2": lambda state: state.has("World 2 Gate", player), + "World 3": lambda state: state.has("World 3 Gate", player), + "World 4": lambda state: state.has("World 4 Gate", player), + "World 5": lambda state: state.has("World 5 Gate", player), + "World 6": lambda state: state.has("World 6 Gate", player) + } + ) + + for cur_world in range(1, 7): + for cur_level in range(8): + if cur_world != 6 or cur_level != 7: + multiworld.get_region(f"World {cur_world}", player).add_exits( + [world.level_location_list[(cur_world - 1) * 8 + cur_level]] + ) + + multiworld.get_region("1-4", player).add_exits([world.boss_order[0]],{world.boss_order[0]: lambda state: logic._14Clear(state)}) + multiworld.get_region("1-8", player).add_exits([world.boss_order[1]],{world.boss_order[1]: lambda state: logic._18Clear(state)}) + multiworld.get_region("2-4", player).add_exits([world.boss_order[2]],{world.boss_order[2]: lambda state: logic._24Clear(state)}) + multiworld.get_region("2-8", player).add_exits([world.boss_order[3]],{world.boss_order[3]: lambda state: logic._28Clear(state)}) + multiworld.get_region("3-4", player).add_exits([world.boss_order[4]],{world.boss_order[4]: lambda state: logic._34Clear(state)}) + multiworld.get_region("3-8", player).add_exits([world.boss_order[5]],{world.boss_order[5]: lambda state: logic._38Clear(state)}) + multiworld.get_region("4-4", player).add_exits([world.boss_order[6]],{world.boss_order[6]: lambda state: logic._44Clear(state)}) + multiworld.get_region("4-8", player).add_exits([world.boss_order[7]],{world.boss_order[7]: lambda state: logic._48Clear(state)}) + multiworld.get_region("5-4", player).add_exits([world.boss_order[8]],{world.boss_order[8]: lambda state: logic._54Clear(state)}) + multiworld.get_region("5-8", player).add_exits([world.boss_order[9]],{world.boss_order[9]: lambda state: logic._58Clear(state)}) + multiworld.get_region("World 6", player).add_exits(["6-8"],{"6-8": lambda state: bosses.castle_access(state)}) + multiworld.get_region("6-4", player).add_exits([world.boss_order[10]],{world.boss_order[10]: lambda state: logic._64Clear(state)}) + multiworld.get_region("6-8", player).add_exits(["Bowser's Room"],{"Bowser's Room": lambda state: bosses.castle_clear(state)}) + + if world.options.extras_enabled: + multiworld.get_region("World 1", player).add_exits( + ["1-Extra"], + {"1-Extra": lambda state: state.has_any({"Extra Panels", "Extra 1"}, player)} + ) + multiworld.get_region("World 2", player).add_exits( + ["2-Extra"], + {"2-Extra": lambda state: state.has_any({"Extra Panels", "Extra 2"}, player)} + ) + multiworld.get_region( + "World 3", player).add_exits(["3-Extra"], + {"3-Extra": lambda state: state.has_any({"Extra Panels", "Extra 3"}, player)} + ) + multiworld.get_region("World 4", player).add_exits( + ["4-Extra"], + {"4-Extra": lambda state: state.has_any({"Extra Panels", "Extra 4"}, player)} + ) + multiworld.get_region("World 5", player).add_exits( + ["5-Extra"], + {"5-Extra": lambda state: state.has_any({"Extra Panels", "Extra 5"}, player)} + ) + multiworld.get_region("World 6", player).add_exits( + ["6-Extra"], + {"6-Extra": lambda state: state.has_any({"Extra Panels", "Extra 6"}, player)} + ) + + if world.options.minigame_checks in {MinigameChecks.option_bonus_games, MinigameChecks.option_both}: + multiworld.get_region("World 1", player).add_exits( + ["1-Bonus"], + {"1-Bonus": lambda state: state.has_any({"Bonus Panels", "Bonus 1"}, player)} + ) + multiworld.get_region("World 2", player).add_exits( + ["2-Bonus"], + {"2-Bonus": lambda state: state.has_any({"Bonus Panels", "Bonus 2"}, player)} + ) + multiworld.get_region("World 3", player).add_exits( + ["3-Bonus"], + {"3-Bonus": lambda state: state.has_any({"Bonus Panels", "Bonus 3"}, player)} + ) + multiworld.get_region("World 4", player).add_exits( + ["4-Bonus"], + {"4-Bonus": lambda state: state.has_any({"Bonus Panels", "Bonus 4"}, player)} + ) + multiworld.get_region("World 5", player).add_exits( + ["5-Bonus"], + {"5-Bonus": lambda state: state.has_any({"Bonus Panels", "Bonus 5"}, player)} + ) + multiworld.get_region("World 6", player).add_exits( + ["6-Bonus"], + {"6-Bonus": lambda state: state.has_any({"Bonus Panels", "Bonus 6"}, player)} + ) + + +def create_location(player: int, location_data: LocationData, region: Region) -> Location: + location = YoshisIslandLocation(player, location_data.name, location_data.code, region) + location.access_rule = location_data.rule + location.level_id = location_data.LevelID + + return location + + +def create_region(world: "YoshisIslandWorld", player: int, locations_per_region: Dict[str, List[LocationData]], name: str) -> Region: + region = Region(name, player, world.multiworld) + + if name in locations_per_region: + for location_data in locations_per_region[name]: + location = create_location(player, location_data, region) + region.locations.append(location) + + return region + +def connect_starting_region(world: "YoshisIslandWorld") -> None: + multiworld = world.multiworld + player = world.player + menu = multiworld.get_region("Menu", player) + world_main = multiworld.get_region("Overworld", player) + + starting_region = multiworld.get_region(f"World {world.options.starting_world + 1}", player) + + menu.connect(world_main, "Start Game") + world_main.connect(starting_region, "Overworld") + + +def get_locations_per_region(locations: List[LocationData]) -> Dict[str, List[LocationData]]: + per_region: Dict[str, List[LocationData]] = {} + + for location in locations: + per_region.setdefault(location.region, []).append(location) + + return per_region diff --git a/worlds/yoshisisland/Rom.py b/worlds/yoshisisland/Rom.py new file mode 100644 index 000000000000..fa3006afcf9f --- /dev/null +++ b/worlds/yoshisisland/Rom.py @@ -0,0 +1,1230 @@ +import hashlib +import os +import Utils +from worlds.Files import APDeltaPatch +from settings import get_settings +from typing import TYPE_CHECKING + +from .Options import YoshiColors, BowserDoor, PlayerGoal, MinigameChecks + +if TYPE_CHECKING: + from . import YoshisIslandWorld +USHASH = "cb472164c5a71ccd3739963390ec6a50" + +item_values = { + 0x302050: [0x1467, 0x01], # ! Switch + 0x302051: [0x1467, 0x02], # Dashed Platform + 0x302052: [0x1467, 0x03], # Dashed Stairs + 0x302053: [0x1467, 0x04], # Beanstalk + 0x302054: [0x1467, 0x05], # Helicopter + 0x302059: [0x1467, 0x06], # Mole Tank + 0x302068: [0x1467, 0x07], # Train + 0x30205E: [0x1467, 0x08], # Car + 0x302063: [0x1467, 0x09], # Submarine + 0x302055: [0x1467, 0x0A], # Spring Ball + 0x302056: [0x1467, 0x0B], # Large Spring Ball + 0x302057: [0x1467, 0x0C], # Arrow Wheel + 0x302058: [0x1467, 0x0D], # Vanishing Arrow Wheel + 0x30205A: [0x1467, 0x0E], # Watermelon + 0x30205B: [0x1467, 0x0F], # Ice Melon + 0x30205C: [0x1467, 0x10], # Fire Melon + 0x30205D: [0x1467, 0x11], # Super Star + 0x30205F: [0x1467, 0x12], # Flashing Eggs + 0x302060: [0x1467, 0x13], # Giant Eggs + 0x302061: [0x1467, 0x14], # Egg Launcher + 0x302062: [0x1467, 0x15], # Egg Plant + 0x302064: [0x1467, 0x16], # Chomp Rock + 0x302065: [0x1467, 0x17], # Poochy + 0x302066: [0x1467, 0x18], # Platform Ghost + 0x302067: [0x1467, 0x19], # Skis + 0x302069: [0x1467, 0x1A], # Key + 0x30206A: [0x1467, 0x1B], # Middle Ring + 0x30206B: [0x1467, 0x1C], # Bucket + 0x30206C: [0x1467, 0x1D], # Tulip + 0x302081: [0x1467, 0x1E], # Secret Lens + + 0x30206D: [0x1467, 0x1F], # Egg Capacity Upgrade + + 0x30206E: [0x1467, 0x20], # World 1 Gate + 0x30206F: [0x1467, 0x21], # World 2 Gate + 0x302070: [0x1467, 0x22], # World 3 Gate + 0x302071: [0x1467, 0x23], # World 4 Gate + 0x302072: [0x1467, 0x24], # World 5 Gate + 0x302073: [0x1467, 0x25], # World 6 Gate + + 0x302074: [0x1467, 0x26], # Extra 1 + 0x302075: [0x1467, 0x27], # Extra 2 + 0x302076: [0x1467, 0x28], # Extra 3 + 0x302077: [0x1467, 0x29], # Extra 4 + 0x302078: [0x1467, 0x2A], # Extra 5 + 0x302079: [0x1467, 0x2B], # Extra 6 + 0x30207A: [0x1467, 0x2C], # Extra Panels + + 0x30207B: [0x1467, 0x2D], # Bonus 1 + 0x30207C: [0x1467, 0x2E], # Bonus 2 + 0x30207D: [0x1467, 0x2F], # Bonus 3 + 0x30207E: [0x1467, 0x30], # Bonus 4 + 0x30207F: [0x1467, 0x31], # Bonus 5 + 0x302080: [0x1467, 0x32], # Bonus 6 + 0x302082: [0x1467, 0x33], # Bonus Panels + + 0x302083: [0x1467, 0x34], # Anytime Egg + 0x302084: [0x1467, 0x35], # Anywhere Pow + 0x302085: [0x1467, 0x36], # Cloud + 0x302086: [0x1467, 0x37], # Pocket Melon + 0x302088: [0x1467, 0x38], # Ice Melon + 0x302087: [0x1467, 0x39], # Fire Melon + 0x302089: [0x1467, 0x3A], # Magnifying Glass + 0x30208A: [0x1467, 0x3B], # 10 Stars + 0x30208B: [0x1467, 0x3C], # 20 Stars + + 0x30208C: [0x1467, 0x3D], # 1up + 0x30208D: [0x1467, 0x3E], # 2up + 0x30208E: [0x1467, 0x3F], # 3up + 0x30208F: [0x1467, 0x40], # 10up + + 0x302090: [0x1467, 0x41], # Fuzzy Trap + 0x302093: [0x1467, 0x42], # Freeze Trap + 0x302091: [0x1467, 0x43], # Reverse Trap + 0x302092: [0x1467, 0x44], # Dark Trap + 0x302094: [0x1467, 0x00], # Boss clear, local handling + + 0x302095: [0x1467, 0x45] # Luigi Piece + +} + +location_table = { + # 1-1 + 0x305020: [0x146D, 0], # Red Coins + 0x305021: [0x146D, 1], # Flowers + 0x305022: [0x146D, 2], # Stars + 0x305023: [0x146D, 3], # Level Clear + # 1-2 + 0x305024: [0x146E, 0], + 0x305025: [0x146E, 1], + 0x305026: [0x146E, 2], + 0x305027: [0x146E, 3], + # 1-3 + 0x305028: [0x146F, 0], + 0x305029: [0x146F, 1], + 0x30502A: [0x146F, 2], + 0x30502B: [0x146F, 3], + 0x3050F8: [0x146F, 4], + # 1-4 + 0x30502C: [0x1470, 0], + 0x30502D: [0x1470, 1], + 0x30502E: [0x1470, 2], + 0x30502F: [0x1470, 3], + # 1-5 + 0x305031: [0x1471, 0], + 0x305032: [0x1471, 1], + 0x305033: [0x1471, 2], + 0x305034: [0x1471, 3], + # 1-6 + 0x305035: [0x1472, 0], + 0x305036: [0x1472, 1], + 0x305037: [0x1472, 2], + 0x305038: [0x1472, 3], + # 1-7 + 0x305039: [0x1473, 0], + 0x30503A: [0x1473, 1], + 0x30503B: [0x1473, 2], + 0x30503C: [0x1473, 3], + 0x3050F9: [0x1473, 4], + # 1-8 + 0x30503D: [0x1474, 0], + 0x30503E: [0x1474, 1], + 0x30503F: [0x1474, 2], + 0x305040: [0x1474, 3], + # 1-E + 0x3050E0: [0x1475, 0], + 0x3050E1: [0x1475, 1], + 0x3050E2: [0x1475, 2], + 0x3050E3: [0x1475, 3], + # 1-B + 0x305106: [0x1476, 4], + ###################### + # 2-1 + 0x305041: [0x1479, 0], + 0x305042: [0x1479, 1], + 0x305043: [0x1479, 2], + 0x305044: [0x1479, 3], + 0x3050FA: [0x1479, 4], + # 2-2 + 0x305045: [0x147A, 0], + 0x305046: [0x147A, 1], + 0x305047: [0x147A, 2], + 0x305048: [0x147A, 3], + # 2-3 + 0x305049: [0x147B, 0], + 0x30504A: [0x147B, 1], + 0x30504B: [0x147B, 2], + 0x30504C: [0x147B, 3], + 0x3050FB: [0x147B, 4], + # 2-4 + 0x30504D: [0x147C, 0], + 0x30504E: [0x147C, 1], + 0x30504F: [0x147C, 2], + 0x305050: [0x147C, 3], + # 2-5 + 0x305051: [0x147D, 0], + 0x305052: [0x147D, 1], + 0x305053: [0x147D, 2], + 0x305054: [0x147D, 3], + # 2-6 + 0x305055: [0x147E, 0], + 0x305056: [0x147E, 1], + 0x305057: [0x147E, 2], + 0x305058: [0x147E, 3], + 0x3050FC: [0x147E, 4], + # 2-7 + 0x305059: [0x147F, 0], + 0x30505A: [0x147F, 1], + 0x30505B: [0x147F, 2], + 0x30505C: [0x147F, 3], + 0x3050FD: [0x147F, 4], + # 2-8 + 0x30505D: [0x1480, 0], + 0x30505E: [0x1480, 1], + 0x30505F: [0x1480, 2], + 0x305060: [0x1480, 3], + # 2-E + 0x3050E4: [0x1481, 0], + 0x3050E5: [0x1481, 1], + 0x3050E6: [0x1481, 2], + 0x3050E7: [0x1481, 3], + # 2-B + 0x305107: [0x1482, 4], + ###################### + # 3-1 + 0x305061: [0x1485, 0], + 0x305062: [0x1485, 1], + 0x305063: [0x1485, 2], + 0x305064: [0x1485, 3], + # 3-2 + 0x305065: [0x1486, 0], + 0x305066: [0x1486, 1], + 0x305067: [0x1486, 2], + 0x305068: [0x1486, 3], + 0x3050FE: [0x1486, 4], + # 3-3 + 0x305069: [0x1487, 0], + 0x30506A: [0x1487, 1], + 0x30506B: [0x1487, 2], + 0x30506C: [0x1487, 3], + # 3-4 + 0x30506D: [0x1488, 0], + 0x30506E: [0x1488, 1], + 0x30506F: [0x1488, 2], + 0x305070: [0x1488, 3], + # 3-5 + 0x305071: [0x1489, 0], + 0x305072: [0x1489, 1], + 0x305073: [0x1489, 2], + 0x305074: [0x1489, 3], + # 3-6 + 0x305075: [0x148A, 0], + 0x305076: [0x148A, 1], + 0x305077: [0x148A, 2], + 0x305078: [0x148A, 3], + # 3-7 + 0x305079: [0x148B, 0], + 0x30507A: [0x148B, 1], + 0x30507B: [0x148B, 2], + 0x30507C: [0x148B, 3], + 0x3050FF: [0x148B, 4], + # 3-8 + 0x30507D: [0x148C, 0], + 0x30507E: [0x148C, 1], + 0x30507F: [0x148C, 2], + 0x305080: [0x148C, 3], + # 3-E + 0x3050E8: [0x148D, 0], + 0x3050E9: [0x148D, 1], + 0x3050EA: [0x148D, 2], + 0x3050EB: [0x148D, 3], + # 3-B + 0x305108: [0x148E, 4], + ###################### + # 4-1 + 0x305081: [0x1491, 0], + 0x305082: [0x1491, 1], + 0x305083: [0x1491, 2], + 0x305084: [0x1491, 3], + # 4-2 + 0x305085: [0x1492, 0], + 0x305086: [0x1492, 1], + 0x305087: [0x1492, 2], + 0x305088: [0x1492, 3], + 0x305100: [0x1492, 4], + # 4-3 + 0x305089: [0x1493, 0], + 0x30508A: [0x1493, 1], + 0x30508B: [0x1493, 2], + 0x30508C: [0x1493, 3], + # 4-4 + 0x30508D: [0x1494, 0], + 0x30508E: [0x1494, 1], + 0x30508F: [0x1494, 2], + 0x305090: [0x1494, 3], + # 4-5 + 0x305091: [0x1495, 0], + 0x305092: [0x1495, 1], + 0x305093: [0x1495, 2], + 0x305094: [0x1495, 3], + # 4-6 + 0x305095: [0x1496, 0], + 0x305096: [0x1496, 1], + 0x305097: [0x1496, 2], + 0x305098: [0x1496, 3], + 0x305101: [0x1496, 4], + # 4-7 + 0x305099: [0x1497, 0], + 0x30509A: [0x1497, 1], + 0x30509B: [0x1497, 2], + 0x30509C: [0x1497, 3], + 0x305102: [0x1497, 4], + # 4-8 + 0x30509D: [0x1498, 0], + 0x30509E: [0x1498, 1], + 0x30509F: [0x1498, 2], + 0x3050A0: [0x1498, 3], + # 4-E + 0x3050EC: [0x1499, 0], + 0x3050ED: [0x1499, 1], + 0x3050EE: [0x1499, 2], + 0x3050EF: [0x1499, 3], + # 4-B + 0x305109: [0x149A, 4], + ###################### + # 5-1 + 0x3050A1: [0x149D, 0], + 0x3050A2: [0x149D, 1], + 0x3050A3: [0x149D, 2], + 0x3050A4: [0x149D, 3], + 0x305103: [0x149D, 4], + # 5-2 + 0x3050A5: [0x149E, 0], + 0x3050A6: [0x149E, 1], + 0x3050A7: [0x149E, 2], + 0x3050A8: [0x149E, 3], + # 5-3 + 0x3050A9: [0x149F, 0], + 0x3050AA: [0x149F, 1], + 0x3050AB: [0x149F, 2], + 0x3050AC: [0x149F, 3], + # 5-4 + 0x3050AD: [0x14A0, 0], + 0x3050AE: [0x14A0, 1], + 0x3050AF: [0x14A0, 2], + 0x3050B0: [0x14A0, 3], + # 5-5 + 0x3050B1: [0x14A1, 0], + 0x3050B2: [0x14A1, 1], + 0x3050B3: [0x14A1, 2], + 0x3050B4: [0x14A1, 3], + # 5-6 + 0x3050B5: [0x14A2, 0], + 0x3050B6: [0x14A2, 1], + 0x3050B7: [0x14A2, 2], + 0x3050B8: [0x14A2, 3], + # 5-7 + 0x3050B9: [0x14A3, 0], + 0x3050BA: [0x14A3, 1], + 0x3050BB: [0x14A3, 2], + 0x3050BC: [0x14A3, 3], + # 5-8 + 0x3050BD: [0x14A4, 0], + 0x3050BE: [0x14A4, 1], + 0x3050BF: [0x14A4, 2], + 0x3050C0: [0x14A4, 3], + # 5-E + 0x3050F0: [0x14A5, 0], + 0x3050F1: [0x14A5, 1], + 0x3050F2: [0x14A5, 2], + 0x3050F3: [0x14A5, 3], + # 5-B + 0x30510A: [0x14A6, 4], + ####################### + # 6-1 + 0x3050C1: [0x14A9, 0], + 0x3050C2: [0x14A9, 1], + 0x3050C3: [0x14A9, 2], + 0x3050C4: [0x14A9, 3], + 0x305104: [0x14A9, 4], + # 6-2 + 0x3050C5: [0x14AA, 0], + 0x3050C6: [0x14AA, 1], + 0x3050C7: [0x14AA, 2], + 0x3050C8: [0x14AA, 3], + # 6-3 + 0x3050C9: [0x14AB, 0], + 0x3050CA: [0x14AB, 1], + 0x3050CB: [0x14AB, 2], + 0x3050CC: [0x14AB, 3], + # 6-4 + 0x3050CD: [0x14AC, 0], + 0x3050CE: [0x14AC, 1], + 0x3050CF: [0x14AC, 2], + 0x3050D0: [0x14AC, 3], + # 6-5 + 0x3050D1: [0x14AD, 0], + 0x3050D2: [0x14AD, 1], + 0x3050D3: [0x14AD, 2], + 0x3050D4: [0x14AD, 3], + # 6-6 + 0x3050D5: [0x14AE, 0], + 0x3050D6: [0x14AE, 1], + 0x3050D7: [0x14AE, 2], + 0x3050D8: [0x14AE, 3], + # 6-7 + 0x3050D9: [0x14AF, 0], + 0x3050DA: [0x14AF, 1], + 0x3050DB: [0x14AF, 2], + 0x3050DC: [0x14AF, 3], + 0x305105: [0x14AF, 4], + # 6-8 + 0x3050DD: [0x14B0, 0], + 0x3050DE: [0x14B0, 1], + 0x3050DF: [0x14B0, 2], + # 6-E + 0x3050F4: [0x14B1, 0], + 0x3050F5: [0x14B1, 1], + 0x3050F6: [0x14B1, 2], + 0x3050F7: [0x14B1, 3], + # 6-B + 0x30510B: [0x14B2, 4] +} + +class LocalRom(object): + + def __init__(self, file: str) -> None: + self.name = None + self.hash = hash + self.orig_buffer = None + + with open(file, "rb") as stream: + self.buffer = Utils.read_snes_rom(stream) + + def read_bit(self, address: int, bit_number: int) -> bool: + bitflag = 1 << bit_number + return (self.buffer[address] & bitflag) != 0 + + def read_byte(self, address: int) -> int: + return self.buffer[address] + + def read_bytes(self, startaddress: int, length: int) -> bytes: + return self.buffer[startaddress:startaddress + length] + + def write_byte(self, address: int, value: int) -> None: + self.buffer[address] = value + + def write_bytes(self, startaddress: int, values: bytearray) -> None: + self.buffer[startaddress:startaddress + len(values)] = values + + def write_to_file(self, file: str) -> None: + with open(file, "wb") as outfile: + outfile.write(self.buffer) + + def read_from_file(self, file: str) -> None: + with open(file, "rb") as stream: + self.buffer = bytearray(stream.read()) + +def handle_items(rom: LocalRom) -> None: + rom.write_bytes(0x0077B0, bytearray([0xE2, 0x20, 0xAD, 0x40, 0x14, 0xC2, 0x20, 0xF0, 0x08, 0xBD, 0x82, 0x71, 0x18, 0x5C, 0x3B, 0xB6])) + rom.write_bytes(0x0077C0, bytearray([0x0E, 0x5C, 0x97, 0xB6, 0x0E, 0xA0, 0xFF, 0xAD, 0x74, 0x79, 0x29, 0x01, 0x00, 0xD0, 0x02, 0xA0])) + rom.write_bytes(0x0077D0, bytearray([0x05, 0x98, 0x9D, 0xA2, 0x74, 0x6B, 0xE2, 0x20, 0xBD, 0x60, 0x73, 0xDA, 0xC2, 0x20, 0xA2, 0x00])) + rom.write_bytes(0x0077E0, bytearray([0xDF, 0x70, 0xAF, 0x09, 0xF0, 0x08, 0xE8, 0xE8, 0xE0, 0x08, 0xF0, 0x23, 0x80, 0xF2, 0xE2, 0x20])) + rom.write_bytes(0x0077F0, bytearray([0x8A, 0x4A, 0xAA, 0xBF, 0x78, 0xAF, 0x09, 0xAA, 0xBD, 0x40, 0x14, 0xC2, 0x20, 0xF0, 0x08, 0xFA])) + rom.write_bytes(0x007800, bytearray([0xA0, 0x05, 0x98, 0x9D, 0xA2, 0x74, 0x60, 0xFA, 0x22, 0xC5, 0xF7, 0x00, 0xEA, 0xEA, 0x60, 0xFA])) + rom.write_bytes(0x007810, bytearray([0x60, 0x22, 0x23, 0xAF, 0x03, 0x20, 0xD6, 0xF7, 0x6B, 0x20, 0x2F, 0xF8, 0xE2, 0x20, 0xC9, 0x00])) + rom.write_bytes(0x007820, bytearray([0xD0, 0x03, 0xC2, 0x20, 0x6B, 0xC2, 0x20, 0xBD, 0x60, 0x73, 0x38, 0x5C, 0xB1, 0xC9, 0x03, 0xDA])) + rom.write_bytes(0x007830, bytearray([0xBD, 0x60, 0x73, 0xA2, 0x00, 0xDF, 0x7C, 0xAF, 0x09, 0xF0, 0x08, 0xE8, 0xE8, 0xE0, 0x0A, 0xF0])) + rom.write_bytes(0x007840, bytearray([0x13, 0x80, 0xF2, 0xE2, 0x20, 0x8A, 0x4A, 0xAA, 0xBF, 0x86, 0xAF, 0x09, 0xAA, 0xBD, 0x40, 0x14])) + rom.write_bytes(0x007850, bytearray([0xFA, 0xC2, 0x20, 0x60, 0xA9, 0x01, 0x00, 0xFA, 0x60, 0x20, 0x2F, 0xF8, 0xE2, 0x20, 0xC9, 0x00])) + rom.write_bytes(0x007860, bytearray([0xC2, 0x20, 0xD0, 0x06, 0x22, 0xC5, 0xF7, 0x00, 0x80, 0x04, 0x22, 0xCF, 0xF7, 0x00, 0xA5, 0x14])) + rom.write_bytes(0x007870, bytearray([0x29, 0x0F, 0x00, 0x5C, 0x9A, 0xC9, 0x03, 0x5A, 0xE2, 0x10, 0x20, 0x2F, 0xF8, 0xC2, 0x10, 0x7A])) + rom.write_bytes(0x007880, bytearray([0xE2, 0x20, 0xC9, 0x00, 0xC2, 0x20, 0xD0, 0x08, 0xAD, 0x74, 0x79, 0x29, 0x01, 0x00, 0xF0, 0x04])) + rom.write_bytes(0x007890, bytearray([0x22, 0x3C, 0xAA, 0x03, 0xE2, 0x10, 0x5C, 0x47, 0xC9, 0x03, 0x22, 0x23, 0xAF, 0x03, 0xBD, 0x60])) + rom.write_bytes(0x0078A0, bytearray([0x73, 0xC9, 0x6F, 0x00, 0xF0, 0x07, 0xE2, 0x20, 0xAD, 0x4A, 0x14, 0x80, 0x05, 0xE2, 0x20, 0xAD])) + rom.write_bytes(0x0078B0, bytearray([0x49, 0x14, 0xC2, 0x20, 0xD0, 0x06, 0x22, 0xC5, 0xF7, 0x00, 0x80, 0x04, 0x22, 0xCF, 0xF7, 0x00])) + rom.write_bytes(0x0078C0, bytearray([0x5C, 0x2D, 0x83, 0x05, 0xBD, 0x60, 0x73, 0xC9, 0x6F, 0x00, 0xF0, 0x07, 0xE2, 0x20, 0xAD, 0x4A])) + rom.write_bytes(0x0078D0, bytearray([0x14, 0x80, 0x05, 0xE2, 0x20, 0xAD, 0x49, 0x14, 0xC2, 0x20, 0xD0, 0x04, 0x5C, 0xA0, 0x83, 0x05])) + rom.write_bytes(0x0078E0, bytearray([0xAD, 0xAC, 0x60, 0x0D, 0xAE, 0x60, 0x5C, 0x84, 0x83, 0x05, 0x22, 0x52, 0xAA, 0x03, 0xBD, 0x60])) + rom.write_bytes(0x0078F0, bytearray([0x73, 0xC9, 0x1E, 0x01, 0xE2, 0x20, 0xF0, 0x05, 0xAD, 0x4C, 0x14, 0x80, 0x03, 0xAD, 0x4B, 0x14])) + rom.write_bytes(0x007900, bytearray([0xEA, 0xC2, 0x20, 0xF0, 0x08, 0x22, 0xCF, 0xF7, 0x00, 0x5C, 0xA6, 0xF0, 0x05, 0x22, 0xC5, 0xF7])) + rom.write_bytes(0x007910, bytearray([0x00, 0x5C, 0xA6, 0xF0, 0x05, 0xE2, 0x20, 0xAD, 0x1C, 0x01, 0xC9, 0x0E, 0xC2, 0x20, 0xF0, 0x18])) + rom.write_bytes(0x007920, bytearray([0x20, 0x59, 0xF9, 0xE2, 0x20, 0xC9, 0x00, 0xF0, 0x04, 0xA9, 0x10, 0x80, 0x2A, 0xA9, 0x02, 0x9D])) + rom.write_bytes(0x007930, bytearray([0x00, 0x6F, 0xC2, 0x20, 0x22, 0xC5, 0xF7, 0x00, 0xA2, 0x0A, 0xA9, 0x2F, 0xCE, 0x5C, 0x22, 0x80])) + rom.write_bytes(0x007940, bytearray([0x04, 0x20, 0x59, 0xF9, 0xE2, 0x20, 0xC9, 0x00, 0xC2, 0x20, 0xF0, 0x0A, 0xAD, 0x0E, 0x30, 0x29])) + rom.write_bytes(0x007950, bytearray([0x03, 0x00, 0x5C, 0x2E, 0x80, 0x04, 0x6B, 0x80, 0xD6, 0xDA, 0xBD, 0x60, 0x73, 0xA2, 0x00, 0xDF])) + rom.write_bytes(0x007960, bytearray([0x8B, 0xAF, 0x09, 0xF0, 0x04, 0xE8, 0xE8, 0x80, 0xF6, 0xE2, 0x20, 0x8A, 0x4A, 0xAA, 0xBF, 0x91])) + rom.write_bytes(0x007970, bytearray([0xAF, 0x09, 0xAA, 0xBD, 0x40, 0x14, 0xFA, 0xC2, 0x20, 0x60, 0x22, 0x2E, 0xAA, 0x03, 0xE2, 0x20])) + rom.write_bytes(0x007980, bytearray([0xAD, 0x50, 0x14, 0xC2, 0x20, 0xD0, 0x06, 0x22, 0xC5, 0xF7, 0x00, 0x80, 0x04, 0x22, 0xCF, 0xF7])) + rom.write_bytes(0x007990, bytearray([0x00, 0x5C, 0x05, 0x99, 0x02, 0x69, 0x20, 0x00, 0xC9, 0x20, 0x01, 0xB0, 0x0D, 0xE2, 0x20, 0xAD])) + rom.write_bytes(0x0079A0, bytearray([0x50, 0x14, 0xC2, 0x20, 0xF0, 0x04, 0x5C, 0x3E, 0x99, 0x02, 0x5C, 0x8C, 0x99, 0x02, 0x22, 0x23])) + rom.write_bytes(0x0079B0, bytearray([0xAF, 0x03, 0xE2, 0x20, 0xAD, 0x1C, 0x01, 0xC9, 0x02, 0xC2, 0x20, 0xD0, 0x18, 0x20, 0x59, 0xF9])) + rom.write_bytes(0x0079C0, bytearray([0xE2, 0x20, 0xC9, 0x00, 0xD0, 0x13, 0xC2, 0x20, 0x22, 0xC5, 0xF7, 0x00, 0xE2, 0x20, 0xA9, 0x02])) + rom.write_bytes(0x0079D0, bytearray([0x9D, 0x00, 0x6F, 0xC2, 0x20, 0x5C, 0x35, 0x80, 0x04, 0xC2, 0x20, 0x22, 0xCF, 0xF7, 0x00, 0x80])) + rom.write_bytes(0x0079E0, bytearray([0xF2, 0xE2, 0x20, 0xAD, 0x4E, 0x14, 0xC2, 0x20, 0xF0, 0x07, 0xA9, 0x14, 0x00, 0x5C, 0x9E, 0xF1])) + rom.write_bytes(0x0079F0, bytearray([0x07, 0xA9, 0x0E, 0x00, 0x80, 0xF7, 0xBD, 0x60, 0x73, 0xDA, 0xA2, 0x00, 0xDF, 0x94, 0xAF, 0x09])) + rom.write_bytes(0x007A00, bytearray([0xF0, 0x11, 0xE0, 0x08, 0xF0, 0x04, 0xE8, 0xE8, 0x80, 0xF2, 0xFA, 0x22, 0x57, 0xF9, 0x0C, 0x5C])) + rom.write_bytes(0x007A10, bytearray([0xBD, 0xBE, 0x03, 0x8A, 0x4A, 0xE2, 0x20, 0xAA, 0xBF, 0x9E, 0xAF, 0x09, 0xAA, 0xBD, 0x40, 0x14])) + rom.write_bytes(0x007A20, bytearray([0xC9, 0x00, 0xC2, 0x20, 0xF0, 0x02, 0x80, 0xE2, 0x4C, 0x61, 0xFF, 0x00, 0x9D, 0x00, 0x6F, 0x74])) + rom.write_bytes(0x007A30, bytearray([0x78, 0x74, 0x18, 0x74, 0x76, 0x9E, 0x36, 0x7A, 0x9E, 0x38, 0x7A, 0x9E, 0x38, 0x7D, 0xBC, 0xC2])) + rom.write_bytes(0x007A40, bytearray([0x77, 0xB9, 0xB5, 0xBE, 0x9D, 0x20, 0x72, 0xA9, 0x00, 0xFC, 0x9D, 0x22, 0x72, 0xA9, 0x40, 0x00])) + rom.write_bytes(0x007A50, bytearray([0x9D, 0x42, 0x75, 0xA9, 0x90, 0x00, 0x22, 0xD2, 0x85, 0x00, 0x6B, 0x5A, 0xE2, 0x20, 0xAD, 0x51])) + rom.write_bytes(0x007A60, bytearray([0x14, 0xC9, 0x00, 0xC2, 0x20, 0xF0, 0x0D, 0x22, 0xCF, 0xF7, 0x00, 0x7A, 0x9B, 0xAD, 0x30, 0x00])) + rom.write_bytes(0x007A70, bytearray([0x5C, 0x62, 0xB7, 0x03, 0x22, 0xC5, 0xF7, 0x00, 0x7A, 0x9B, 0xA9, 0x03, 0x00, 0x5C, 0x62, 0xB7])) + rom.write_bytes(0x007A80, bytearray([0x03, 0x22, 0x23, 0xAF, 0x03, 0xE2, 0x20, 0xAD, 0x53, 0x14, 0xF0, 0x07, 0xC2, 0x20, 0x22, 0xCF])) + rom.write_bytes(0x007A90, bytearray([0xF7, 0x00, 0x6B, 0xC2, 0x20, 0x22, 0xC5, 0xF7, 0x00, 0x6B, 0xE2, 0x20, 0xAD, 0x53, 0x14, 0xF0])) + rom.write_bytes(0x007AA0, bytearray([0x07, 0xC2, 0x20, 0x22, 0x78, 0xBA, 0x07, 0x6B, 0xC2, 0x20, 0x6B, 0xC9, 0x06, 0x00, 0xB0, 0x0F])) + rom.write_bytes(0x007AB0, bytearray([0xE2, 0x20, 0xAD, 0x54, 0x14, 0xC9, 0x00, 0xC2, 0x20, 0xF0, 0x04, 0x5C, 0x94, 0x81, 0x07, 0x5C])) + rom.write_bytes(0x007AC0, bytearray([0xFB, 0x81, 0x07, 0x22, 0x23, 0xAF, 0x03, 0xE2, 0x20, 0xAD, 0x54, 0x14, 0xC2, 0x20, 0xF0, 0x08])) + rom.write_bytes(0x007AD0, bytearray([0x22, 0xCF, 0xF7, 0x00, 0x5C, 0xF7, 0x80, 0x07, 0x22, 0xC5, 0xF7, 0x00, 0x5C, 0xF7, 0x80, 0x07])) + rom.write_bytes(0x007AE0, bytearray([0x5A, 0xE2, 0x20, 0xAD, 0x55, 0x14, 0xC2, 0x20, 0xF0, 0x06, 0x22, 0xCF, 0xF7, 0x00, 0x80, 0x06])) + rom.write_bytes(0x007AF0, bytearray([0x22, 0xC5, 0xF7, 0x00, 0x80, 0x04, 0x22, 0x65, 0xC3, 0x0E, 0x7A, 0x5C, 0xFA, 0xBE, 0x0E, 0xE2])) + rom.write_bytes(0x007B00, bytearray([0x20, 0xAD, 0x56, 0x14, 0xC2, 0x20, 0xF0, 0x0A, 0x22, 0xCF, 0xF7, 0x00, 0x22, 0xB7, 0xA5, 0x03])) + rom.write_bytes(0x007B10, bytearray([0x80, 0x04, 0x22, 0xC5, 0xF7, 0x00, 0x5C, 0x3D, 0x96, 0x07, 0xBD, 0x02, 0x79, 0x85, 0x0E, 0xE2])) + rom.write_bytes(0x007B20, bytearray([0x20, 0xAD, 0x57, 0x14, 0xC2, 0x20, 0xF0, 0x05, 0x22, 0xCF, 0xF7, 0x00, 0x6B, 0x22, 0xC5, 0xF7])) + rom.write_bytes(0x007B30, bytearray([0x00, 0x6B, 0xE2, 0x20, 0xAD, 0x57, 0x14, 0xC2, 0x20, 0xD0, 0x0C, 0xAD, 0x74, 0x79, 0x29, 0x01])) + rom.write_bytes(0x007B40, bytearray([0x00, 0xD0, 0x04, 0x5C, 0x4A, 0xF3, 0x06, 0xBD, 0xD6, 0x79, 0x38, 0xFD, 0xE2, 0x70, 0x5C, 0x45])) + rom.write_bytes(0x007B50, bytearray([0xF2, 0x06, 0xAD, 0xAA, 0x60, 0x48, 0x30, 0x0E, 0xE2, 0x20, 0xAD, 0x57, 0x14, 0xC2, 0x20, 0xF0])) + rom.write_bytes(0x007B60, bytearray([0x05, 0x68, 0x5C, 0xA0, 0xF3, 0x06, 0x68, 0x5C, 0xE6, 0xF3, 0x06, 0xBD, 0x02, 0x79, 0x85, 0x0E])) + rom.write_bytes(0x007B70, bytearray([0xE2, 0x20, 0xAD, 0x57, 0x14, 0xC2, 0x20, 0xD0, 0x08, 0x22, 0xC5, 0xF7, 0x00, 0x5C, 0x35, 0xE5])) + rom.write_bytes(0x007B80, bytearray([0x06, 0x22, 0xCF, 0xF7, 0x00, 0x5C, 0x35, 0xE5, 0x06, 0xE2, 0x20, 0xAD, 0x57, 0x14, 0xC2, 0x20])) + rom.write_bytes(0x007B90, bytearray([0xD0, 0x0C, 0xAD, 0x74, 0x79, 0x29, 0x01, 0x00, 0xD0, 0x04, 0x5C, 0x48, 0xF3, 0x06, 0xBD, 0x36])) + rom.write_bytes(0x007BA0, bytearray([0x7A, 0x38, 0xE9, 0x08, 0x00, 0x5C, 0x63, 0xE8, 0x06, 0xAD, 0xAA, 0x60, 0x30, 0x0D, 0xE2, 0x20])) + rom.write_bytes(0x007BB0, bytearray([0xAD, 0x57, 0x14, 0xC2, 0x20, 0xF0, 0x04, 0x5C, 0x99, 0xE8, 0x06, 0x5C, 0xF1, 0xE8, 0x06, 0x9C])) + rom.write_bytes(0x007BC0, bytearray([0xB0, 0x61, 0x9C, 0x8C, 0x0C, 0xE2, 0x20, 0xAD, 0x58, 0x14, 0xC2, 0x20, 0xF0, 0x07, 0x9C, 0x8E])) + rom.write_bytes(0x007BD0, bytearray([0x0C, 0x5C, 0x9D, 0xA4, 0x02, 0xA9, 0x00, 0x00, 0x8F, 0xAE, 0x00, 0x70, 0x8F, 0xAC, 0x00, 0x70])) + rom.write_bytes(0x007BE0, bytearray([0xE2, 0x20, 0xA9, 0xFE, 0x9D, 0x78, 0x79, 0x8F, 0x49, 0x00, 0x7E, 0xC2, 0x20, 0x5C, 0x9D, 0xA4])) + rom.write_bytes(0x007BF0, bytearray([0x02, 0xE2, 0x20, 0xAF, 0x49, 0x00, 0x7E, 0xC2, 0x20, 0xF0, 0x0D, 0xA9, 0x00, 0x00, 0x9D, 0xD8])) + rom.write_bytes(0x007C00, bytearray([0x79, 0x9D, 0x78, 0x79, 0x8F, 0x49, 0x00, 0x7E, 0xBD, 0x16, 0x7C, 0x18, 0x5C, 0x51, 0xA3, 0x02])) + rom.write_bytes(0x007C10, bytearray([0xE2, 0x20, 0xAD, 0x59, 0x14, 0xC2, 0x20, 0xD0, 0x0D, 0x22, 0xC5, 0xF7, 0x00, 0xBD, 0x38, 0x7D])) + rom.write_bytes(0x007C20, bytearray([0xF0, 0x0A, 0x5C, 0x4F, 0xA0, 0x02, 0x22, 0xCF, 0xF7, 0x00, 0x80, 0xF1, 0x5C, 0x59, 0xA0, 0x02])) + rom.write_bytes(0x007C30, bytearray([0xE2, 0x20, 0xAD, 0x59, 0x14, 0xC2, 0x20, 0xF0, 0x09, 0xBB, 0x22, 0x87, 0xBF, 0x03, 0x5C, 0x8D])) + rom.write_bytes(0x007C40, bytearray([0xA3, 0x02, 0x5C, 0x81, 0xA3, 0x02, 0xE2, 0x20, 0xAD, 0x5A, 0x14, 0xC2, 0x20, 0xF0, 0x09, 0xB5])) + rom.write_bytes(0x007C50, bytearray([0x76, 0x29, 0xFF, 0x00, 0x5C, 0x9D, 0x93, 0x02, 0x8D, 0x04, 0x30, 0xA9, 0x00, 0x00, 0x8D, 0x08])) + rom.write_bytes(0x007C60, bytearray([0x30, 0x5C, 0xA5, 0x93, 0x02, 0xE2, 0x20, 0xAD, 0x5A, 0x14, 0xC2, 0x20, 0xD0, 0x01, 0x6B, 0x22])) + rom.write_bytes(0x007C70, bytearray([0x23, 0xAF, 0x03, 0x5C, 0xDA, 0x93, 0x02, 0xE2, 0x20, 0xAD, 0x5B, 0x14, 0xC2, 0x20, 0xF0, 0x09])) + rom.write_bytes(0x007C80, bytearray([0x9B, 0xBD, 0xD6, 0x79, 0x0A, 0x5C, 0xCA, 0xC4, 0x05, 0x6B, 0xE2, 0x20, 0xAD, 0x5B, 0x14, 0xC2])) + rom.write_bytes(0x007C90, bytearray([0x20, 0xF0, 0x09, 0x9B, 0xBD, 0xD6, 0x79, 0x0A, 0x5C, 0xC1, 0xC8, 0x05, 0x6B, 0x22, 0x52, 0xAA])) + rom.write_bytes(0x007CA0, bytearray([0x03, 0xE2, 0x20, 0xAD, 0x5B, 0x14, 0xC2, 0x20, 0xF0, 0x0A, 0xA0, 0x00, 0x22, 0xD1, 0xF7, 0x00])) + rom.write_bytes(0x007CB0, bytearray([0x5C, 0xD9, 0xC4, 0x05, 0x22, 0xC5, 0xF7, 0x00, 0x5C, 0x70, 0xC5, 0x05, 0x22, 0x23, 0xAF, 0x03])) + rom.write_bytes(0x007CC0, bytearray([0xE2, 0x20, 0xAD, 0x5C, 0x14, 0xC2, 0x20, 0xF0, 0x0A, 0xA0, 0x00, 0x22, 0xD1, 0xF7, 0x00, 0x5C])) + rom.write_bytes(0x007CD0, bytearray([0x24, 0xC9, 0x0C, 0x22, 0xC5, 0xF7, 0x00, 0x80, 0xF6, 0xE2, 0x20, 0xAD, 0x5C, 0x14, 0xC2, 0x20])) + rom.write_bytes(0x007CE0, bytearray([0xF0, 0x08, 0x8A, 0x8D, 0x02, 0x30, 0x5C, 0x4D, 0xCD, 0x0C, 0xFA, 0x5C, 0x3A, 0xCD, 0x0C, 0x48])) + rom.write_bytes(0x007CF0, bytearray([0xDA, 0xE2, 0x20, 0xAD, 0x5D, 0x14, 0xF0, 0x33, 0xAA, 0x4C, 0x53, 0xFF, 0xFF, 0x18, 0x4C, 0x71])) + rom.write_bytes(0x007D00, bytearray([0xFF, 0x8D, 0x5E, 0x14, 0xC2, 0x20, 0xFA, 0x68, 0x1A, 0x1A, 0xC9, 0x0E, 0x00, 0x90, 0x06, 0x80])) + rom.write_bytes(0x007D10, bytearray([0x16, 0x5C, 0x15, 0xBF, 0x03, 0xE2, 0x20, 0x48, 0xBD, 0x60, 0x73, 0xC9, 0x27, 0xF0, 0x12, 0x68])) + rom.write_bytes(0x007D20, bytearray([0xCD, 0x5E, 0x14, 0xC2, 0x20, 0x90, 0xEA, 0x5C, 0xE5, 0xFA, 0x0B, 0x1A, 0x8D, 0x5D, 0x14, 0x80])) + rom.write_bytes(0x007D30, bytearray([0xC0, 0x68, 0xC2, 0x20, 0xEE, 0xCC, 0x00, 0xEE, 0xCC, 0x00, 0x80, 0xD5, 0xA8, 0x5C, 0x20, 0xBF])) + rom.write_bytes(0x007D40, bytearray([0x03, 0x8B, 0xA9, 0x03, 0x8D, 0x4B, 0x09, 0x8D, 0x01, 0x21, 0x22, 0x39, 0xB4, 0x00, 0x22, 0x79])) + rom.write_bytes(0x007D50, bytearray([0x82, 0x10, 0xDA, 0xAD, 0x0E, 0x03, 0x4A, 0xAA, 0xBF, 0xF3, 0xFE, 0x06, 0xAA, 0xAD, 0x1A, 0x02])) + rom.write_bytes(0x007D60, bytearray([0x9F, 0x00, 0x7C, 0x70, 0x9C, 0x22, 0x02, 0xAF, 0x83, 0xFC, 0x0D, 0xAA, 0xBF, 0xB2, 0xAF, 0x09])) + rom.write_bytes(0x007D70, bytearray([0x0C, 0xCE, 0x00, 0xAD, 0x60, 0x14, 0x0C, 0xCE, 0x00, 0x5A, 0xC2, 0x10, 0xA2, 0xAA, 0xAF, 0xAD])) + rom.write_bytes(0x007D80, bytearray([0xCE, 0x00, 0x89, 0x01, 0xF0, 0x06, 0xA0, 0x22, 0x02, 0x20, 0xCA, 0xFD, 0x89, 0x02, 0xF0, 0x06])) + rom.write_bytes(0x007D90, bytearray([0xA0, 0x2E, 0x02, 0x20, 0xCA, 0xFD, 0x89, 0x04, 0xF0, 0x06, 0xA0, 0x3A, 0x02, 0x20, 0xCA, 0xFD])) + rom.write_bytes(0x007DA0, bytearray([0x89, 0x08, 0xF0, 0x06, 0xA0, 0x46, 0x02, 0x20, 0xCA, 0xFD, 0x89, 0x10, 0xF0, 0x06, 0xA0, 0x52])) + rom.write_bytes(0x007DB0, bytearray([0x02, 0x20, 0xCA, 0xFD, 0x89, 0x20, 0xF0, 0x06, 0xA0, 0x5E, 0x02, 0x20, 0xCA, 0xFD, 0x9C, 0x65])) + rom.write_bytes(0x007DC0, bytearray([0x02, 0xE2, 0x10, 0x7A, 0xFA, 0xAB, 0x5C, 0xB6, 0xA5, 0x17, 0xC2, 0x20, 0x48, 0xA9, 0x07, 0x00])) + rom.write_bytes(0x007DD0, bytearray([0xDA, 0x54, 0x00, 0x09, 0xFA, 0x68, 0xE2, 0x20, 0x60, 0xDA, 0x5A, 0x8B, 0xAD, 0x0E, 0x03, 0xC2])) + rom.write_bytes(0x007DE0, bytearray([0x20, 0xC2, 0x10, 0xAA, 0xBF, 0x07, 0xFF, 0x06, 0xA8, 0xE2, 0x20, 0xA9, 0x00, 0xEB, 0xA9, 0x7F])) + rom.write_bytes(0x007DF0, bytearray([0xA2, 0xC0, 0x14, 0x54, 0x70, 0x7E, 0xA2, 0xC0, 0x14, 0xA0, 0x40, 0x14, 0xA9, 0x00, 0xEB, 0xA9])) + rom.write_bytes(0x007E00, bytearray([0x7F, 0x54, 0x7E, 0x7E, 0xE2, 0x10, 0xAB, 0x7A, 0xFA, 0xA9, 0x1E, 0x8D, 0x18, 0x01, 0xAF, 0x83])) + rom.write_bytes(0x007E10, bytearray([0xFC, 0x0D, 0xDA, 0xAA, 0xBF, 0xB8, 0xAF, 0x09, 0x8D, 0x18, 0x02, 0xAF, 0x88, 0xFC, 0x0D, 0x49])) + rom.write_bytes(0x007E20, bytearray([0x01, 0x8D, 0x5A, 0x14, 0xFA, 0x5C, 0x58, 0x99, 0x17, 0xAE, 0x15, 0x11, 0xAD, 0x60, 0x14, 0x89])) + rom.write_bytes(0x007E30, bytearray([0x01, 0xD0, 0x0D, 0xAF, 0x83, 0xFC, 0x0D, 0xF0, 0x07, 0x9E, 0x10, 0x00, 0x5C, 0xB1, 0xD8, 0x17])) + rom.write_bytes(0x007E40, bytearray([0xFE, 0x10, 0x00, 0x80, 0xF7, 0xA9, 0xF0, 0x85, 0x4D, 0x8D, 0x63, 0x14, 0xA9, 0x80, 0x8D, 0x20])) + rom.write_bytes(0x007E50, bytearray([0x02, 0x8D, 0x4A, 0x00, 0x5C, 0x59, 0xC1, 0x01, 0xE2, 0x20, 0xAD, 0x61, 0x14, 0x89, 0x01, 0xF0])) + rom.write_bytes(0x007E60, bytearray([0x08, 0x48, 0xA9, 0x09, 0x8F, 0x17, 0x03, 0x17, 0x68, 0x89, 0x02, 0xF0, 0x08, 0x48, 0xA9, 0x09])) + rom.write_bytes(0x007E70, bytearray([0x8F, 0x23, 0x03, 0x17, 0x68, 0x89, 0x04, 0xF0, 0x08, 0x48, 0xA9, 0x09, 0x8F, 0x2F, 0x03, 0x17])) + rom.write_bytes(0x007E80, bytearray([0x68, 0x89, 0x08, 0xF0, 0x08, 0x48, 0xA9, 0x09, 0x8F, 0x3B, 0x03, 0x17, 0x68, 0x89, 0x10, 0xF0])) + rom.write_bytes(0x007E90, bytearray([0x08, 0x48, 0xA9, 0x09, 0x8F, 0x47, 0x03, 0x17, 0x68, 0x89, 0x20, 0xF0, 0x08, 0x48, 0xA9, 0x09])) + rom.write_bytes(0x007EA0, bytearray([0x8F, 0x53, 0x03, 0x17, 0x68, 0xAD, 0x62, 0x14, 0x89, 0x01, 0xF0, 0x08, 0x48, 0xA9, 0x0A, 0x8F])) + rom.write_bytes(0x007EB0, bytearray([0x18, 0x03, 0x17, 0x68, 0x89, 0x02, 0xF0, 0x08, 0x48, 0xA9, 0x0A, 0x8F, 0x24, 0x03, 0x17, 0x68])) + rom.write_bytes(0x007EC0, bytearray([0x89, 0x04, 0xF0, 0x08, 0x48, 0xA9, 0x0A, 0x8F, 0x30, 0x03, 0x17, 0x68, 0x89, 0x08, 0xF0, 0x08])) + rom.write_bytes(0x007ED0, bytearray([0x48, 0xA9, 0x0A, 0x8F, 0x3C, 0x03, 0x17, 0x68, 0x89, 0x10, 0xF0, 0x08, 0x48, 0xA9, 0x0A, 0x8F])) + rom.write_bytes(0x007EE0, bytearray([0x48, 0x03, 0x17, 0x68, 0x89, 0x20, 0xF0, 0x08, 0x48, 0xA9, 0x0A, 0x8F, 0x54, 0x03, 0x17, 0x68])) + rom.write_bytes(0x007EF0, bytearray([0xC2, 0x20, 0x5C, 0x26, 0xDB, 0x17, 0xAD, 0x63, 0x14, 0xF0, 0x0E, 0xA9, 0x00, 0x8D, 0x63, 0x14])) + rom.write_bytes(0x007F00, bytearray([0xA9, 0x20, 0x8D, 0x18, 0x01, 0x5C, 0x04, 0xA9, 0x17, 0xA9, 0x25, 0x80, 0xF5, 0xAD, 0x06, 0x7E])) + rom.write_bytes(0x007F10, bytearray([0xD0, 0x15, 0xE2, 0x20, 0xAD, 0x64, 0x14, 0xD0, 0x0E, 0xAF, 0x84, 0xFC, 0x0D, 0x89, 0x01, 0xD0])) + rom.write_bytes(0x007F20, bytearray([0x06, 0xC2, 0x20, 0x5C, 0x49, 0xEA, 0x0C, 0xC2, 0x20, 0x5C, 0x47, 0xEA, 0x0C, 0xAD, 0x06, 0x7E])) + rom.write_bytes(0x007F30, bytearray([0xD0, 0x15, 0xE2, 0x20, 0xAD, 0x64, 0x14, 0xD0, 0x0E, 0xAF, 0x84, 0xFC, 0x0D, 0x89, 0x02, 0xD0])) + rom.write_bytes(0x007F40, bytearray([0x06, 0xC2, 0x20, 0x5C, 0x91, 0xC0, 0x03, 0xC2, 0x20, 0x5C, 0xCC, 0xC0, 0x03])) + rom.write_bytes(0x007F53, bytearray([0xBF, 0xA3, 0xAF, 0x09, 0xE0, 0x06, 0xF0, 0x03, 0x4C, 0xFD, 0xFC, 0x4C, 0x01, 0xFD])) + rom.write_bytes(0x007F61, bytearray([0xAF, 0xAE, 0x00, 0x70, 0xD0, 0x07, 0xFA, 0xA9, 0x0E, 0x00, 0x4C, 0x2C, 0xFA, 0x4C, 0x26, 0xFA])) + rom.write_bytes(0x007F71, bytearray([0x6D, 0xCC, 0x00, 0xC9, 0x0E, 0x90, 0x02, 0xA9, 0x0E, 0x4C, 0x01, 0xFD])) + + rom.write_bytes(0x077F82, bytearray([0xE2, 0x20, 0xAD, 0x40, 0x14, 0xD0, 0x08, 0xC2, 0x20, 0x22, 0xC5, 0xF7, 0x00, 0x80])) + rom.write_bytes(0x077F90, bytearray([0x06, 0xA0, 0x00, 0x22, 0xD1, 0xF7, 0x00, 0xC2, 0x20, 0x20, 0x1A, 0xB6, 0x60, 0xE2, 0x20, 0xAD])) + rom.write_bytes(0x077FA0, bytearray([0x55, 0x14, 0xC2, 0x20, 0xD0, 0x03, 0x4C, 0xFD, 0xBE, 0x20, 0xBB, 0xBF, 0x4C, 0xFD, 0xBE])) + + rom.write_bytes(0x01FEEE, bytearray([0xB9, 0x00])) + rom.write_bytes(0x01FEF0, bytearray([0x6F, 0x48, 0xDA, 0xBD, 0x60, 0x73, 0xA2, 0x00, 0xDF, 0x70, 0xAF, 0x09, 0xF0, 0x08, 0xE8, 0xE8])) + rom.write_bytes(0x01FF00, bytearray([0xE0, 0x08, 0xF0, 0x1A, 0x80, 0xF2, 0x8A, 0x4A, 0xE2, 0x20, 0xAA, 0xBF, 0x78, 0xAF, 0x09, 0xAA])) + rom.write_bytes(0x01FF10, bytearray([0xBD, 0x40, 0x14, 0xC2, 0x20, 0xD0, 0x07, 0xFA, 0x68, 0xC9, 0x00, 0x00, 0x80, 0x05, 0xFA, 0x68])) + rom.write_bytes(0x01FF20, bytearray([0xC9, 0x10, 0x00, 0x5C, 0x34, 0xC3, 0x03, 0xAE, 0x12, 0x98, 0xE2, 0x20, 0xAD, 0x5E, 0x14, 0xC9])) + rom.write_bytes(0x01FF30, bytearray([0x0E, 0xF0, 0x08, 0x3A, 0x3A, 0xA8, 0xC2, 0x20, 0x4C, 0x15, 0xBF, 0x98, 0x80, 0xF8])) + + rom.write_bytes(0x02FFC0, bytearray([0x0C, 0xA6, 0x12, 0x6B, 0xBD, 0x60, 0x73, 0xC9, 0x1E, 0x01, 0xE2, 0x20, 0xF0, 0x05, 0xAD, 0x4C])) + rom.write_bytes(0x02FFD0, bytearray([0x14, 0x80, 0x03, 0xAD, 0x4B, 0x14, 0xC9, 0x00, 0xC2, 0x20, 0xF0, 0x03, 0x20, 0xF6, 0xF1, 0x4C])) + rom.write_bytes(0x02FFE0, bytearray([0xB0, 0xF0])) + + rom.write_bytes(0x017FD7, bytearray([0xE2, 0x20, 0xAD, 0x4D, 0x14, 0xC2, 0x20, 0xF0, 0x10])) + rom.write_bytes(0x017FE0, bytearray([0xBD, 0x60, 0x73, 0xC9, 0xA9, 0x01, 0xF0, 0x04, 0xA9, 0x04, 0x00, 0x60, 0xA9, 0x0A, 0x00, 0x60])) + rom.write_bytes(0x017FF0, bytearray([0x68, 0x4C, 0x90, 0xAD])) + + rom.write_bytes(0x03FF48, bytearray([0xE2, 0x20, 0xAD, 0x56, 0x14, 0xC2, 0x20, 0xD0])) + rom.write_bytes(0x03FF50, bytearray([0x03, 0x4C, 0x5B, 0x96, 0x20, 0x3D, 0x9D, 0x4C, 0x4F, 0x96])) + + +def Item_Data(rom: LocalRom) -> None: + rom.write_bytes(0x04AF70, bytearray([0xBB, 0x00, 0xBA, 0x00, 0xC7, 0x00, 0xC8, 0x00, 0x01, 0x02, 0x03, 0x03, 0xB1, 0x00, 0xB0, 0x00])) + rom.write_bytes(0x04AF80, bytearray([0xB2, 0x00, 0xAF, 0x00, 0xB4, 0x00, 0x04, 0x05, 0x06, 0x07, 0x08, 0x07, 0x00, 0x05, 0x00, 0x09])) + rom.write_bytes(0x04AF90, bytearray([0x00, 0x0D, 0x0E, 0x0F, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, 0x11, 0x12])) + rom.write_bytes(0x04AFA0, bytearray([0x12, 0x12, 0x12, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01])) + rom.write_bytes(0x04AFB0, bytearray([0x01, 0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A])) + + +def Server_Data(rom: LocalRom) -> None: + rom.write_bytes(0x037EAA, bytearray([0x00, 0x00, 0x01, 0x02, 0x03, 0x04])) + rom.write_bytes(0x037EB0, bytearray([0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14])) + rom.write_bytes(0x037EC0, bytearray([0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x24, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x01])) + rom.write_bytes(0x037ED0, bytearray([0x02, 0x04, 0x08, 0x10, 0x20, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30])) + rom.write_bytes(0x037EE0, bytearray([0x31, 0x32, 0x33, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0xFF, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39])) + rom.write_bytes(0x037EF0, bytearray([0x3A, 0x3B, 0x3C, 0x02, 0x6A, 0xD2, 0x04, 0x03, 0x06, 0x07, 0x08, 0x09, 0x05, 0x01, 0x02, 0x3D])) + rom.write_bytes(0x037F00, bytearray([0x3E, 0x3F, 0x40, 0x01, 0x02, 0x03, 0x0A, 0x80, 0x7E, 0x00, 0x7F, 0x80, 0x7F])) + + +def Menu_Data(rom: LocalRom) -> None: + rom.write_bytes(0x115348, bytearray([0x80, 0x80, 0x4E, 0x80, 0x80, 0x4E, 0x80, 0x80])) + rom.write_bytes(0x115350, bytearray([0x4E, 0x80, 0x80, 0x4E, 0x80, 0x80, 0x4E, 0x80, 0x80, 0x4E, 0x80, 0x80, 0x4E, 0x80, 0x80, 0x4E])) + rom.write_bytes(0x115360, bytearray([0x80, 0x80, 0x4E, 0x80, 0x80, 0x4E, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03])) + rom.write_bytes(0x115370, bytearray([0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08])) + rom.write_bytes(0x115380, bytearray([0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x24, 0x2C, 0x00, 0x06, 0x1E, 0x00, 0x06, 0x24, 0x00])) + rom.write_bytes(0x115390, bytearray([0x02, 0x24, 0x00, 0x0E, 0x04, 0x00, 0x18, 0x26, 0x00, 0x26, 0x1A, 0x00, 0x04, 0x22, 0x00, 0x24])) + rom.write_bytes(0x1153A0, bytearray([0x18, 0x00, 0x24, 0x02, 0x00, 0x16, 0x24, 0x00, 0x00, 0x2C, 0x00, 0x2A, 0x2C, 0x00, 0x2C, 0x18])) + rom.write_bytes(0x1153B0, bytearray([0x00, 0x10, 0x18, 0x00, 0x0A, 0x18, 0x00, 0x24, 0x24, 0x00, 0x0A, 0x08, 0x00, 0x0C, 0x08, 0x00])) + rom.write_bytes(0x1153C0, bytearray([0x08, 0x16, 0x00, 0x08, 0x1E, 0x00, 0x04, 0x14, 0x00, 0x1E, 0x0E, 0x00, 0x1E, 0x0C, 0x00, 0x24])) + rom.write_bytes(0x1153D0, bytearray([0x14, 0x00, 0x14, 0x30, 0x00, 0x18, 0x22, 0x00, 0x02, 0x04, 0x00, 0x26, 0x16, 0x00, 0x24, 0x16])) + rom.write_bytes(0x1153E0, bytearray([0x00, 0x5C, 0x38, 0x60, 0x4E, 0x28, 0x1A, 0x16, 0x1C, 0x04, 0x14, 0x36, 0x36, 0x36, 0x80, 0x80])) + rom.write_bytes(0x1153F0, bytearray([0x34, 0x81, 0x81, 0x4E, 0x4E, 0x4E, 0x5C, 0x38, 0x60, 0x4E, 0x04, 0x16, 0x08, 0x00, 0x22, 0x36])) + rom.write_bytes(0x115400, bytearray([0x36, 0x36, 0x36, 0x80, 0x80, 0x34, 0x81, 0x81, 0x4E, 0x4E, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58])) + rom.write_bytes(0x115410, bytearray([0x5A, 0x5C, 0x5E, 0x60, 0x62, 0x50, 0x52, 0x54, 0x09, 0x15, 0x21, 0x2D, 0x39, 0x45, 0x0C, 0x03])) + rom.write_bytes(0x115420, bytearray([0x07, 0x0F, 0x13, 0x1B, 0x1F, 0x27, 0x2B, 0x33, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x02, 0x04, 0x04])) + rom.write_bytes(0x115430, bytearray([0x06, 0x06, 0x08, 0x08, 0x0A, 0x41, 0x00, 0x3C, 0x00, 0x33, 0x00, 0x25, 0x00, 0x1B, 0x00, 0x14])) + rom.write_bytes(0x115440, bytearray([0x00, 0x0B, 0x00, 0x02, 0x00, 0xF6, 0x3F, 0xEC, 0x3F, 0xDC, 0x3F])) + + rom.write_bytes(0x082660, bytearray([0x07])) + rom.write_bytes(0x082667, bytearray([0x05])) + rom.write_bytes(0x082677, bytearray([0x0A, 0x03, 0x05])) + rom.write_bytes(0x082688, bytearray([0x00])) + + rom.write_bytes(0x11548E, bytearray([0x60, 0x3d, 0x66, 0x3b, 0x60, 0x3f, 0x60, 0x39, 0x66, 0x39, 0x66, 0x3d, 0x66, 0x3f, 0x60, 0x3b])) + rom.write_bytes(0x11549E, bytearray([0x02, 0x06, 0x04, 0x00, 0x01, 0x03, 0x05, 0x07])) + + +def CodeHandler(rom: LocalRom) -> None: + rom.write_bytes(0x073637, bytearray([0x5C, 0xB0, 0xF7, 0x00])) # Check ! Switch + rom.write_bytes(0x07360B, bytearray([0x20, 0x82, 0xFF])) # Flash ! Switch + + rom.write_bytes(0x01C2F3, bytearray([0x22, 0x11, 0xF8, 0x00])) # Check visibility of winged clouds + rom.write_bytes(0x01C32E, bytearray([0x5C, 0xEE, 0xFE, 0x03])) # Check items in winged clouds + + rom.write_bytes(0x01C9AD, bytearray([0x5C, 0x19, 0xF8, 0x00])) # Check transformations + rom.write_bytes(0x01C995, bytearray([0x5C, 0x59, 0xF8, 0x00])) # Flash transformations + rom.write_bytes(0x01C943, bytearray([0x5C, 0x77, 0xF8, 0x00])) # Fixes a bug where transformation bubbles flashing would displace the sprite + + rom.write_bytes(0x028329, bytearray([0x5C, 0x9A, 0xF8, 0x00])) # Flash Spring Ball + rom.write_bytes(0x02837E, bytearray([0x5C, 0xC4, 0xF8, 0x00])) # Check Spring Ball + + rom.write_bytes(0x02F0A2, bytearray([0x5C, 0xEA, 0xF8, 0x00])) # Flash Arrow Wheel + rom.write_bytes(0x02F0AD, bytearray([0x4C, 0xC4, 0xFF])) # Check Arrow Wheel + + rom.write_bytes(0x02001D, bytearray([0x5C, 0x15, 0xF9, 0x00])) # Check Melon + rom.write_bytes(0x020028, bytearray([0x5C, 0x41, 0xF9, 0x00])) # Secondary check for melon used to overwrite visibility on the ground + rom.write_bytes(0x020031, bytearray([0x5C, 0xAE, 0xF9, 0x00])) # Check for melons that are spawned by objects which skips the initial check + rom.write_bytes(0x012DF7, bytearray([0x20, 0xD7, 0xFF])) # Check for monkeys holding melons + rom.write_bytes(0x012E07, bytearray([0x20, 0xD7, 0xFF])) # Check for monkeys holding melons + rom.write_bytes(0x03F17D, bytearray([0x5C, 0xE1, 0xF9, 0x00])) # Fixes a bug where balloons with ice melons will write to yoshi's mouth before deactivating the melon. + + rom.write_bytes(0x011901, bytearray([0x5C, 0x7A, 0xF9, 0x00])) # Flash Super Star + rom.write_bytes(0x01192A, bytearray([0x5C, 0x95, 0xF9, 0x00])) # Check Super Star + + rom.write_bytes(0x01BEB9, bytearray([0x5C, 0xF6, 0xF9, 0x00])) # Check egg-type items + rom.write_bytes(0x01B75E, bytearray([0x5C, 0x5B, 0xFA, 0x00])) # Flash flashing eggs and force them to purple + + rom.write_bytes(0x03BA31, bytearray([0x22, 0x81, 0xFA, 0x00])) # Flash Arrow Cloud + rom.write_bytes(0x03BA35, bytearray([0x22, 0x9A, 0xFA, 0x00])) # Check Arrow Cloud + rom.write_bytes(0x03BA3D, bytearray([0x22, 0x81, 0xFA, 0x00])) # Flash Arrow Cloud, rotating + rom.write_bytes(0x03BA5A, bytearray([0x22, 0x9A, 0xFA, 0x00])) # Check Arrow Cloud, rotating + + rom.write_bytes(0x03818F, bytearray([0x5C, 0xAB, 0xFA, 0x00])) # Check Egg Plant + rom.write_bytes(0x0380F3, bytearray([0x5C, 0xC3, 0xFA, 0x00])) # Flash Egg Plant + + rom.write_bytes(0x073EF6, bytearray([0x5C, 0xE0, 0xFA, 0x00])) # Flash Chomp Rock + rom.write_bytes(0x073EFA, bytearray([0x4C, 0x9D, 0xFF])) # Check Chomp Rock + + rom.write_bytes(0x039639, bytearray([0x5C, 0xFF, 0xFA, 0x00])) # Flash Poochy + rom.write_bytes(0x03964C, bytearray([0x4C, 0x48, 0xFF])) # Check Poochy + + rom.write_bytes(0x0370C2, bytearray([0x22, 0x1A, 0xFB, 0x00, 0xEA])) # Flash Platform Ghosts + rom.write_bytes(0x03723F, bytearray([0x5C, 0x32, 0xFB, 0x00])) # Fixes a bug where the eyes would assign to a random sprite while flashing + rom.write_bytes(0x03739B, bytearray([0x5C, 0x52, 0xFB, 0x00])) # Check Vertical Platform Ghost + rom.write_bytes(0x036530, bytearray([0x5C, 0x6B, 0xFB, 0x00])) # Flash horizontal ghost + rom.write_bytes(0x03685C, bytearray([0x5C, 0x89, 0xFB, 0x00])) # Fix flashing horizontal ghost + rom.write_bytes(0x036894, bytearray([0x5C, 0xA9, 0xFB, 0x00])) # Check horizontal ghost + + rom.write_bytes(0x012497, bytearray([0x5C, 0xBF, 0xFB, 0x00])) # Check Skis + rom.write_bytes(0x01234D, bytearray([0x5C, 0xF1, 0xFB, 0x00])) # Allow ski doors to be re-entered + + rom.write_bytes(0x01204A, bytearray([0x5C, 0x10, 0xFC, 0x00])) # Flash Key + rom.write_bytes(0x012388, bytearray([0x5C, 0x30, 0xFC, 0x00])) # Check Key + + rom.write_bytes(0x011398, bytearray([0x5C, 0x46, 0xFC, 0x00])) # Flash MidRing + rom.write_bytes(0x0113D6, bytearray([0x5C, 0x65, 0xFC, 0x00])) # Check MidRing + + rom.write_bytes(0x02C4C6, bytearray([0x5C, 0x77, 0xFC, 0x00])) # Check Bucket w/ Item + rom.write_bytes(0x02C8BD, bytearray([0x5C, 0x8A, 0xFC, 0x00])) # Check Bucket, ridable + rom.write_bytes(0x02C4D5, bytearray([0x5C, 0x9D, 0xFC, 0x00])) # Flash Bucket + + rom.write_bytes(0x064920, bytearray([0x5C, 0xBC, 0xFC, 0x00])) # Flash Tulip + rom.write_bytes(0x064D49, bytearray([0x5C, 0xD9, 0xFC, 0x00])) # Check Tulip + + rom.write_bytes(0x01BEC7, bytearray([0x5C, 0xEF, 0xFC, 0x00])) # Check Egg Capacity + rom.write_bytes(0x01BF12, bytearray([0x4C, 0x27, 0xFF])) # Set current egg max + rom.write_bytes(0x01BF1A, bytearray([0x5C, 0x3C, 0xFD, 0x00])) # Cap eggs + + rom.write_bytes(0x0BA5AE, bytearray([0x5C, 0x41, 0xFD, 0x00])) # Unlock Levels + + rom.write_bytes(0x0B9953, bytearray([0x5C, 0xD9, 0xFD, 0x00])) # File initialization + + rom.write_bytes(0x0BD8AB, bytearray([0x5C, 0x29, 0xFE, 0x00])) # Prevent the world 1 tab from being drawn without it being unlocked + + rom.write_bytes(0x00C155, bytearray([0x5C, 0x45, 0xFE, 0x00])) # Save between levels + + rom.write_bytes(0x0BDB20, bytearray([0x5C, 0x58, 0xFE, 0x00])) # Unlock extra and bonus stages + + rom.write_bytes(0x0BA8FF, bytearray([0x5C, 0xF6, 0xFE, 0x00])) # Skip the score animation if coming from start-select, but still save + + rom.write_bytes(0x0BA8A9, bytearray([0x80, 0x46])) # Prevent unlocking new levels + + rom.write_bytes(0x066A42, bytearray([0x5C, 0x0D, 0xFF, 0x00])) # Coin visibility + rom.write_bytes(0x01C08C, bytearray([0x5C, 0x2D, 0xFF, 0x00])) # Cloud visibility + + rom.write_bytes(0x00C0D9, bytearray([0x5C, 0xB8, 0xF3, 0x0B])) # Receive item from server + + rom.write_bytes(0x00C153, bytearray([0xEA, 0xEA])) # Always enable Start/Select + + rom.write_bytes(0x00C18B, bytearray([0x5C, 0x1B, 0xF5, 0x0B])) # Enable traps + + rom.write_bytes(0x01B365, bytearray([0x5C, 0x86, 0xF5, 0x0B])) # Red Coin checks + rom.write_bytes(0x0734C6, bytearray([0x5C, 0xCE, 0xF5, 0x0B])) # Flower checks + rom.write_bytes(0x00C0DE, bytearray([0x5C, 0xF5, 0xF5, 0x0B])) # Star checks + rom.write_bytes(0x00B580, bytearray([0x5C, 0xB1, 0xF5, 0x0B])) # Level Clear checks + + rom.write_bytes(0x0B9937, bytearray([0x5C, 0x23, 0xF6, 0x0B])) # Load AP data + rom.write_bytes(0x0BE14A, bytearray([0x5C, 0x58, 0xF6, 0x0B])) # Save AP data + + rom.write_bytes(0x00D09F, bytearray([0x5C, 0x8C, 0xF6, 0x0B])) # Clear Menu + rom.write_bytes(0x00BCB5, bytearray([0x5C, 0xAD, 0xF6, 0x0B])) # Clear Score for menu + rom.write_bytes(0x00D072, bytearray([0x5C, 0xC3, 0xF6, 0x0B])) # Loads the data for the AP menu + rom.write_bytes(0x00D07A, bytearray([0x5C, 0x5A, 0xF7, 0x0B])) # Draw the AP menu over the pause menu + rom.write_bytes(0x00D17A, bytearray([0x5C, 0xDA, 0xF7, 0x0B])) # Skip the flower counter in the AP menu + rom.write_bytes(0x00D0DE, bytearray([0x5C, 0xF1, 0xF7, 0x0B])) # Skip the coin counter in the AP menu + rom.write_bytes(0x00CFB4, bytearray([0x5C, 0x06, 0xF8, 0x0B])) # Get the number of bosses required to unlock 6-8 + rom.write_bytes(0x00CFD0, bytearray([0x5C, 0x2B, 0xF8, 0x0B])) # Get bosses for 6-8 clear + rom.write_bytes(0x00D203, bytearray([0x5C, 0xF0, 0xF8, 0x0B])) # Wipe total score line + rom.write_bytes(0x00D277, bytearray([0x5C, 0x04, 0xF9, 0x0B])) # Wipe high score line + rom.write_bytes(0x00C104, bytearray([0x5C, 0x18, 0xF9, 0x0B])) # Replace the pause menu with AP menu when SELECT is pressed + rom.write_bytes(0x00C137, bytearray([0x5C, 0x31, 0xF9, 0x0B])) # Prevent accidentally quitting out of a stage while opening the AP menu + rom.write_bytes(0x00CE48, bytearray([0x5C, 0x42, 0xF9, 0x0B])) # When closing the AP menu, reset the AP menu flag so the normal menu can be opened. + + rom.write_bytes(0x0BA5B6, bytearray([0x5C, 0x4E, 0xF9, 0x0B])) # Unlock 6-8 if the current number of defeated bosses is higher than the number of bosses required. If 6-8 is marked 'cleared', skip boss checks + rom.write_bytes(0x01209E, bytearray([0x5C, 0x92, 0xF9, 0x0B])) # Write a flag to check bosses if setting up the final boss door + rom.write_bytes(0x0123AA, bytearray([0x5C, 0xA3, 0xF9, 0x0B])) # If the boss check flag is set, read the number of bosses before opening door + + rom.write_bytes(0x015F7A, bytearray([0x5C, 0xCA, 0xF9, 0x0B])) # Write Boss Clears + + rom.write_bytes(0x0BE16E, bytearray([0x80, 0x12])) # Disable overworld bandit code + + rom.write_bytes(0x083015, bytearray([0x5C, 0x26, 0xFA, 0x0B])) # Flip Cards + rom.write_bytes(0x0839B6, bytearray([0x5C, 0x18, 0xFA, 0x0B])) # Scratch Cards + rom.write_bytes(0x085094, bytearray([0x5C, 0x31, 0xFA, 0x0B])) # Draw Lots + rom.write_bytes(0x0852C5, bytearray([0x5C, 0x3D, 0xFA, 0x0B])) # Match Cards + rom.write_bytes(0x0845EA, bytearray([0x5C, 0x48, 0xFA, 0x0B])) # Roulette + rom.write_bytes(0x083E0A, bytearray([0x5C, 0x53, 0xFA, 0x0B])) # Slots + + rom.write_bytes(0x01D845, bytearray([0x5C, 0x76, 0xF9, 0x0B])) # Check setting for disabled autoscrolls + + rom.write_bytes(0x0BDAC2, bytearray([0x80, 0x0E])) # Prevent extra and bonus stages from auto-unlocking at 100 points + rom.write_bytes(0x0BA720, bytearray([0xA9, 0x00, 0x00])) # Always read level scores as 0. This stops extras and bonus from trying to unlock + + rom.write_bytes(0x0BA720, bytearray([0xA9, 0x00, 0x00])) # Always read level scores as 0. This stops extras and bonus from trying to unlock + + rom.write_bytes(0x03FE85, bytearray([0x5C, 0x09, 0xFB, 0x0B])) # Decrement the key counter when unlocking the 6-4 cork + + rom.write_bytes(0x06F1B4, bytearray([0x5C, 0x22, 0xFB, 0x0B])) # Mark the goal and bowser clear after defeating bowser + + rom.write_bytes(0x005FE2, bytearray([0x5C, 0x9C, 0xFB, 0x0B])) # Flag red coins as checked if the last one came from a pole + + rom.write_bytes(0x01C2E1, bytearray([0x80])) # Makes hidden clouds not flash + rom.write_bytes(0x0120C0, bytearray([0x80])) # Prevents bandit game doors from sealing + + rom.write_bytes(0x0382A7, bytearray([0x5C, 0xC2, 0xFB, 0x0B])) # Make cactus eggplants check the eggplant item correctly + + rom.write_bytes(0x025E71, bytearray([0x5C, 0xFA, 0xFB, 0x0B])) # Write the stored reverse value + + rom.write_bytes(0x00B587, bytearray([0x5C, 0x24, 0xFC, 0x0B])) # Store the reverse value and zero it + + rom.write_bytes(0x0B9932, bytearray([0x5C, 0x96, 0xFA, 0x0B])) # Get 16 bit life count + + rom.write_bytes(0x00C288, bytearray([0x00])) + rom.write_bytes(0x00C28B, bytearray([0x80])) # Disable baby mario tutorial text + + rom.write_bytes(0x01141F, bytearray([0x80])) # Disable Middle Ring tutorial + + rom.write_bytes(0x073534, bytearray([0x80])) # Disable Flower tutorial + + rom.write_bytes(0x065B24, bytearray([0x5C, 0x45, 0xFC, 0x0B])) # Fix boss cutscenes + + rom.write_bytes(0x011507, bytearray([0x5C, 0x70, 0xFC, 0x0B])) # Fix Hookbill middle ring during boss shuffle + + rom.write_bytes(0x019E98, bytearray([0x5C, 0xB4, 0xFC, 0x0B])) # Flag red coins as checked if the last one was eaten + + rom.write_bytes(0x011AB6, bytearray([0x5C, 0xD7, 0xFC, 0x0B])) # Check egg refills for how many eggs to spawn + + rom.write_bytes(0x00DCA6, bytearray([0x5C, 0x00, 0xFD, 0x0B])) # Check egg refill pause use + + rom.write_bytes(0x0BE06B, bytearray([0x5C, 0x56, 0xFD, 0x0B])) # Get level from shuffled order + + rom.write_bytes(0x00C14B, bytearray([0xAE, 0x7C, 0x02, 0x8E, 0x1A, 0x02])) # Return to the original list when exiting a level + + rom.write_bytes(0x00BEA8, bytearray([0x5C, 0x3F, 0xFE, 0x0B])) # Save the original level when beating a shuffled one. + + rom.write_bytes(0x00E702, bytearray([0xAD, 0x7C, 0x02, 0x8D, 0x1A, 0x02, 0x80, 0x05])) # Save the original level when leaving through death + + rom.write_bytes(0x0BE72A, bytearray([0x7C])) # Load yoshi colors by slot number not level number + + rom.write_bytes(0x003346, bytearray([0x22, 0x54, 0xFE, 0x0B, 0xEA, 0xEA])) # Fix World 6 levels using weird tilesets + + rom.write_bytes(0x003A37, bytearray([0x22, 0x54, 0xFE, 0x0B, 0xEA, 0xEA])) # Fix World 6 levels using weird tilesets + + rom.write_bytes(0x0B87D5, bytearray([0x5C, 0x67, 0xFE, 0x0B])) + + rom.write_bytes(0x07081F, bytearray([0x80])) # Fix for weird falling chomps. Why does this even read the world number????? + + rom.write_bytes(0x0BC0B2, bytearray([0x5C, 0xD0, 0xED, 0x01])) # Load randomized yoshi colors on the world map + + rom.write_bytes(0x0BC6F7, bytearray([0x5C, 0x04, 0xEE, 0x01])) # Load selected yoshi color on the world map + + rom.write_bytes(0x0BC0AB, bytearray([0x80])) # Skip special color check for world 6; Levels handle this anyway + + +def write_lives(rom: LocalRom) -> None: + rom.write_bytes(0x05FA96, bytearray([0xC2, 0x20, 0xAF, 0x89, 0xFC, 0x0D, 0x8D, 0x79, 0x03, 0xE2, 0x20, 0x5C, 0x37, 0x99, 0x17])) + rom.write_bytes(0x05FABF, bytearray([0x48, 0xE2, 0x20, 0xAD, 0xCC, 0x00, 0xF0, 0x06, 0xCE, 0xCC, 0x00, 0xCE, 0xCC, 0x00, 0xC2, 0x20, 0x68, 0x22, 0x87, 0xBF, 0x03, 0x5C, 0x89, 0xFE, 0x07])) + + +def bonus_checks(rom: LocalRom) -> None: + rom.write_bytes(0x082156, bytearray([0x5C, 0x5F, 0xFA, 0x0B])) # Write bonus check + + +def bandit_checks(rom: LocalRom) -> None: + rom.write_bytes(0x08C9E4, bytearray([0x5C, 0xF3, 0xF9, 0x0B])) # Write Bandit Checks + + +def Handle_Locations(rom: LocalRom) -> None: + rom.write_bytes(0x05F3B8, bytearray([0xAD, 0x67, 0x14, 0xF0, 0x59, 0xDA, 0xC9, 0x1F])) + rom.write_bytes(0x05F3C0, bytearray([0xF0, 0x16, 0xC9, 0x20, 0xB0, 0x27, 0xAA, 0xBF, 0xAA, 0xFE, 0x06, 0xAA, 0xA9, 0x01, 0x9D, 0x40])) + rom.write_bytes(0x05F3D0, bytearray([0x14, 0xA9, 0x43, 0x8D, 0x53, 0x00, 0x80, 0x67, 0xAD, 0x5D, 0x14, 0xD0, 0x01, 0x1A, 0xC9, 0x06])) + rom.write_bytes(0x05F3E0, bytearray([0xF0, 0x04, 0x1A, 0x8D, 0x5D, 0x14, 0xA9, 0x03, 0x8D, 0x53, 0x00, 0x80, 0x52, 0xC9, 0x26, 0xB0])) + rom.write_bytes(0x05F3F0, bytearray([0x27, 0xA2, 0x00, 0xDF, 0xC9, 0xFE, 0x06, 0xF0, 0x03, 0xE8, 0x80, 0xF7, 0xBF, 0xCF, 0xFE, 0x06])) + rom.write_bytes(0x05F400, bytearray([0x8D, 0x4C, 0x00, 0xAD, 0x60, 0x14, 0x0C, 0x4C, 0x00, 0xAD, 0x4C, 0x00, 0x8D, 0x60, 0x14, 0xA9])) + rom.write_bytes(0x05F410, bytearray([0x97, 0x8D, 0x53, 0x00, 0x80, 0x29, 0x80, 0x70, 0xC9, 0x2D, 0xB0, 0x25, 0xA2, 0x00, 0xDF, 0xD5])) + rom.write_bytes(0x05F420, bytearray([0xFE, 0x06, 0xF0, 0x03, 0xE8, 0x80, 0xF7, 0xBF, 0xE3, 0xFE, 0x06, 0x8D, 0xCF, 0x00, 0xAD, 0x61])) + rom.write_bytes(0x05F430, bytearray([0x14, 0x0C, 0xCF, 0x00, 0xAD, 0xCF, 0x00, 0x8D, 0x61, 0x14, 0xA9, 0x95, 0x8D, 0x53, 0x00, 0x80])) + rom.write_bytes(0x05F440, bytearray([0x78, 0xC9, 0x34, 0xB0, 0x25, 0xA2, 0x00, 0xDF, 0xDC, 0xFE, 0x06, 0xF0, 0x03, 0xE8, 0x80, 0xF7])) + rom.write_bytes(0x05F450, bytearray([0xBF, 0xE3, 0xFE, 0x06, 0x8D, 0xCF, 0x00, 0xAD, 0x62, 0x14, 0x0C, 0xCF, 0x00, 0xAD, 0xCF, 0x00])) + rom.write_bytes(0x05F460, bytearray([0x8D, 0x62, 0x14, 0xA9, 0x95, 0x8D, 0x53, 0x00, 0x80, 0x4F, 0xC9, 0x3D, 0xB0, 0x1C, 0xA2, 0x00])) + rom.write_bytes(0x05F470, bytearray([0xDF, 0xEA, 0xFE, 0x06, 0xF0, 0x03, 0xE8, 0x80, 0xF7, 0xBF, 0xF6, 0xFE, 0x06, 0x22, 0xA6, 0x9C])) + rom.write_bytes(0x05F480, bytearray([0x10, 0xA9, 0x36, 0x8D, 0x53, 0x00, 0x80, 0x31, 0x80, 0x64, 0xC9, 0x41, 0xB0, 0x2D, 0xA2, 0x00])) + rom.write_bytes(0x05F490, bytearray([0xDF, 0xFF, 0xFE, 0x06, 0xF0, 0x03, 0xE8, 0x80, 0xF7, 0xA9, 0x00, 0xEB, 0xBF, 0x03, 0xFF, 0x06])) + rom.write_bytes(0x05F4A0, bytearray([0xAA, 0x18, 0xC2, 0x20, 0x6D, 0x79, 0x03, 0x8D, 0x79, 0x03, 0xE2, 0x20, 0xA9, 0x08, 0x22, 0xD2])) + rom.write_bytes(0x05F4B0, bytearray([0x85, 0x00, 0xCA, 0xE0, 0x00, 0xF0, 0x02, 0x80, 0xF5, 0x80, 0x51, 0xC9, 0x41, 0xF0, 0x1E, 0xC9])) + rom.write_bytes(0x05F4C0, bytearray([0x42, 0xF0, 0x2D, 0xC9, 0x43, 0xF0, 0x3A, 0xC2, 0x20, 0x5C, 0xFB, 0xB3, 0x21, 0x77, 0x14, 0xE2])) + rom.write_bytes(0x05F4D0, bytearray([0x20, 0xA9, 0x01, 0x8D, 0x7D, 0x02, 0xA9, 0x2E, 0x8D, 0x53, 0x00, 0x80, 0x2F, 0xA9, 0x01, 0x8D])) + rom.write_bytes(0x05F4E0, bytearray([0x68, 0x14, 0xC2, 0x20, 0xA9, 0x00, 0x04, 0x8D, 0x69, 0x14, 0xE2, 0x20, 0x80, 0x1E, 0x80, 0x22])) + rom.write_bytes(0x05F4F0, bytearray([0xC2, 0x20, 0xA9, 0x2C, 0x01, 0x8D, 0xCC, 0x0C, 0xE2, 0x20, 0xA9, 0xA0, 0x8D, 0x53, 0x00, 0x80])) + rom.write_bytes(0x05F500, bytearray([0x0B, 0xA9, 0x15, 0x8D, 0x53, 0x00, 0xA9, 0x05, 0x8F, 0xED, 0x61, 0x04, 0xFA, 0xA9, 0x00, 0x8D])) + rom.write_bytes(0x05F510, bytearray([0x67, 0x14, 0xA9, 0x10, 0x8D, 0x83, 0x0B, 0x5C, 0xDE, 0xC0, 0x01, 0xE2, 0x20, 0xAD, 0x7D, 0x02])) + rom.write_bytes(0x05F520, bytearray([0xF0, 0x25, 0xC2, 0x20, 0xAD, 0x7E, 0x02, 0xE2, 0x20, 0xF0, 0x12, 0xA9, 0x02, 0x8D, 0x00, 0x02])) + rom.write_bytes(0x05F530, bytearray([0xC2, 0x20, 0xAD, 0x7E, 0x02, 0x3A, 0x8D, 0x7E, 0x02, 0xE2, 0x20, 0x80, 0x0A, 0xA9, 0x0F, 0x8D])) + rom.write_bytes(0x05F540, bytearray([0x00, 0x02, 0xA9, 0x00, 0x8D, 0x7D, 0x02, 0xAD, 0x68, 0x14, 0xF0, 0x32, 0xC2, 0x20, 0xAD, 0x69])) + rom.write_bytes(0x05F550, bytearray([0x14, 0xF0, 0x1B, 0x3A, 0x8D, 0x69, 0x14, 0xE2, 0x20, 0x4C, 0x40, 0xFD, 0xE8, 0x1F, 0x70, 0xAD])) + rom.write_bytes(0x05F560, bytearray([0xD0, 0x00, 0xD0, 0x08, 0xEE, 0xD0, 0x00, 0xA9, 0x21, 0x8D, 0x53, 0x00, 0x80, 0x10, 0xE2, 0x20])) + rom.write_bytes(0x05F570, bytearray([0xA9, 0x22, 0x8D, 0x53, 0x00, 0xA9, 0x00, 0x8D, 0x68, 0x14, 0x8F, 0xE8, 0x1F, 0x70, 0x22, 0x59])) + rom.write_bytes(0x05F580, bytearray([0x82, 0x00, 0x5C, 0x8F, 0xC1, 0x01, 0xAC, 0xB4, 0x03, 0xC0, 0x14, 0x30, 0x20, 0x48, 0xDA, 0xE2])) + rom.write_bytes(0x05F590, bytearray([0x20, 0xAE, 0x1A, 0x02, 0xBD, 0x6D, 0x14, 0x8D, 0xD1, 0x00, 0xA9, 0x01, 0x0C, 0xD1, 0x00, 0xAD])) + rom.write_bytes(0x05F5A0, bytearray([0xD1, 0x00, 0x9D, 0x6D, 0x14, 0xC2, 0x20, 0xFA, 0x68, 0x5C, 0x6C, 0xB3, 0x03, 0x5C, 0x6D, 0xB3])) + rom.write_bytes(0x05F5B0, bytearray([0x03, 0xAE, 0x1A, 0x02, 0xBD, 0x6D, 0x14, 0x8D, 0xD1, 0x00, 0xA9, 0x08, 0x0C, 0xD1, 0x00, 0xAD])) + rom.write_bytes(0x05F5C0, bytearray([0xD1, 0x00, 0x9D, 0x6D, 0x14, 0xAE, 0x57, 0x0B, 0xE0, 0x0D, 0x5C, 0x85, 0xB5, 0x01, 0xA0, 0x05])) + rom.write_bytes(0x05F5D0, bytearray([0x8C, 0xB8, 0x03, 0x08, 0xE2, 0x20, 0xDA, 0x48, 0xAE, 0x1A, 0x02, 0xBD, 0x6D, 0x14, 0x8D, 0xD1])) + rom.write_bytes(0x05F5E0, bytearray([0x00, 0xA9, 0x02, 0x0C, 0xD1, 0x00, 0xAD, 0xD1, 0x00, 0x9D, 0x6D, 0x14, 0x68, 0xFA, 0xC2, 0x20])) + rom.write_bytes(0x05F5F0, bytearray([0x28, 0x5C, 0xCB, 0xB4, 0x0E, 0xC2, 0x20, 0xAD, 0xB6, 0x03, 0xC9, 0x2C, 0x01, 0x90, 0x18, 0xE2])) + rom.write_bytes(0x05F600, bytearray([0x20, 0xDA, 0xAE, 0x1A, 0x02, 0xBD, 0x6D, 0x14, 0x8D, 0xD1, 0x00, 0xA9, 0x04, 0x0C, 0xD1, 0x00])) + rom.write_bytes(0x05F610, bytearray([0xAD, 0xD1, 0x00, 0x9D, 0x6D, 0x14, 0xFA, 0x9C, 0x84, 0x0B, 0xE2, 0x20, 0xAD, 0x0F, 0x0D, 0x5C])) + rom.write_bytes(0x05F620, bytearray([0xE4, 0xC0, 0x01, 0xC2, 0x20, 0x48, 0xE2, 0x20, 0xA9, 0x1F, 0x8D, 0x18, 0x01, 0xDA, 0x5A, 0x8B])) + rom.write_bytes(0x05F630, bytearray([0x4C, 0xB2, 0xFA, 0xC2, 0x20, 0xC2, 0x10, 0xAA, 0xBF, 0x07, 0xFF, 0x06, 0xAA, 0xE2, 0x20, 0xA9])) + rom.write_bytes(0x05F640, bytearray([0x00, 0xEB, 0xA9, 0x7F, 0xA0, 0x40, 0x14, 0x54, 0x7E, 0x70, 0xE2, 0x10, 0xAB, 0x7A, 0xFA, 0xC2])) + rom.write_bytes(0x05F650, bytearray([0x20, 0x68, 0xE2, 0x20, 0x5C, 0x3C, 0x99, 0x17, 0xC2, 0x20, 0x48, 0xC2, 0x10, 0xDA, 0x5A, 0x8B])) + rom.write_bytes(0x05F660, bytearray([0xAD, 0x0E, 0x03, 0x29, 0x0F, 0x00, 0xAA, 0xBF, 0x07, 0xFF, 0x06, 0xA8, 0xE2, 0x20, 0xA9, 0x00])) + rom.write_bytes(0x05F670, bytearray([0xEB, 0xA9, 0x7F, 0xA2, 0x40, 0x14, 0x54, 0x70, 0x7E, 0xAB, 0x7A, 0xFA, 0xE2, 0x10, 0xC2, 0x20])) + rom.write_bytes(0x05F680, bytearray([0x68, 0xE2, 0x20, 0xAD, 0x3D, 0x09, 0x29, 0x20, 0x5C, 0x4F, 0xE1, 0x17, 0xE2, 0x20, 0xAD, 0xD2])) + rom.write_bytes(0x05F690, bytearray([0x00, 0xC2, 0x20, 0xD0, 0x09, 0xA9, 0xC1, 0xB1, 0x85, 0x10, 0x5C, 0xA4, 0xD0, 0x01, 0xA9, 0x00])) + rom.write_bytes(0x05F6A0, bytearray([0x00, 0x85, 0x10, 0x85, 0x12, 0x85, 0x14, 0x85, 0x16, 0x5C, 0xB3, 0xD0, 0x01, 0xE2, 0x20, 0xAD])) + rom.write_bytes(0x05F6B0, bytearray([0xD2, 0x00, 0xC2, 0x20, 0xD0, 0x09, 0xA9, 0x6F, 0x01, 0x05, 0x02, 0x5C, 0xBA, 0xBC, 0x01, 0x5C])) + rom.write_bytes(0x05F6C0, bytearray([0xBC, 0xBC, 0x01, 0xE2, 0x20, 0xAD, 0xD2, 0x00, 0xC2, 0x20, 0xD0, 0x0B, 0xBF, 0xED, 0xB7, 0x01])) + rom.write_bytes(0x05F6D0, bytearray([0x29, 0xFF, 0x00, 0x5C, 0x79, 0xD0, 0x01, 0xBF, 0x48, 0xD3, 0x22, 0x29, 0xFF, 0x00, 0xC9, 0x80])) + rom.write_bytes(0x05F6E0, bytearray([0x00, 0xF0, 0x04, 0x5C, 0x79, 0xD0, 0x01, 0xBF, 0x66, 0xD3, 0x22, 0xDA, 0xAA, 0xAD, 0xD3, 0x00])) + rom.write_bytes(0x05F6F0, bytearray([0x29, 0xFF, 0x00, 0xC9, 0x01, 0x00, 0xF0, 0x21, 0xC9, 0x02, 0x00, 0xF0, 0x38, 0xBD, 0x40, 0x14])) + rom.write_bytes(0x05F700, bytearray([0x29, 0xFF, 0x00, 0xF0, 0x0C, 0xFA, 0xBF, 0x87, 0xD3, 0x22, 0x29, 0xFF, 0x00, 0x5C, 0x79, 0xD0])) + rom.write_bytes(0x05F710, bytearray([0x01, 0xFA, 0xA9, 0x4E, 0x00, 0x5C, 0x79, 0xD0, 0x01, 0xBD, 0x4A, 0x14, 0x29, 0xFF, 0x00, 0xF0])) + rom.write_bytes(0x05F720, bytearray([0x0C, 0xFA, 0xBF, 0xA5, 0xD3, 0x22, 0x29, 0xFF, 0x00, 0x5C, 0x79, 0xD0, 0x01, 0xFA, 0xA9, 0x4E])) + rom.write_bytes(0x05F730, bytearray([0x00, 0x5C, 0x79, 0xD0, 0x01, 0xE0, 0x09, 0xD0, 0x05, 0xAD, 0x64, 0x14, 0x80, 0x03, 0xBD, 0x54])) + rom.write_bytes(0x05F740, bytearray([0x14, 0x29, 0xFF, 0x00, 0xF0, 0x0C, 0xFA, 0xBF, 0xC3, 0xD3, 0x22, 0x29, 0xFF, 0x00, 0x5C, 0x79])) + rom.write_bytes(0x05F750, bytearray([0xD0, 0x01, 0xFA, 0xA9, 0x4E, 0x00, 0x5C, 0x79, 0xD0, 0x01, 0xE2, 0x20, 0xAD, 0xD2, 0x00, 0xC2])) + rom.write_bytes(0x05F760, bytearray([0x20, 0xD0, 0x08, 0xBF, 0x5F, 0xB8, 0x01, 0x5C, 0x7E, 0xD0, 0x01, 0xAD, 0xD3, 0x00, 0x29, 0xFF])) + rom.write_bytes(0x05F770, bytearray([0x00, 0xC9, 0x01, 0x00, 0xF0, 0x3C, 0xC9, 0x02, 0x00, 0xF0, 0x4B, 0xBF, 0x5F, 0xB8, 0x01, 0x05])) + rom.write_bytes(0x05F780, bytearray([0x18, 0x99, 0xA1, 0xB1, 0xBF, 0xDD, 0xB8, 0x01, 0x05, 0x18, 0x99, 0xE1, 0xB1, 0xFA, 0xC8, 0xC8])) + rom.write_bytes(0x05F790, bytearray([0xE8, 0xE0, 0x1D, 0x90, 0x19, 0xEE, 0xD3, 0x00, 0xA0, 0x00, 0xA2, 0x00, 0xAD, 0xD3, 0x00, 0x29])) + rom.write_bytes(0x05F7A0, bytearray([0xFF, 0x00, 0xC9, 0x03, 0x00, 0xD0, 0x07, 0x9C, 0xD3, 0x00, 0x5C, 0x94, 0xD0, 0x01, 0x5C, 0x71])) + rom.write_bytes(0x05F7B0, bytearray([0xD0, 0x01, 0xBF, 0x5F, 0xB8, 0x01, 0x05, 0x18, 0x99, 0x21, 0xB2, 0xBF, 0xDD, 0xB8, 0x01, 0x05])) + rom.write_bytes(0x05F7C0, bytearray([0x18, 0x99, 0x61, 0xB2, 0x80, 0xC7, 0xBF, 0x5F, 0xB8, 0x01, 0x05, 0x18, 0x99, 0xA1, 0xB2, 0xBF])) + rom.write_bytes(0x05F7D0, bytearray([0xDD, 0xB8, 0x01, 0x05, 0x18, 0x99, 0xE1, 0xB2, 0x80, 0xB3, 0xE2, 0x20, 0xAD, 0xD2, 0x00, 0xC2])) + rom.write_bytes(0x05F7E0, bytearray([0x20, 0xD0, 0x0A, 0x64, 0x18, 0xAF, 0xB8, 0x03, 0x00, 0x5C, 0x80, 0xD1, 0x01, 0x5C, 0x02, 0xD2])) + rom.write_bytes(0x05F7F0, bytearray([0x01, 0xE2, 0x20, 0xAD, 0xD2, 0x00, 0xC2, 0x20, 0xD0, 0x08, 0x64, 0x18, 0xA0, 0x00, 0x5C, 0xE2])) + rom.write_bytes(0x05F800, bytearray([0xD0, 0x01, 0x5C, 0x02, 0xD2, 0x01, 0xAD, 0xD2, 0x00, 0x29, 0xFF, 0x00, 0xD0, 0x08, 0xBF, 0x35])) + rom.write_bytes(0x05F810, bytearray([0xB8, 0x01, 0x5C, 0xB8, 0xCF, 0x01, 0xBF, 0xE1, 0xD3, 0x22, 0x29, 0xFF, 0x00, 0xC9, 0x80, 0x00])) + rom.write_bytes(0x05F820, bytearray([0xF0, 0x2E, 0xC9, 0x81, 0x00, 0xF0, 0x47, 0x5C, 0xB8, 0xCF, 0x01, 0xAD, 0xD2, 0x00, 0x29, 0xFF])) + rom.write_bytes(0x05F830, bytearray([0x00, 0xD0, 0x08, 0xBF, 0x4A, 0xB8, 0x01, 0x5C, 0xD4, 0xCF, 0x01, 0xBF, 0xF6, 0xD3, 0x22, 0x29])) + rom.write_bytes(0x05F840, bytearray([0xFF, 0x00, 0x4C, 0xB6, 0xFD, 0xF0, 0x18, 0xC9, 0x81, 0x00, 0xF0, 0x30, 0x5C, 0xD4, 0xCF, 0x01])) + rom.write_bytes(0x05F850, bytearray([0xDA, 0xE2, 0x20, 0xAD, 0xB3, 0x14, 0xAA, 0xC2, 0x20, 0x20, 0x8A, 0xF8, 0xFA, 0x80, 0xC8, 0xDA])) + rom.write_bytes(0x05F860, bytearray([0xE2, 0x20, 0xAD, 0xB3, 0x14, 0xAA, 0xC2, 0x20, 0x20, 0xBD, 0xF8, 0xFA, 0x80, 0xDE, 0xDA, 0xE2])) + rom.write_bytes(0x05F870, bytearray([0x20, 0xAF, 0x85, 0xFC, 0x0D, 0xAA, 0x20, 0x8A, 0xF8, 0xFA, 0x80, 0xAB, 0xDA, 0xE2, 0x20, 0xAF])) + rom.write_bytes(0x05F880, bytearray([0x86, 0xFC, 0x0D, 0xAA, 0x20, 0xBD, 0xF8, 0xFA, 0x80, 0xC2, 0xE2, 0x20, 0xC9, 0x0A, 0xB0, 0x1F])) + rom.write_bytes(0x05F890, bytearray([0xAD, 0xD5, 0x00, 0xD0, 0x0D, 0xBF, 0x0B, 0xD4, 0x22, 0xC2, 0x20, 0xA9, 0x50, 0x00, 0xEE, 0xD5])) + rom.write_bytes(0x05F8A0, bytearray([0x00, 0x60, 0xBF, 0x0B, 0xD4, 0x22, 0x9C, 0xD4, 0x00, 0x9C, 0xD5, 0x00, 0xC2, 0x20, 0x60, 0xAD])) + rom.write_bytes(0x05F8B0, bytearray([0xD4, 0x00, 0xD0, 0xEE, 0xEE, 0xD4, 0x00, 0xC2, 0x20, 0xA9, 0x52, 0x00, 0x60, 0xE2, 0x20, 0xC9])) + rom.write_bytes(0x05F8C0, bytearray([0x0A, 0xB0, 0x1F, 0xAD, 0xD6, 0x00, 0xD0, 0x0D, 0xBF, 0x0B, 0xD4, 0x22, 0xC2, 0x20, 0xA9, 0x50])) + rom.write_bytes(0x05F8D0, bytearray([0x00, 0xEE, 0xD6, 0x00, 0x60, 0xBF, 0x0B, 0xD4, 0x22, 0x9C, 0xD7, 0x00, 0x9C, 0xD6, 0x00, 0xC2])) + rom.write_bytes(0x05F8E0, bytearray([0x20, 0x60, 0xAD, 0xD7, 0x00, 0xD0, 0xEE, 0xEE, 0xD7, 0x00, 0xC2, 0x20, 0xA9, 0x52, 0x00, 0x60])) + rom.write_bytes(0x05F8F0, bytearray([0xAD, 0xD2, 0x00, 0x29, 0xFF, 0x00, 0xF0, 0x04, 0x5C, 0x74, 0xD2, 0x01, 0x64, 0x18, 0xA0, 0x00])) + rom.write_bytes(0x05F900, bytearray([0x5C, 0x07, 0xD2, 0x01, 0xAD, 0xD2, 0x00, 0x29, 0xFF, 0x00, 0xF0, 0x04, 0x5C, 0x74, 0xD2, 0x01])) + rom.write_bytes(0x05F910, bytearray([0xAF, 0x7C, 0x02, 0x00, 0x5C, 0x7B, 0xD2, 0x01, 0xA5, 0x38, 0x89, 0x20, 0xD0, 0x0A, 0x29, 0x10])) + rom.write_bytes(0x05F920, bytearray([0xF0, 0x02, 0xA9, 0x01, 0x5C, 0x08, 0xC1, 0x01, 0xEE, 0xD2, 0x00, 0x64, 0x38, 0x5C, 0x08, 0xC1])) + rom.write_bytes(0x05F930, bytearray([0x01, 0xAD, 0xD2, 0x00, 0xD0, 0x08, 0xA5, 0x38, 0x29, 0x20, 0x5C, 0x3B, 0xC1, 0x01, 0xA9, 0x00])) + rom.write_bytes(0x05F940, bytearray([0x80, 0xF8, 0xAD, 0x10, 0x0B, 0x49, 0x01, 0x9C, 0xD2, 0x00, 0x5C, 0x4D, 0xCE, 0x01, 0x9C, 0x01])) + rom.write_bytes(0x05F950, bytearray([0x02, 0xAD, 0x5E, 0x02, 0xF0, 0x16, 0xAD, 0xB0, 0x14, 0x89, 0x08, 0xD0, 0x15, 0xAD, 0xB3, 0x14])) + rom.write_bytes(0x05F960, bytearray([0xCF, 0x85, 0xFC, 0x0D, 0x90, 0x06, 0xA9, 0x80, 0x8F, 0x65, 0x02, 0x7E, 0xC2, 0x20, 0x5C, 0xBB])) + rom.write_bytes(0x05F970, bytearray([0xA5, 0x17, 0xA9, 0x01, 0x80, 0xF2, 0xE2, 0x20, 0xAF, 0x87, 0xFC, 0x0D, 0xC2, 0x20, 0xF0, 0x0D])) + rom.write_bytes(0x05F980, bytearray([0x4C, 0xBF, 0xFA, 0x8D, 0x1C, 0x0C, 0x8D, 0x1E, 0x0C, 0x5C, 0x4E, 0xD8, 0x03, 0xB9, 0x04, 0x0C])) + rom.write_bytes(0x05F990, bytearray([0x80, 0xF1, 0xE2, 0x20, 0xA9, 0x01, 0x8D, 0xD8, 0x00, 0xC2, 0x20, 0x22, 0xBE, 0xAE, 0x03, 0x5C])) + rom.write_bytes(0x05F9A0, bytearray([0xA2, 0xA0, 0x02, 0xE2, 0x20, 0xAD, 0xD8, 0x00, 0xD0, 0x0F, 0xC2, 0x20, 0xA9, 0x02, 0x00, 0x9D])) + rom.write_bytes(0x05F9B0, bytearray([0x96, 0x7A, 0xFE, 0x78, 0x79, 0x5C, 0xAF, 0xA3, 0x02, 0xAD, 0xB3, 0x14, 0xCF, 0x86, 0xFC, 0x0D])) + rom.write_bytes(0x05F9C0, bytearray([0xC2, 0x20, 0xB0, 0xE8, 0xC2, 0x20, 0x5C, 0x81, 0xA3, 0x02, 0xE2, 0x20, 0xDA, 0xAE, 0x1A, 0x02])) + rom.write_bytes(0x05F9D0, bytearray([0xBD, 0x6D, 0x14, 0x89, 0x20, 0xF0, 0x0D, 0xFA, 0xC2, 0x20, 0xAD, 0x02, 0x74, 0xC9, 0x32, 0x00])) + rom.write_bytes(0x05F9E0, bytearray([0x5C, 0x80, 0xDF, 0x02, 0x18, 0x69, 0x20, 0x9D, 0x6D, 0x14, 0xAD, 0xB3, 0x14, 0x1A, 0x8D, 0xB3])) + rom.write_bytes(0x05F9F0, bytearray([0x14, 0x80, 0xE4, 0xE2, 0x20, 0xDA, 0xAE, 0x1A, 0x02, 0xBD, 0x6D, 0x14, 0x8D, 0xD1, 0x00, 0xA9])) + rom.write_bytes(0x05FA00, bytearray([0x10, 0x0C, 0xD1, 0x00, 0xAD, 0xD1, 0x00, 0x9D, 0x6D, 0x14, 0xFA, 0xC2, 0x20, 0xA9, 0x36, 0x00])) + rom.write_bytes(0x05FA10, bytearray([0x22, 0xD2, 0x85, 0x00, 0x5C, 0xEB, 0xC9, 0x11, 0xB9, 0xE4, 0xB9, 0xC0, 0x00, 0xF0, 0x03, 0xEE])) + rom.write_bytes(0x05FA20, bytearray([0xD9, 0x00, 0x5C, 0xBB, 0xB9, 0x10, 0xA9, 0x06, 0x85, 0x4D, 0xEE, 0xD9, 0x00, 0x5C, 0x19, 0xB0])) + rom.write_bytes(0x05FA30, bytearray([0x10, 0xA9, 0x05, 0x00, 0x85, 0x4D, 0xEE, 0xD9, 0x00, 0x5C, 0x9A, 0xD0, 0x10, 0xA9, 0x06, 0x85])) + rom.write_bytes(0x05FA40, bytearray([0x4D, 0xEE, 0xD9, 0x00, 0x5C, 0xC9, 0xD2, 0x10, 0xA9, 0x05, 0x85, 0x4D, 0xEE, 0xD9, 0x00, 0x5C])) + rom.write_bytes(0x05FA50, bytearray([0xEE, 0xC5, 0x10, 0xA9, 0x05, 0x00, 0x85, 0x4D, 0xEE, 0xD9, 0x00, 0x5C, 0x0F, 0xBE, 0x10, 0xDA])) + rom.write_bytes(0x05FA60, bytearray([0xE2, 0x20, 0xAD, 0xD9, 0x00, 0xF0, 0x26, 0xA2, 0x00, 0xAD, 0x1A, 0x02, 0xDF, 0x18, 0xD4, 0x22])) + rom.write_bytes(0x05FA70, bytearray([0xF0, 0x07, 0xE8, 0xE0, 0x06, 0xF0, 0x16, 0x80, 0xF3, 0xAE, 0x1A, 0x02, 0xBD, 0x6D, 0x14, 0x8D])) + rom.write_bytes(0x05FA80, bytearray([0xD1, 0x00, 0xA9, 0x10, 0x0C, 0xD1, 0x00, 0xAD, 0xD1, 0x00, 0x9D, 0x6D, 0x14, 0xFA, 0x22, 0x67])) + rom.write_bytes(0x05FA90, bytearray([0xFA, 0x04, 0x5C, 0x5A, 0xA1, 0x10])) + + rom.write_bytes(0x05FAB2, bytearray([0xA9, 0x00, 0xEB, 0xAD, 0x0E, 0x03, 0xC2, 0x20, 0xC2, 0x10, 0x4C, 0x37, 0xF6])) + rom.write_bytes(0x05FABF, bytearray([0xE2])) + rom.write_bytes(0x05FAC0, bytearray([0x20, 0xAD, 0x1A, 0x02, 0xDA, 0xA2, 0x00, 0x00, 0xDF, 0x1E, 0xD4, 0x22, 0xF0, 0x11, 0xE8, 0xE0])) + rom.write_bytes(0x05FAD0, bytearray([0x01, 0x00, 0xF0, 0x02, 0x80, 0xF2, 0xFA, 0xC2, 0x20, 0xA9, 0x00, 0x00, 0x4C, 0x83, 0xF9, 0xFA])) + rom.write_bytes(0x05FAE0, bytearray([0xC2, 0x20, 0x4C, 0x8D, 0xF9])) + rom.write_bytes(0x05FAE5, bytearray([0x48, 0xE2, 0x20, 0xAD, 0x5D, 0x14, 0xC9, 0x01, 0xF0, 0x07])) + rom.write_bytes(0x05FAEF, bytearray([0xC2, 0x20, 0x68, 0x5C, 0xCE, 0xBE, 0x03, 0xAD, 0xCC, 0x00, 0xD0, 0xF4, 0xAF, 0xFA, 0x1D, 0x70])) + rom.write_bytes(0x05FAFF, bytearray([0xF0, 0xEE, 0xA9, 0x00, 0x8F, 0xFA, 0x1D, 0x70, 0x80, 0xE6])) + rom.write_bytes(0x05FB09, bytearray([0x48, 0xE2, 0x20, 0xAD, 0xCC, 0x00, 0xF0, 0x06, 0xCE, 0xCC, 0x00, 0xCE, 0xCC, 0x00, 0xC2, 0x20, 0x68, 0x22, 0x87, 0xBF, 0x03, 0x5C, 0x89, 0xFE, 0x07])) + rom.write_bytes(0x05FB22, bytearray([0xA0, 0x0A, 0x8C, 0x4D, 0x00, 0xE2, 0x20, 0xA9, 0x08, 0x0C, 0xB0, 0x14, 0x8D, 0xB6, 0x14, 0xC2, 0x20, 0x5C, 0xB9, 0xF1, 0x0D, 0x0D, 0xA8, 0xE2])) + rom.write_bytes(0x05FB3A, bytearray([0x20, 0xA9, 0x08, 0x0C, 0xB0, 0x14, 0xA9, 0x00, 0xEB, 0xA9, 0x7F, 0xA2, 0x40, 0x14, 0x54, 0x70, 0x7E, 0xAB, 0x7A, 0xFA, 0x1A, 0xEE, 0x14, 0xC2, 0x20, 0x68, 0x5C, 0xB9, 0xF1, 0x0D])) + rom.write_bytes(0x05FB58, bytearray([0x4C, 0xDD, 0xFB, 0x04, 0xAF, 0xAC, 0x00, 0x70])) + rom.write_bytes(0x05FB60, bytearray([0xD0, 0x2C, 0xAD, 0x35, 0x00, 0xC9, 0x50, 0xD0, 0x25, 0xAD, 0xDA, 0x00, 0xC9, 0x80, 0xF0, 0x11])) + rom.write_bytes(0x05FB70, bytearray([0xC9, 0x00, 0xF0, 0x21, 0xC9, 0x2A, 0xF0, 0x1D, 0xC9, 0x54, 0xF0, 0x19, 0xEE, 0xDA, 0x00, 0x80])) + rom.write_bytes(0x05FB80, bytearray([0x10, 0xA9, 0x2F, 0x8D, 0x53, 0x00, 0xA9, 0x11, 0x8D, 0x18, 0x01, 0xEE, 0xDB, 0x00, 0x9C, 0xDA])) + rom.write_bytes(0x05FB90, bytearray([0x00, 0x5C, 0x93, 0xC1, 0x01, 0xA9, 0x28, 0x8D, 0x53, 0x00, 0x80, 0xE0])) + rom.write_bytes(0x05FB9C, bytearray([0xA9, 0x93, 0x00, 0xEE])) + rom.write_bytes(0x05FBA0, bytearray([0xB4, 0x03, 0xAC, 0xB4, 0x03, 0xC0, 0x14, 0x00, 0x90, 0x14, 0xE2, 0x20, 0xDA, 0xAE, 0x1A, 0x02])) + rom.write_bytes(0x05FBB0, bytearray([0xBD, 0x6D, 0x14, 0x09, 0x01, 0x9D, 0x6D, 0x14, 0xFA, 0xC2, 0x20, 0xA9, 0x94, 0x00, 0x5C, 0xF1, 0xDF, 0x00])) + rom.write_bytes(0x05FBC2, bytearray([0x48, 0xC9, 0x06, 0x00, 0xB0, 0x10, 0xE2, 0x20, 0xAD, 0x54, 0x14, 0xC9, 0x00, 0xC2, 0x20, 0xF0])) + rom.write_bytes(0x05FBD2, bytearray([0x05, 0x68, 0x5C, 0xAC, 0x82, 0x07, 0x68, 0x5C, 0xFB, 0x81, 0x07, 0xAD, 0x6A, 0x02, 0xF0, 0x11])) + rom.write_bytes(0x05FBE2, bytearray([0xC2, 0x20, 0xA9, 0x0E, 0x00, 0x22, 0xE2, 0xF6, 0x04, 0xA9, 0x00, 0x00, 0x8D, 0x6A, 0x02, 0xE2])) + rom.write_bytes(0x05FBF2, bytearray([0x20, 0x22, 0x28, 0xFD, 0x04, 0x4C, 0x5C, 0xFB, 0xAF, 0xB0, 0x23, 0x7E, 0xF0, 0x18, 0xAF, 0xAC])) + rom.write_bytes(0x05FC02, bytearray([0x00, 0x70, 0x29, 0xFF, 0x00, 0xD0, 0x0F, 0xAF, 0xB0, 0x23, 0x7E, 0x8F, 0xEC, 0x61, 0x04, 0xA9])) + rom.write_bytes(0x05FC12, bytearray([0x00, 0x00, 0x8F, 0xB0, 0x23, 0x7E, 0xBD, 0xD0, 0x61, 0xF0, 0x03, 0xDE, 0xD0, 0x61, 0x5C, 0x79])) + rom.write_bytes(0x05FC22, bytearray([0xDE, 0x04, 0x48, 0xC2, 0x20, 0xAF, 0xEC, 0x61, 0x04, 0xD0, 0x0B, 0xE2, 0x20, 0x68, 0x22, 0xCE])) + rom.write_bytes(0x05FC32, bytearray([0xC0, 0x01, 0x5C, 0x8B, 0xB5, 0x01, 0x8F, 0xB0, 0x23, 0x7E, 0xA9, 0x00, 0x00, 0x8F, 0xEC, 0x61])) + rom.write_bytes(0x05FC42, bytearray([0x04, 0x80, 0xE8, 0x48, 0xDA, 0xE2, 0x20, 0x4C, 0xA5, 0xFC, 0xA2, 0x00, 0xDF, 0x1F, 0xD4, 0x22])) + rom.write_bytes(0x05FC52, bytearray([0xF0, 0x03, 0xE8, 0x80, 0xF7, 0xBF, 0x8D, 0xFC, 0x0D, 0xAA, 0xBF, 0x2A, 0xD4, 0x22, 0x8D, 0xDC])) + rom.write_bytes(0x05FC62, bytearray([0x00, 0xC2, 0x20, 0xFA, 0x68, 0x0D, 0xDC, 0x00, 0x95, 0x76, 0x5C, 0x29, 0xDB, 0x0C, 0xE2, 0x20])) + rom.write_bytes(0x05FC72, bytearray([0xAD, 0x48, 0x0B, 0xF0, 0x23, 0xAF, 0xBE, 0x03, 0x02, 0xC9, 0x02, 0xD0, 0x1B, 0xAD, 0x1A, 0x02])) + rom.write_bytes(0x05FC82, bytearray([0xA2, 0x00, 0xDF, 0x1F, 0xD4, 0x22, 0xF0, 0x03, 0xE8, 0x80, 0xF7, 0x8A, 0x0A, 0xAA, 0xC2, 0x20])) + rom.write_bytes(0x05FC92, bytearray([0xBF, 0x35, 0xD4, 0x22, 0x8F, 0xBE, 0x03, 0x02, 0xC2, 0x20, 0xEE, 0xAC, 0x03, 0xC2, 0x10, 0x5C])) + rom.write_bytes(0x05FCA2, bytearray([0x0C, 0x95, 0x02, 0xAD, 0x1A, 0x02, 0xC9, 0x43, 0xF0, 0x03, 0x4C, 0x4C, 0xFC, 0xA9, 0x0A, 0x4C])) + rom.write_bytes(0x05FCB2, bytearray([0x60, 0xFC, 0xAC, 0xB4, 0x03, 0xC0, 0x14, 0x30, 0x14, 0x1A, 0xE2, 0x20, 0xDA, 0x48, 0xAE, 0x1A])) + rom.write_bytes(0x05FCC2, bytearray([0x02, 0xBD, 0x6D, 0x14, 0x09, 0x01, 0x9D, 0x6D, 0x14, 0x68, 0xFA, 0xC2, 0x20, 0x22, 0xD2, 0x85])) + rom.write_bytes(0x05FCD2, bytearray([0x00, 0x5C, 0xA4, 0x9E, 0x03, 0xE2, 0x20, 0xAD, 0xF6, 0x7D, 0xC9, 0x0C, 0xB0, 0x1A, 0xAD, 0xCC])) + rom.write_bytes(0x05FCE2, bytearray([0x00, 0xAD, 0x5E, 0x14, 0x38, 0xED, 0xCC, 0x00, 0x3A, 0x3A, 0x8D, 0xDE, 0x00, 0xAD, 0xF6, 0x7D])) + rom.write_bytes(0x05FCF2, bytearray([0x38, 0xED, 0xCC, 0x00, 0x18, 0xCD, 0xDE, 0x00, 0xC2, 0x20, 0x5C, 0xBC, 0x9A, 0x02, 0xE2, 0x20])) + rom.write_bytes(0x05FD02, bytearray([0xAD, 0x5D, 0x14, 0xF0, 0x33, 0xAA, 0xBF, 0xA3, 0xAF, 0x09, 0x18, 0x6D, 0xCC, 0x00, 0x8D, 0x5E])) + rom.write_bytes(0x05FD12, bytearray([0x14, 0xAD, 0xF6, 0x7D, 0xC9, 0x0C, 0xB0, 0x1A, 0xAD, 0xCC, 0x00, 0xAD, 0x5E, 0x14, 0x38, 0xED])) + rom.write_bytes(0x05FD22, bytearray([0xCC, 0x00, 0x3A, 0x3A, 0x8D, 0xDE, 0x00, 0xAD, 0xF6, 0x7D, 0x38, 0xED, 0xCC, 0x00, 0x18, 0xCD])) + rom.write_bytes(0x05FD32, bytearray([0xDE, 0x00, 0xC2, 0x20, 0x5C, 0xAC, 0xDC, 0x01, 0x1A, 0x8D, 0x5D, 0x14, 0x80, 0xC0, 0xA9, 0x00])) + rom.write_bytes(0x05FD42, bytearray([0x8F, 0xE8, 0x1F, 0x70, 0xAD, 0xAC, 0x60, 0xC9, 0x00, 0xD0, 0x06, 0xA9, 0x01, 0x8F, 0xE8, 0x1F])) + rom.write_bytes(0x05FD52, bytearray([0x70, 0x4C, 0x5F, 0xF5, 0xDA, 0xAD, 0x1A, 0x02, 0x8D, 0x7C, 0x02, 0xAD, 0x12, 0x11, 0xC9, 0x08])) + rom.write_bytes(0x05FD62, bytearray([0xB0, 0x1D, 0xAD, 0x18, 0x02, 0x4A, 0xAA, 0xA9, 0x00, 0xE0, 0x00, 0xF0, 0x06, 0x18, 0x69, 0x08])) + rom.write_bytes(0x05FD72, bytearray([0xCA, 0x80, 0xF6, 0x18, 0x6D, 0x12, 0x11, 0xAA, 0xBF, 0x4B, 0xD4, 0x22, 0x8D, 0x1A, 0x02, 0xFA])) + rom.write_bytes(0x05FD82, bytearray([0xA9, 0x02, 0x8D, 0x13, 0x11, 0x5C, 0x70, 0xE0, 0x17, 0xAC, 0x7C, 0x02, 0x8C, 0x1A, 0x02, 0xB9])) + rom.write_bytes(0x05FD92, bytearray([0x22, 0x02, 0x5C, 0xA7, 0x82, 0x10, 0xAD, 0x7C, 0x02, 0x8D, 0x1A, 0x02, 0xC2, 0x20, 0xE2, 0x10])) + rom.write_bytes(0x05FDA2, bytearray([0x5C, 0xBC, 0xB2, 0x01, 0xC9, 0x45, 0xB0, 0x03, 0x8D, 0x7C, 0x02, 0x8D, 0x1A, 0x02, 0x29, 0x07])) + rom.write_bytes(0x05FDB2, bytearray([0x5C, 0x3A, 0x81, 0x10, 0xC9, 0x82, 0x00, 0xF0, 0x2E, 0xC9, 0x83, 0x00, 0xF0, 0x40, 0xC9, 0x84])) + rom.write_bytes(0x05FDC2, bytearray([0x00, 0xF0, 0x0B, 0xC9, 0x85, 0x00, 0xF0, 0x0E, 0xC9, 0x80, 0x00, 0x4C, 0x45, 0xF8, 0xE2, 0x20])) + rom.write_bytes(0x05FDD2, bytearray([0xAF, 0x99, 0xFC, 0x0D, 0x80, 0x16, 0xDA, 0xE2, 0x20, 0xAD, 0xE3, 0x00, 0xD0, 0x4E, 0x9C, 0xE1])) + rom.write_bytes(0x05FDE2, bytearray([0x00, 0xAF, 0x99, 0xFC, 0x0D, 0x80, 0x25, 0xE2, 0x20, 0xAD, 0xB5, 0x14, 0xC9, 0x64, 0xC2, 0x20])) + rom.write_bytes(0x05FDF2, bytearray([0xB0, 0x06, 0xA9, 0x4E, 0x00, 0x4C, 0x4C, 0xF8, 0xA9, 0x52, 0x00, 0x4C, 0x4C, 0xF8, 0xDA, 0xE2])) + rom.write_bytes(0x05FE02, bytearray([0x20, 0xAD, 0xE3, 0x00, 0xD0, 0x26, 0x9C, 0xE1, 0x00, 0xAD, 0xB5, 0x14, 0xC9, 0x0A, 0x90, 0x08])) + rom.write_bytes(0x05FE12, bytearray([0x38, 0xE9, 0x0A, 0xEE, 0xE1, 0x00, 0x80, 0xF4, 0x8D, 0xE2, 0x00, 0xEE, 0xE3, 0x00, 0xAD, 0xE1])) + rom.write_bytes(0x05FE22, bytearray([0x00, 0xAA, 0xBF, 0x0B, 0xD4, 0x22, 0xC2, 0x20, 0xFA, 0x4C, 0x46, 0xF8, 0x9C, 0xE3, 0x00, 0xAD])) + rom.write_bytes(0x05FE32, bytearray([0xE2, 0x00, 0xAA, 0xBF, 0x0B, 0xD4, 0x22, 0xC2, 0x20, 0xFA, 0x4C, 0x4C, 0xF8, 0x22, 0xB7, 0xB2])) + rom.write_bytes(0x05FE42, bytearray([0x01, 0xEA, 0xEA, 0xEA, 0xAE, 0x7C, 0x02, 0x8E, 0x1A, 0x02, 0xEA, 0xEA, 0xEA, 0xEA, 0x5C, 0xAC])) + rom.write_bytes(0x05FE52, bytearray([0xBE, 0x01, 0xE2, 0x20, 0xAD, 0x1A, 0x02, 0xc9, 0x3C, 0xC2, 0x20, 0xB0, 0x04, 0xA9, 0x02, 0x00])) + rom.write_bytes(0x05FE62, bytearray([0x6B, 0xA9, 0x00, 0x00, 0x6B, 0xAD, 0x18, 0x01, 0xC9, 0x19, 0xD0, 0x3A, 0xC2, 0x20, 0x48, 0xA9])) + rom.write_bytes(0x05FE72, bytearray([0x00, 0x00, 0xE2, 0x20, 0xAF, 0x9A, 0xFC, 0x0D, 0xD0, 0x05, 0xA9, 0x08, 0x0C, 0xB0, 0x14, 0xC2])) + rom.write_bytes(0x05FE82, bytearray([0x10, 0xDA, 0x5A, 0x8B, 0xAD, 0x0E, 0x03, 0xC2, 0x20, 0xAA, 0xBF, 0x07, 0xFF, 0x06, 0xA8, 0xE2])) + rom.write_bytes(0x05FE92, bytearray([0x20, 0xA9, 0x00, 0xEB, 0xA9, 0x7F, 0xA2, 0x40, 0x14, 0x54, 0x70, 0x7E, 0xAB, 0x7A, 0xFA, 0xC2])) + rom.write_bytes(0x05FEA2, bytearray([0x20, 0x68, 0xE2, 0x20, 0xE2, 0x10, 0x22, 0x4B, 0x82, 0x00, 0x5C, 0xD9, 0x87, 0x17])) + + rom.write_bytes(0x00EDD0, bytearray([0xda, 0xa2, 0x00, 0x00, 0xe2, 0x20, 0xc9, 0x00, 0xf0, 0x0b, 0x48, 0x8a, 0x18, 0x69, 0x0c, 0xaa])) + rom.write_bytes(0x00EDE0, bytearray([0x68, 0x3a, 0x3a, 0x80, 0xf1, 0x98, 0x4a, 0x8f, 0x80, 0x24, 0x7e, 0x18, 0x8a, 0x6f, 0x80, 0x24])) + rom.write_bytes(0x00EDF0, bytearray([0x7e, 0xaa, 0xbf, 0x00, 0x80, 0x02, 0x0a, 0xaa, 0xc2, 0x20, 0xbf, 0x8e, 0xd4, 0x22, 0xfa, 0x18])) + rom.write_bytes(0x00EE00, bytearray([0x5c, 0xb6, 0xc0, 0x17, 0xda, 0xe2, 0x20, 0xa2, 0x00, 0x00, 0xdf, 0x4b, 0xd4, 0x22, 0xf0, 0x0e])) + rom.write_bytes(0x00EE10, bytearray([0xe8, 0xe0, 0x30, 0x00, 0xb0, 0x02, 0x80, 0xf2, 0xa9, 0x00, 0xeb, 0xad, 0x1a, 0x02, 0xaa, 0xbf])) + rom.write_bytes(0x00EE20, bytearray([0x00, 0x80, 0x02, 0xaa, 0xbf, 0x9e, 0xd4, 0x22, 0xc2, 0x20, 0x29, 0xff, 0x00, 0xfa, 0x5c, 0xfd])) + rom.write_bytes(0x00EE30, bytearray([0xc6, 0x17])) + + +def ExtendedItemHandler(rom: LocalRom) -> None: + rom.write_bytes(0x10B3FB, bytearray([0xE2, 0x20, 0xC9, 0x45, 0xB0])) + rom.write_bytes(0x10B400, bytearray([0x0C, 0xC2, 0x20, 0xA9, 0x10, 0x03, 0x8D, 0x7E, 0x02, 0x5C, 0xCF, 0xF4, 0x0B, 0xAD, 0x0F, 0x0B])) + rom.write_bytes(0x10B410, bytearray([0xD0, 0x38, 0xEE, 0xB5, 0x14, 0xA9, 0x18, 0x8D, 0x53, 0x00, 0xAF, 0x9A, 0xFC, 0x0D, 0xF0, 0x09])) + rom.write_bytes(0x10B420, bytearray([0xAD, 0xB5, 0x14, 0xCF, 0x99, 0xFC, 0x0D, 0xB0, 0x04, 0x5C, 0x0A, 0xF5, 0x0B, 0xAD, 0xB6, 0x14])) + rom.write_bytes(0x10B430, bytearray([0xD0, 0xF7, 0xA9, 0x01, 0x8D, 0xB6, 0x14, 0xA9, 0x0A, 0x8D, 0x18, 0x02, 0xA9, 0x16, 0x8D, 0x18])) + rom.write_bytes(0x10B440, bytearray([0x01, 0xA9, 0x97, 0x8D, 0x53, 0x00, 0x5C, 0x0A, 0xF5, 0x0B, 0xFA, 0x5C, 0x10, 0xF5, 0x0B])) + + +def patch_rom(world: "YoshisIslandWorld", rom: LocalRom, player: int) -> None: + handle_items(rom) # Implement main item functionality + Item_Data(rom) # Pointers necessary for item functionality + write_lives(rom) # Writes the number of lives as set in AP + CodeHandler(rom) # Jumps to my code + Server_Data(rom) # Pointers mostly related to receiving items + Menu_Data(rom) # Data related to the AP menu + Handle_Locations(rom) + ExtendedItemHandler(rom) + rom.write_bytes(0x11544B, bytearray(world.global_level_list)) + rom.write_bytes(0x11547A, bytearray([0x43])) + + rom.write_bytes(0x06FC89, world.starting_lives) + rom.write_bytes(0x03464F, ([world.baby_mario_sfx])) + rom.write_bytes(0x06FC83, ([world.options.starting_world.value])) + rom.write_bytes(0x06FC84, ([world.options.hidden_object_visibility.value])) + rom.write_bytes(0x06FC88, ([world.options.shuffle_midrings.value])) + rom.write_bytes(0x06FC85, ([world.options.castle_open_condition.value])) + rom.write_bytes(0x06FC86, ([world.options.castle_clear_condition.value])) + rom.write_bytes(0x06FC87, ([world.options.disable_autoscroll.value])) + rom.write_bytes(0x06FC8B, ([world.options.minigame_checks.value])) + rom.write_byte(0x06FC8C, world.options.death_link.value) + rom.write_bytes(0x06FC8D, bytearray(world.boss_room_id)) + rom.write_bytes(0x06FC99, bytearray([world.options.luigi_pieces_required.value])) + rom.write_bytes(0x06FC9A, bytearray([world.options.goal.value])) + + if world.options.yoshi_colors != YoshiColors.option_normal: + rom.write_bytes(0x113A33, bytearray(world.bowser_text)) + + rom.write_bytes(0x0A060C, bytearray(world.boss_burt_data)) + rom.write_bytes(0x0A8666, bytearray(world.boss_slime_data)) + rom.write_bytes(0x0A9D90, bytearray(world.boss_boo_data)) + rom.write_bytes(0x0074EA, bytearray(world.boss_pot_data)) + rom.write_bytes(0x08DC0A, bytearray(world.boss_frog_data)) + rom.write_bytes(0x0A4440, bytearray(world.boss_plant_data)) + rom.write_bytes(0x0968A2, bytearray(world.boss_milde_data)) + rom.write_bytes(0x0B3E10, bytearray(world.boss_koop_data)) + rom.write_bytes(0x0B4BD0, bytearray(world.boss_slug_data)) + rom.write_bytes(0x0B6BBA, bytearray(world.boss_raph_data)) + rom.write_bytes(0x087BED, bytearray(world.boss_tap_data)) + + rom.write_bytes(0x07A00D, ([world.tap_tap_room])) + rom.write_bytes(0x079DF2, ([world.tap_tap_room])) + rom.write_bytes(0x079CCF, ([world.tap_tap_room])) + rom.write_bytes(0x079C4D, ([world.tap_tap_room])) + + rom.write_bytes(0x045A2E, bytearray(world.Stage11StageGFX)) + rom.write_bytes(0x045A31, bytearray(world.Stage12StageGFX)) + rom.write_bytes(0x045A34, bytearray(world.Stage13StageGFX)) + rom.write_bytes(0x045A37, bytearray(world.Stage14StageGFX)) + rom.write_bytes(0x045A3A, bytearray(world.Stage15StageGFX)) + rom.write_bytes(0x045A3D, bytearray(world.Stage16StageGFX)) + rom.write_bytes(0x045A40, bytearray(world.Stage17StageGFX)) + rom.write_bytes(0x045A43, bytearray(world.Stage18StageGFX)) + + rom.write_bytes(0x045A52, bytearray(world.Stage21StageGFX)) + rom.write_bytes(0x045A55, bytearray(world.Stage22StageGFX)) + rom.write_bytes(0x045A58, bytearray(world.Stage23StageGFX)) + rom.write_bytes(0x045A5B, bytearray(world.Stage24StageGFX)) + rom.write_bytes(0x045A5E, bytearray(world.Stage25StageGFX)) + rom.write_bytes(0x045A61, bytearray(world.Stage26StageGFX)) + rom.write_bytes(0x045A64, bytearray(world.Stage27StageGFX)) + rom.write_bytes(0x045A67, bytearray(world.Stage28StageGFX)) + + rom.write_bytes(0x045A76, bytearray(world.Stage31StageGFX)) + rom.write_bytes(0x045A79, bytearray(world.Stage32StageGFX)) + rom.write_bytes(0x045A7C, bytearray(world.Stage33StageGFX)) + rom.write_bytes(0x045A7F, bytearray(world.Stage34StageGFX)) + rom.write_bytes(0x045A82, bytearray(world.Stage35StageGFX)) + rom.write_bytes(0x045A85, bytearray(world.Stage36StageGFX)) + rom.write_bytes(0x045A88, bytearray(world.Stage37StageGFX)) + rom.write_bytes(0x045A8B, bytearray(world.Stage38StageGFX)) + + rom.write_bytes(0x045A9A, bytearray(world.Stage41StageGFX)) + rom.write_bytes(0x045A9D, bytearray(world.Stage42StageGFX)) + rom.write_bytes(0x045AA0, bytearray(world.Stage43StageGFX)) + rom.write_bytes(0x045AA3, bytearray(world.Stage44StageGFX)) + rom.write_bytes(0x045AA6, bytearray(world.Stage45StageGFX)) + rom.write_bytes(0x045AA9, bytearray(world.Stage46StageGFX)) + rom.write_bytes(0x045AAC, bytearray(world.Stage47StageGFX)) + rom.write_bytes(0x045AAF, bytearray(world.Stage48StageGFX)) + + rom.write_bytes(0x045ABE, bytearray(world.Stage51StageGFX)) + rom.write_bytes(0x045AC1, bytearray(world.Stage52StageGFX)) + rom.write_bytes(0x045AC4, bytearray(world.Stage53StageGFX)) + rom.write_bytes(0x045AC7, bytearray(world.Stage54StageGFX)) + rom.write_bytes(0x045ACA, bytearray(world.Stage55StageGFX)) + rom.write_bytes(0x045ACD, bytearray(world.Stage56StageGFX)) + rom.write_bytes(0x045AD0, bytearray(world.Stage57StageGFX)) + rom.write_bytes(0x045AD3, bytearray(world.Stage58StageGFX)) + + rom.write_bytes(0x045AE2, bytearray(world.Stage61StageGFX)) + rom.write_bytes(0x045AE5, bytearray(world.Stage62StageGFX)) + rom.write_bytes(0x045AE8, bytearray(world.Stage63StageGFX)) + rom.write_bytes(0x045AEB, bytearray(world.Stage64StageGFX)) + rom.write_bytes(0x045AEE, bytearray(world.Stage65StageGFX)) + rom.write_bytes(0x045AF1, bytearray(world.Stage66StageGFX)) + rom.write_bytes(0x045AF4, bytearray(world.Stage67StageGFX)) + + rom.write_bytes(0x0BDBAF, bytearray(world.level_gfx_table)) + rom.write_bytes(0x0BDC4F, bytearray(world.palette_panel_list)) + + if world.options.yoshi_colors == YoshiColors.option_random_order: + rom.write_bytes(0x010000, ([world.leader_color])) + rom.write_bytes(0x010008, ([world.leader_color])) + rom.write_bytes(0x010009, ([world.leader_color])) + rom.write_bytes(0x010001, bytearray(world.color_order)) + rom.write_bytes(0x01000C, ([world.leader_color])) + rom.write_bytes(0x010014, ([world.leader_color])) + rom.write_bytes(0x010015, ([world.leader_color])) + rom.write_bytes(0x01000D, bytearray(world.color_order)) + rom.write_bytes(0x010018, ([world.leader_color])) + rom.write_bytes(0x010020, ([world.leader_color])) + rom.write_bytes(0x010021, ([world.leader_color])) + rom.write_bytes(0x01001A, bytearray(world.color_order)) + rom.write_bytes(0x010024, ([world.leader_color])) + rom.write_bytes(0x01002C, ([world.leader_color])) + rom.write_bytes(0x01002D, ([world.leader_color])) + rom.write_bytes(0x010025, bytearray(world.color_order)) + rom.write_bytes(0x010030, ([world.leader_color])) + rom.write_bytes(0x010038, ([world.leader_color])) + rom.write_bytes(0x010039, ([world.leader_color])) + rom.write_bytes(0x010031, bytearray(world.color_order)) + rom.write_bytes(0x01003C, ([world.leader_color])) + rom.write_bytes(0x010044, ([world.leader_color])) + rom.write_bytes(0x010045, ([world.leader_color])) + rom.write_bytes(0x01003D, bytearray(world.color_order)) + rom.write_bytes(0x010043, ([world.leader_color])) + elif world.options.yoshi_colors in {YoshiColors.option_random_color, YoshiColors.option_singularity}: + rom.write_bytes(0x010000, bytearray(world.level_colors)) + + if world.options.minigame_checks in {MinigameChecks.option_bonus_games, MinigameChecks.option_both}: + bonus_checks(rom) + + if world.options.minigame_checks in {MinigameChecks.option_bandit_games, MinigameChecks.option_both}: + bandit_checks(rom) + + rom.write_bytes(0x00BF2C, bytearray(world.world_bonus)) + + if world.options.softlock_prevention: + rom.write_bytes(0x00C18F, bytearray([0x5C, 0x58, 0xFB, 0x0B])) # R + X Code + + if world.options.bowser_door_mode != BowserDoor.option_manual: + rom.write_bytes(0x07891F, bytearray(world.castle_door)) # 1 Entry + rom.write_bytes(0x078923, bytearray(world.castle_door)) # 2 Entry + rom.write_bytes(0x078927, bytearray(world.castle_door)) # 3 Entry + rom.write_bytes(0x07892B, bytearray(world.castle_door)) # 4 Entry + + if world.options.bowser_door_mode == BowserDoor.option_gauntlet: + rom.write_bytes(0x0AF517, bytearray([0xC6, 0x07, 0x7A, 0x00])) # Door 2 + rom.write_bytes(0x0AF6B7, bytearray([0xCD, 0x05, 0x5B, 0x00])) # Door 3 + rom.write_bytes(0x0AF8F2, bytearray([0xD3, 0x00, 0x77, 0x06])) # Door 4 + + if world.options.goal == PlayerGoal.option_luigi_hunt: + rom.write_bytes(0x1153F6, bytearray([0x16, 0x28, 0x10, 0x0C, 0x10, 0x4E, 0x1E, 0x10, 0x08, 0x04, 0x08, 0x24, 0x36, 0x82, 0x83, 0x83, 0x34, 0x84, 0x85, 0x85])) # Luigi piece clear text + rom.write_bytes(0x06FC86, bytearray([0xFF])) # Boss clear goal = 255, renders bowser inaccessible + + from Main import __version__ + rom.name = bytearray(f'YOSHIAP{__version__.replace(".", "")[0:3]}_{player}_{world.multiworld.seed:11}\0', "utf8")[:21] + rom.name.extend([0] * (21 - len(rom.name))) + rom.write_bytes(0x007FC0, rom.name) + + +class YoshisIslandDeltaPatch(APDeltaPatch): + hash = USHASH + game: str = "Yoshi's Island" + patch_file_ending = ".apyi" + + @classmethod + def get_source_data(cls) -> bytes: + return get_base_rom_bytes() + + +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: + file_name = get_base_rom_path(file_name) + base_rom_bytes = bytes(Utils.read_snes_rom(open(file_name, "rb"))) + + basemd5 = hashlib.md5() + basemd5.update(base_rom_bytes) + if USHASH != basemd5.hexdigest(): + raise Exception("Supplied Base Rom does not match known MD5 for US(1.0) release. " + "Get the correct game and version, then dump it") + get_base_rom_bytes.base_rom_bytes = base_rom_bytes + return base_rom_bytes + + +def get_base_rom_path(file_name: str = "") -> str: + if not file_name: + file_name = get_settings()["yoshisisland_options"]["rom_file"] + if not os.path.exists(file_name): + file_name = Utils.user_path(file_name) + return file_name diff --git a/worlds/yoshisisland/Rules.py b/worlds/yoshisisland/Rules.py new file mode 100644 index 000000000000..09f6eaced07c --- /dev/null +++ b/worlds/yoshisisland/Rules.py @@ -0,0 +1,612 @@ +from .level_logic import YoshiLogic +from worlds.generic.Rules import set_rule +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from . import YoshisIslandWorld + + +def set_easy_rules(world: "YoshisIslandWorld") -> None: + logic = YoshiLogic(world) + player = world.player + + set_rule(world.multiworld.get_location("Make Eggs, Throw Eggs: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Beanstalk"}, player)) + set_rule(world.multiworld.get_location("Make Eggs, Throw Eggs: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Beanstalk"}, player)) + set_rule(world.multiworld.get_location("Make Eggs, Throw Eggs: Stars", player), lambda state: state.has_all({"Tulip", "Beanstalk", "Dashed Stairs"}, player)) + set_rule(world.multiworld.get_location("Make Eggs, Throw Eggs: Level Clear", player), lambda state: state.has("Beanstalk", player)) + + set_rule(world.multiworld.get_location("Watch Out Below!: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Watch Out Below!: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Watch Out Below!: Stars", player), lambda state: state.has("Large Spring Ball", player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Watch Out Below!: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("The Cave Of Chomp Rock: Red Coins", player), lambda state: state.has("Chomp Rock", player)) + set_rule(world.multiworld.get_location("The Cave Of Chomp Rock: Flowers", player), lambda state: state.has("Chomp Rock", player)) + + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Red Coins", player), lambda state: state.has("Spring Ball", player)) + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Flowers", player), lambda state: state.has_all({"Spring Ball", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Stars", player), lambda state: state.has("Spring Ball", player) and (logic.has_midring(state) or state.has("Key", player))) + + set_rule(world.multiworld.get_location("Hop! Hop! Donut Lifts: Stars", player), lambda state: logic.has_midring(state) or logic.cansee_clouds(state)) + + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "Flashing Eggs", "Mole Tank Morph", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Stars", player), lambda state: (logic.has_midring(state) and state.has("Tulip", player) or logic.has_midring(state) and state.has("Beanstalk", player)) and state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "Beanstalk"}, player)) + + set_rule(world.multiworld.get_location("Touch Fuzzy Get Dizzy: Red Coins", player), lambda state: state.has_all({"Flashing Eggs", "Spring Ball", "Chomp Rock", "Beanstalk"}, player)) + set_rule(world.multiworld.get_location("Touch Fuzzy Get Dizzy: Stars", player), lambda state: logic.has_midring(state) or (logic.cansee_clouds and state.has_all({"Spring Ball", "Chomp Rock", "Beanstalk"}, player))) + + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Red Coins", player), lambda state: state.has("Platform Ghost", player)) + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Flowers", player), lambda state: state.has("Platform Ghost", player)) + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Stars", player), lambda state: logic.has_midring(state) and (state.has("Platform Ghost", player) or state.has_all({"Arrow Wheel", "Key"}, player))) + + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Red Coins", player), lambda state: state.has_all({"Poochy", "Large Spring Ball", "Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Flowers", player), lambda state: state.has_all({"Super Star", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Stars", player), lambda state: state.has("Large Spring Ball", player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("The Baseball Boys: Red Coins", player), lambda state: state.has_all({"Beanstalk", "Super Star", "Egg Launcher", "Large Spring Ball", "Mole Tank Morph"}, player)) + set_rule(world.multiworld.get_location("The Baseball Boys: Flowers", player), lambda state: state.has_all({"Beanstalk", "Super Star", "Egg Launcher", "Large Spring Ball", "Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Baseball Boys: Stars", player), lambda state: (logic.has_midring(state) and (state.has("Tulip", player))) and state.has_all({"Beanstalk", "Super Star", "Large Spring Ball", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Baseball Boys: Level Clear", player), lambda state: state.has_all({"Beanstalk", "Super Star", "Egg Launcher", "Large Spring Ball"}, player)) + + set_rule(world.multiworld.get_location("What's Gusty Taste Like?: Red Coins", player), lambda state: state.has("! Switch", player)) + set_rule(world.multiworld.get_location("What's Gusty Taste Like?: Flowers", player), lambda state: state.has_any({"Large Spring Ball", "Super Star"}, player)) + set_rule(world.multiworld.get_location("What's Gusty Taste Like?: Level Clear", player), lambda state: state.has_any({"Large Spring Ball", "Super Star"}, player)) + + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Red Coins", player), lambda state: state.has_all({"! Switch", "Key", "Dashed Stairs"}, player)) + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Flowers", player), lambda state: state.has_all({"! Switch", "Key", "Dashed Stairs"}, player)) + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Stars", player), lambda state: state.has_all({"! Switch", "Key", "Dashed Stairs"}, player) and logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Watch Out For Lakitu: Red Coins", player), lambda state: state.has("Chomp Rock", player)) + set_rule(world.multiworld.get_location("Watch Out For Lakitu: Flowers", player), lambda state: state.has_all({"Key", "Train Morph", "Chomp Rock"}, player)) + set_rule(world.multiworld.get_location("Watch Out For Lakitu: Level Clear", player), lambda state: state.has("Chomp Rock", player)) + + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Stars", player), lambda state: state.has("Large Spring Ball", player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Lakitu's Wall: Red Coins", player), lambda state: (state.has_any({"Dashed Platform", "Giant Eggs"}, player) or logic.combat_item(state)) and state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Lakitu's Wall: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player) and (logic.combat_item(state) or state.has("Giant Eggs", player))) + set_rule(world.multiworld.get_location("Lakitu's Wall: Stars", player), lambda state: state.has("Giant Eggs", player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Lakitu's Wall: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "Car Morph"}, player)) + + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Red Coins", player), lambda state: state.has_all({"Arrow Wheel", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 1))) + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Flowers", player), lambda state: state.has_all({"Arrow Wheel", "Train Morph", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 1))) + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Stars", player), lambda state: state.has_all({"Arrow Wheel", "Key"}, player) and logic.has_midring(state) and (state.has("Egg Capacity Upgrade", player, 1))) + + set_rule(world.multiworld.get_location("Welcome To Monkey World!: Stars", player), lambda state: logic.has_midring(state)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Stars", player), lambda state: logic.has_midring(state) and state.has("Tulip", player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Level Clear", player), lambda state: state.has_all({"Dashed Stairs", "Spring Ball"}, player)) + + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Red Coins", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Flowers", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Stars", player), lambda state: logic.has_midring(state) or state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Level Clear", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Red Coins", player), lambda state: state.has("Submarine Morph", player)) + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Flowers", player), lambda state: (state.has("Egg Capacity Upgrade", player, 5) or logic.combat_item(state)) and (state.has("Dashed Platform", player))) + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Jammin' Through The Trees: Flowers", player), lambda state: state.has("Watermelon", player) or logic.melon_item(state)) + set_rule(world.multiworld.get_location("Jammin' Through The Trees: Stars", player), lambda state: ((logic.has_midring(state) or state.has("Tulip", player)) and logic.cansee_clouds(state)) or logic.has_midring(state) and state.has("Tulip", player)) + + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Red Coins", player), lambda state: state.has_all({"Chomp Rock", "Beanstalk", "Mole Tank Morph", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Flowers", player), lambda state: state.has_all({"Chomp Rock", "Beanstalk", "Mole Tank Morph", "Large Spring Ball", "! Switch"}, player)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Stars", player), lambda state: state.has_all({"Tulip", "Large Spring Ball", "Dashed Stairs", "Chomp Rock", "Beanstalk", "Mole Tank Morph"}, player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Level Clear", player), lambda state: state.has_all({"Chomp Rock", "Large Spring Ball", "Key"}, player)) + + set_rule(world.multiworld.get_location("Monkeys' Favorite Lake: Red Coins", player), lambda state: state.has_all({"! Switch", "Submarine Morph", "Large Spring Ball", "Beanstalk"}, player)) + set_rule(world.multiworld.get_location("Monkeys' Favorite Lake: Flowers", player), lambda state: state.has_all({"Beanstalk", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Monkeys' Favorite Lake: Stars", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Monkeys' Favorite Lake: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Naval Piranha's Castle: Red Coins", player), lambda state: (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Naval Piranha's Castle: Flowers", player), lambda state: (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Naval Piranha's Castle: Stars", player), lambda state: logic.has_midring(state) and state.has("Tulip", player)) + + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Red Coins", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Flowers", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Stars", player), lambda state: logic.has_midring(state) or (state.has("Tulip", player) and logic.cansee_clouds(state))) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Level Clear", player), lambda state: state.has("Super Star", player)) + + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "! Switch", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Stars", player), lambda state: state.has_all({"Large Spring Ball", "Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Don't Look Back!: Red Coins", player), lambda state: state.has_all({"Helicopter Morph", "! Switch", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Flowers", player), lambda state: state.has_all({"! Switch", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Stars", player), lambda state: (logic.has_midring(state) and state.has("Tulip", player)) and state.has("! Switch", player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Level Clear", player), lambda state: state.has("! Switch", player)) + + set_rule(world.multiworld.get_location("Marching Milde's Fort: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Marching Milde's Fort: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket"}, player) and (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Marching Milde's Fort: Stars", player), lambda state: state.has("Dashed Stairs", player) and (logic.has_midring(state) or state.has("Vanishing Arrow Wheel", player) or logic.cansee_clouds(state))) + + set_rule(world.multiworld.get_location("Chomp Rock Zone: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "Chomp Rock"}, player)) + set_rule(world.multiworld.get_location("Chomp Rock Zone: Flowers", player), lambda state: state.has_all({"Chomp Rock", "! Switch", "Spring Ball", "Dashed Platform"}, player)) + set_rule(world.multiworld.get_location("Chomp Rock Zone: Stars", player), lambda state: state.has_all({"Chomp Rock", "! Switch", "Spring Ball", "Dashed Platform"}, player)) + + set_rule(world.multiworld.get_location("Lake Shore Paradise: Red Coins", player), lambda state: state.has_any({"Large Spring Ball", "Spring Ball"}, player) and (state.has("Egg Plant", player) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Lake Shore Paradise: Flowers", player), lambda state: state.has_any({"Large Spring Ball", "Spring Ball"}, player) and (state.has("Egg Plant", player) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Lake Shore Paradise: Stars", player), lambda state: (logic.has_midring(state) or (state.has("Tulip", player) and logic.cansee_clouds(state))) and (state.has("Egg Plant", player) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Lake Shore Paradise: Level Clear", player), lambda state: state.has("Egg Plant", player) or logic.combat_item(state)) + + set_rule(world.multiworld.get_location("Ride Like The Wind: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Stars", player), lambda state: (logic.has_midring(state) and state.has("Helicopter Morph", player)) and state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Key"}, player)) + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Key"}, player)) + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Stars", player), lambda state: logic.has_midring(state) and (state.has_any({"Dashed Stairs", "Vanishing Arrow Wheel"}, player))) + + set_rule(world.multiworld.get_location("BLIZZARD!!!: Red Coins", player), lambda state: state.has_all({"Helicopter Morph", "Dashed Stairs"}, player)) + set_rule(world.multiworld.get_location("BLIZZARD!!!: Stars", player), lambda state: logic.cansee_clouds(state) or ((logic.has_midring(state) and state.has("Dashed Stairs", player)) or state.has("Tulip", player))) + + set_rule(world.multiworld.get_location("Ride The Ski Lifts: Stars", player), lambda state: logic.has_midring(state) or state.has("Super Star", player)) + + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Red Coins", player), lambda state: (state.has("Fire Melon", player) or logic.melon_item(state)) and (state.has_all({"Bucket", "Spring Ball", "Super Star", "Skis", "Dashed Platform"}, player))) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Flowers", player), lambda state: (state.has("Fire Melon", player) or logic.melon_item(state)) and state.has_all({"Spring Ball", "Skis", "Dashed Platform"}, player)) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Stars", player), lambda state: (logic.has_midring(state) and (state.has("Fire Melon", player) or logic.melon_item(state))) and state.has("Spring Ball", player)) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Level Clear", player), lambda state: state.has_all({"Spring Ball", "Skis", "Dashed Platform"}, player)) + + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Dashed Platform", "Platform Ghost"}, player)) + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Platform Ghost", "Dashed Platform"}, player)) + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Stars", player), lambda state: ((state.has_all({"Dashed Stairs", "Platform Ghost"}, player)) and logic.has_midring(state)) or (logic.cansee_clouds(state) and state.has("Dashed Stairs", player) and state.has("Dashed Platform", player))) + + set_rule(world.multiworld.get_location("Goonie Rides!: Red Coins", player), lambda state: state.has_all({"Helicopter Morph", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Goonie Rides!: Flowers", player), lambda state: state.has_all({"Helicopter Morph", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Goonie Rides!: Stars", player), lambda state: logic.has_midring(state)) + set_rule(world.multiworld.get_location("Goonie Rides!: Level Clear", player), lambda state: state.has_all({"Helicopter Morph", "! Switch"}, player)) + + set_rule(world.multiworld.get_location("Welcome To Cloud World: Stars", player), lambda state: logic.has_midring(state) or state.has("Tulip", player)) + + set_rule(world.multiworld.get_location("Shifting Platforms Ahead: Red Coins", player), lambda state: state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state)) + set_rule(world.multiworld.get_location("Shifting Platforms Ahead: Flowers", player), lambda state: state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state)) + set_rule(world.multiworld.get_location("Shifting Platforms Ahead: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Red Coins", player), lambda state: state.has_all({"Arrow Wheel", "Train Morph"}, player)) + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Flowers", player), lambda state: state.has_all({"Arrow Wheel", "Train Morph"}, player)) + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Stars", player), lambda state: logic.has_midring(state) and state.has("Arrow Wheel", player)) + + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Red Coins", player), lambda state: state.has_all({"Dashed Platform", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Flowers", player), lambda state: state.has_all({"Dashed Platform", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Stars", player), lambda state: state.has("Dashed Platform", player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Level Clear", player), lambda state: state.has_all({"Dashed Platform", "Large Spring Ball"}, player)) + + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Red Coins", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Flowers", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Stars", player), lambda state: logic.cansee_clouds(state) or logic.has_midring(state)) + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Level Clear", player), lambda state: state.has("Super Star", player)) + + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Red Coins", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Egg Plant", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Flowers", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Egg Plant", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Stars", player), lambda state: logic.has_midring(state) and state.has_all({"Spring Ball", "Large Spring Ball", "Egg Plant", "Key"}, player)) + + set_rule(world.multiworld.get_location("The Very Loooooong Cave: Red Coins", player), lambda state: state.has("Chomp Rock", player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("The Very Loooooong Cave: Flowers", player), lambda state: state.has("Chomp Rock", player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("The Very Loooooong Cave: Stars", player), lambda state: state.has("Chomp Rock", player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state)) and logic.has_midring(state)) + + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Red Coins", player), lambda state: state.has_all({"Chomp Rock", "Key", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Flowers", player), lambda state: state.has_all({"Chomp Rock", "Key", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Stars", player), lambda state: state.has_all({"Chomp Rock", "Tulip", "Key"}, player) or (logic.has_midring(state) and state.has_all({"Key", "Chomp Rock", "Large Spring Ball"}, player))) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Level Clear", player), lambda state: state.has_all({"Chomp Rock", "Key", "Large Spring Ball", "Dashed Platform"}, player)) + + set_rule(world.multiworld.get_location("KEEP MOVING!!!!: Red Coins", player), lambda state: (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("KEEP MOVING!!!!: Flowers", player), lambda state: state.has("Egg Plant", player)) + set_rule(world.multiworld.get_location("KEEP MOVING!!!!: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("King Bowser's Castle: Red Coins", player), lambda state: state.has_all({"Helicopter Morph", "Egg Plant"}, player) and logic._68CollectibleRoute(state)) + set_rule(world.multiworld.get_location("King Bowser's Castle: Flowers", player), lambda state: state.has_all({"Helicopter Morph", "Egg Plant"}, player) and logic._68CollectibleRoute(state)) + set_rule(world.multiworld.get_location("King Bowser's Castle: Stars", player), lambda state: state.has_all({"Helicopter Morph", "Egg Plant"}, player) and logic._68Route(state)) + + set_easy_extra_rules(world) + + +def set_easy_extra_rules(world: "YoshisIslandWorld") -> None: + player = world.player + logic = YoshiLogic(world) + if not world.options.extras_enabled: + return + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Red Coins", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Flowers", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Stars", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Level Clear", player), lambda state: state.has("Poochy", player)) + + set_rule(world.multiworld.get_location("Hit That Switch!!: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Hit That Switch!!: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Hit That Switch!!: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + + set_rule(world.multiworld.get_location("The Impossible? Maze: Red Coins", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph", "Flashing Eggs"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Flowers", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Stars", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Level Clear", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Kamek's Revenge: Red Coins", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph", "! Switch"}, player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Flowers", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph", "! Switch"}, player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Stars", player), lambda state: state.has("! Switch", player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Level Clear", player), lambda state: state.has_all({"Key", "Skis", "! Switch", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Red Coins", player), lambda state: (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state)) and state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Flowers", player), lambda state: (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state)) and state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Stars", player), lambda state: logic.has_midring(state) and state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Level Clear", player), lambda state: (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state)) and state.has(("Large Spring Ball"), player)) + + +def set_normal_rules(world: "YoshisIslandWorld") -> None: + logic = YoshiLogic(world) + player = world.player + + set_rule(world.multiworld.get_location("Make Eggs, Throw Eggs: Red Coins", player), lambda state: state.has("Dashed Stairs", player)) + set_rule(world.multiworld.get_location("Make Eggs, Throw Eggs: Flowers", player), lambda state: state.has("Dashed Stairs", player)) + set_rule(world.multiworld.get_location("Make Eggs, Throw Eggs: Stars", player), lambda state: state.has_any({"Tulip", "Dashed Stairs"}, player)) + + set_rule(world.multiworld.get_location("Watch Out Below!: Red Coins", player), lambda state: state.has("Helicopter Morph", player)) + set_rule(world.multiworld.get_location("Watch Out Below!: Flowers", player), lambda state: state.has("Helicopter Morph", player)) + set_rule(world.multiworld.get_location("Watch Out Below!: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Red Coins", player), lambda state: state.has("Spring Ball", player)) + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Flowers", player), lambda state: state.has_all({"Spring Ball", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Stars", player), lambda state: state.has("Spring Ball", player)) + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Level Clear", player), lambda state: logic._14CanFightBoss(state)) + + + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "Flashing Eggs", "Mole Tank Morph", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Stars", player), lambda state: (logic.has_midring(state) and state.has_any(["Tulip", "Beanstalk"], player)) or (state.has_all(["Tulip", "Beanstalk", "Large Spring Ball"], player))) + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "Beanstalk"}, player)) + + set_rule(world.multiworld.get_location("Touch Fuzzy Get Dizzy: Red Coins", player), lambda state: state.has_all({"Flashing Eggs", "Spring Ball", "Chomp Rock", "Beanstalk"}, player)) + set_rule(world.multiworld.get_location("Touch Fuzzy Get Dizzy: Stars", player), lambda state: logic.has_midring(state) or (logic.cansee_clouds and state.has_all({"Spring Ball", "Chomp Rock", "Beanstalk"}, player))) + + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Red Coins", player), lambda state: state.has("Platform Ghost", player)) + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Flowers", player), lambda state: state.has("Platform Ghost", player)) + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Stars", player), lambda state: logic.has_midring(state) and (state.has("Platform Ghost", player) or state.has_all({"Arrow Wheel", "Key"}, player))) + + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Red Coins", player), lambda state: state.has_all({"Poochy", "Large Spring Ball", "Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Flowers", player), lambda state: state.has_all({"Super Star", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Stars", player), lambda state: state.has("Large Spring Ball", player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("The Baseball Boys: Red Coins", player), lambda state: state.has_all({"Beanstalk", "Super Star", "Large Spring Ball", "Mole Tank Morph"}, player)) + set_rule(world.multiworld.get_location("The Baseball Boys: Flowers", player), lambda state: state.has_all({"Super Star", "Large Spring Ball", "Beanstalk", "Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Baseball Boys: Stars", player), lambda state: (logic.has_midring(state) or (state.has("Tulip", player))) and state.has_all({"Beanstalk", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Baseball Boys: Level Clear", player), lambda state: state.has_all({"Beanstalk", "Super Star", "Large Spring Ball"}, player)) + + set_rule(world.multiworld.get_location("What's Gusty Taste Like?: Red Coins", player), lambda state: state.has("! Switch", player)) + + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Red Coins", player), lambda state: state.has_all({"! Switch", "Key", "Dashed Stairs"}, player)) + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Flowers", player), lambda state: state.has_all({"! Switch", "Key", "Dashed Stairs"}, player)) + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Stars", player), lambda state: state.has_all({"! Switch", "Dashed Stairs"}, player)) + + set_rule(world.multiworld.get_location("Watch Out For Lakitu: Flowers", player), lambda state: state.has_all({"Key", "Train Morph"}, player)) + + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Stars", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Lakitu's Wall: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player) and (logic.combat_item(state) or state.has("Giant Eggs", player))) + set_rule(world.multiworld.get_location("Lakitu's Wall: Stars", player), lambda state: state.has("Giant Eggs", player) or logic.has_midring(state)) + + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Red Coins", player), lambda state: state.has_all({"Arrow Wheel", "Key"}, player)) + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Flowers", player), lambda state: state.has_all({"Arrow Wheel", "Key", "Train Morph"}, player)) + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Stars", player), lambda state: state.has("Arrow Wheel", player) and (logic.has_midring(state) or state.has("Key", player))) + + set_rule(world.multiworld.get_location("Welcome To Monkey World!: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Jungle Rhythm...: Red Coins", player), lambda state: state.has("Dashed Stairs", player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Flowers", player), lambda state: state.has("Dashed Stairs", player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Stars", player), lambda state: logic.has_midring(state) and state.has("Tulip", player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Level Clear", player), lambda state: state.has("Dashed Stairs", player)) + + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Red Coins", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Flowers", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Level Clear", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Red Coins", player), lambda state: state.has("Submarine Morph", player)) + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Flowers", player), lambda state: (state.has("Egg Capacity Upgrade", player, 5) or logic.combat_item(state)) and (state.has("Dashed Platform", player) or logic.has_midring(state))) + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Jammin' Through The Trees: Flowers", player), lambda state: state.has("Watermelon", player) or logic.melon_item(state)) + + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Red Coins", player), lambda state: state.has_any({"Dashed Stairs", "Beanstalk"}, player) and state.has_all({"Mole Tank Morph", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Flowers", player), lambda state: state.has_any({"Dashed Stairs", "Beanstalk"}, player) and state.has_all({"! Switch", "Mole Tank Morph", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Stars", player), lambda state: (state.has_any({"Dashed Stairs", "Beanstalk"}, player) and state.has_all({"Mole Tank Morph", "Large Spring Ball"}, player)) and (logic.has_midring(state) or state.has("Tulip", player))) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "Key"}, player)) + + set_rule(world.multiworld.get_location("Monkeys' Favorite Lake: Red Coins", player), lambda state: state.has_all({"! Switch", "Submarine Morph", "Large Spring Ball", "Beanstalk"}, player)) + set_rule(world.multiworld.get_location("Monkeys' Favorite Lake: Flowers", player), lambda state: state.has("Beanstalk", player)) + + set_rule(world.multiworld.get_location("Naval Piranha's Castle: Red Coins", player), lambda state: (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Naval Piranha's Castle: Flowers", player), lambda state: (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Naval Piranha's Castle: Stars", player), lambda state: (logic.has_midring(state) and state.has("Tulip", player)) and state.has("Egg Capacity Upgrade", player, 1)) + + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Red Coins", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Flowers", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Stars", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Level Clear", player), lambda state: state.has("Super Star", player)) + + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "! Switch", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Stars", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Don't Look Back!: Red Coins", player), lambda state: state.has_all({"Helicopter Morph", "! Switch", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Stars", player), lambda state: (logic.has_midring(state) or state.has("Tulip", player)) and state.has("! Switch", player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Level Clear", player), lambda state: state.has("! Switch", player)) + + set_rule(world.multiworld.get_location("Marching Milde's Fort: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket", "Key"}, player)) + set_rule(world.multiworld.get_location("Marching Milde's Fort: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket"}, player)) + set_rule(world.multiworld.get_location("Marching Milde's Fort: Stars", player), lambda state: state.has("Dashed Stairs", player)) + + set_rule(world.multiworld.get_location("Chomp Rock Zone: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "Chomp Rock"}, player)) + set_rule(world.multiworld.get_location("Chomp Rock Zone: Flowers", player), lambda state: state.has_all({"Chomp Rock", "! Switch", "Dashed Platform"}, player)) + set_rule(world.multiworld.get_location("Chomp Rock Zone: Stars", player), lambda state: state.has_all({"Chomp Rock", "! Switch", "Dashed Platform"}, player)) + + set_rule(world.multiworld.get_location("Lake Shore Paradise: Red Coins", player), lambda state: state.has("Egg Plant", player) or logic.combat_item(state)) + set_rule(world.multiworld.get_location("Lake Shore Paradise: Flowers", player), lambda state: state.has("Egg Plant", player) or logic.combat_item(state)) + set_rule(world.multiworld.get_location("Lake Shore Paradise: Stars", player), lambda state: (logic.has_midring(state) or (state.has("Tulip", player) and logic.cansee_clouds(state))) and (state.has("Egg Plant", player) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Lake Shore Paradise: Level Clear", player), lambda state: state.has("Egg Plant", player) or logic.combat_item(state)) + + set_rule(world.multiworld.get_location("Ride Like The Wind: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Stars", player), lambda state: (logic.has_midring(state) or state.has("Helicopter Morph", player)) and state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Key"}, player)) + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Key"}, player)) + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Stars", player), lambda state: logic.has_midring(state) or (state.has_any({"Dashed Stairs", "Vanishing Arrow Wheel"}, player))) + + set_rule(world.multiworld.get_location("BLIZZARD!!!: Red Coins", player), lambda state: state.has_any({"Dashed Stairs", "Ice Melon"}, player) and (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state) or state.has("Helicopter Morph", player))) + + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Red Coins", player), lambda state: (state.has("Fire Melon", player) or logic.melon_item(state)) and (state.has_all({"Spring Ball", "Skis"}, player)) and (state.has("Super Star", player) or logic.melon_item(state))) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Flowers", player), lambda state: (state.has("Fire Melon", player) or logic.melon_item(state)) and state.has_all({"Spring Ball", "Skis"}, player)) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Stars", player), lambda state: (logic.has_midring(state) and (state.has("Fire Melon", player) or logic.melon_item(state))) or (logic.has_midring(state) and (state.has_all({"Tulip", "Dashed Platform"}, player)))) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Level Clear", player), lambda state: state.has_all({"Spring Ball", "Skis"}, player)) + + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Dashed Platform", "Platform Ghost"}, player)) + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Platform Ghost", "Dashed Platform"}, player)) + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Stars", player), lambda state: ((state.has_all({"Dashed Stairs", "Platform Ghost"}, player))) or (logic.cansee_clouds(state) and state.has("Dashed Stairs", player))) + + set_rule(world.multiworld.get_location("Goonie Rides!: Red Coins", player), lambda state: state.has("Helicopter Morph", player)) + set_rule(world.multiworld.get_location("Goonie Rides!: Flowers", player), lambda state: state.has_all({"Helicopter Morph", "! Switch"}, player)) + + set_rule(world.multiworld.get_location("Shifting Platforms Ahead: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Red Coins", player), lambda state: state.has_all({"Arrow Wheel", "Train Morph"}, player)) + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Flowers", player), lambda state: state.has_all({"Arrow Wheel", "Train Morph"}, player)) + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Stars", player), lambda state: logic.has_midring(state)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Red Coins", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Flowers", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Level Clear", player), lambda state: state.has("Super Star", player)) + + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "Egg Plant", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "Egg Plant", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Stars", player), lambda state: logic.has_midring(state) and state.has_all({"Spring Ball", "Egg Plant", "Key"}, player)) + + set_rule(world.multiworld.get_location("The Very Loooooong Cave: Red Coins", player), lambda state: state.has("Chomp Rock", player) and (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("The Very Loooooong Cave: Flowers", player), lambda state: state.has("Chomp Rock", player) and (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("The Very Loooooong Cave: Stars", player), lambda state: state.has("Chomp Rock", player) and (state.has("Egg Capacity Upgrade", player, 2) or logic.combat_item(state)) and logic.has_midring(state)) + + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Red Coins", player), lambda state: state.has_all({"Chomp Rock", "Key", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Flowers", player), lambda state: state.has_all({"Chomp Rock", "Key", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Stars", player), lambda state: state.has_all({"Chomp Rock", "Tulip", "Key"}, player) or (logic.has_midring(state) and state.has_all({"Key", "Chomp Rock", "Large Spring Ball"}, player))) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Level Clear", player), lambda state: state.has_all({"Key", "Large Spring Ball", "Dashed Platform"}, player) and (logic.combat_item(state) or state.has("Chomp Rock", player))) + + set_rule(world.multiworld.get_location("KEEP MOVING!!!!: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("King Bowser's Castle: Red Coins", player), lambda state: state.has_all({"Helicopter Morph", "Egg Plant"}, player) and logic._68CollectibleRoute(state)) + set_rule(world.multiworld.get_location("King Bowser's Castle: Flowers", player), lambda state: state.has_all({"Helicopter Morph", "Egg Plant"}, player) and logic._68CollectibleRoute(state)) + set_rule(world.multiworld.get_location("King Bowser's Castle: Stars", player), lambda state: state.has_all({"Helicopter Morph", "Egg Plant"}, player) and logic._68Route(state)) + + set_normal_extra_rules(world) + + +def set_normal_extra_rules(world: "YoshisIslandWorld") -> None: + player = world.player + logic = YoshiLogic(world) + if not world.options.extras_enabled: + return + + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Red Coins", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Flowers", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Stars", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Level Clear", player), lambda state: state.has("Poochy", player)) + + set_rule(world.multiworld.get_location("Hit That Switch!!: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Hit That Switch!!: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Hit That Switch!!: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + + set_rule(world.multiworld.get_location("The Impossible? Maze: Red Coins", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph", "Flashing Eggs"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Flowers", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Stars", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Level Clear", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Kamek's Revenge: Red Coins", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph", "! Switch"}, player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Flowers", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph", "! Switch"}, player) and logic.has_midring(state)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Stars", player), lambda state: state.has("! Switch", player) or logic.has_midring(state)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Level Clear", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Red Coins", player), lambda state: (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state)) and state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Flowers", player), lambda state: (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state)) and state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Stars", player), lambda state: logic.has_midring(state) or state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Level Clear", player), lambda state: (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state)) and state.has(("Large Spring Ball"), player)) + + +def set_hard_rules(world: "YoshisIslandWorld"): + logic = YoshiLogic(world) + player = world.player + + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Red Coins", player), lambda state: state.has("Spring Ball", player)) + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Flowers", player), lambda state: state.has_all({"Spring Ball", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 3) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Burt The Bashful's Fort: Stars", player), lambda state: state.has("Spring Ball", player)) + + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "Flashing Eggs", "Mole Tank Morph", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Shy-Guys On Stilts: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Touch Fuzzy Get Dizzy: Red Coins", player), lambda state: state.has_all({"Flashing Eggs", "Spring Ball", "Chomp Rock", "Beanstalk"}, player)) + + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Red Coins", player), lambda state: state.has("Platform Ghost", player)) + set_rule(world.multiworld.get_location("Salvo The Slime's Castle: Flowers", player), lambda state: state.has("Platform Ghost", player)) + + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Red Coins", player), lambda state: state.has("Large Spring Ball", player) and (state.has("Poochy", player) or logic.melon_item(state))) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Flowers", player), lambda state: state.has_all({"Super Star", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Stars", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Visit Koopa And Para-Koopa: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("The Baseball Boys: Red Coins", player), lambda state: state.has("Mole Tank Morph", player) and (state.has_any({"Ice Melon", "Large Spring Ball"}, player) or logic.melon_item(state))) + set_rule(world.multiworld.get_location("The Baseball Boys: Flowers", player), lambda state: (state.has_any({"Ice Melon", "Large Spring Ball"}, player) or logic.melon_item(state))) + set_rule(world.multiworld.get_location("The Baseball Boys: Level Clear", player), lambda state: (state.has_any({"Ice Melon", "Large Spring Ball"}, player) or logic.melon_item(state))) + + set_rule(world.multiworld.get_location("What's Gusty Taste Like?: Red Coins", player), lambda state: state.has("! Switch", player)) + + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Red Coins", player), lambda state: state.has_all({"! Switch", "Key"}, player)) + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Flowers", player), lambda state: state.has_all({"! Switch", "Key"}, player)) + set_rule(world.multiworld.get_location("Bigger Boo's Fort: Stars", player), lambda state: state.has("! Switch", player)) + + set_rule(world.multiworld.get_location("Watch Out For Lakitu: Flowers", player), lambda state: state.has_all({"Key", "Train Morph"}, player)) + + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("The Cave Of The Mystery Maze: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Lakitu's Wall: Flowers", player), lambda state: state.has("! Switch", player)) + set_rule(world.multiworld.get_location("Lakitu's Wall: Stars", player), lambda state: state.has("Giant Eggs", player) or logic.has_midring(state)) + + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Red Coins", player), lambda state: state.has_all({"Arrow Wheel", "Key"}, player)) + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Flowers", player), lambda state: state.has_all({"Arrow Wheel", "Key", "Train Morph"}, player)) + set_rule(world.multiworld.get_location("The Potted Ghost's Castle: Stars", player), lambda state: state.has("Arrow Wheel", player)) + + set_rule(world.multiworld.get_location("Welcome To Monkey World!: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Jungle Rhythm...: Red Coins", player), lambda state: state.has("Dashed Stairs", player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Flowers", player), lambda state: state.has("Dashed Stairs", player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Stars", player), lambda state: logic.has_midring(state) and state.has("Tulip", player)) + set_rule(world.multiworld.get_location("Jungle Rhythm...: Level Clear", player), lambda state: state.has("Dashed Stairs", player)) + + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Red Coins", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Flowers", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Nep-Enuts' Domain: Level Clear", player), lambda state: state.has_all({"Submarine Morph", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Red Coins", player), lambda state: state.has("Submarine Morph", player)) + set_rule(world.multiworld.get_location("Prince Froggy's Fort: Flowers", player), lambda state: (state.has("Egg Capacity Upgrade", player, 5) or logic.combat_item(state))) + + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Red Coins", player), lambda state: state.has("Mole Tank Morph", player)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Flowers", player), lambda state: state.has_all({"Mole Tank Morph", "! Switch"}, player)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Stars", player), lambda state: logic.has_midring(state) or state.has("Tulip", player)) + set_rule(world.multiworld.get_location("The Cave Of Harry Hedgehog: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "Key"}, player)) + + set_rule(world.multiworld.get_location("Monkeys' Favorite Lake: Red Coins", player), lambda state: state.has_all({"! Switch", "Submarine Morph"}, player)) + + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Red Coins", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Flowers", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("GO! GO! MARIO!!: Level Clear", player), lambda state: state.has("Super Star", player)) + + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Red Coins", player), lambda state: state.has_all({"! Switch", "Egg Launcher"}, player)) + set_rule(world.multiworld.get_location("The Cave Of The Lakitus: Flowers", player), lambda state: state.has("Egg Launcher", player)) + + set_rule(world.multiworld.get_location("Don't Look Back!: Red Coins", player), lambda state: state.has_all({"Helicopter Morph", "Large Spring Ball"}, player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Don't Look Back!: Stars", player), lambda state: logic.has_midring(state) or state.has("Tulip", player)) + + set_rule(world.multiworld.get_location("Marching Milde's Fort: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket", "Key"}, player)) + set_rule(world.multiworld.get_location("Marching Milde's Fort: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket"}, player)) + set_rule(world.multiworld.get_location("Marching Milde's Fort: Stars", player), lambda state: state.has("Dashed Stairs", player)) + + set_rule(world.multiworld.get_location("Chomp Rock Zone: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Chomp Rock Zone: Flowers", player), lambda state: state.has_all({"Chomp Rock", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Chomp Rock Zone: Stars", player), lambda state: state.has_all({"Chomp Rock", "! Switch"}, player)) + + set_rule(world.multiworld.get_location("Lake Shore Paradise: Stars", player), lambda state: (logic.has_midring(state) or (state.has("Tulip", player) and logic.cansee_clouds(state)))) + + set_rule(world.multiworld.get_location("Ride Like The Wind: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Stars", player), lambda state: (logic.has_midring(state) or state.has("Helicopter Morph", player)) and state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Ride Like The Wind: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Red Coins", player), lambda state: state.has_all({"Key", "Dashed Stairs"}, player)) + set_rule(world.multiworld.get_location("Hookbill The Koopa's Castle: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Key"}, player)) + + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Red Coins", player), lambda state: (state.has("Fire Melon", player) or logic.melon_item(state)) and (state.has_all({"Spring Ball", "Skis"}, player)) and (state.has("Super Star", player) or logic.melon_item(state))) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Flowers", player), lambda state: (state.has("Fire Melon", player) or logic.melon_item(state)) and state.has_all({"Spring Ball", "Skis"}, player)) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Stars", player), lambda state: (logic.has_midring(state) and (state.has("Fire Melon", player) or logic.melon_item(state))) or (logic.has_midring(state) and (state.has_all({"Tulip", "Dashed Platform"}, player)))) + set_rule(world.multiworld.get_location("Danger - Icy Conditions Ahead: Level Clear", player), lambda state: state.has_all({"Spring Ball", "Skis"}, player)) + + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Red Coins", player), lambda state: state.has_all({"Dashed Stairs", "Dashed Platform", "Platform Ghost"}, player)) + set_rule(world.multiworld.get_location("Sluggy The Unshaven's Fort: Flowers", player), lambda state: state.has_all({"Dashed Stairs", "Platform Ghost"}, player)) + + set_rule(world.multiworld.get_location("Shifting Platforms Ahead: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Red Coins", player), lambda state: state.has_all({"Arrow Wheel", "Train Morph"}, player)) + set_rule(world.multiworld.get_location("Raphael The Raven's Castle: Flowers", player), lambda state: state.has_all({"Arrow Wheel", "Train Morph"}, player)) + + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Red Coins", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Flowers", player), lambda state: state.has("Large Spring Ball", player)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Stars", player), lambda state: logic.has_midring(state)) + set_rule(world.multiworld.get_location("Scary Skeleton Goonies!: Level Clear", player), lambda state: state.has("Large Spring Ball", player)) + + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Red Coins", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Flowers", player), lambda state: state.has("Super Star", player)) + set_rule(world.multiworld.get_location("The Cave Of The Bandits: Level Clear", player), lambda state: state.has("Super Star", player)) + + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Red Coins", player), lambda state: state.has_all({"Egg Plant", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Flowers", player), lambda state: state.has_all({"Egg Plant", "Key"}, player) and (state.has("Egg Capacity Upgrade", player, 1) or logic.combat_item(state))) + set_rule(world.multiworld.get_location("Tap-Tap The Red Nose's Fort: Stars", player), lambda state: state.has("Egg Plant", player) and state.has("Key", player)) + + set_rule(world.multiworld.get_location("The Very Loooooong Cave: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Red Coins", player), lambda state: state.has_all({"Key", "Large Spring Ball"}, player) and (logic.combat_item(state) or state.has("Chomp Rock", player))) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Flowers", player), lambda state: state.has_all({"Key", "Large Spring Ball"}, player) and (logic.combat_item(state) or state.has("Chomp Rock", player))) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Stars", player), lambda state: state.has_all({"Chomp Rock", "Key"}, player)) + set_rule(world.multiworld.get_location("The Deep, Underground Maze: Level Clear", player), lambda state: state.has_all({"Key", "Large Spring Ball", "Dashed Platform"}, player) and (logic.combat_item(state) or state.has("Chomp Rock", player))) + + set_rule(world.multiworld.get_location("KEEP MOVING!!!!: Stars", player), lambda state: logic.has_midring(state)) + + set_rule(world.multiworld.get_location("King Bowser's Castle: Red Coins", player), lambda state: state.has("Helicopter Morph", player) and logic._68CollectibleRoute(state)) + set_rule(world.multiworld.get_location("King Bowser's Castle: Flowers", player), lambda state: state.has("Helicopter Morph", player) and logic._68CollectibleRoute(state)) + set_rule(world.multiworld.get_location("King Bowser's Castle: Stars", player), lambda state: state.has("Helicopter Morph", player) and logic._68Route(state)) + + set_hard_extra_rules(world) + + +def set_hard_extra_rules(world: "YoshisIslandWorld") -> None: + player = world.player + logic = YoshiLogic(world) + if not world.options.extras_enabled: + return + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Red Coins", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Flowers", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Stars", player), lambda state: state.has("Poochy", player)) + set_rule(world.multiworld.get_location("Poochy Ain't Stupid: Level Clear", player), lambda state: state.has("Poochy", player)) + + set_rule(world.multiworld.get_location("Hit That Switch!!: Red Coins", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Hit That Switch!!: Flowers", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Hit That Switch!!: Level Clear", player), lambda state: state.has_all({"Large Spring Ball", "! Switch"}, player)) + + set_rule(world.multiworld.get_location("The Impossible? Maze: Red Coins", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph", "Flashing Eggs"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Flowers", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Stars", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph"}, player)) + set_rule(world.multiworld.get_location("The Impossible? Maze: Level Clear", player), lambda state: state.has_all({"Spring Ball", "Large Spring Ball", "Mole Tank Morph", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Kamek's Revenge: Red Coins", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph"}, player)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Flowers", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph", "! Switch"}, player)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Stars", player), lambda state: state.has("! Switch", player) or logic.has_midring(state)) + set_rule(world.multiworld.get_location("Kamek's Revenge: Level Clear", player), lambda state: state.has_all({"Key", "Skis", "Helicopter Morph"}, player)) + + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Red Coins", player), lambda state: state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Flowers", player), lambda state: state.has(("Large Spring Ball"), player)) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Stars", player), lambda state: True) + set_rule(world.multiworld.get_location("Castles - Masterpiece Set: Level Clear", player), lambda state: state.has(("Large Spring Ball"), player)) diff --git a/worlds/yoshisisland/__init__.py b/worlds/yoshisisland/__init__.py new file mode 100644 index 000000000000..b5d7e137b5f3 --- /dev/null +++ b/worlds/yoshisisland/__init__.py @@ -0,0 +1,388 @@ +import base64 +import os +import typing +import threading + +from typing import List, Set, TextIO, Dict +from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification +from worlds.AutoWorld import World, WebWorld +import settings +from .Items import get_item_names_per_category, item_table, filler_items, trap_items +from .Locations import get_locations +from .Regions import init_areas +from .Options import YoshisIslandOptions, PlayerGoal, ObjectVis, StageLogic, MinigameChecks +from .setup_game import setup_gamevars +from .Client import YoshisIslandSNIClient +from .Rules import set_easy_rules, set_normal_rules, set_hard_rules +from .Rom import LocalRom, patch_rom, get_base_rom_path, YoshisIslandDeltaPatch, USHASH + + +class YoshisIslandSettings(settings.Group): + class RomFile(settings.SNESRomPath): + """File name of the Yoshi's Island 1.0 US rom""" + description = "Yoshi's Island ROM File" + copy_to = "Super Mario World 2 - Yoshi's Island (U).sfc" + md5s = [USHASH] + + rom_file: RomFile = RomFile(RomFile.copy_to) + + +class YoshisIslandWeb(WebWorld): + theme = "ocean" + + setup_en = Tutorial( + "Multiworld Setup Guide", + "A guide to setting up the Yoshi's Island randomizer" + "and connecting to an Archipelago server.", + "English", + "setup_en.md", + "setup/en", + ["Pink Switch"] + ) + + tutorials = [setup_en] + + +class YoshisIslandWorld(World): + """ + Yoshi's Island is a 2D platforming game. + During a delivery, Bowser's evil ward, Kamek, attacked the stork, kidnapping Luigi and dropping Mario onto Yoshi's Island. + As Yoshi, you must run, jump, and throw eggs to escort the baby Mario across the island to defeat Bowser and reunite the two brothers with their parents. + """ + game = "Yoshi's Island" + option_definitions = YoshisIslandOptions + required_client_version = (0, 4, 4) + + item_name_to_id = {item: item_table[item].code for item in item_table} + location_name_to_id = {location.name: location.code for location in get_locations(None)} + item_name_groups = get_item_names_per_category() + + web = YoshisIslandWeb() + settings: typing.ClassVar[YoshisIslandSettings] + # topology_present = True + + options_dataclass = YoshisIslandOptions + options: YoshisIslandOptions + + locked_locations: List[str] + set_req_bosses: str + lives_high: int + lives_low: int + castle_bosses: int + bowser_bosses: int + baby_mario_sfx: int + leader_color: int + boss_order: list + boss_burt: int + luigi_count: int + + rom_name: bytearray + + def __init__(self, multiworld: MultiWorld, player: int): + self.rom_name_available_event = threading.Event() + super().__init__(multiworld, player) + self.locked_locations = [] + + @classmethod + def stage_assert_generate(cls, multiworld: MultiWorld) -> None: + rom_file = get_base_rom_path() + if not os.path.exists(rom_file): + raise FileNotFoundError(rom_file) + + def fill_slot_data(self) -> Dict[str, List[int]]: + return { + "world_1": self.world_1_stages, + "world_2": self.world_2_stages, + "world_3": self.world_3_stages, + "world_4": self.world_4_stages, + "world_5": self.world_5_stages, + "world_6": self.world_6_stages + } + + def write_spoiler_header(self, spoiler_handle: TextIO) -> None: + spoiler_handle.write(f"Burt The Bashful's Boss Door: {self.boss_order[0]}\n") + spoiler_handle.write(f"Salvo The Slime's Boss Door: {self.boss_order[1]}\n") + spoiler_handle.write(f"Bigger Boo's Boss Door: {self.boss_order[2]}\n") + spoiler_handle.write(f"Roger The Ghost's Boss Door: {self.boss_order[3]}\n") + spoiler_handle.write(f"Prince Froggy's Boss Door: {self.boss_order[4]}\n") + spoiler_handle.write(f"Naval Piranha's Boss Door: {self.boss_order[5]}\n") + spoiler_handle.write(f"Marching Milde's Boss Door: {self.boss_order[6]}\n") + spoiler_handle.write(f"Hookbill The Koopa's Boss Door: {self.boss_order[7]}\n") + spoiler_handle.write(f"Sluggy The Unshaven's Boss Door: {self.boss_order[8]}\n") + spoiler_handle.write(f"Raphael The Raven's Boss Door: {self.boss_order[9]}\n") + spoiler_handle.write(f"Tap-Tap The Red Nose's Boss Door: {self.boss_order[10]}\n") + spoiler_handle.write(f"\nLevels:\n1-1: {self.level_name_list[0]}\n") + spoiler_handle.write(f"1-2: {self.level_name_list[1]}\n") + spoiler_handle.write(f"1-3: {self.level_name_list[2]}\n") + spoiler_handle.write(f"1-4: {self.level_name_list[3]}\n") + spoiler_handle.write(f"1-5: {self.level_name_list[4]}\n") + spoiler_handle.write(f"1-6: {self.level_name_list[5]}\n") + spoiler_handle.write(f"1-7: {self.level_name_list[6]}\n") + spoiler_handle.write(f"1-8: {self.level_name_list[7]}\n") + + spoiler_handle.write(f"\n2-1: {self.level_name_list[8]}\n") + spoiler_handle.write(f"2-2: {self.level_name_list[9]}\n") + spoiler_handle.write(f"2-3: {self.level_name_list[10]}\n") + spoiler_handle.write(f"2-4: {self.level_name_list[11]}\n") + spoiler_handle.write(f"2-5: {self.level_name_list[12]}\n") + spoiler_handle.write(f"2-6: {self.level_name_list[13]}\n") + spoiler_handle.write(f"2-7: {self.level_name_list[14]}\n") + spoiler_handle.write(f"2-8: {self.level_name_list[15]}\n") + + spoiler_handle.write(f"\n3-1: {self.level_name_list[16]}\n") + spoiler_handle.write(f"3-2: {self.level_name_list[17]}\n") + spoiler_handle.write(f"3-3: {self.level_name_list[18]}\n") + spoiler_handle.write(f"3-4: {self.level_name_list[19]}\n") + spoiler_handle.write(f"3-5: {self.level_name_list[20]}\n") + spoiler_handle.write(f"3-6: {self.level_name_list[21]}\n") + spoiler_handle.write(f"3-7: {self.level_name_list[22]}\n") + spoiler_handle.write(f"3-8: {self.level_name_list[23]}\n") + + spoiler_handle.write(f"\n4-1: {self.level_name_list[24]}\n") + spoiler_handle.write(f"4-2: {self.level_name_list[25]}\n") + spoiler_handle.write(f"4-3: {self.level_name_list[26]}\n") + spoiler_handle.write(f"4-4: {self.level_name_list[27]}\n") + spoiler_handle.write(f"4-5: {self.level_name_list[28]}\n") + spoiler_handle.write(f"4-6: {self.level_name_list[29]}\n") + spoiler_handle.write(f"4-7: {self.level_name_list[30]}\n") + spoiler_handle.write(f"4-8: {self.level_name_list[31]}\n") + + spoiler_handle.write(f"\n5-1: {self.level_name_list[32]}\n") + spoiler_handle.write(f"5-2: {self.level_name_list[33]}\n") + spoiler_handle.write(f"5-3: {self.level_name_list[34]}\n") + spoiler_handle.write(f"5-4: {self.level_name_list[35]}\n") + spoiler_handle.write(f"5-5: {self.level_name_list[36]}\n") + spoiler_handle.write(f"5-6: {self.level_name_list[37]}\n") + spoiler_handle.write(f"5-7: {self.level_name_list[38]}\n") + spoiler_handle.write(f"5-8: {self.level_name_list[39]}\n") + + spoiler_handle.write(f"\n6-1: {self.level_name_list[40]}\n") + spoiler_handle.write(f"6-2: {self.level_name_list[41]}\n") + spoiler_handle.write(f"6-3: {self.level_name_list[42]}\n") + spoiler_handle.write(f"6-4: {self.level_name_list[43]}\n") + spoiler_handle.write(f"6-5: {self.level_name_list[44]}\n") + spoiler_handle.write(f"6-6: {self.level_name_list[45]}\n") + spoiler_handle.write(f"6-7: {self.level_name_list[46]}\n") + spoiler_handle.write("6-8: King Bowser's Castle") + + def create_item(self, name: str) -> Item: + data = item_table[name] + return Item(name, data.classification, data.code, self.player) + + def create_regions(self) -> None: + init_areas(self, get_locations(self)) + + def get_filler_item_name(self) -> str: + trap_chance: int = self.options.trap_percent.value + + if self.random.random() < (trap_chance / 100) and self.options.traps_enabled: + return self.random.choice(trap_items) + else: + return self.random.choice(filler_items) + + def set_rules(self) -> None: + rules_per_difficulty = { + 0: set_easy_rules, + 1: set_normal_rules, + 2: set_hard_rules + } + + rules_per_difficulty[self.options.stage_logic.value](self) + self.multiworld.completion_condition[self.player] = lambda state: state.has("Saved Baby Luigi", self.player) + self.get_location("Burt The Bashful's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Salvo The Slime's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Bigger Boo's Boss Room", ).place_locked_item(self.create_item("Boss Clear")) + self.get_location("Roger The Ghost's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Prince Froggy's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Naval Piranha's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Marching Milde's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Hookbill The Koopa's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Sluggy The Unshaven's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Raphael The Raven's Boss Room").place_locked_item(self.create_item("Boss Clear")) + self.get_location("Tap-Tap The Red Nose's Boss Room").place_locked_item(self.create_item("Boss Clear")) + + if self.options.goal == PlayerGoal.option_luigi_hunt: + self.get_location("Reconstituted Luigi").place_locked_item(self.create_item("Saved Baby Luigi")) + else: + self.get_location("King Bowser's Castle: Level Clear").place_locked_item( + self.create_item("Saved Baby Luigi") + ) + + self.get_location("Touch Fuzzy Get Dizzy: Gather Coins").place_locked_item( + self.create_item("Bandit Consumables") + ) + self.get_location("The Cave Of the Mystery Maze: Seed Spitting Contest").place_locked_item( + self.create_item("Bandit Watermelons") + ) + self.get_location("Lakitu's Wall: Gather Coins").place_locked_item(self.create_item("Bandit Consumables")) + self.get_location("Ride Like The Wind: Gather Coins").place_locked_item(self.create_item("Bandit Consumables")) + + def generate_early(self) -> None: + setup_gamevars(self) + + def get_excluded_items(self) -> Set[str]: + excluded_items: Set[str] = set() + + starting_gate = ["World 1 Gate", "World 2 Gate", "World 3 Gate", + "World 4 Gate", "World 5 Gate", "World 6 Gate"] + + excluded_items.add(starting_gate[self.options.starting_world]) + + if not self.options.shuffle_midrings: + excluded_items.add("Middle Ring") + + if not self.options.add_secretlens: + excluded_items.add("Secret Lens") + + if not self.options.extras_enabled: + excluded_items.add("Extra Panels") + excluded_items.add("Extra 1") + excluded_items.add("Extra 2") + excluded_items.add("Extra 3") + excluded_items.add("Extra 4") + excluded_items.add("Extra 5") + excluded_items.add("Extra 6") + + if self.options.split_extras: + excluded_items.add("Extra Panels") + else: + excluded_items.add("Extra 1") + excluded_items.add("Extra 2") + excluded_items.add("Extra 3") + excluded_items.add("Extra 4") + excluded_items.add("Extra 5") + excluded_items.add("Extra 6") + + if self.options.split_bonus: + excluded_items.add("Bonus Panels") + else: + excluded_items.add("Bonus 1") + excluded_items.add("Bonus 2") + excluded_items.add("Bonus 3") + excluded_items.add("Bonus 4") + excluded_items.add("Bonus 5") + excluded_items.add("Bonus 6") + + return excluded_items + + def create_item_with_correct_settings(self, name: str) -> Item: + data = item_table[name] + item = Item(name, data.classification, data.code, self.player) + + if not item.advancement: + return item + + if name == "Car Morph" and self.options.stage_logic != StageLogic.option_strict: + item.classification = ItemClassification.useful + + secret_lens_visibility_check = ( + self.options.hidden_object_visibility >= ObjectVis.option_clouds_only + or self.options.stage_logic != StageLogic.option_strict + ) + if name == "Secret Lens" and secret_lens_visibility_check: + item.classification = ItemClassification.useful + + is_bonus_location = name in {"Bonus 1", "Bonus 2", "Bonus 3", "Bonus 4", "Bonus 5", "Bonus 6", "Bonus Panels"} + bonus_games_disabled = ( + self.options.minigame_checks not in {MinigameChecks.option_bonus_games, MinigameChecks.option_both} + ) + if is_bonus_location and bonus_games_disabled: + item.classification = ItemClassification.useful + + if name in {"Bonus 1", "Bonus 3", "Bonus 4", "Bonus Panels"} and self.options.item_logic: + item.classification = ItemClassification.progression + + if name == "Piece of Luigi" and self.options.goal == PlayerGoal.option_luigi_hunt: + if self.luigi_count >= self.options.luigi_pieces_required: + item.classification = ItemClassification.useful + else: + item.classification = ItemClassification.progression_skip_balancing + self.luigi_count += 1 + + return item + + def generate_filler(self, pool: List[Item]) -> None: + if self.options.goal == PlayerGoal.option_luigi_hunt: + for _ in range(self.options.luigi_pieces_in_pool.value): + item = self.create_item_with_correct_settings("Piece of Luigi") + pool.append(item) + + for _ in range(len(self.multiworld.get_unfilled_locations(self.player)) - len(pool) - 16): + item = self.create_item_with_correct_settings(self.get_filler_item_name()) + pool.append(item) + + def get_item_pool(self, excluded_items: Set[str]) -> List[Item]: + pool: List[Item] = [] + + for name, data in item_table.items(): + if name not in excluded_items: + for _ in range(data.amount): + item = self.create_item_with_correct_settings(name) + pool.append(item) + + return pool + + def create_items(self) -> None: + self.luigi_count = 0 + + if self.options.minigame_checks in {MinigameChecks.option_bonus_games, MinigameChecks.option_both}: + self.multiworld.get_location("Flip Cards", self.player).place_locked_item( + self.create_item("Bonus Consumables")) + self.multiworld.get_location("Drawing Lots", self.player).place_locked_item( + self.create_item("Bonus Consumables")) + self.multiworld.get_location("Match Cards", self.player).place_locked_item( + self.create_item("Bonus Consumables")) + + pool = self.get_item_pool(self.get_excluded_items()) + + self.generate_filler(pool) + + self.multiworld.itempool += pool + + def generate_output(self, output_directory: str) -> None: + rompath = "" # if variable is not declared finally clause may fail + try: + world = self.multiworld + player = self.player + rom = LocalRom(get_base_rom_path()) + patch_rom(self, rom, self.player) + + 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 = YoshisIslandDeltaPatch(os.path.splitext(rompath)[0] + YoshisIslandDeltaPatch.patch_file_ending, + player=player, player_name=world.player_name[player], patched_path=rompath) + patch.write() + finally: + self.rom_name_available_event.set() + if os.path.exists(rompath): + os.unlink(rompath) + + def modify_multidata(self, multidata: dict) -> None: + # wait for self.rom_name to be available. + self.rom_name_available_event.wait() + rom_name = getattr(self, "rom_name", None) + if rom_name: + new_name = base64.b64encode(bytes(self.rom_name)).decode() + multidata["connect_names"][new_name] = multidata["connect_names"][self.multiworld.player_name[self.player]] + + def extend_hint_information(self, hint_data: typing.Dict[int, typing.Dict[int, str]]) -> None: + world_names = [f"World {i}" for i in range(1, 7)] + world_stages = [ + self.world_1_stages, self.world_2_stages, self.world_3_stages, + self.world_4_stages, self.world_5_stages, self.world_6_stages + ] + + stage_pos_data = {} + for loc in self.multiworld.get_locations(self.player): + if loc.address is None: + continue + + level_id = getattr(loc, "level_id") + for level, stages in zip(world_names, world_stages): + if level_id in stages: + stage_pos_data[loc.address] = level + break + + hint_data[self.player] = stage_pos_data diff --git a/worlds/yoshisisland/docs/en_Yoshi's Island.md b/worlds/yoshisisland/docs/en_Yoshi's Island.md new file mode 100644 index 000000000000..8cd825cc7f34 --- /dev/null +++ b/worlds/yoshisisland/docs/en_Yoshi's Island.md @@ -0,0 +1,71 @@ +# Yoshi's Island + +## Where is the settings page? + +The [player options page for this game](../player-options) contains all the options you need to configure and export a config file. + +## What does randomization do to this game? + +Certain interactable objects within levels will be unable to be used until the corresponding item is found. If the item is not in the player's posession, the object will flash and will not function. Objects include: +- Spring Ball +- Large Spring Ball +- ! Switch +- Dashed Platform +- Dashed Stairs +- Beanstalk +- Arrow Wheel +- Vanishing Arrow Wheel +- Ice, fire, and normal watermelons +- Super Star +- Flashing Eggs +- Giant Eggs +- Egg Launcher +- Egg Refill Plant +- Chomp Rock +- Poochy +- Transformation Morphs +- Skis +- Platform Ghost +- Middle Rings +- Buckets +- Tulips + +Yoshi will start out being able to carry only one egg, and 5 capacity upgrades can be found to bring the total up to 6. +The player will start with all levels unlocked in their starting world, and can collect 'World Gates' to unlock levels from other worlds. +Extra and Bonus stages will also start out locked, and require respective items to access them. 6-8 is locked, and will be unlocked +upon reaching the number of boss clears defined by the player. +Other checks will grant the player extra lives, consumables for use in the inventory, or traps. + +Additionally, the player is able to randomize the bosses found at the end of boss stages, the order of stages, +the world they start in, the starting amount of lives, route through 6-8, and the color of Yoshi for each stage. + +## What is the goal of Yoshi's Island when randomized? + +The player can choose one of two goals: +- Bowser: Defeat a pre-defined number of bosses, and defeat Bowser at the end of 6-8. +- Luigi Hunt: Collect a pre-defined number of 'Pieces of Luigi' within levels. + +## What items and locations get shuffled? + +Locations consist of 'level objectives', that being: +- Beating the stage +- Collecting 20 red coins. +- Collecting 5 flowers. +- Collecting 30 stars. + +Checks will be sent immediately upon achieving that objective, regardless of if the stage is cleared or not. +Additional checks can be placed on Bandit mini-battles, or overworld minigames. + + +## Which items can be in another player's world? + +Any shuffled item can be in other players' worlds. + +## What does another world's item look like in Yoshi's Island + +Items do not have an appearance in Yoshi's Island + +## When the player receives an item, what happens? + +When the player recieves an item, a fanfare or sound will be heard to reflect the item received. Most items, aside from Egg Capacity and level unlocks, can be checked on the menu by pressing SELECT. +If an item is in the queue and has not been received, checks will not be processed. diff --git a/worlds/yoshisisland/docs/setup_en.md b/worlds/yoshisisland/docs/setup_en.md new file mode 100644 index 000000000000..30aadbfa604d --- /dev/null +++ b/worlds/yoshisisland/docs/setup_en.md @@ -0,0 +1,123 @@ +# Yoshi's Island Archipelago Randomizer Setup Guide + +## 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) + - snes9x-nwa from: [snes9x nwa](https://github.com/Skarsnik/snes9x-emunwa/releases) + + NOTE: RetroArch and FXPakPro are not currently supported. +- Your legally obtained Yoshi's Island English 1.0 ROM file, probably named `Super Mario World 2 - Yoshi's Island (U).sfc` + + +## Installation Procedures + +### Windows Setup + +1. Download and install Archipelago from the link above, making sure to install the most recent version. +2. During generation/patching, you will be asked to locate your base ROM file. This is your Yoshi's Island ROM file. +3. If you are using an emulator, you should assign your Lua capable emulator as your default program for launching ROM + files. + 1. Extract your emulator's folder to your Desktop, or somewhere you will remember. + 2. Right-click on a ROM file and select **Open with...** + 3. Check the box next to **Always use this app to open .sfc files** + 4. Scroll to the bottom of the list and click the grey text **Look for another App on this PC** + 5. Browse for your emulator's `.exe` file and click **Open**. This file should be located inside the folder you + extracted in step one. + +## Create a Config (.yaml) File + +### What is a config file and why do I need one? + +See the guide on setting up a basic YAML at the Archipelago setup +guide: [Basic Multiworld Setup Guide](/tutorial/Archipelago/setup/en) + +### Where do I get a config file? + +The Player Options page on the website allows you to configure your personal settings and export a config file from +them. + +### Verifying your config file + +If you would like to validate your config file to make sure it works, you may do so on the YAML Validator page. YAML +validator page: [YAML Validation page](/mysterycheck) + +## Joining a MultiWorld Game + +### Obtain your patch file and create your ROM + +When you join a multiworld game, you will be asked to provide your config file to whomever is hosting. Once that is done, +the host will provide you with either a link to download your patch file, or with a zip file containing everyone's patch +files. Your patch file should have a `.apyi` extension. + +Put your patch file on your desktop or somewhere convenient, and double click it. This should automatically launch the +client, and will also create your ROM in the same place as your patch file. + +### Connect to the client + +#### With an emulator + +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-rr + +1. Load your ROM file if it hasn't already been loaded. +2. Click on the File menu and hover on **Lua Scripting** +3. Click on **New Lua Script Window...** +4. In the new window, click **Browse...** +5. Select the connector lua file included with your client + - Look in the Archipelago folder for `/SNI/lua/x64` or `/SNI/lua/x86` depending on if the + emulator is 64-bit or 32-bit. +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. + +##### BizHawk + +1. Ensure you have the BSNES core loaded. This is done with the main menubar, under: + - (≤ 2.8) `Config` 〉 `Cores` 〉 `SNES` 〉 `BSNES` + - (≥ 2.9) `Config` 〉 `Preferred Cores` 〉 `SNES` 〉 `BSNESv115+` +2. Load your ROM file if it hasn't already been loaded. + If you changed your core preference after loading the ROM, don't forget to reload it (default hotkey: Ctrl+R). +3. Drag+drop the `Connector.lua` file included with your client onto the main EmuHawk window. + - Look in the Archipelago folder for `/SNI/lua/x64` or `/SNI/lua/x86` depending on if the + emulator is 64-bit or 32-bit. Please note the most recent versions of BizHawk are 64-bit only. + - You could instead open the Lua Console manually, click `Script` 〉 `Open Script`, and navigate to `Connector.lua` + with the file picker. + + + +### Connect to the Archipelago Server + +The patch file which launched your client should have automatically connected you to the AP Server. There are a few +reasons this may not happen however, including if the game is hosted on the website but was generated elsewhere. If the +client window shows "Server Status: Not Connected", simply ask the host for the address of the server, and copy/paste it +into the "Server" input field then press enter. + +The client will attempt to reconnect to the new server address, and should momentarily show "Server Status: Connected". + +### Play the game + +When the client shows both SNES Device and Server as connected, you're ready to begin playing. Congratulations on +successfully joining a multiworld game! + +## Hosting a MultiWorld game + +The recommended way to host a game is to use our hosting service. The process is relatively simple: + +1. Collect config files from your players. +2. Create a zip file containing your players' config files. +3. Upload that zip file to the Generate page above. + - Generate page: [WebHost Seed Generation Page](/generate) +4. Wait a moment while the seed is generated. +5. When the seed is generated, you will be redirected to a "Seed Info" page. +6. Click "Create New Room". This will take you to the server page. Provide the link to this page to your players, so + they may download their patch files from there. +7. Note that a link to a MultiWorld Tracker is at the top of the room page. The tracker shows the progress of all + players in the game. Any observers may also be given the link to this page. +8. Once all players have joined, you may begin playing. diff --git a/worlds/yoshisisland/level_logic.py b/worlds/yoshisisland/level_logic.py new file mode 100644 index 000000000000..094e5efed12d --- /dev/null +++ b/worlds/yoshisisland/level_logic.py @@ -0,0 +1,482 @@ +from BaseClasses import CollectionState +from typing import TYPE_CHECKING + +from .Options import StageLogic, BowserDoor, ObjectVis + +if TYPE_CHECKING: + from . import YoshisIslandWorld + + +class YoshiLogic: + player: int + game_logic: str + midring_start: bool + clouds_always_visible: bool + consumable_logic: bool + luigi_pieces: int + + def __init__(self, world: "YoshisIslandWorld") -> None: + self.player = world.player + self.boss_order = world.boss_order + self.luigi_pieces = world.options.luigi_pieces_required.value + + if world.options.stage_logic == StageLogic.option_strict: + self.game_logic = "Easy" + elif world.options.stage_logic == StageLogic.option_loose: + self.game_logic = "Normal" + else: + self.game_logic = "Hard" + + self.midring_start = not world.options.shuffle_midrings + self.consumable_logic = not world.options.item_logic + + self.clouds_always_visible = world.options.hidden_object_visibility >= ObjectVis.option_clouds_only + + self.bowser_door = world.options.bowser_door_mode.value + if self.bowser_door == BowserDoor.option_door_4: + self.bowser_door = BowserDoor.option_door_3 + + def has_midring(self, state: CollectionState) -> bool: + return self.midring_start or state.has("Middle Ring", self.player) + + def reconstitute_luigi(self, state: CollectionState) -> bool: + return state.has("Piece of Luigi", self.player, self.luigi_pieces) + + def bandit_bonus(self, state: CollectionState) -> bool: + return state.has("Bandit Consumables", self.player) or state.has("Bandit Watermelons", self.player) + + def item_bonus(self, state: CollectionState) -> bool: + return state.has("Bonus Consumables", self.player) + + def combat_item(self, state: CollectionState) -> bool: + if not self.consumable_logic: + return False + else: + if self.game_logic == "Easy": + return self.item_bonus(state) + else: + return self.bandit_bonus(state) or self.item_bonus(state) + + def melon_item(self, state: CollectionState) -> bool: + if not self.consumable_logic: + return False + else: + if self.game_logic == "Easy": + return self.item_bonus(state) + else: + return state.has("Bandit Watermelons", self.player) or self.item_bonus(state) + + def default_vis(self, state: CollectionState) -> bool: + if self.clouds_always_visible: + return True + else: + return False + + def cansee_clouds(self, state: CollectionState) -> bool: + if self.game_logic != "Easy": + return True + else: + return self.default_vis(state) or state.has("Secret Lens", self.player) or self.combat_item(state) + + def bowserdoor_1(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Egg Plant", "! Switch"}, self.player) and state.has("Egg Capacity Upgrade", self.player, 2) + elif self.game_logic == "Normal": + return state.has("Egg Plant", self.player) and state.has("Egg Capacity Upgrade", self.player, 1) + else: + return state.has("Egg Plant", self.player) + + def bowserdoor_2(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return ((state.has("Egg Capacity Upgrade", self.player, 3) and state.has("Egg Plant", self.player)) or self.combat_item(state)) and state.has("Key", self.player) + elif self.game_logic == "Normal": + return ((state.has("Egg Capacity Upgrade", self.player, 2) and state.has("Egg Plant", self.player)) or self.combat_item(state)) and state.has("Key", self.player) + else: + return ((state.has("Egg Capacity Upgrade", self.player, 1) and state.has("Egg Plant", self.player)) or self.combat_item(state)) and state.has("Key", self.player) + + def bowserdoor_3(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def bowserdoor_4(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def _68Route(self, state: CollectionState) -> bool: + if self.bowser_door == 0: + return True + elif self.bowser_door == 1: + return self.bowserdoor_1(state) + elif self.bowser_door == 2: + return self.bowserdoor_2(state) + elif self.bowser_door == 3: + return True + elif self.bowser_door == 4: + return True + elif self.bowser_door == 5: + return self.bowserdoor_1(state) and self.bowserdoor_2(state) and self.bowserdoor_3(state) + + def _68CollectibleRoute(self, state: CollectionState) -> bool: + if self.bowser_door == 0: + return True + elif self.bowser_door == 1: + return self.bowserdoor_1(state) + elif self.bowser_door == 2: + return self.bowserdoor_2(state) + elif self.bowser_door == 3: + return True + elif self.bowser_door == 4: + return True + elif self.bowser_door == 5: + return self.bowserdoor_1(state) + + +############################################################################## + def _13Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Key", self.player) + elif self.game_logic == "Normal": + return state.has("Key", self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _14Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Spring Ball", "Key"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Spring Ball", "Key"}, self.player) + else: + return state.has_all({"Spring Ball", "Key"}, self.player) + + def _14Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Egg Plant", self.player) + elif self.game_logic == "Normal": + return state.has("Egg Plant", self.player) + else: + return (state.has("Egg Capacity Upgrade", self.player, 5) or state.has("Egg Plant", self.player)) + + def _14CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[0], "Location", self.player): + return True +############################################################################## + def _17Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Key", self.player) + elif self.game_logic == "Normal": + return state.has("Key", self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _18Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Key", "Arrow Wheel"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Key", "Arrow Wheel"}, self.player) + else: + return state.has_all({"Key", "Arrow Wheel"}, self.player) + + def _18Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def _18CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[1], "Location", self.player): + return True +############################################################################## + def _21Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Poochy", "Large Spring Ball", "Key"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Poochy", "Large Spring Ball", "Key"}, self.player) + else: + return state.has_all({"Poochy", "Large Spring Ball", "Key"}, self.player) +############################################################################## + def _23Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Mole Tank Morph", "Key"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Mole Tank Morph", "Key"}, self.player) + else: + return state.has_all({"Mole Tank Morph", "Key"}, self.player) +############################################################################## + def _24Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"! Switch", "Key", "Dashed Stairs"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"! Switch", "Dashed Stairs"}, self.player) + else: + return state.has("! Switch", self.player) + + def _24Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def _24CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[2], "Location", self.player): + return True +############################################################################## + def _26Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Large Spring Ball", "Key"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Large Spring Ball", "Key"}, self.player) + else: + return state.has_all({"Large Spring Ball", "Key"}, self.player) +############################################################################## + def _27Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Key", self.player) + elif self.game_logic == "Normal": + return state.has("Key", self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _28Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Arrow Wheel", "Key"}, self.player) and (state.has("Egg Capacity Upgrade", self.player, 1)) + elif self.game_logic == "Normal": + return state.has_all({"Arrow Wheel", "Key"}, self.player) + else: + return state.has_all({"Arrow Wheel", "Key"}, self.player) + + def _28Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def _28CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[3], "Location", self.player): + return True +############################################################################## + def _32Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Dashed Stairs", "Spring Ball", "Key"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Dashed Stairs", "Key"}, self.player) + else: + return state.has_all({"Dashed Stairs", "Key"}, self.player) +############################################################################## + def _34Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Dashed Platform", self.player) + elif self.game_logic == "Normal": + return (state.has("Dashed Platform", self.player) or self.has_midring(state)) + else: + return True + + def _34Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Giant Eggs", self.player) + elif self.game_logic == "Normal": + return True + else: + return True + + def _34CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[4], "Location", self.player): + return True +############################################################################## + def _37Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Key", "Large Spring Ball"}, self.player) + elif self.game_logic == "Normal": + return state.has("Key", self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _38Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return (state.has("Egg Capacity Upgrade", self.player, 3) or self.combat_item(state)) + elif self.game_logic == "Normal": + return (state.has("Egg Capacity Upgrade", self.player, 1) or self.combat_item(state)) + else: + return True + + def _38Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def _38CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[5], "Location", self.player): + return True +############################################################################## + def _42Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Large Spring Ball", "Key"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Large Spring Ball", "Key"}, self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _44Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket", "Key"}, self.player) and (state.has("Egg Capacity Upgrade", self.player, 1) or self.combat_item(state)) + elif self.game_logic == "Normal": + return state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket", "Key"}, self.player) + else: + return state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Arrow Wheel", "Bucket", "Key"}, self.player) + + def _44Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def _44CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[6], "Location", self.player): + return True +######################################################################################################## + + def _46Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Key", "Large Spring Ball"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Key", "Large Spring Ball"}, self.player) + else: + return state.has_all({"Key", "Large Spring Ball"}, self.player) + + def _47Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Key", "Large Spring Ball"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Key", "Large Spring Ball"}, self.player) + else: + return state.has_all({"Key", "Large Spring Ball"}, self.player) +############################################################################## + def _48Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return (state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Key", "Large Spring Ball"}, self.player)) + elif self.game_logic == "Normal": + return (state.has_all({"Dashed Stairs", "Vanishing Arrow Wheel", "Key", "Large Spring Ball"}, self.player)) + else: + return (state.has_all({"Key", "Large Spring Ball"}, self.player)) + + def _48Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return (state.has("Egg Capacity Upgrade", self.player, 3)) + elif self.game_logic == "Normal": + return (state.has("Egg Capacity Upgrade", self.player, 2)) + else: + return (state.has("Egg Capacity Upgrade", self.player, 1)) + + def _48CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[7], "Location", self.player): + return True +###################################################################################################################### + def _51Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Key", self.player) + elif self.game_logic == "Normal": + return state.has("Key", self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _54Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return (state.has_all({"Dashed Stairs", "Platform Ghost", "Dashed Platform"}, self.player)) + elif self.game_logic == "Normal": + return (state.has_all({"Dashed Stairs", "Platform Ghost", "Dashed Platform"}, self.player)) + else: + return (state.has_all({"Dashed Stairs", "Platform Ghost"}, self.player)) + + def _54Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return (state.has("Egg Capacity Upgrade", self.player, 2) and state.has("Egg Plant", self.player)) + elif self.game_logic == "Normal": + return ((state.has("Egg Capacity Upgrade", self.player, 1) and state.has("Egg Plant", self.player)) or (state.has("Egg Capacity Upgrade", self.player, 5) and self.has_midring(state))) + else: + return ((state.has("Egg Plant", self.player)) or (state.has("Egg Capacity Upgrade", self.player, 3) and self.has_midring(state))) + + def _54CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[8], "Location", self.player): + return True +################################################################################################### + def _58Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Arrow Wheel", "Large Spring Ball"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Arrow Wheel", "Large Spring Ball"}, self.player) + else: + return state.has_all({"Arrow Wheel", "Large Spring Ball"}, self.player) + + def _58Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return True + elif self.game_logic == "Normal": + return True + else: + return True + + def _58CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[9], "Location", self.player): + return True +############################################################################## + def _61Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Dashed Platform", "Key", "Beanstalk"}, self.player) + elif self.game_logic == "Normal": + return state.has_all({"Dashed Platform", "Key", "Beanstalk"}, self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _64Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Spring Ball", "Large Spring Ball", "Egg Plant", "Key"}, self.player) and (state.has("Egg Capacity Upgrade", self.player, 3) or self.combat_item(state)) + elif self.game_logic == "Normal": + return state.has_all({"Large Spring Ball", "Egg Plant", "Key"}, self.player) and (state.has("Egg Capacity Upgrade", self.player, 2) or self.combat_item(state)) + else: + return state.has_all({"Egg Plant", "Key"}, self.player) and (state.has("Egg Capacity Upgrade", self.player, 1) or self.combat_item(state)) + + def _64Boss(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Egg Plant", self.player) + elif self.game_logic == "Normal": + return state.has("Egg Plant", self.player) + else: + return True + + def _64CanFightBoss(self, state: CollectionState) -> bool: + if state.can_reach(self.boss_order[10], "Location", self.player): + return True +############################################################################## + def _67Game(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has("Key", self.player) + elif self.game_logic == "Normal": + return state.has("Key", self.player) + else: + return state.has("Key", self.player) +############################################################################## + def _68Clear(self, state: CollectionState) -> bool: + if self.game_logic == "Easy": + return state.has_all({"Helicopter Morph", "Egg Plant", "Giant Eggs"}, self.player) and self._68Route(state) + elif self.game_logic == "Normal": + return state.has_all({"Helicopter Morph", "Egg Plant", "Giant Eggs"}, self.player) and self._68Route(state) + else: + return state.has_all({"Helicopter Morph", "Giant Eggs"}, self.player) and self._68Route(state) diff --git a/worlds/yoshisisland/setup_bosses.py b/worlds/yoshisisland/setup_bosses.py new file mode 100644 index 000000000000..bbefdd31a05c --- /dev/null +++ b/worlds/yoshisisland/setup_bosses.py @@ -0,0 +1,19 @@ +from BaseClasses import CollectionState +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from . import YoshisIslandWorld + + +class BossReqs: + player: int + + def __init__(self, world: "YoshisIslandWorld") -> None: + self.player = world.player + self.castle_unlock = world.options.castle_open_condition.value + self.boss_unlock = world.options.castle_clear_condition.value + + def castle_access(self, state: CollectionState) -> bool: + return state.has("Boss Clear", self.player, self.castle_unlock) + + def castle_clear(self, state: CollectionState) -> bool: + return state.has("Boss Clear", self.player, self.boss_unlock) diff --git a/worlds/yoshisisland/setup_game.py b/worlds/yoshisisland/setup_game.py new file mode 100644 index 000000000000..000420a95b07 --- /dev/null +++ b/worlds/yoshisisland/setup_game.py @@ -0,0 +1,460 @@ +import struct +from typing import TYPE_CHECKING + +from .Options import YoshiColors, BabySound, LevelShuffle + +if TYPE_CHECKING: + from . import YoshisIslandWorld + + +def setup_gamevars(world: "YoshisIslandWorld") -> None: + if world.options.luigi_pieces_in_pool < world.options.luigi_pieces_required: + world.options.luigi_pieces_in_pool.value = world.random.randint(world.options.luigi_pieces_required.value, 100) + world.starting_lives = struct.pack("H", world.options.starting_lives) + + world.level_colors = [] + world.color_order = [] + for i in range(72): + world.level_colors.append(world.random.randint(0, 7)) + if world.options.yoshi_colors == YoshiColors.option_singularity: + singularity_color = world.options.yoshi_singularity_color.value + for i in range(len(world.level_colors)): + world.level_colors[i] = singularity_color + elif world.options.yoshi_colors == YoshiColors.option_random_order: + world.leader_color = world.random.randint(0, 7) + for i in range(7): + world.color_order.append(world.random.randint(0, 7)) + + bonus_valid = [0x00, 0x02, 0x04, 0x06, 0x08, 0x0A] + + world.world_bonus = [] + for i in range(12): + world.world_bonus.append(world.random.choice(bonus_valid)) + + safe_baby_sounds = [0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, + 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, + 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x52, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x73, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, + 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2] + + if world.options.baby_mario_sound == BabySound.option_random_sound_effect: + world.baby_mario_sfx = world.random.choice(safe_baby_sounds) + elif world.options.baby_mario_sound == BabySound.option_disabled: + world.baby_mario_sfx = 0x42 + else: + world.baby_mario_sfx = 0x44 + + boss_list = ["Burt The Bashful's Boss Room", "Salvo The Slime's Boss Room", + "Bigger Boo's Boss Room", "Roger The Ghost's Boss Room", + "Prince Froggy's Boss Room", "Naval Piranha's Boss Room", + "Marching Milde's Boss Room", "Hookbill The Koopa's Boss Room", + "Sluggy The Unshaven's Boss Room", "Raphael The Raven's Boss Room", + "Tap-Tap The Red Nose's Boss Room"] + + world.boss_order = [] + + if world.options.boss_shuffle: + world.random.shuffle(boss_list) + world.boss_order = boss_list + + burt_pointers = [0x3D, 0x05, 0x63, 0x00] + slime_pointers = [0x70, 0x04, 0x78, 0x00] + boo_pointers = [0x74, 0xBB, 0x7A, 0x00] + pot_pointers = [0xCF, 0x04, 0x4D, 0x00] + frog_pointers = [0xBF, 0x12, 0x62, 0x04] + plant_pointers = [0x7F, 0x0D, 0x42, 0x00] + milde_pointers = [0x82, 0x06, 0x64, 0x00] + koop_pointers = [0x86, 0x0D, 0x78, 0x00] + slug_pointers = [0x8A, 0x09, 0x7A, 0x00] + raph_pointers = [0xC4, 0x03, 0x4B, 0x05] + tap_pointers = [0xCC, 0x49, 0x64, 0x02] + + boss_data_list = [ + burt_pointers, + slime_pointers, + boo_pointers, + pot_pointers, + frog_pointers, + plant_pointers, + milde_pointers, + koop_pointers, + slug_pointers, + raph_pointers, + tap_pointers + ] + + boss_levels = [0x03, 0x07, 0x0F, 0x13, 0x1B, 0x1F, 0x27, 0x2B, 0x33, 0x37, 0x3F] + + boss_room_idlist = { + "Burt The Bashful's Boss Room": 0, + "Salvo The Slime's Boss Room": 1, + "Bigger Boo's Boss Room": 2, + "Roger The Ghost's Boss Room": 3, + "Prince Froggy's Boss Room": 4, + "Naval Piranha's Boss Room": 5, + "Marching Milde's Boss Room": 6, + "Hookbill The Koopa's Boss Room": 7, + "Sluggy The Unshaven's Boss Room": 8, + "Raphael The Raven's Boss Room": 9, + "Tap-Tap The Red Nose's Boss Room": 10, + } + + boss_check_list = { + "Burt The Bashful's Boss Room": "Burt The Bashful Defeated", + "Salvo The Slime's Boss Room": "Salvo The Slime Defeated", + "Bigger Boo's Boss Room": "Bigger Boo Defeated", + "Roger The Ghost's Boss Room": "Roger The Ghost Defeated", + "Prince Froggy's Boss Room": "Prince Froggy Defeated", + "Naval Piranha's Boss Room": "Naval Piranha Defeated", + "Marching Milde's Boss Room": "Marching Milde Defeated", + "Hookbill The Koopa's Boss Room": "Hookbill The Koopa Defeated", + "Sluggy The Unshaven's Boss Room": "Sluggy The Unshaven Defeated", + "Raphael The Raven's Boss Room": "Raphael The Raven Defeated", + "Tap-Tap The Red Nose's Boss Room": "Tap-Tap The Red Nose Defeated", + } + + world.boss_room_id = [boss_room_idlist[roomnum] for roomnum in world.boss_order] + world.tap_tap_room = boss_levels[world.boss_room_id.index(10)] + world.boss_ap_loc = [boss_check_list[roomnum] for roomnum in world.boss_order] + + world.boss_burt_data = boss_data_list[world.boss_room_id[0]] + + world.boss_slime_data = boss_data_list[world.boss_room_id[1]] + + world.boss_boo_data = boss_data_list[world.boss_room_id[2]] + + world.boss_pot_data = boss_data_list[world.boss_room_id[3]] + + world.boss_frog_data = boss_data_list[world.boss_room_id[4]] + + world.boss_plant_data = boss_data_list[world.boss_room_id[5]] + + world.boss_milde_data = boss_data_list[world.boss_room_id[6]] + + world.boss_koop_data = boss_data_list[world.boss_room_id[7]] + + world.boss_slug_data = boss_data_list[world.boss_room_id[8]] + + world.boss_raph_data = boss_data_list[world.boss_room_id[9]] + + world.boss_tap_data = boss_data_list[world.boss_room_id[10]] + + world.global_level_list = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42] + level_id_list = { + 0x00: "1-1", + 0x01: "1-2", + 0x02: "1-3", + 0x03: "1-4", + 0x04: "1-5", + 0x05: "1-6", + 0x06: "1-7", + 0x07: "1-8", + 0x0C: "2-1", + 0x0D: "2-2", + 0x0E: "2-3", + 0x0F: "2-4", + 0x10: "2-5", + 0x11: "2-6", + 0x12: "2-7", + 0x13: "2-8", + 0x18: "3-1", + 0x19: "3-2", + 0x1A: "3-3", + 0x1B: "3-4", + 0x1C: "3-5", + 0x1D: "3-6", + 0x1E: "3-7", + 0x1F: "3-8", + 0x24: "4-1", + 0x25: "4-2", + 0x26: "4-3", + 0x27: "4-4", + 0x28: "4-5", + 0x29: "4-6", + 0x2A: "4-7", + 0x2B: "4-8", + 0x30: "5-1", + 0x31: "5-2", + 0x32: "5-3", + 0x33: "5-4", + 0x34: "5-5", + 0x35: "5-6", + 0x36: "5-7", + 0x37: "5-8", + 0x3C: "6-1", + 0x3D: "6-2", + 0x3E: "6-3", + 0x3F: "6-4", + 0x40: "6-5", + 0x41: "6-6", + 0x42: "6-7" + } + + level_names = { + 0x00: "Make Eggs, Throw Eggs", + 0x01: "Watch Out Below!", + 0x02: "The Cave Of Chomp Rock", + 0x03: "Burt The Bashful's Fort", + 0x04: "Hop! Hop! Donut Lifts", + 0x05: "Shy-Guys On Stilts", + 0x06: "Touch Fuzzy Get Dizzy", + 0x07: "Salvo The Slime's Castle", + 0x0C: "Visit Koopa And Para-Koopa", + 0x0D: "The Baseball Boys", + 0x0E: "What's Gusty Taste Like?", + 0x0F: "Bigger Boo's Fort", + 0x10: "Watch Out For Lakitu", + 0x11: "The Cave Of The Mystery Maze", + 0x12: "Lakitu's Wall", + 0x13: "The Potted Ghost's Castle", + 0x18: "Welcome To Monkey World!", + 0x19: "Jungle Rhythm...", + 0x1A: "Nep-Enuts' Domain", + 0x1B: "Prince Froggy's Fort", + 0x1C: "Jammin' Through The Trees", + 0x1D: "The Cave Of Harry Hedgehog", + 0x1E: "Monkeys' Favorite Lake", + 0x1F: "Naval Piranha's Castle", + 0x24: "GO! GO! MARIO!!", + 0x25: "The Cave Of The Lakitus", + 0x26: "Don't Look Back!", + 0x27: "Marching Milde's Fort", + 0x28: "Chomp Rock Zone", + 0x29: "Lake Shore Paradise", + 0x2A: "Ride Like The Wind", + 0x2B: "Hookbill The Koopa's Castle", + 0x30: "BLIZZARD!!!", + 0x31: "Ride The Ski Lifts", + 0x32: "Danger - Icy Conditions Ahead", + 0x33: "Sluggy The Unshaven's Fort", + 0x34: "Goonie Rides!", + 0x35: "Welcome To Cloud World", + 0x36: "Shifting Platforms Ahead", + 0x37: "Raphael The Raven's Castle", + 0x3C: "Scary Skeleton Goonies!", + 0x3D: "The Cave Of The Bandits", + 0x3E: "Beware The Spinning Logs", + 0x3F: "Tap-Tap The Red Nose's Fort", + 0x40: "The Very Loooooong Cave", + 0x41: "The Deep, Underground Maze", + 0x42: "KEEP MOVING!!!!" + } + + world_1_offsets = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00] + world_2_offsets = [0x01, 0x01, 0x00, 0x00, 0x00, 0x00] + world_3_offsets = [0x01, 0x01, 0x01, 0x00, 0x00, 0x00] + world_4_offsets = [0x01, 0x01, 0x01, 0x01, 0x00, 0x00] + world_5_offsets = [0x01, 0x01, 0x01, 0x01, 0x01, 0x00] + easy_start_lv = [0x02, 0x04, 0x06, 0x0E, 0x10, 0x18, 0x1C, 0x28, + 0x30, 0x31, 0x35, 0x36, 0x3E, 0x40, 0x42] + norm_start_lv = [0x00, 0x01, 0x02, 0x04, 0x06, 0x0E, 0x10, 0x12, 0x18, 0x1A, + 0x1C, 0x1E, 0x28, 0x30, 0x31, 0x34, 0x35, 0x36, 0x3D, 0x3E, 0x40, 0x42] + hard_start_lv = [0x00, 0x01, 0x02, 0x04, 0x06, 0x0D, 0x0E, 0x10, 0x11, 0x12, 0x18, 0x1A, 0x1C, + 0x1E, 0x24, 0x25, 0x26, 0x28, 0x29, 0x30, 0x31, 0x34, 0x35, 0x36, 0x3D, 0x3E, + 0x40, 0x42] + diff_index = [easy_start_lv, norm_start_lv, hard_start_lv] + diff_level = diff_index[world.options.stage_logic.value] + boss_lv = [0x03, 0x07, 0x0F, 0x13, 0x1B, 0x1F, 0x27, 0x2B, 0x33, 0x37, 0x3F] + world.world_start_lv = [0, 8, 16, 24, 32, 40] + if not world.options.shuffle_midrings: + easy_start_lv.extend([0x1A, 0x24, 0x34]) + norm_start_lv.extend([0x24, 0x3C]) + hard_start_lv.extend([0x1D, 0x3C]) + + if world.options.level_shuffle != LevelShuffle.option_bosses_guranteed: + hard_start_lv.extend([0x07, 0x1B, 0x1F, 0x2B, 0x33, 0x37]) + if not world.options.shuffle_midrings: + easy_start_lv.extend([0x1B]) + norm_start_lv.extend([0x1B, 0x2B, 0x37]) + + starting_level = world.random.choice(diff_level) + + starting_level_entrance = world.world_start_lv[world.options.starting_world.value] + if world.options.level_shuffle: + world.global_level_list.remove(starting_level) + world.random.shuffle(world.global_level_list) + if world.options.level_shuffle == LevelShuffle.option_bosses_guranteed: + for i in range(11): + world.global_level_list = [item for item in world.global_level_list + if item not in boss_lv] + world.random.shuffle(boss_lv) + + world.global_level_list.insert(3 - world_1_offsets[world.options.starting_world.value], boss_lv[0]) # 1 if starting world is 1, 0 otherwise + world.global_level_list.insert(7 - world_1_offsets[world.options.starting_world.value], boss_lv[1]) + world.global_level_list.insert(11 - world_2_offsets[world.options.starting_world.value], boss_lv[2]) + world.global_level_list.insert(15 - world_2_offsets[world.options.starting_world.value], boss_lv[3]) + world.global_level_list.insert(19 - world_3_offsets[world.options.starting_world.value], boss_lv[4]) + world.global_level_list.insert(23 - world_3_offsets[world.options.starting_world.value], boss_lv[5]) + world.global_level_list.insert(27 - world_4_offsets[world.options.starting_world.value], boss_lv[6]) + world.global_level_list.insert(31 - world_4_offsets[world.options.starting_world.value], boss_lv[7]) + world.global_level_list.insert(35 - world_5_offsets[world.options.starting_world.value], boss_lv[8]) + world.global_level_list.insert(39 - world_5_offsets[world.options.starting_world.value], boss_lv[9]) + world.global_level_list.insert(43 - 1, boss_lv[10]) + world.global_level_list.insert(starting_level_entrance, starting_level) + world.level_location_list = [level_id_list[LevelID] for LevelID in world.global_level_list] + world.level_name_list = [level_names[LevelID] for LevelID in world.global_level_list] + + level_panel_dict = { + 0x00: [0x04, 0x04, 0x53], + 0x01: [0x20, 0x04, 0x53], + 0x02: [0x3C, 0x04, 0x53], + 0x03: [0x58, 0x04, 0x53], + 0x04: [0x74, 0x04, 0x53], + 0x05: [0x90, 0x04, 0x53], + 0x06: [0xAC, 0x04, 0x53], + 0x07: [0xC8, 0x04, 0x53], + 0x0C: [0x04, 0x24, 0x53], + 0x0D: [0x20, 0x24, 0x53], + 0x0E: [0x3C, 0x24, 0x53], + 0x0F: [0x58, 0x24, 0x53], + 0x10: [0x74, 0x24, 0x53], + 0x11: [0x90, 0x24, 0x53], + 0x12: [0xAC, 0x24, 0x53], + 0x13: [0xC8, 0x24, 0x53], + 0x18: [0x04, 0x44, 0x53], + 0x19: [0x20, 0x44, 0x53], + 0x1A: [0x3C, 0x44, 0x53], + 0x1B: [0x58, 0x44, 0x53], + 0x1C: [0x74, 0x44, 0x53], + 0x1D: [0x90, 0x44, 0x53], + 0x1E: [0xAC, 0x44, 0x53], + 0x1F: [0xC8, 0x44, 0x53], + 0x24: [0x04, 0x64, 0x53], + 0x25: [0x20, 0x64, 0x53], + 0x26: [0x3C, 0x64, 0x53], + 0x27: [0x58, 0x64, 0x53], + 0x28: [0x74, 0x64, 0x53], + 0x29: [0x90, 0x64, 0x53], + 0x2A: [0xAC, 0x64, 0x53], + 0x2B: [0xC8, 0x64, 0x53], + 0x30: [0x04, 0x04, 0x53], + 0x31: [0x20, 0x04, 0x53], + 0x32: [0x3C, 0x04, 0x53], + 0x33: [0x58, 0x04, 0x53], + 0x34: [0x74, 0x04, 0x53], + 0x35: [0x90, 0x04, 0x53], + 0x36: [0xAC, 0x04, 0x53], + 0x37: [0xC8, 0x04, 0x53], + 0x3C: [0x04, 0x24, 0x53], + 0x3D: [0x20, 0x24, 0x53], + 0x3E: [0x3C, 0x24, 0x53], + 0x3F: [0x58, 0x24, 0x53], + 0x40: [0x74, 0x24, 0x53], + 0x41: [0x90, 0x24, 0x53], + 0x42: [0xAC, 0x24, 0x53], + } + panel_palette_1 = [0x00, 0x03, 0x04, 0x05, 0x0C, 0x10, 0x12, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x24, 0x26, 0x27, 0x29, 0x2A, 0x2B, 0x30, 0x32, 0x34, + 0x35, 0x37, 0x3C, 0x3D, 0x40, 0x41] # 000C + panel_palette_2 = [0x01, 0x02, 0x06, 0x07, 0x0D, 0x0E, 0x0F, 0x11, 0x18, 0x1E, 0x1F, 0x25, 0x28, + 0x31, 0x33, 0x36, 0x3E, 0x3F, 0x42] # 0010 + + stage_number = 0 + world_number = 1 + for i in range(47): + stage_number += 1 + if stage_number >= 9: + world_number += 1 + stage_number = 1 + for _ in range(3): + setattr(world, f"Stage{world_number}{stage_number}StageGFX", + level_panel_dict[world.global_level_list[i]]) + + world.level_gfx_table = [] + world.palette_panel_list = [] + + for i in range(47): + if world.global_level_list[i] >= 0x30: + world.level_gfx_table.append(0x15) + else: + world.level_gfx_table.append(0x11) + + if world.global_level_list[i] in panel_palette_1: + world.palette_panel_list.extend([0x00, 0x0C]) + elif world.global_level_list[i] in panel_palette_2: + world.palette_panel_list.extend([0x00, 0x10]) + + world.palette_panel_list[16:16] = [0x00, 0x0c, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x18] + world.palette_panel_list[40:40] = [0x00, 0x0c, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x18] + world.palette_panel_list[64:64] = [0x00, 0x0c, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x18] + world.palette_panel_list[88:88] = [0x00, 0x0c, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x18] + world.palette_panel_list[112:112] = [0x00, 0x0c, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x18] + + world.level_gfx_table.insert(8, 0x15) + world.level_gfx_table.insert(8, 0x15) + world.level_gfx_table.insert(8, 0x15) + world.level_gfx_table.insert(8, 0x11) + + world.level_gfx_table.insert(20, 0x15) + world.level_gfx_table.insert(20, 0x15) + world.level_gfx_table.insert(20, 0x15) + world.level_gfx_table.insert(20, 0x11) + + world.level_gfx_table.insert(32, 0x15) + world.level_gfx_table.insert(32, 0x15) + world.level_gfx_table.insert(32, 0x15) + world.level_gfx_table.insert(32, 0x11) + + world.level_gfx_table.insert(44, 0x15) + world.level_gfx_table.insert(44, 0x15) + world.level_gfx_table.insert(44, 0x15) + world.level_gfx_table.insert(44, 0x11) + + world.level_gfx_table.insert(56, 0x15) + world.level_gfx_table.insert(56, 0x15) + world.level_gfx_table.insert(56, 0x15) + world.level_gfx_table.insert(56, 0x15) + + castle_door_dict = { + 0: [0xB8, 0x05, 0x77, 0x00], + 1: [0xB8, 0x05, 0x77, 0x00], + 2: [0xC6, 0x07, 0x7A, 0x00], + 3: [0xCD, 0x05, 0x5B, 0x00], + 4: [0xD3, 0x00, 0x77, 0x06], + 5: [0xB8, 0x05, 0x77, 0x00], + } + + world.castle_door = castle_door_dict[world.options.bowser_door_mode.value] + + world.world_1_stages = world.global_level_list[0:8] + world.world_2_stages = world.global_level_list[8:16] + world.world_3_stages = world.global_level_list[16:24] + world.world_4_stages = world.global_level_list[24:32] + world.world_5_stages = world.global_level_list[32:40] + world.world_6_stages = world.global_level_list[40:47] + + world.world_1_stages.extend([0x08, 0x09]) + world.world_2_stages.extend([0x14, 0x15]) + world.world_3_stages.extend([0x20, 0x21]) + world.world_4_stages.extend([0x2C, 0x2D]) + world.world_5_stages.extend([0x38, 0x39]) + world.world_6_stages.extend([0x43, 0x44, 0x45]) + + bowser_text_table = { + 0: [0xDE, 0xEE, 0xDC, 0xDC, 0xE5], # Gween + 1: [0xE7, 0xE0, 0xE5, 0xE2, 0xD0], # Pink + 3: [0xEB, 0xDF, 0xF0, 0xD8, 0xE5], # Thyan + 2: [0xF0, 0xDC, 0xEE, 0xEE, 0xE6], # Yewow + 4: [0xE7, 0xEC, 0xDF, 0xE7, 0xE3], # puhpl + 5: [0xD9, 0xEE, 0xE6, 0xEE, 0xE5], # Bwown + 6: [0xEE, 0xDC, 0xDB, 0xD0, 0xD0], # Wed + 7: [0xD9, 0xEE, 0xEC, 0xDC, 0xD0], # Bwue + } + + if world.options.yoshi_colors == YoshiColors.option_random_order: + world.bowser_text = bowser_text_table[world.leader_color] + else: + world.bowser_text = bowser_text_table[world.level_colors[67]]