From 1ee9467891709d2503f9644082d4130877420c85 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:18:23 -0600 Subject: [PATCH 01/30] Create d --- mariomissing/d | 1 + 1 file changed, 1 insertion(+) create mode 100644 mariomissing/d diff --git a/mariomissing/d b/mariomissing/d new file mode 100644 index 000000000000..4bcfe98e640c --- /dev/null +++ b/mariomissing/d @@ -0,0 +1 @@ +d From f14c704a366ceffe61c60f46089912bb49070295 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:40:46 -0600 Subject: [PATCH 02/30] Create d --- worlds/mariomissing/d | 1 + 1 file changed, 1 insertion(+) create mode 100644 worlds/mariomissing/d diff --git a/worlds/mariomissing/d b/worlds/mariomissing/d new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/worlds/mariomissing/d @@ -0,0 +1 @@ + From cad67a885c91578ab5f60487c472730bddf8fc7f Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:41:05 -0600 Subject: [PATCH 03/30] Delete worlds/mariomissing/d --- worlds/mariomissing/d | 1 - 1 file changed, 1 deletion(-) delete mode 100644 worlds/mariomissing/d diff --git a/worlds/mariomissing/d b/worlds/mariomissing/d deleted file mode 100644 index 8b137891791f..000000000000 --- a/worlds/mariomissing/d +++ /dev/null @@ -1 +0,0 @@ - From 1e6d15f8f5244ebe1fb3dad2fbc4975876bf4cdd Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:41:48 -0600 Subject: [PATCH 04/30] Delete mariomissing directory --- mariomissing/d | 1 - 1 file changed, 1 deletion(-) delete mode 100644 mariomissing/d diff --git a/mariomissing/d b/mariomissing/d deleted file mode 100644 index 4bcfe98e640c..000000000000 --- a/mariomissing/d +++ /dev/null @@ -1 +0,0 @@ -d From 4a964e49591992b984443d987f07dba43669f5b3 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:42:54 -0600 Subject: [PATCH 05/30] Create d --- worlds/mariomissing/d | 1 + 1 file changed, 1 insertion(+) create mode 100644 worlds/mariomissing/d diff --git a/worlds/mariomissing/d b/worlds/mariomissing/d new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/worlds/mariomissing/d @@ -0,0 +1 @@ + From 5f3608b14a81c47cc7687842bc47ef4c431eab07 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:44:56 -0600 Subject: [PATCH 06/30] Add files via upload --- worlds/mariomissing/Client.py | 146 +++++++ worlds/mariomissing/Items.py | 105 +++++ worlds/mariomissing/Locations.py | 535 +++++++++++++++++++++++ worlds/mariomissing/Options.py | 24 ++ worlds/mariomissing/Regions.py | 97 +++++ worlds/mariomissing/Rom.py | 698 +++++++++++++++++++++++++++++++ worlds/mariomissing/SetupGame.py | 27 ++ worlds/mariomissing/__init__.py | 251 +++++++++++ 8 files changed, 1883 insertions(+) create mode 100644 worlds/mariomissing/Client.py create mode 100644 worlds/mariomissing/Items.py create mode 100644 worlds/mariomissing/Locations.py create mode 100644 worlds/mariomissing/Options.py create mode 100644 worlds/mariomissing/Regions.py create mode 100644 worlds/mariomissing/Rom.py create mode 100644 worlds/mariomissing/SetupGame.py create mode 100644 worlds/mariomissing/__init__.py diff --git a/worlds/mariomissing/Client.py b/worlds/mariomissing/Client.py new file mode 100644 index 000000000000..e89ee0036b7b --- /dev/null +++ b/worlds/mariomissing/Client.py @@ -0,0 +1,146 @@ +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 +else: + SNIContext = typing.Any + +snes_logger = logging.getLogger("SNES") + +GAME_MIM = "Mario is Missing" + +ROM_START = 0x000000 +WRAM_START = 0xF50000 +WRAM_SIZE = 0x20000 +SRAM_START = 0xE00000 + +MIM_ROMHASH_START = 0x007FC0 +ROMHASH_SIZE = 0x0F + +ITEM_RECEIVED = WRAM_START + 0x1550 +ITEM_LIST = WRAM_START + 0x1551 +DEATH_RECEIVED = WRAM_START + 0x1554 +GOAL_FLAG = WRAM_START + 0x1543 +VALIDATION_CHECK = WRAM_START + 0x1545 +VALIDATION_CHECK_2 = WRAM_START + 0x1546 +MIM_DEATHLINK_ENABLED = ROM_START + 0x0FFF11 + +class MIMSNIClient(SNIClient): + game = "Mario is Missing" + + async def deathlink_kill_player(self, ctx): + from SNIClient import DeathState, snes_buffered_write, snes_flush_writes, snes_read + validation_check_low = await snes_read(ctx, VALIDATION_CHECK, 0x1) + if validation_check_low[0] != 0x69: + return + + validation_check_high = await snes_read(ctx, VALIDATION_CHECK_2, 0x1) + if validation_check_high[0] != 0x42: + return + + snes_buffered_write(ctx, WRAM_START + 0x0565, bytes([0x84])) + snes_buffered_write(ctx, WRAM_START + 0x0566, bytes([0x03])) + await snes_flush_writes(ctx) + ctx.death_state = DeathState.dead + ctx.last_death_link = time.time() + + async def validate_rom(self, ctx): + from SNIClient import snes_buffered_write, snes_flush_writes, snes_read + + rom_name = await snes_read(ctx, MIM_ROMHASH_START, ROMHASH_SIZE) + if rom_name is None or rom_name == bytes([0] * ROMHASH_SIZE) or rom_name[:14] != b"MarioMissingAP": + return False + + ctx.game = self.game + ctx.items_handling = 0b111 # remote items + ctx.rom = rom_name + + death_link = await snes_read(ctx, MIM_DEATHLINK_ENABLED, 1) + if death_link: + await ctx.update_death_link(bool(death_link[0] & 0b1)) + return True + + async def game_watcher(self, ctx): + from SNIClient import snes_buffered_write, snes_flush_writes, snes_read + + + validation_check_low = await snes_read(ctx, VALIDATION_CHECK, 0x1) + validation_check_high = await snes_read(ctx, VALIDATION_CHECK_2, 0x1) + goal_done = await snes_read(ctx, GOAL_FLAG, 0x1) + current_item = await snes_read(ctx, ITEM_RECEIVED, 0x1) + is_dead = await snes_read(ctx, DEATH_RECEIVED, 0x1) + + if "DeathLink" in ctx.tags and ctx.last_death_link + 1 < time.time(): + currently_dead = is_dead[0] == 0x01 + await ctx.handle_deathlink_state(currently_dead) + if is_dead[0] != 0x00: + snes_buffered_write(ctx, WRAM_START + 0x1554, bytes([0x00])) + if validation_check_low is None: + return + + if validation_check_high is None: + return + if validation_check_low[0] != 0x69: + return + if validation_check_high[0] != 0x42: + return + if current_item[0] > 0x00: + return + if goal_done[0] == 0x69: + await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) + ctx.finished_game = True + + rom = await snes_read(ctx, MIM_ROMHASH_START, ROMHASH_SIZE) + if rom != ctx.rom: + ctx.rom = None + return + + new_checks = [] + from .Rom import location_table, item_values + + location_ram_data = await snes_read(ctx, WRAM_START + 0x1555, 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] - 0x1555] + 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] + snes_logger.info( + f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})') + await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) + + recv_count = await snes_read(ctx, ITEM_LIST, 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, ITEM_LIST, 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/mariomissing/Items.py b/worlds/mariomissing/Items.py new file mode 100644 index 000000000000..3da72ca3a9c9 --- /dev/null +++ b/worlds/mariomissing/Items.py @@ -0,0 +1,105 @@ +from typing import Dict, Set, Tuple, NamedTuple + +class ItemData(NamedTuple): + category: str + code: int + amount: int = 1 + progression: bool = False + progression_skip_balancing: bool = False + useful: bool = False + trap: bool = False + +item_table: Dict[str, ItemData] = { + #Rome + "Gladiator's Spear": ItemData('Artifacts', 0x198401, progression=True), + 'Coins from the Trevi Fountain': ItemData('Artifacts', 0x198402, progression=True), + 'Sistine Chapel Ceiling': ItemData('Artifacts', 0x198403, progression=True), + #Paris + 'Notre Dame Bell': ItemData('Artifacts', 0x198404, progression=True), + 'Eternal Flame': ItemData('Artifacts', 0x198405, progression=True), + 'Tricolor': ItemData('Artifacts', 0x198406, progression=True), + #London + 'Crown Jewels': ItemData('Artifacts', 0x198407, progression=True), + 'Bust of Shakespeare': ItemData('Artifacts', 0x198408, progression=True), + "Big Ben's Minute Hand": ItemData('Artifacts', 0x198409, progression=True), + #New York + 'King Kong': ItemData('Artifacts', 0x19840A, progression=True), + 'Statue of Liberty Torch': ItemData('Artifacts', 0x19840B, progression=True), + "Statue of Prometheus": ItemData('Artifacts', 0x19840C, progression=True), + #San Francisco + 'Golden Gate Bridge Foghorn': ItemData('Artifacts', 0x19840D, progression=True), + 'Window from Coit Tower': ItemData('Artifacts', 0x19840E, progression=True), + "Top of the Transamerica Pyramid": ItemData('Artifacts', 0x19840F, progression=True), + #Athens + 'Caryatid': ItemData('Artifacts', 0x198410, progression=True), + 'Brass Plaque': ItemData('Artifacts', 0x198411, progression=True), + "Parthenon Column": ItemData('Artifacts', 0x198412, progression=True), + #Sydney + 'Surfboard from Bondi Beach': ItemData('Artifacts', 0x198413, progression=True), + 'Taronga Zoo Koala': ItemData('Artifacts', 0x198414, progression=True), + "Sydney Opera Sheet Music": ItemData('Artifacts', 0x198415, progression=True), + #Tokyo + "Great Buddha's Orange": ItemData('Artifacts', 0x198416, progression=True), + 'Sensoji Temple Latern': ItemData('Artifacts', 0x198417, progression=True), + "Sumo Apron": ItemData('Artifacts', 0x198418, progression=True), + #Nairobi + 'Baby Elephant': ItemData('Artifacts', 0x198419, progression=True), + 'Maasai Headdress': ItemData('Artifacts', 0x19841A, progression=True), + "Human Skull": ItemData('Artifacts', 0x19841B, progression=True), + #Rio de Janeiro + 'Spotlight from Christ the Redeemer Statue': ItemData('Artifacts', 0x19841C, progression=True), + 'Copacabana Beach Seashell': ItemData('Artifacts', 0x19841D, progression=True), + "Sugar Loaf Mountain Cable Car": ItemData('Artifacts', 0x19841E, progression=True), + #Cairo + 'Top Brick of the Great Pyramid': ItemData('Artifacts', 0x19841F, progression=True), + 'Gingerbread Clock': ItemData('Artifacts', 0x198420, progression=True), + "Klaft of the Sphinx": ItemData('Artifacts', 0x198421, progression=True), + #Moscow + "Cannonball from the Emperor's Cannon": ItemData('Artifacts', 0x198422, progression=True), + 'Cathedral Dome': ItemData('Artifacts', 0x198423, progression=True), + "Bolshoi Ballet Slipper": ItemData('Artifacts', 0x198424, progression=True), + #Beijing + 'Hall of Good Harvest': ItemData('Artifacts', 0x198425, progression=True), + 'Stone from the Great Wall': ItemData('Artifacts', 0x198426, progression=True), + "Gate of Heavenly Peace": ItemData('Artifacts', 0x198427, progression=True), + #Buenos Aires + 'Flute from the Teatro Colon': ItemData('Artifacts', 0x198428, progression=True), + 'Boleadoras': ItemData('Artifacts', 0x198429, progression=True), + "Stone from the Obelisk": ItemData('Artifacts', 0x19842A, progression=True), + #Mexico City + 'Angel': ItemData('Artifacts', 0x19842B, progression=True), + 'Diego Rivera Mural': ItemData('Artifacts', 0x19842C, progression=True), + "Fine Arts Catalog": ItemData('Artifacts', 0x19842D, progression=True), + + "Castle Floor Key": ItemData('Other', 0x19842E, 2, progression=True), + "Newspaper": ItemData('Other', 0x19842F), + "Mario": ItemData('Events', None, 0, progression=True), + "Artifact Secured": ItemData('Events', None, 0, progression=True), + "Photograph": ItemData('Other', 0x198430), + "Advice": ItemData('Other', 0x198431) + +} + +filler_items: Tuple[str, ...] = ( + 'Photograph', + 'Newspaper', + 'Advice' +) + +artifacts: Tuple[str, ...] = ( + "Gladiator's Spear" + "Coins from the Trevi Fountain" + "Sistine Chapel Ceiling" + "Notre Dame Bell" + "Eternal Flame" + "Tricolor" +) + +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/mariomissing/Locations.py b/worlds/mariomissing/Locations.py new file mode 100644 index 000000000000..05a30cc0845a --- /dev/null +++ b/worlds/mariomissing/Locations.py @@ -0,0 +1,535 @@ +from typing import List, Tuple, Optional, Callable, NamedTuple +from BaseClasses import MultiWorld + + +class LocationData(NamedTuple): + region: str + name: str + code: Optional[int] + rule: Callable = lambda state: True + + +def get_locations(multiworld: Optional[MultiWorld], player: Optional[int], world) -> Tuple[LocationData, ...]: + + location_table: List[LocationData] = [ + + LocationData('Rome', 'Rome - Koopa Treasure 1', 0x198400), + LocationData('Rome', 'Rome - Koopa Treasure 2', 0x198401), + LocationData('Rome', 'Rome - Koopa Treasure 3', 0x198402), + LocationData('Rome', 'Colosseum - Photograph', 0x198403, lambda state:state.has("Gladiator's Spear", player)), + LocationData('Rome', 'Trevi Fountain - Photograph', 0x198404, lambda state:state.has('Coins from the Trevi Fountain', player)), + LocationData('Rome', 'Sistine Chapel - Photograph', 0x198405, lambda state:state.has("Sistine Chapel Ceiling", player)), + + LocationData('Paris', 'Paris - Koopa Treasure 1', 0x198406), + LocationData('Paris', 'Paris - Koopa Treasure 2', 0x198407), + LocationData('Paris', 'Paris - Koopa Treasure 3', 0x198408), + LocationData('Paris', 'Cathedral of Notre Dame - Photograph', 0x198409, lambda state: state.has('Notre Dame Bell', player)), + LocationData('Paris', 'Arc de Triomphe - Photograph', 0x19840A, lambda state: state.has('Eternal Flame', player)), + LocationData('Paris', 'Eiffel Tower - Photograph', 0x19840B, lambda state: state.has('Tricolor', player)), + + LocationData('London', 'London - Koopa Treasure 1', 0x19840C), + LocationData('London', 'London - Koopa Treasure 2', 0x19840D), + LocationData('London', 'London - Koopa Treasure 3', 0x19840E), + LocationData('London', 'Tower of London - Photograph', 0x19840F, lambda state: state.has('Crown Jewels', player)), + LocationData('London', 'Westminster Abbey - Photograph', 0x198410, lambda state: state.has('Bust of Shakespeare', player)), + LocationData('London', 'Big Ben - Photograph', 0x198411, lambda state: state.has("Big Ben's Minute Hand", player)), + + LocationData('New York', 'New York - Koopa Treasure 1', 0x198412), + LocationData('New York', 'New York - Koopa Treasure 2', 0x198413), + LocationData('New York', 'New York - Koopa Treasure 3', 0x198414), + LocationData('New York', 'Empire State Building - Photograph', 0x198415, lambda state: state.has('King Kong', player)), + LocationData('New York', 'Statue of Liberty - Photograph', 0x198416, lambda state: state.has('Statue of Liberty Torch', player)), + LocationData('New York', 'Rockefeller Center - Photograph', 0x198417, lambda state: state.has('Statue of Prometheus', player)), + + LocationData('San Francisco', 'San Francisco - Koopa Treasure 1', 0x198418), + LocationData('San Francisco', 'San Francisco - Koopa Treasure 2', 0x198419), + LocationData('San Francisco', 'San Francisco - Koopa Treasure 3', 0x19841A), + LocationData('San Francisco', 'Golden Gate Bridge - Photograph', 0x19841B, lambda state: state.has('Golden Gate Bridge Foghorn', player)), + LocationData('San Francisco', 'Coit Tower - Photograph', 0x19841C, lambda state: state.has('Window from Coit Tower', player)), + LocationData('San Francisco', 'Transamerica Pyramid - Photograph', 0x1981D, lambda state: state.has('Top of the Transamerica Pyramid', player)), + + LocationData('Athens', 'Athens - Koopa Treasure 1', 0x19841E), + LocationData('Athens', 'Athens - Koopa Treasure 2', 0x19841F), + LocationData('Athens', 'Athens - Koopa Treasure 3', 0x198420), + LocationData('Athens', 'Erechtheion Temple - Photograph', 0x198421, lambda state: state.has('Caryatid', player)), + LocationData('Athens', "Hadrian's Arch - Photograph", 0x198422, lambda state: state.has('Brass Plaque', player)), + LocationData('Athens', 'Parthenon - Photograph', 0x198423, lambda state: state.has('Parthenon Column', player)), + + LocationData('Sydney', 'Sydney - Koopa Treasure 1', 0x198424), + LocationData('Sydney', 'Sydney - Koopa Treasure 2', 0x198425), + LocationData('Sydney', 'Sydney - Koopa Treasure 3', 0x198426), + LocationData('Sydney', 'Bondi Beach - Photograph', 0x198427, lambda state: state.has('Surfboard from Bondi Beach', player)), + LocationData('Sydney', 'Taronga Zoo - Photograph', 0x198428, lambda state: state.has('Taronga Zoo Koala', player)), + LocationData('Sydney', 'Sydney Opera - Photograph', 0x198429, lambda state: state.has('Sydney Opera Sheet Music', player)), + + LocationData('Tokyo', 'Tokyo - Koopa Treasure 1', 0x19842A), + LocationData('Tokyo', 'Tokyo - Koopa Treasure 2', 0x19842B), + LocationData('Tokyo', 'Tokyo - Koopa Treasure 3', 0x19842C), + LocationData('Tokyo', 'Great Buddha of Kamakura - Photograph', 0x19842D, lambda state: state.has("Great Buddha's Orange", player)), + LocationData('Tokyo', 'Sensoji Temple - Photograph', 0x19842E, lambda state: state.has('Sensoji Temple Latern', player)), + LocationData('Tokyo', 'Kokugikan Arena - Photograph', 0x19842F, lambda state: state.has('Sumo Apron', player)), + + LocationData('Nairobi', 'Nairobi - Koopa Treasure 1', 0x198430), + LocationData('Nairobi', 'Nairobi - Koopa Treasure 2', 0x198431), + LocationData('Nairobi', 'Nairobi - Koopa Treasure 3', 0x198432), + LocationData('Nairobi', 'Nairobi National Park - Photograph', 0x198433, lambda state: state.has('Baby Elephant', player)), + LocationData('Nairobi', 'Maasai Village - Photograph', 0x198434, lambda state: state.has('Maasai Headdress', player)), + LocationData('Nairobi', 'National Museum of Kenya - Photograph', 0x198435, lambda state: state.has('Human Skull', player)), + + LocationData('Rio de Janeiro', 'Rio de Janeiro - Koopa Treasure 1', 0x198436), + LocationData('Rio de Janeiro', 'Rio de Janeiro - Koopa Treasure 2', 0x198437), + LocationData('Rio de Janeiro', 'Rio de Janeiro - Koopa Treasure 3', 0x198438), + LocationData('Rio de Janeiro', 'Christ the Redeemer Statue - Photograph', 0x198439, lambda state: state.has('Spotlight from Christ the Redeemer Statue', player)), + LocationData('Rio de Janeiro', 'Copacabana Beach - Photograph', 0x19843A, lambda state: state.has('Copacabana Beach Seashell', player)), + LocationData('Rio de Janeiro', 'Sugar Loaf Mountain - Photograph', 0x19843B, lambda state: state.has('Sugar Loaf Mountain Cable Car', player)), + + LocationData('Cairo', 'Cairo - Koopa Treasure 1', 0x19843C), + LocationData('Cairo', 'Cairo - Koopa Treasure 2', 0x19843D), + LocationData('Cairo', 'Cairo - Koopa Treasure 3', 0x19843E), + LocationData('Cairo', 'Great Pyramid - Photograph', 0x19843F, lambda state: state.has('Top Brick of the Great Pyramid', player)), + LocationData('Cairo', 'Mosque of Mohammed - Photograph', 0x198440, lambda state: state.has('Gingerbread Clock', player)), + LocationData('Cairo', 'Sphinx - Photograph', 0x198441, lambda state: state.has('Klaft of the Sphinx', player)), + + LocationData('Moscow', 'Moscow - Koopa Treasure 1', 0x198442), + LocationData('Moscow', 'Moscow - Koopa Treasure 2', 0x198443), + LocationData('Moscow', 'Moscow - Koopa Treasure 3', 0x198444), + LocationData('Moscow', 'Kremlin - Photograph', 0x198445, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), + LocationData('Moscow', "St. Basil's Cathedral - Photograph", 0x198446, lambda state: state.has('Cathedral Dome', player)), + LocationData('Moscow', 'Bolshoi Ballet - Photograph', 0x198447, lambda state: state.has('Bolshoi Ballet Slipper', player)), + + LocationData('Beijing', 'Beijing - Koopa Treasure 1', 0x198448), + LocationData('Beijing', 'Beijing - Koopa Treasure 2', 0x198449), + LocationData('Beijing', 'Beijing - Koopa Treasure 3', 0x19844A), + LocationData('Beijing', 'Temple of Heaven - Photograph', 0x19844B, lambda state: state.has('Hall of Good Harvest', player)), + LocationData('Beijing', 'Great Wall of China - Photograph', 0x19844C, lambda state: state.has('Stone from the Great Wall', player)), + LocationData('Beijing', 'Forbidden City - Photograph', 0x19844D, lambda state: state.has('Gate of Heavenly Peace', player)), + + LocationData('Buenos Aires', 'Buenos Aires - Koopa Treasure 1', 0x19844E), + LocationData('Buenos Aires', 'Buenos Aires - Koopa Treasure 2', 0x19844F), + LocationData('Buenos Aires', 'Buenos Aires - Koopa Treasure 3', 0x198450), + LocationData('Buenos Aires', 'Teatro Colon - Photograph', 0x198451, lambda state: state.has('Flute from the Teatro Colon', player)), + LocationData('Buenos Aires', 'Gaucho Museum - Photograph', 0x198452, lambda state: state.has('Boleadoras', player)), + LocationData('Buenos Aires', 'Obelisk Monument - Photograph', 0x198453, lambda state: state.has('Stone from the Obelisk', player)), + + LocationData('Mexico City', 'Mexico City - Koopa Treasure 1', 0x198454), + LocationData('Mexico City', 'Mexico City - Koopa Treasure 2', 0x198455), + LocationData('Mexico City', 'Mexico City - Koopa Treasure 3', 0x198456), + LocationData('Mexico City', 'Angel of Independence - Photograph', 0x198457, lambda state: state.has('Angel', player)), + LocationData('Mexico City', 'National Palace - Photograph', 0x198458, lambda state: state.has('Diego Rivera Mural', player)), + LocationData('Mexico City', 'Fine Arts Palace - Photograph', 0x198459, lambda state: state.has('Fine Arts Catalog', player)), + + + LocationData('Rome', 'Colosseum - Return Artifact', None, lambda state:state.has("Gladiator's Spear", player)), + LocationData('Rome', 'Trevi Fountain - Return Artifact', None, lambda state:state.has('Coins from the Trevi Fountain', player)), + LocationData('Rome', 'Sistine Chapel - Return Artifact', None, lambda state:state.has("Sistine Chapel Ceiling", player)), + LocationData('Paris', 'Cathedral of Notre Dame - Return Artifact', None, lambda state: state.has('Notre Dame Bell', player)), + LocationData('Paris', 'Arc de Triomphe - Return Artifact', None, lambda state: state.has('Eternal Flame', player)), + LocationData('Paris', 'Eiffel Tower - Return Artifact', None, lambda state: state.has('Tricolor', player)), + LocationData('London', 'Tower of London - Return Artifact', None, lambda state: state.has('Crown Jewels', player)), + LocationData('London', 'Westminster Abbey - Return Artifact', None, lambda state: state.has('Bust of Shakespeare', player)), + LocationData('London', 'Big Ben - Return Artifact', None, lambda state: state.has("Big Ben's Minute Hand", player)), + LocationData('New York', 'Empire State Building - Return Artifact', None, lambda state: state.has('King Kong', player)), + LocationData('New York', 'Statue of Liberty - Return Artifact', None, lambda state: state.has('Statue of Liberty Torch', player)), + LocationData('New York', 'Rockefeller Center - Return Artifact', None, lambda state: state.has('Statue of Prometheus', player)), + LocationData('San Francisco', 'Golden Gate Bridge - Return Artifact', None, lambda state: state.has('Golden Gate Bridge Foghorn', player)), + LocationData('San Francisco', 'Coit Tower - Return Artifact', None, lambda state: state.has('Window from Coit Tower', player)), + LocationData('San Francisco', 'Transamerica Pyramid - Return Artifact', None, lambda state: state.has('Top of the Transamerica Pyramid', player)), + LocationData('Athens', 'Erechtheion Temple - Return Artifact', None, lambda state: state.has('Caryatid', player)), + LocationData('Athens', "Hadrian's Arch - Return Artifact", None, lambda state: state.has('Brass Plaque', player)), + LocationData('Athens', 'Parthenon - Return Artifact', None, lambda state: state.has('Parthenon Column', player)), + LocationData('Sydney', 'Bondi Beach - Return Artifact', None, lambda state: state.has('Surfboard from Bondi Beach', player)), + LocationData('Sydney', 'Taronga Zoo - Return Artifact', None, lambda state: state.has('Taronga Zoo Koala', player)), + LocationData('Sydney', 'Sydney Opera - Return Artifact', None, lambda state: state.has('Sydney Opera Sheet Music', player)), + LocationData('Tokyo', 'Great Buddha of Kamakura - Return Artifact', None, lambda state: state.has("Great Buddha's Orange", player)), + LocationData('Tokyo', 'Sensoji Temple - Return Artifact', None, lambda state: state.has('Sensoji Temple Latern', player)), + LocationData('Tokyo', 'Kokugikan Arena - Return Artifact', None, lambda state: state.has('Sumo Apron', player)), + LocationData('Nairobi', 'Nairobi National Park - Return Artifact', None, lambda state: state.has('Baby Elephant', player)), + LocationData('Nairobi', 'Maasai Village - Return Artifact', None, lambda state: state.has('Maasai Headdress', player)), + LocationData('Nairobi', 'National Museum of Kenya - Return Artifact', None, lambda state: state.has('Human Skull', player)), + LocationData('Rio de Janeiro', 'Christ the Redeemer Statue - Return Artifact', None, lambda state: state.has('Spotlight from Christ the Redeemer Statue', player)), + LocationData('Rio de Janeiro', 'Copacabana Beach - Return Artifact', None, lambda state: state.has('Copacabana Beach Seashell', player)), + LocationData('Rio de Janeiro', 'Sugar Loaf Mountain - Return Artifact', None, lambda state: state.has('Sugar Loaf Mountain Cable Car', player)), + LocationData('Cairo', 'Great Pyramid - Return Artifact', None, lambda state: state.has('Top Brick of the Great Pyramid', player)), + LocationData('Cairo', 'Mosque of Mohammed - Return Artifact', None, lambda state: state.has('Gingerbread Clock', player)), + LocationData('Cairo', 'Sphinx - Return Artifact', None, lambda state: state.has('Klaft of the Sphinx', player)), + LocationData('Moscow', 'Kremlin - Return Artifact', None, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), + LocationData('Moscow', "St. Basil's Cathedral - Return Artifact", None, lambda state: state.has('Cathedral Dome', player)), + LocationData('Moscow', 'Bolshoi Ballet - Return Artifact', None, lambda state: state.has('Bolshoi Ballet Slipper', player)), + LocationData('Beijing', 'Temple of Heaven - Return Artifact', None, lambda state: state.has('Hall of Good Harvest', player)), + LocationData('Beijing', 'Great Wall of China - Return Artifact', None, lambda state: state.has('Stone from the Great Wall', player)), + LocationData('Beijing', 'Forbidden City - Return Artifact', None, lambda state: state.has('Gate of Heavenly Peace', player)), + LocationData('Buenos Aires', 'Teatro Colon - Return Artifact', None, lambda state: state.has('Flute from the Teatro Colon', player)), + LocationData('Buenos Aires', 'Gaucho Museum - Return Artifact', None, lambda state: state.has('Boleadoras', player)), + LocationData('Buenos Aires', 'Obelisk Monument - Return Artifact', None, lambda state: state.has('Stone from the Obelisk', player)), + LocationData('Mexico City', 'Angel of Independence - Return Artifact', None, lambda state: state.has('Angel', player)), + LocationData('Mexico City', 'National Palace - Return Artifact', None, lambda state: state.has('Diego Rivera Mural', player)), + LocationData('Mexico City', 'Fine Arts Palace - Return Artifact', None, lambda state: state.has('Fine Arts Catalog', player)), + + LocationData('Castle Floor 4', 'Bowser', None) + ] + + if not multiworld or world.options.computer_sanity.value == 1: + location_table += ( + LocationData("Rome", "Rome - Colosseum - Newspaper Article", 0x19845A), + LocationData("Rome", "Rome - Trevi Fountain - Newspaper Article", 0x19845B), + LocationData("Rome", "Rome - Sistine Chapel - Newspaper Article", 0x19845C), + LocationData("Rome", "Rome - Scientist - Location Advice", 0x19845D), + LocationData("Rome", "Rome - Scientist - Artifact 1 Advice", 0x19845E, lambda state: state.has("Gladiator's Spear", player)), + LocationData("Rome", "Rome - Scientist - Artifact 2 Advice", 0x19845F, lambda state: state.has("Coins from the Trevi Fountain", player)), + LocationData("Rome", "Rome - Scientist - Artifact 3 Advice", 0x198460, lambda state: state.has("Sistine Chapel Ceiling", player)), + LocationData("Rome", "Rome - Officer - Location Advice", 0x198461), + LocationData("Rome", "Rome - Officer - Artifact 1 Advice", 0x198462, lambda state: state.has("Gladiator's Spear", player)), + LocationData("Rome", "Rome - Officer - Artifact 2 Advice", 0x198463, lambda state: state.has("Coins from the Trevi Fountain", player)), + LocationData("Rome", "Rome - Officer - Artifact 3 Advice", 0x198464, lambda state: state.has("Sistine Chapel Ceiling", player)), + LocationData("Rome", "Rome - Child - Location Advice", 0x198465), + LocationData("Rome", "Rome - Child - Artifact 1 Advice", 0x198466, lambda state: state.has("Gladiator's Spear", player)), + LocationData("Rome", "Rome - Child - Artifact 2 Advice", 0x198467, lambda state: state.has("Coins from the Trevi Fountain", player)), + LocationData("Rome", "Rome - Child - Artifact 3 Advice", 0x198468, lambda state: state.has("Sistine Chapel Ceiling", player)), + LocationData("Rome", "Rome - Tourist - Location Advice", 0x198469), + LocationData("Rome", "Rome - Tourist - Artifact 1 Advice", 0x19846A, lambda state: state.has("Gladiator's Spear", player)), + LocationData("Rome", "Rome - Tourist - Artifact 2 Advice", 0x19846B, lambda state: state.has("Coins from the Trevi Fountain", player)), + LocationData("Rome", "Rome - Tourist - Artifact 3 Advice", 0x19846C, lambda state: state.has("Sistine Chapel Ceiling", player)), + LocationData("Rome", "Rome - Businesswoman - Location Advice", 0x19846D), + LocationData("Rome", "Rome - Businesswoman - Artifact 1 Advice", 0x19846E, lambda state: state.has("Gladiator's Spear", player)), + LocationData("Rome", "Rome - Businesswoman - Artifact 2 Advice", 0x19846F, lambda state: state.has("Coins from the Trevi Fountain", player)), + LocationData("Rome", "Rome - Businesswoman - Artifact 3 Advice", 0x198470, lambda state: state.has("Sistine Chapel Ceiling", player)), + + LocationData("Paris", "Paris - Cathedral of Notre Dame - Newspaper Article", 0x198471), + LocationData("Paris", "Paris - Arc de Triomphe - Newspaper Article", 0x198472), + LocationData("Paris", "Paris - Eiffel Tower - Newspaper Article", 0x198473), + LocationData("Paris", "Paris - Scientist - Location Advice", 0x198474), + LocationData("Paris", "Paris - Scientist - Artifact 1 Advice", 0x198475, lambda state: state.has("Notre Dame Bell", player)), + LocationData("Paris", "Paris - Scientist - Artifact 2 Advice", 0x198476, lambda state: state.has("Eternal Flame", player)), + LocationData("Paris", "Paris - Scientist - Artifact 3 Advice", 0x198477, lambda state: state.has("Tricolor", player)), + LocationData("Paris", "Paris - Officer - Location Advice", 0x198478), + LocationData("Paris", "Paris - Officer - Artifact 1 Advice", 0x198479, lambda state: state.has("Notre Dame Bell", player)), + LocationData("Paris", "Paris - Officer - Artifact 2 Advice", 0x19847A, lambda state: state.has("Eternal Flame", player)), + LocationData("Paris", "Paris - Officer - Artifact 3 Advice", 0x19847B, lambda state: state.has("Tricolor", player)), + LocationData("Paris", "Paris - Child - Location Advice", 0x19847C), + LocationData("Paris", "Paris - Child - Artifact 1 Advice", 0x19847D, lambda state: state.has("Notre Dame Bell", player)), + LocationData("Paris", "Paris - Child - Artifact 2 Advice", 0x19847E, lambda state: state.has("Eternal Flame", player)), + LocationData("Paris", "Paris - Child - Artifact 3 Advice", 0x19847F, lambda state: state.has("Tricolor", player)), + LocationData("Paris", "Paris - Tourist - Location Advice", 0x198480), + LocationData("Paris", "Paris - Tourist - Artifact 1 Advice", 0x198481, lambda state: state.has("Notre Dame Bell", player)), + LocationData("Paris", "Paris - Tourist - Artifact 2 Advice", 0x198482, lambda state: state.has("Eternal Flame", player)), + LocationData("Paris", "Paris - Tourist - Artifact 3 Advice", 0x198483, lambda state: state.has("Tricolor", player)), + LocationData("Paris", "Paris - Businesswoman - Location Advice", 0x198484), + LocationData("Paris", "Paris - Businesswoman - Artifact 1 Advice", 0x198485, lambda state: state.has("Notre Dame Bell", player)), + LocationData("Paris", "Paris - Businesswoman - Artifact 2 Advice", 0x198486, lambda state: state.has("Eternal Flame", player)), + LocationData("Paris", "Paris - Businesswoman - Artifact 3 Advice", 0x198487, lambda state: state.has("Tricolor", player)), + + LocationData("London", "London - Tower of London - Newspaper Article", 0x198488), + LocationData("London", "London - Westminster Abbey - Newspaper Article", 0x198489), + LocationData("London", "London - Big Ben - Newspaper Article", 0x19848A), + LocationData("London", "London - Scientist - Location Advice", 0x19848B), + LocationData("London", "London - Scientist - Artifact 1 Advice", 0x19848C, lambda state: state.has("Crown Jewels", player)), + LocationData("London", "London - Scientist - Artifact 2 Advice", 0x19848D, lambda state: state.has("Bust of Shakespeare", player)), + LocationData("London", "London - Scientist - Artifact 3 Advice", 0x19848E, lambda state: state.has("Big Ben's Minute Hand", player)), + LocationData("London", "London - Officer - Location Advice", 0x19848F), + LocationData("London", "London - Officer - Artifact 1 Advice", 0x198490, lambda state: state.has("Crown Jewels", player)), + LocationData("London", "London - Officer - Artifact 2 Advice", 0x198491, lambda state: state.has("Bust of Shakespeare", player)), + LocationData("London", "London - Officer - Artifact 3 Advice", 0x198492, lambda state: state.has("Big Ben's Minute Hand", player)), + LocationData("London", "London - Child - Location Advice", 0x198493), + LocationData("London", "London - Child - Artifact 1 Advice", 0x198494, lambda state: state.has("Crown Jewels", player)), + LocationData("London", "London - Child - Artifact 2 Advice", 0x198495, lambda state: state.has("Bust of Shakespeare", player)), + LocationData("London", "London - Child - Artifact 3 Advice", 0x198496, lambda state: state.has("Big Ben's Minute Hand", player)), + LocationData("London", "London - Tourist - Location Advice", 0x198497), + LocationData("London", "London - Tourist - Artifact 1 Advice", 0x198498, lambda state: state.has("Crown Jewels", player)), + LocationData("London", "London - Tourist - Artifact 2 Advice", 0x198499, lambda state: state.has("Bust of Shakespeare", player)), + LocationData("London", "London - Tourist - Artifact 3 Advice", 0x19849A, lambda state: state.has("Big Ben's Minute Hand", player)), + LocationData("London", "London - Businesswoman - Location Advice", 0x19849B), + LocationData("London", "London - Businesswoman - Artifact 1 Advice", 0x19849C, lambda state: state.has("Crown Jewels", player)), + LocationData("London", "London - Businesswoman - Artifact 2 Advice", 0x19849D, lambda state: state.has("Eternal Flame", player)), + LocationData("London", "London - Businesswoman - Artifact 3 Advice", 0x19849E, lambda state: state.has("Big Ben's Minute Hand", player)), + + LocationData("New York", "New York - Empire State Building - Newspaper Article", 0x19849F), + LocationData("New York", "New York - Statue of Liberty - Newspaper Article", 0x1984A0), + LocationData("New York", "New York - Rockefeller Center - Newspaper Article", 0x1984A1), + LocationData("New York", "New York - Scientist - Location Advice", 0x1984A2), + LocationData("New York", "New York - Scientist - Artifact 1 Advice", 0x1984A3, lambda state: state.has("King Kong", player)), + LocationData("New York", "New York - Scientist - Artifact 2 Advice", 0x1984A4, lambda state: state.has("Statue of Liberty Torch", player)), + LocationData("New York", "New York - Scientist - Artifact 3 Advice", 0x1984A5, lambda state: state.has("Statue of Prometheus", player)), + LocationData("New York", "New York - Officer - Location Advice", 0x1984A6), + LocationData("New York", "New York - Officer - Artifact 1 Advice", 0x1984A7, lambda state: state.has("King Kong", player)), + LocationData("New York", "New York - Officer - Artifact 2 Advice", 0x1984A8, lambda state: state.has("Statue of Liberty Torch", player)), + LocationData("New York", "New York - Officer - Artifact 3 Advice", 0x1984A9, lambda state: state.has("Statue of Prometheus", player)), + LocationData("New York", "New York - Child - Location Advice", 0x1984AA), + LocationData("New York", "New York - Child - Artifact 1 Advice", 0x1984AB, lambda state: state.has("King Kong", player)), + LocationData("New York", "New York - Child - Artifact 2 Advice", 0x1984AC, lambda state: state.has("Statue of Liberty Torch", player)), + LocationData("New York", "New York - Child - Artifact 3 Advice", 0x1984AD, lambda state: state.has("Statue of Prometheus", player)), + LocationData("New York", "New York - Tourist - Location Advice", 0x1984AE), + LocationData("New York", "New York - Tourist - Artifact 1 Advice", 0x1984AF, lambda state: state.has("King Kong", player)), + LocationData("New York", "New York - Tourist - Artifact 2 Advice", 0x1984B0, lambda state: state.has("Statue of Liberty Torch", player)), + LocationData("New York", "New York - Tourist - Artifact 3 Advice", 0x1984B1, lambda state: state.has("Statue of Prometheus", player)), + LocationData("New York", "New York - Businesswoman - Location Advice", 0x1984B2), + LocationData("New York", "New York - Businesswoman - Artifact 1 Advice", 0x1984B3, lambda state: state.has("King Kong", player)), + LocationData("New York", "New York - Businesswoman - Artifact 2 Advice", 0x1984B4, lambda state: state.has("Statue of Liberty Torch", player)), + LocationData("New York", "New York - Businesswoman - Artifact 3 Advice", 0x1984B5, lambda state: state.has("Statue of Prometheus", player)), + + LocationData("San Francisco", "San Francisco - Golden Gate Bridge - Newspaper Article", 0x1984B6), + LocationData("San Francisco", "San Francisco - Coit Tower - Newspaper Article", 0x1984B7), + LocationData("San Francisco", "San Francisco - Transamerica Pyramid - Newspaper Article", 0x1984B8), + LocationData("San Francisco", "San Francisco - Scientist - Location Advice", 0x1984B9), + LocationData("San Francisco", "San Francisco - Scientist - Artifact 1 Advice", 0x1984BA, lambda state: state.has("Golden Gate Bridge Foghorn", player)), + LocationData("San Francisco", "San Francisco - Scientist - Artifact 2 Advice", 0x1984BB, lambda state: state.has("Window from Coit Tower", player)), + LocationData("San Francisco", "San Francisco - Scientist - Artifact 3 Advice", 0x1984BC, lambda state: state.has("Top of the Transamerica Pyramid", player)), + LocationData("San Francisco", "San Francisco - Officer - Location Advice", 0x1984BD), + LocationData("San Francisco", "San Francisco - Officer - Artifact 1 Advice", 0x1984BE, lambda state: state.has("Golden Gate Bridge Foghorn", player)), + LocationData("San Francisco", "San Francisco - Officer - Artifact 2 Advice", 0x1984BF, lambda state: state.has("Window from Coit Tower", player)), + LocationData("San Francisco", "San Francisco - Officer - Artifact 3 Advice", 0x1984C0, lambda state: state.has("Top of the Transamerica Pyramid", player)), + LocationData("San Francisco", "San Francisco - Child - Location Advice", 0x1984C1), + LocationData("San Francisco", "San Francisco - Child - Artifact 1 Advice", 0x1984C2, lambda state: state.has("Golden Gate Bridge Foghorn", player)), + LocationData("San Francisco", "San Francisco - Child - Artifact 2 Advice", 0x1984C3, lambda state: state.has("Window from Coit Tower", player)), + LocationData("San Francisco", "San Francisco - Child - Artifact 3 Advice", 0x1984C4, lambda state: state.has("Top of the Transamerica Pyramid", player)), + LocationData("San Francisco", "San Francisco - Tourist - Location Advice", 0x1984C5), + LocationData("San Francisco", "San Francisco - Tourist - Artifact 1 Advice", 0x1984C6, lambda state: state.has("Golden Gate Bridge Foghorn", player)), + LocationData("San Francisco", "San Francisco - Tourist - Artifact 2 Advice", 0x1984C7, lambda state: state.has("Window from Coit Tower", player)), + LocationData("San Francisco", "San Francisco - Tourist - Artifact 3 Advice", 0x1984C8, lambda state: state.has("Top of the Transamerica Pyramid", player)), + LocationData("San Francisco", "San Francisco - Businesswoman - Location Advice", 0x1984C9), + LocationData("San Francisco", "San Francisco - Businesswoman - Artifact 1 Advice", 0x1984CA, lambda state: state.has("Golden Gate Bridge Foghorn", player)), + LocationData("San Francisco", "San Francisco - Businesswoman - Artifact 2 Advice", 0x1984CB, lambda state: state.has("Window from Coit Tower", player)), + LocationData("San Francisco", "San Francisco - Businesswoman - Artifact 3 Advice", 0x1984CC, lambda state: state.has("Top of the Transamerica Pyramid", player)), + + LocationData("Athens", "Athens - Erechtheion Temple - Newspaper Article", 0x1984CD), + LocationData("Athens", "Athens - Hadrian's Arch - Newspaper Article", 0x1984CE), + LocationData("Athens", "Athens - Sydney Opera - Newspaper Article", 0x1984CF), + LocationData("Athens", "Athens - Scientist - Location Advice", 0x1984D0), + LocationData("Athens", "Athens - Scientist - Artifact 1 Advice", 0x1984D1, lambda state: state.has("Caryatid", player)), + LocationData("Athens", "Athens - Scientist - Artifact 2 Advice", 0x1984D2, lambda state: state.has("Brass Plaque", player)), + LocationData("Athens", "Athens - Scientist - Artifact 3 Advice", 0x1984D3, lambda state: state.has("Parthenon Column", player)), + LocationData("Athens", "Athens - Officer - Location Advice", 0x1984D4), + LocationData("Athens", "Athens - Officer - Artifact 1 Advice", 0x1984D5, lambda state: state.has("Caryatid", player)), + LocationData("Athens", "Athens - Officer - Artifact 2 Advice", 0x1984D6, lambda state: state.has("Brass Plaque", player)), + LocationData("Athens", "Athens - Officer - Artifact 3 Advice", 0x1984D7, lambda state: state.has("Parthenon Column", player)), + LocationData("Athens", "Athens - Child - Location Advice", 0x1984D8), + LocationData("Athens", "Athens - Child - Artifact 1 Advice", 0x1984D9, lambda state: state.has("Caryatid", player)), + LocationData("Athens", "Athens - Child - Artifact 2 Advice", 0x1984DA, lambda state: state.has("Brass Plaque", player)), + LocationData("Athens", "Athens - Child - Artifact 3 Advice", 0x1984DB, lambda state: state.has("Parthenon Column", player)), + LocationData("Athens", "Athens - Tourist - Location Advice", 0x1984DC), + LocationData("Athens", "Athens - Tourist - Artifact 1 Advice", 0x1984DD, lambda state: state.has("Caryatid", player)), + LocationData("Athens", "Athens - Tourist - Artifact 2 Advice", 0x1984DE, lambda state: state.has("Brass Plaque", player)), + LocationData("Athens", "Athens - Tourist - Artifact 3 Advice", 0x1984DF, lambda state: state.has("Parthenon Column", player)), + LocationData("Athens", "Athens - Businesswoman - Location Advice", 0x1984E0), + LocationData("Athens", "Athens - Businesswoman - Artifact 1 Advice", 0x1984E1, lambda state: state.has("Caryatid", player)), + LocationData("Athens", "Athens - Businesswoman - Artifact 2 Advice", 0x1984E2, lambda state: state.has("Brass Plaque", player)), + LocationData("Athens", "Athens - Businesswoman - Artifact 3 Advice", 0x1984E3, lambda state: state.has("Parthenon Column", player)), + + LocationData("Sydney", "Sydney - Bondi Beach - Newspaper Article", 0x1984E4), + LocationData("Sydney", "Sydney - Taronga Zoo - Newspaper Article", 0x1984E5), + LocationData("Sydney", "Sydney - Parthenon - Newspaper Article", 0x1984E6), + LocationData("Sydney", "Sydney - Scientist - Location Advice", 0x1984E7), + LocationData("Sydney", "Sydney - Scientist - Artifact 1 Advice", 0x1984E8, lambda state: state.has("Surfboard from Bondi Beach", player)), + LocationData("Sydney", "Sydney - Scientist - Artifact 2 Advice", 0x1984E9, lambda state: state.has("Taronga Zoo Koala", player)), + LocationData("Sydney", "Sydney - Scientist - Artifact 3 Advice", 0x1984EA, lambda state: state.has("Sydney Opera Sheet Music", player)), + LocationData("Sydney", "Sydney - Officer - Location Advice", 0x1984EB), + LocationData("Sydney", "Sydney - Officer - Artifact 1 Advice", 0x1984EC, lambda state: state.has("Surfboard from Bondi Beach", player)), + LocationData("Sydney", "Sydney - Officer - Artifact 2 Advice", 0x1984ED, lambda state: state.has("Taronga Zoo Koala", player)), + LocationData("Sydney", "Sydney - Officer - Artifact 3 Advice", 0x1984EE, lambda state: state.has("Sydney Opera Sheet Music", player)), + LocationData("Sydney", "Sydney - Child - Location Advice", 0x1984EF), + LocationData("Sydney", "Sydney - Child - Artifact 1 Advice", 0x1984F0, lambda state: state.has("Surfboard from Bondi Beach", player)), + LocationData("Sydney", "Sydney - Child - Artifact 2 Advice", 0x1984F1, lambda state: state.has("Taronga Zoo Koala", player)), + LocationData("Sydney", "Sydney - Child - Artifact 3 Advice", 0x1984F2, lambda state: state.has("Sydney Opera Sheet Music", player)), + LocationData("Sydney", "Sydney - Tourist - Location Advice", 0x1984F3), + LocationData("Sydney", "Sydney - Tourist - Artifact 1 Advice", 0x1984F4, lambda state: state.has("Surfboard from Bondi Beach", player)), + LocationData("Sydney", "Sydney - Tourist - Artifact 2 Advice", 0x1984F5, lambda state: state.has("Taronga Zoo Koala", player)), + LocationData("Sydney", "Sydney - Tourist - Artifact 3 Advice", 0x1984F6, lambda state: state.has("Sydney Opera Sheet Music", player)), + LocationData("Sydney", "Sydney - Businesswoman - Location Advice", 0x1984F7), + LocationData("Sydney", "Sydney - Businesswoman - Artifact 1 Advice", 0x1984F8, lambda state: state.has("Surfboard from Bondi Beach", player)), + LocationData("Sydney", "Sydney - Businesswoman - Artifact 2 Advice", 0x1984F9, lambda state: state.has("Taronga Zoo Koala", player)), + LocationData("Sydney", "Sydney - Businesswoman - Artifact 3 Advice", 0x1984FA, lambda state: state.has("Sydney Opera Sheet Music", player)), + + LocationData("Tokyo", "Tokyo - Great Buddha of Kamakura - Newspaper Article", 0x1984FB), + LocationData("Tokyo", "Tokyo - Sensoji Temple - Newspaper Article", 0x1984FC), + LocationData("Tokyo", "Tokyo - Kokugikan Arena - Newspaper Article", 0x1984FD), + LocationData("Tokyo", "Tokyo - Scientist - Location Advice", 0x1984FE), + LocationData("Tokyo", "Tokyo - Scientist - Artifact 1 Advice", 0x1984FF, lambda state: state.has("Great Buddha's Orange", player)), + LocationData("Tokyo", "Tokyo - Scientist - Artifact 2 Advice", 0x198500, lambda state: state.has("Sensoji Temple Latern", player)), + LocationData("Tokyo", "Tokyo - Scientist - Artifact 3 Advice", 0x198501, lambda state: state.has("Sumo Apron", player)), + LocationData("Tokyo", "Tokyo - Officer - Location Advice", 0x198502), + LocationData("Tokyo", "Tokyo - Officer - Artifact 1 Advice", 0x198503, lambda state: state.has("Great Buddha's Orange", player)), + LocationData("Tokyo", "Tokyo - Officer - Artifact 2 Advice", 0x198504, lambda state: state.has("Sensoji Temple Latern", player)), + LocationData("Tokyo", "Tokyo - Officer - Artifact 3 Advice", 0x198505, lambda state: state.has("Sumo Apron", player)), + LocationData("Tokyo", "Tokyo - Child - Location Advice", 0x198506), + LocationData("Tokyo", "Tokyo - Child - Artifact 1 Advice", 0x198507, lambda state: state.has("Great Buddha's Orange", player)), + LocationData("Tokyo", "Tokyo - Child - Artifact 2 Advice", 0x198508, lambda state: state.has("Sensoji Temple Latern", player)), + LocationData("Tokyo", "Tokyo - Child - Artifact 3 Advice", 0x198509, lambda state: state.has("Sumo Apron", player)), + LocationData("Tokyo", "Tokyo - Tourist - Location Advice", 0x19850A), + LocationData("Tokyo", "Tokyo - Tourist - Artifact 1 Advice", 0x19850B, lambda state: state.has("Great Buddha's Orange", player)), + LocationData("Tokyo", "Tokyo - Tourist - Artifact 2 Advice", 0x19850C, lambda state: state.has("Sensoji Temple Latern", player)), + LocationData("Tokyo", "Tokyo - Tourist - Artifact 3 Advice", 0x19850D, lambda state: state.has("Sumo Apron", player)), + LocationData("Tokyo", "Tokyo - Businesswoman - Location Advice", 0x19850E), + LocationData("Tokyo", "Tokyo - Businesswoman - Artifact 1 Advice", 0x19850F, lambda state: state.has("Great Buddha's Orange", player)), + LocationData("Tokyo", "Tokyo - Businesswoman - Artifact 2 Advice", 0x198510, lambda state: state.has("Sensoji Temple Latern", player)), + LocationData("Tokyo", "Tokyo - Businesswoman - Artifact 3 Advice", 0x198511, lambda state: state.has("Sumo Apron", player)), + + LocationData("Nairobi", "Nairobi - Nairobi National Park - Newspaper Article", 0x198512), + LocationData("Nairobi", "Nairobi - Maasai Village - Newspaper Article", 0x198513), + LocationData("Nairobi", "Nairobi - National Museum of Kenya - Newspaper Article", 0x198514), + LocationData("Nairobi", "Nairobi - Scientist - Location Advice", 0x198515), + LocationData("Nairobi", "Nairobi - Scientist - Artifact 1 Advice", 0x198516, lambda state: state.has("Baby Elephant", player)), + LocationData("Nairobi", "Nairobi - Scientist - Artifact 2 Advice", 0x198517, lambda state: state.has("Maasai Headdress", player)), + LocationData("Nairobi", "Nairobi - Scientist - Artifact 3 Advice", 0x198518, lambda state: state.has("Human Skull", player)), + LocationData("Nairobi", "Nairobi - Officer - Location Advice", 0x198519), + LocationData("Nairobi", "Nairobi - Officer - Artifact 1 Advice", 0x19851A, lambda state: state.has("Baby Elephant", player)), + LocationData("Nairobi", "Nairobi - Officer - Artifact 2 Advice", 0x19851B, lambda state: state.has("Maasai Headdress", player)), + LocationData("Nairobi", "Nairobi - Officer - Artifact 3 Advice", 0x19851C, lambda state: state.has("Human Skull", player)), + LocationData("Nairobi", "Nairobi - Child - Location Advice", 0x19851D), + LocationData("Nairobi", "Nairobi - Child - Artifact 1 Advice", 0x19851E, lambda state: state.has("Baby Elephant", player)), + LocationData("Nairobi", "Nairobi - Child - Artifact 2 Advice", 0x19851F, lambda state: state.has("Maasai Headdress", player)), + LocationData("Nairobi", "Nairobi - Child - Artifact 3 Advice", 0x198520, lambda state: state.has("Human Skull", player)), + LocationData("Nairobi", "Nairobi - Tourist - Location Advice", 0x198521), + LocationData("Nairobi", "Nairobi - Tourist - Artifact 1 Advice", 0x198522, lambda state: state.has("Baby Elephant", player)), + LocationData("Nairobi", "Nairobi - Tourist - Artifact 2 Advice", 0x198523, lambda state: state.has("Maasai Headdress", player)), + LocationData("Nairobi", "Nairobi - Tourist - Artifact 3 Advice", 0x198524, lambda state: state.has("Human Skull", player)), + LocationData("Nairobi", "Nairobi - Businesswoman - Location Advice", 0x198525), + LocationData("Nairobi", "Nairobi - Businesswoman - Artifact 1 Advice", 0x198526, lambda state: state.has("Baby Elephant", player)), + LocationData("Nairobi", "Nairobi - Businesswoman - Artifact 2 Advice", 0x198527, lambda state: state.has("Maasai Headdress", player)), + LocationData("Nairobi", "Nairobi - Businesswoman - Artifact 3 Advice", 0x198528, lambda state: state.has("Human Skull", player)), + + LocationData("Rio de Janeiro", "Rio de Janeiro - Christ the Redeemer Statue - Newspaper Article", 0x198529), + LocationData("Rio de Janeiro", "Rio de Janeiro - Copacabana Beach - Newspaper Article", 0x19852A), + LocationData("Rio de Janeiro", "Rio de Janeiro - Sugar Loaf Mountain - Newspaper Article", 0x19852B), + LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Location Advice", 0x19852C), + LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Artifact 1 Advice", 0x19852D, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Artifact 2 Advice", 0x19852E, lambda state: state.has("Copacabana Beach Seashell", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Artifact 3 Advice", 0x19852F, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Location Advice", 0x198530), + LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Artifact 1 Advice", 0x198531, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Artifact 2 Advice", 0x198532, lambda state: state.has("Copacabana Beach Seashell", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Artifact 3 Advice", 0x198533, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Location Advice", 0x198534), + LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Artifact 1 Advice", 0x198535, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Artifact 2 Advice", 0x198536, lambda state: state.has("Copacabana Beach Seashell", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Artifact 3 Advice", 0x198537, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Location Advice", 0x198538), + LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Artifact 1 Advice", 0x198539, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Artifact 2 Advice", 0x19853A, lambda state: state.has("Copacabana Beach Seashell", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Artifact 3 Advice", 0x19853B, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Location Advice", 0x19853C), + LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Artifact 1 Advice", 0x19853D, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Artifact 2 Advice", 0x19853E, lambda state: state.has("Copacabana Beach Seashell", player)), + LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Artifact 3 Advice", 0x19853F, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), + + LocationData("Cairo", "Cairo - Great Pyramid - Newspaper Article", 0x198540), + LocationData("Cairo", "Cairo - Mosque of Mohammed - Newspaper Article", 0x198541), + LocationData("Cairo", "Cairo - Sphinx - Newspaper Article", 0x198542), + LocationData("Cairo", "Cairo - Scientist - Location Advice", 0x198543), + LocationData("Cairo", "Cairo - Scientist - Artifact 1 Advice", 0x198544, lambda state: state.has("Top Brick of the Great Pyramid", player)), + LocationData("Cairo", "Cairo - Scientist - Artifact 2 Advice", 0x198545, lambda state: state.has("Gingerbread Clock", player)), + LocationData("Cairo", "Cairo - Scientist - Artifact 3 Advice", 0x198546, lambda state: state.has("Klaft of the Sphinx", player)), + LocationData("Cairo", "Cairo - Officer - Location Advice", 0x198547), + LocationData("Cairo", "Cairo - Officer - Artifact 1 Advice", 0x198548, lambda state: state.has("Top Brick of the Great Pyramid", player)), + LocationData("Cairo", "Cairo - Officer - Artifact 2 Advice", 0x198549, lambda state: state.has("Gingerbread Clock", player)), + LocationData("Cairo", "Cairo - Officer - Artifact 3 Advice", 0x19854A, lambda state: state.has("Klaft of the Sphinx", player)), + LocationData("Cairo", "Cairo - Child - Location Advice", 0x19854B), + LocationData("Cairo", "Cairo - Child - Artifact 1 Advice", 0x19854C, lambda state: state.has("Top Brick of the Great Pyramid", player)), + LocationData("Cairo", "Cairo - Child - Artifact 2 Advice", 0x19854D, lambda state: state.has("Gingerbread Clock", player)), + LocationData("Cairo", "Cairo - Child - Artifact 3 Advice", 0x19854E, lambda state: state.has("Klaft of the Sphinx", player)), + LocationData("Cairo", "Cairo - Tourist - Location Advice", 0x19854F), + LocationData("Cairo", "Cairo - Tourist - Artifact 1 Advice", 0x198550, lambda state: state.has("Top Brick of the Great Pyramid", player)), + LocationData("Cairo", "Cairo - Tourist - Artifact 2 Advice", 0x198551, lambda state: state.has("Gingerbread Clock", player)), + LocationData("Cairo", "Cairo - Tourist - Artifact 3 Advice", 0x198552, lambda state: state.has("Klaft of the Sphinx", player)), + LocationData("Cairo", "Cairo - Businesswoman - Location Advice", 0x198553), + LocationData("Cairo", "Cairo - Businesswoman - Artifact 1 Advice", 0x198554, lambda state: state.has("Top Brick of the Great Pyramid", player)), + LocationData("Cairo", "Cairo - Businesswoman - Artifact 2 Advice", 0x198555, lambda state: state.has("Gingerbread Clock", player)), + LocationData("Cairo", "Cairo - Businesswoman - Artifact 3 Advice", 0x198556, lambda state: state.has("Klaft of the Sphinx", player)), + + LocationData("Moscow", "Moscow - Kremlin - Newspaper Article", 0x198557), + LocationData("Moscow", "Moscow - St. Basil's Cathedral - Newspaper Article", 0x198558), + LocationData("Moscow", "Moscow - Bolshoi Ballet - Newspaper Article", 0x198559), + LocationData("Moscow", "Moscow - Scientist - Location Advice", 0x19855A), + LocationData("Moscow", "Moscow - Scientist - Artifact 1 Advice", 0x19855B, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), + LocationData("Moscow", "Moscow - Scientist - Artifact 2 Advice", 0x19855C, lambda state: state.has("Cathedral Dome", player)), + LocationData("Moscow", "Moscow - Scientist - Artifact 3 Advice", 0x19855D, lambda state: state.has("Bolshoi Ballet Slipper", player)), + LocationData("Moscow", "Moscow - Officer - Location Advice", 0x19855E), + LocationData("Moscow", "Moscow - Officer - Artifact 1 Advice", 0x19855F, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), + LocationData("Moscow", "Moscow - Officer - Artifact 2 Advice", 0x198560, lambda state: state.has("Cathedral Dome", player)), + LocationData("Moscow", "Moscow - Officer - Artifact 3 Advice", 0x198561, lambda state: state.has("Bolshoi Ballet Slipper", player)), + LocationData("Moscow", "Moscow - Child - Location Advice", 0x198562), + LocationData("Moscow", "Moscow - Child - Artifact 1 Advice", 0x198563, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), + LocationData("Moscow", "Moscow - Child - Artifact 2 Advice", 0x198564, lambda state: state.has("Cathedral Dome", player)), + LocationData("Moscow", "Moscow - Child - Artifact 3 Advice", 0x198565, lambda state: state.has("Bolshoi Ballet Slipper", player)), + LocationData("Moscow", "Moscow - Tourist - Location Advice", 0x198566), + LocationData("Moscow", "Moscow - Tourist - Artifact 1 Advice", 0x198567, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), + LocationData("Moscow", "Moscow - Tourist - Artifact 2 Advice", 0x198568, lambda state: state.has("Cathedral Dome", player)), + LocationData("Moscow", "Moscow - Tourist - Artifact 3 Advice", 0x198569, lambda state: state.has("Bolshoi Ballet Slipper", player)), + LocationData("Moscow", "Moscow - Businesswoman - Location Advice", 0x19856A), + LocationData("Moscow", "Moscow - Businesswoman - Artifact 1 Advice", 0x19856B, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), + LocationData("Moscow", "Moscow - Businesswoman - Artifact 2 Advice", 0x19856C, lambda state: state.has("Cathedral Dome", player)), + LocationData("Moscow", "Moscow - Businesswoman - Artifact 3 Advice", 0x19856D, lambda state: state.has("Bolshoi Ballet Slipper", player)), + + LocationData("Beijing", "Beijing - Temple of Heaven - Newspaper Article", 0x19856E), + LocationData("Beijing", "Beijing - Great Wall of China - Newspaper Article", 0x19856F), + LocationData("Beijing", "Beijing - Forbidden City - Newspaper Article", 0x198570), + LocationData("Beijing", "Beijing - Scientist - Location Advice", 0x198571), + LocationData("Beijing", "Beijing - Scientist - Artifact 1 Advice", 0x198572, lambda state: state.has("Hall of Good Harvest", player)), + LocationData("Beijing", "Beijing - Scientist - Artifact 2 Advice", 0x198573, lambda state: state.has("Stone from the Great Wall", player)), + LocationData("Beijing", "Beijing - Scientist - Artifact 3 Advice", 0x198574, lambda state: state.has("Gate of Heavenly Peace", player)), + LocationData("Beijing", "Beijing - Officer - Location Advice", 0x198575), + LocationData("Beijing", "Beijing - Officer - Artifact 1 Advice", 0x198576, lambda state: state.has("Hall of Good Harvest", player)), + LocationData("Beijing", "Beijing - Officer - Artifact 2 Advice", 0x198577, lambda state: state.has("Stone from the Great Wall", player)), + LocationData("Beijing", "Beijing - Officer - Artifact 3 Advice", 0x198578, lambda state: state.has("Gate of Heavenly Peace", player)), + LocationData("Beijing", "Beijing - Child - Location Advice", 0x198579), + LocationData("Beijing", "Beijing - Child - Artifact 1 Advice", 0x19857A, lambda state: state.has("Hall of Good Harvest", player)), + LocationData("Beijing", "Beijing - Child - Artifact 2 Advice", 0x19857B, lambda state: state.has("Stone from the Great Wall", player)), + LocationData("Beijing", "Beijing - Child - Artifact 3 Advice", 0x19857C, lambda state: state.has("Gate of Heavenly Peace", player)), + LocationData("Beijing", "Beijing - Tourist - Location Advice", 0x19857D), + LocationData("Beijing", "Beijing - Tourist - Artifact 1 Advice", 0x19857E, lambda state: state.has("Hall of Good Harvest", player)), + LocationData("Beijing", "Beijing - Tourist - Artifact 2 Advice", 0x19857F, lambda state: state.has("Stone from the Great Wall", player)), + LocationData("Beijing", "Beijing - Tourist - Artifact 3 Advice", 0x198580, lambda state: state.has("Gate of Heavenly Peace", player)), + LocationData("Beijing", "Beijing - Businesswoman - Location Advice", 0x198581), + LocationData("Beijing", "Beijing - Businesswoman - Artifact 1 Advice", 0x198582, lambda state: state.has("Hall of Good Harvest", player)), + LocationData("Beijing", "Beijing - Businesswoman - Artifact 2 Advice", 0x198583, lambda state: state.has("Stone from the Great Wall", player)), + LocationData("Beijing", "Beijing - Businesswoman - Artifact 3 Advice", 0x198584, lambda state: state.has("Gate of Heavenly Peace", player)), + + LocationData("Buenos Aires", "Buenos Aires - Teatro Colon - Newspaper Article", 0x198585), + LocationData("Buenos Aires", "Buenos Aires - Gaucho Museum - Newspaper Article", 0x198586), + LocationData("Buenos Aires", "Buenos Aires - Obelisk Monument - Newspaper Article", 0x198587), + LocationData("Buenos Aires", "Buenos Aires - Scientist - Location Advice", 0x19858A), + LocationData("Buenos Aires", "Buenos Aires - Scientist - Artifact 1 Advice", 0x19858B, lambda state: state.has("Flute from the Teatro Colon", player)), + LocationData("Buenos Aires", "Buenos Aires - Scientist - Artifact 2 Advice", 0x19858C, lambda state: state.has("Boleadoras", player)), + LocationData("Buenos Aires", "Buenos Aires - Scientist - Artifact 3 Advice", 0x19858D, lambda state: state.has("Stone from the Obelisk", player)), + LocationData("Buenos Aires", "Buenos Aires - Officer - Location Advice", 0x19858E), + LocationData("Buenos Aires", "Buenos Aires - Officer - Artifact 1 Advice", 0x19858F, lambda state: state.has("Flute from the Teatro Colon", player)), + LocationData("Buenos Aires", "Buenos Aires - Officer - Artifact 2 Advice", 0x198590, lambda state: state.has("Boleadoras", player)), + LocationData("Buenos Aires", "Buenos Aires - Officer - Artifact 3 Advice", 0x198591, lambda state: state.has("Stone from the Obelisk", player)), + LocationData("Buenos Aires", "Buenos Aires - Child - Location Advice", 0x198592), + LocationData("Buenos Aires", "Buenos Aires - Child - Artifact 1 Advice", 0x198593, lambda state: state.has("Flute from the Teatro Colon", player)), + LocationData("Buenos Aires", "Buenos Aires - Child - Artifact 2 Advice", 0x198594, lambda state: state.has("Boleadoras", player)), + LocationData("Buenos Aires", "Buenos Aires - Child - Artifact 3 Advice", 0x198595, lambda state: state.has("Stone from the Obelisk", player)), + LocationData("Buenos Aires", "Buenos Aires - Tourist - Location Advice", 0x198596), + LocationData("Buenos Aires", "Buenos Aires - Tourist - Artifact 1 Advice", 0x198597, lambda state: state.has("Flute from the Teatro Colon", player)), + LocationData("Buenos Aires", "Buenos Aires - Tourist - Artifact 2 Advice", 0x198598, lambda state: state.has("Boleadoras", player)), + LocationData("Buenos Aires", "Buenos Aires - Tourist - Artifact 3 Advice", 0x198599, lambda state: state.has("Stone from the Obelisk", player)), + LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Location Advice", 0x19859A), + LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Artifact 1 Advice", 0x19859B, lambda state: state.has("Flute from the Teatro Colon", player)), + LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Artifact 2 Advice", 0x19859C, lambda state: state.has("Boleadoras", player)), + LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Artifact 3 Advice", 0x19859D, lambda state: state.has("Stone from the Obelisk", player)), + + LocationData("Mexico City", "Mexico City - Angel of Independence - Newspaper Article", 0x19859E), + LocationData("Mexico City", "Mexico City - National Palace - Newspaper Article", 0x19859F), + LocationData("Mexico City", "Mexico City - Fine Arts Palace - Newspaper Article", 0x1985A0), + LocationData("Mexico City", "Mexico City - Scientist - Location Advice", 0x1985A1), + LocationData("Mexico City", "Mexico City - Scientist - Artifact 1 Advice", 0x1985A2, lambda state: state.has("Angel", player)), + LocationData("Mexico City", "Mexico City - Scientist - Artifact 2 Advice", 0x1985A3, lambda state: state.has("Diego Rivera Mural", player)), + LocationData("Mexico City", "Mexico City - Scientist - Artifact 3 Advice", 0x1985A4, lambda state: state.has("Fine Arts Catalog", player)), + LocationData("Mexico City", "Mexico City - Officer - Location Advice", 0x1985A5), + LocationData("Mexico City", "Mexico City - Officer - Artifact 1 Advice", 0x1985A6, lambda state: state.has("Angel", player)), + LocationData("Mexico City", "Mexico City - Officer - Artifact 2 Advice", 0x1985A7, lambda state: state.has("Diego Rivera Mural", player)), + LocationData("Mexico City", "Mexico City - Officer - Artifact 3 Advice", 0x1985A8, lambda state: state.has("Fine Arts Catalog", player)), + LocationData("Mexico City", "Mexico City - Child - Location Advice", 0x1985A9), + LocationData("Mexico City", "Mexico City - Child - Artifact 1 Advice", 0x1985AA, lambda state: state.has("Angel", player)), + LocationData("Mexico City", "Mexico City - Child - Artifact 2 Advice", 0x1985AB, lambda state: state.has("Diego Rivera Mural", player)), + LocationData("Mexico City", "Mexico City - Child - Artifact 3 Advice", 0x1985AC, lambda state: state.has("Fine Arts Catalog", player)), + LocationData("Mexico City", "Mexico City - Tourist - Location Advice", 0x1985AD), + LocationData("Mexico City", "Mexico City - Tourist - Artifact 1 Advice", 0x1985AE, lambda state: state.has("Angel", player)), + LocationData("Mexico City", "Mexico City - Tourist - Artifact 2 Advice", 0x1985AF, lambda state: state.has("Diego Rivera Mural", player)), + LocationData("Mexico City", "Mexico City - Tourist - Artifact 3 Advice", 0x1985B0, lambda state: state.has("Fine Arts Catalog", player)), + LocationData("Mexico City", "Mexico City - Businesswoman - Location Advice", 0x1985B1), + LocationData("Mexico City", "Mexico City - Businesswoman - Artifact 1 Advice", 0x1985B2, lambda state: state.has("Angel", player)), + LocationData("Mexico City", "Mexico City - Businesswoman - Artifact 2 Advice", 0x1985B3, lambda state: state.has("Diego Rivera Mural", player)), + LocationData("Mexico City", "Mexico City - Businesswoman - Artifact 3 Advice", 0x1985B4, lambda state: state.has("Fine Arts Catalog", player)) + + + ) + return list(location_table) diff --git a/worlds/mariomissing/Options.py b/worlds/mariomissing/Options.py new file mode 100644 index 000000000000..84e7a7cf7c81 --- /dev/null +++ b/worlds/mariomissing/Options.py @@ -0,0 +1,24 @@ +from dataclasses import dataclass +from Options import Toggle, DeathLink, Range, PerGameCommonOptions + +class RequiredArtifacts(Range): + """How many Artifacts are required to finish""" + display_name = "Required Artifacts" + range_start = 0 + range_end = 45 + default = 25 + +class ComputerChecks(Toggle): + """If enabled, places checks on the Computer data locations""" + display_name = "Computer Checks" + +class CityShuffle(Toggle): + """Shuffles which doors lead to which cities""" + display_name = "City Shuffle" + +@dataclass +class MarioisMissingOptions(PerGameCommonOptions): + required_artifacts: RequiredArtifacts + computer_sanity: ComputerChecks + city_shuffle: CityShuffle + death_link: DeathLink diff --git a/worlds/mariomissing/Regions.py b/worlds/mariomissing/Regions.py new file mode 100644 index 000000000000..c8ae032ec485 --- /dev/null +++ b/worlds/mariomissing/Regions.py @@ -0,0 +1,97 @@ +from typing import List, Dict, Tuple +from BaseClasses import MultiWorld, Region, Location +from .Locations import LocationData + +class YILocation(Location): + game: str = "Mario is Missing" + +def __init__(player: int, name: str = " ", address: int = None, parent=None): + super().__init__(player, name, address, parent) + + +def create_regions(multiworld: MultiWorld, player: int, locations: Tuple[LocationData, ...], location_cache: List[Location], world): + + locations_per_region = get_locations_per_region(locations) + + regions = [ + create_region(multiworld, player, locations_per_region, location_cache, 'Menu'), + create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 1'), + create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 2'), + create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 3'), + create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 4'), + + create_region(multiworld, player, locations_per_region, location_cache, 'Rome'), + create_region(multiworld, player, locations_per_region, location_cache, 'Paris'), + create_region(multiworld, player, locations_per_region, location_cache, 'London'), + create_region(multiworld, player, locations_per_region, location_cache, 'New York'), + create_region(multiworld, player, locations_per_region, location_cache, 'San Francisco'), + create_region(multiworld, player, locations_per_region, location_cache, 'Athens'), + create_region(multiworld, player, locations_per_region, location_cache, 'Sydney'), + create_region(multiworld, player, locations_per_region, location_cache, 'Tokyo'), + create_region(multiworld, player, locations_per_region, location_cache, 'Nairobi'), + create_region(multiworld, player, locations_per_region, location_cache, 'Rio de Janeiro'), + create_region(multiworld, player, locations_per_region, location_cache, 'Cairo'), + create_region(multiworld, player, locations_per_region, location_cache, 'Moscow'), + create_region(multiworld, player, locations_per_region, location_cache, 'Beijing'), + create_region(multiworld, player, locations_per_region, location_cache, 'Buenos Aires'), + create_region(multiworld, player, locations_per_region, location_cache, 'Mexico City') + + ] + multiworld.regions += regions + multiworld.get_region('Menu', player).add_exits(["Castle Floor 1"]) + multiworld.get_region('Castle Floor 1', player).add_exits(["Castle Floor 2"], + {"Castle Floor 2": lambda state: state.has_any({'Castle Floor Key'}, player)}) + multiworld.get_region('Castle Floor 2', player).add_exits(["Castle Floor 3"], + {"Castle Floor 3": lambda state: state.has('Castle Floor Key', player, 2)}) + multiworld.get_region('Castle Floor 3', player).add_exits(["Castle Floor 4"], + {"Castle Floor 4": lambda state: state.has('Artifact Secured', player, world.options.required_artifacts.value)}) + + multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[0]]) + multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[1]]) + multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[2]]) + multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[3]]) + multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[4]]) + + multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[5]]) + multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[6]]) + multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[7]]) + multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[8]]) + multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[9]]) + + multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[10]]) + multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[11]]) + multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[12]]) + multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[13]]) + multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[14]]) + +def create_location(player: int, location_data: LocationData, region: Region, location_cache: List[Location]) -> Location: + location = YILocation(player, location_data.name, location_data.code, region) + location.access_rule = location_data.rule + + if id is None: + location.event = True + location.locked = True + + location_cache.append(location) + + return location + +def create_region(multiworld: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], location_cache: List[Location], name: str) -> Region: + region = Region(name, player, multiworld) + region.world = multiworld + + if name in locations_per_region: + for location_data in locations_per_region[name]: + location = create_location(player, location_data, region, location_cache) + region.locations.append(location) + + return region + + +def get_locations_per_region(locations: Tuple[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/mariomissing/Rom.py b/worlds/mariomissing/Rom.py new file mode 100644 index 000000000000..5da09d216d4e --- /dev/null +++ b/worlds/mariomissing/Rom.py @@ -0,0 +1,698 @@ +import hashlib +import os +import Utils +from worlds.Files import APDeltaPatch +USHASH = '2a2152976e503eaacd9815f44c262d73' +ROM_PLAYER_LIMIT = 65535 + +item_values = { + 0x198401: [0x1550, 0x01], + 0x198402: [0x1550, 0x02], + 0x198403: [0x1550, 0x03], + 0x198404: [0x1550, 0x04], + 0x198405: [0x1550, 0x05], + 0x198406: [0x1550, 0x06], + 0x198407: [0x1550, 0x07], + 0x198408: [0x1550, 0x08], + 0x198409: [0x1550, 0x09], + 0x19840A: [0x1550, 0x0A], + 0x19840B: [0x1550, 0x0B], + 0x19840C: [0x1550, 0x0C], + 0x19840D: [0x1550, 0x0D], + 0x19840E: [0x1550, 0x0E], + 0x19840F: [0x1550, 0x0F], + 0x198410: [0x1550, 0x10], + 0x198411: [0x1550, 0x11], + 0x198412: [0x1550, 0x12], + 0x198413: [0x1550, 0x13], + 0x198414: [0x1550, 0x14], + 0x198415: [0x1550, 0x15], + 0x198416: [0x1550, 0x16], + 0x198417: [0x1550, 0x17], + 0x198418: [0x1550, 0x18], + 0x198419: [0x1550, 0x19], + 0x19841A: [0x1550, 0x1A], + 0x19841B: [0x1550, 0x1B], + 0x19841C: [0x1550, 0x1C], + 0x19841D: [0x1550, 0x1D], + 0x19841E: [0x1550, 0x1E], + 0x19841F: [0x1550, 0x1F], + 0x198420: [0x1550, 0x20], + 0x198421: [0x1550, 0x21], + 0x198422: [0x1550, 0x22], + 0x198423: [0x1550, 0x23], + 0x198424: [0x1550, 0x24], + 0x198425: [0x1550, 0x25], + 0x198426: [0x1550, 0x26], + 0x198427: [0x1550, 0x27], + 0x198428: [0x1550, 0x28], + 0x198429: [0x1550, 0x29], + 0x19842A: [0x1550, 0x2A], + 0x19842B: [0x1550, 0x2B], + 0x19842C: [0x1550, 0x2C], + 0x19842D: [0x1550, 0x2D], + 0x19842E: [0x1550, 0x2E] + +} + +location_table = { + 0x198400: [0x1555, 3], + 0x198401: [0x1555, 4], + 0x198402: [0x1555, 5], + 0x198403: [0x1564, 3], + 0x198404: [0x1564, 4], + 0x198405: [0x1564, 5], + + 0x198406: [0x1556, 3], + 0x198407: [0x1556, 4], + 0x198408: [0x1556, 5], + 0x198409: [0x1565, 3], + 0x19840A: [0x1565, 4], + 0x19840B: [0x1565, 5], + + 0x19840C: [0x1557, 3], + 0x19840D: [0x1557, 4], + 0x19840E: [0x1557, 5], + 0x19840F: [0x1566, 3], + 0x198410: [0x1566, 4], + 0x198411: [0x1566, 5], + + 0x198412: [0x1558, 3], + 0x198413: [0x1558, 4], + 0x198414: [0x1558, 5], + 0x198415: [0x1567, 3], + 0x198416: [0x1567, 4], + 0x198417: [0x1567, 5], + + 0x198418: [0x1559, 3], + 0x198419: [0x1559, 4], + 0x19841A: [0x1559, 5], + 0x19841B: [0x1568, 3], + 0x19841C: [0x1568, 4], + 0x19841D: [0x1568, 5], + + 0x19841E: [0x155A, 3], + 0x19841F: [0x155A, 4], + 0x198420: [0x155A, 5], + 0x198421: [0x1569, 3], + 0x198422: [0x1569, 4], + 0x198423: [0x1569, 5], + + 0x198424: [0x155B, 3], + 0x198425: [0x155B, 4], + 0x198426: [0x155B, 5], + 0x198427: [0x156A, 3], + 0x198428: [0x156A, 4], + 0x198429: [0x156A, 5], + + 0x19842A: [0x155C, 3], + 0x19842B: [0x155C, 4], + 0x19842C: [0x155C, 5], + 0x19842D: [0x156B, 3], + 0x19842E: [0x156B, 4], + 0x19842F: [0x156B, 5], + + 0x198430: [0x155D, 3], + 0x198431: [0x155D, 4], + 0x198432: [0x155D, 5], + 0x198433: [0x156C, 3], + 0x198434: [0x156C, 4], + 0x198435: [0x156C, 5], + + 0x198436: [0x155E, 3], + 0x198437: [0x155E, 4], + 0x198438: [0x155E, 5], + 0x198439: [0x156D, 3], + 0x19843A: [0x156D, 4], + 0x19843B: [0x156D, 5], + + 0x19843C: [0x155F, 3], + 0x19843D: [0x155F, 4], + 0x19843E: [0x155F, 5], + 0x19843F: [0x156E, 3], + 0x198440: [0x156E, 4], + 0x198441: [0x156E, 5], + + 0x198442: [0x1560, 3], + 0x198443: [0x1560, 4], + 0x198444: [0x1560, 5], + 0x198445: [0x156F, 3], + 0x198446: [0x156F, 4], + 0x198447: [0x156F, 5], + + 0x198448: [0x1561, 3], + 0x198449: [0x1561, 4], + 0x19844A: [0x1561, 5], + 0x19844B: [0x1570, 3], + 0x19844C: [0x1570, 4], + 0x19844D: [0x1570, 5], + + 0x19844E: [0x1562, 3], + 0x19844F: [0x1562, 4], + 0x198450: [0x1562, 5], + 0x198451: [0x1571, 3], + 0x198452: [0x1571, 4], + 0x198453: [0x1571, 5], + + 0x198454: [0x1563, 3], + 0x198455: [0x1563, 4], + 0x198456: [0x1563, 5], + 0x198457: [0x1572, 3], + 0x198458: [0x1572, 4], + 0x198459: [0x1572, 5], + + 0x19845A: [0x15AA, 0], + 0x19845B: [0x15AC, 0], + 0x19845C: [0x15AE, 0], + 0x19845D: [0x15A0, 0], + 0x19845E: [0x159A, 0], + 0x19845F: [0x159C, 0], + 0x198460: [0x159E, 0], + 0x198461: [0x15A8, 0], + 0x198462: [0x15A2, 0], + 0x198463: [0x15A4, 0], + 0x198464: [0x15A6, 0], + 0x198465: [0x1588, 0], + 0x198466: [0x1582, 0], + 0x198467: [0x1584, 0], + 0x198468: [0x1586, 0], + 0x198469: [0x1590, 0], + 0x19846A: [0x158A, 0], + 0x19846B: [0x158C, 0], + 0x19846C: [0x158E, 0], + 0x19846D: [0x1598, 0], + 0x19846E: [0x1592, 0], + 0x19846F: [0x1594, 0], + 0x198470: [0x1596, 0], + + 0x198471: [0x15AA, 1], + 0x198472: [0x15AC, 1], + 0x198473: [0x15AE, 1], + 0x198474: [0x15A0, 1], + 0x198475: [0x159A, 1], + 0x198476: [0x159C, 1], + 0x198477: [0x159E, 1], + 0x198478: [0x15A8, 1], + 0x198479: [0x15A2, 1], + 0x19847A: [0x15A4, 1], + 0x19847B: [0x15A6, 1], + 0x19847C: [0x1588, 1], + 0x19847D: [0x1582, 1], + 0x19847E: [0x1584, 1], + 0x19847F: [0x1586, 1], + 0x198480: [0x1590, 1], + 0x198481: [0x158A, 1], + 0x198482: [0x158C, 1], + 0x198483: [0x158E, 1], + 0x198484: [0x1598, 1], + 0x198485: [0x1592, 1], + 0x198486: [0x1594, 1], + 0x198487: [0x1596, 1], + + 0x198488: [0x15AA, 2], + 0x198489: [0x15AC, 2], + 0x19848A: [0x15AE, 2], + 0x19848B: [0x15A0, 2], + 0x19848C: [0x159A, 2], + 0x19848D: [0x159C, 2], + 0x19848E: [0x159E, 2], + 0x19848F: [0x15A8, 2], + 0x198490: [0x15A2, 2], + 0x198491: [0x15A4, 2], + 0x198492: [0x15A6, 2], + 0x198493: [0x1588, 2], + 0x198494: [0x1582, 2], + 0x198495: [0x1584, 2], + 0x198496: [0x1586, 2], + 0x198497: [0x1590, 2], + 0x198498: [0x158A, 2], + 0x198499: [0x158C, 2], + 0x19849A: [0x158E, 2], + 0x19849B: [0x1598, 2], + 0x19849C: [0x1592, 2], + 0x19849D: [0x1594, 2], + 0x19849E: [0x1596, 2], + + 0x19849F: [0x15AA, 3], + 0x1984A0: [0x15AC, 3], + 0x1984A1: [0x15AE, 3], + 0x1984A2: [0x15A0, 3], + 0x1984A3: [0x159A, 3], + 0x1984A4: [0x159C, 3], + 0x1984A5: [0x159E, 3], + 0x1984A6: [0x15A8, 3], + 0x1984A7: [0x15A2, 3], + 0x1984A8: [0x15A4, 3], + 0x1984A9: [0x15A6, 3], + 0x1984AA: [0x1588, 3], + 0x1984AB: [0x1582, 3], + 0x1984AC: [0x1584, 3], + 0x1984AD: [0x1586, 3], + 0x1984AE: [0x1590, 3], + 0x1984AF: [0x158A, 3], + 0x1984B0: [0x158C, 3], + 0x1984B1: [0x158E, 3], + 0x1984B2: [0x1598, 3], + 0x1984B3: [0x1592, 3], + 0x1984B4: [0x1594, 3], + 0x1984B5: [0x1596, 3], + + 0x1984B6: [0x15AA, 4], + 0x1984B7: [0x15AC, 4], + 0x1984B8: [0x15AE, 4], + 0x1984B9: [0x15A0, 4], + 0x1984BA: [0x159A, 4], + 0x1984BB: [0x159C, 4], + 0x1984BC: [0x159E, 4], + 0x1984BD: [0x15A8, 4], + 0x1984BE: [0x15A2, 4], + 0x1984BF: [0x15A4, 4], + 0x1984C0: [0x15A6, 4], + 0x1984c1: [0x1588, 4], + 0x1984c2: [0x1582, 4], + 0x1984C3: [0x1584, 4], + 0x1984C4: [0x1586, 4], + 0x1984C5: [0x1590, 4], + 0x1984C6: [0x158A, 4], + 0x1984C7: [0x158C, 4], + 0x1984C8: [0x158E, 4], + 0x1984C9: [0x1598, 4], + 0x1984CA: [0x1592, 4], + 0x1984CB: [0x1594, 4], + 0x1984CC: [0x1596, 4], + + 0x1984CD: [0x15AA, 5], + 0x1984CE: [0x15AC, 5], + 0x1984CF: [0x15AE, 5], + 0x1984D0: [0x15A0, 5], + 0x1984D1: [0x159A, 5], + 0x1984D2: [0x159C, 5], + 0x1984D3: [0x159E, 5], + 0x1984D4: [0x15A8, 5], + 0x1984D5: [0x15A2, 5], + 0x1984D6: [0x15A4, 5], + 0x1984D7: [0x15A6, 5], + 0x1984D8: [0x1588, 5], + 0x1984D9: [0x1582, 5], + 0x1984DA: [0x1584, 5], + 0x1984DB: [0x1586, 5], + 0x1984DC: [0x1590, 5], + 0x1984DD: [0x158A, 5], + 0x1984DE: [0x158C, 5], + 0x1984DF: [0x158E, 5], + 0x1984E0: [0x1598, 5], + 0x1984E1: [0x1592, 5], + 0x1984E2: [0x1594, 5], + 0x1984E3: [0x1596, 5], + + 0x1984E4: [0x15AA, 6], + 0x1984E5: [0x15AC, 6], + 0x1984E6: [0x15AE, 6], + 0x1984E7: [0x15A0, 6], + 0x1984E8: [0x159A, 6], + 0x1984E9: [0x159C, 6], + 0x1984EA: [0x159E, 6], + 0x1984EB: [0x15A8, 6], + 0x1984EC: [0x15A2, 6], + 0x1984ED: [0x15A4, 6], + 0x1984EE: [0x15A6, 6], + 0x1984EF: [0x1588, 6], + 0x1984F0: [0x1582, 6], + 0x1984F1: [0x1584, 6], + 0x1984F2: [0x1586, 6], + 0x1984F3: [0x1590, 6], + 0x1984F4: [0x158A, 6], + 0x1984F5: [0x158C, 6], + 0x1984F6: [0x158E, 6], + 0x1984F7: [0x1598, 6], + 0x1984F8: [0x1592, 6], + 0x1984F9: [0x1594, 6], + 0x1984FA: [0x1596, 6], + + 0x1984FB: [0x15AA, 7], + 0x1984FC: [0x15AC, 7], + 0x1984FD: [0x15AE, 7], + 0x1984FE: [0x15A0, 7], + 0x1984FF: [0x159A, 7], + 0x198500: [0x159C, 7], + 0x198501: [0x159E, 7], + 0x198502: [0x15A8, 7], + 0x198503: [0x15A2, 7], + 0x198504: [0x15A4, 7], + 0x198505: [0x15A6, 7], + 0x198506: [0x1588, 7], + 0x198507: [0x1582, 7], + 0x198508: [0x1584, 7], + 0x198509: [0x1586, 7], + 0x19850A: [0x1590, 7], + 0x19850B: [0x158A, 7], + 0x19850C: [0x158C, 7], + 0x19850D: [0x158E, 7], + 0x19850E: [0x1598, 7], + 0x19850F: [0x1592, 7], + 0x198510: [0x1594, 7], + 0x198511: [0x1596, 7], + + 0x198512: [0x15AB, 0], + 0x198513: [0x15AD, 0], + 0x198514: [0x15AF, 0], + 0x198515: [0x15A1, 0], + 0x198516: [0x159B, 0], + 0x198517: [0x159D, 0], + 0x198518: [0x159F, 0], + 0x198519: [0x15A9, 0], + 0x19851A: [0x15A3, 0], + 0x19851B: [0x15A5, 0], + 0x19851C: [0x15A7, 0], + 0x19851D: [0x1589, 0], + 0x19851E: [0x1583, 0], + 0x19851F: [0x1585, 0], + 0x198520: [0x1587, 0], + 0x198521: [0x1591, 0], + 0x198522: [0x158B, 0], + 0x198523: [0x158D, 0], + 0x198524: [0x158F, 0], + 0x198525: [0x1599, 0], + 0x198526: [0x1593, 0], + 0x198527: [0x1595, 0], + 0x198528: [0x1597, 0], + + 0x198529: [0x15AB, 1], + 0x19852A: [0x15AD, 1], + 0x19852B: [0x15AF, 1], + 0x19852C: [0x15A1, 1], + 0x19852D: [0x159B, 1], + 0x19852E: [0x159D, 1], + 0x19852F: [0x159F, 1], + 0x198530: [0x15A9, 1], + 0x198531: [0x15A3, 1], + 0x198532: [0x15A5, 1], + 0x198533: [0x15A7, 1], + 0x198534: [0x1589, 1], + 0x198535: [0x1583, 1], + 0x198536: [0x1585, 1], + 0x198537: [0x1587, 1], + 0x198538: [0x1591, 1], + 0x198539: [0x158B, 1], + 0x19853A: [0x158D, 1], + 0x19853B: [0x158F, 1], + 0x19853C: [0x1599, 1], + 0x19853D: [0x1593, 1], + 0x19853E: [0x1595, 1], + 0x19853F: [0x1597, 1], + + 0x198540: [0x15AB, 2], + 0x198541: [0x15AD, 2], + 0x198542: [0x15AF, 2], + 0x198543: [0x15A1, 2], + 0x198544: [0x159B, 2], + 0x198545: [0x159D, 2], + 0x198546: [0x159F, 2], + 0x198547: [0x15A9, 2], + 0x198548: [0x15A3, 2], + 0x198549: [0x15A5, 2], + 0x19854A: [0x15A7, 2], + 0x19854B: [0x1589, 2], + 0x19854C: [0x1583, 2], + 0x19854D: [0x1585, 2], + 0x19854E: [0x1587, 2], + 0x19854F: [0x1591, 2], + 0x198550: [0x158B, 2], + 0x198551: [0x158D, 2], + 0x198552: [0x158F, 2], + 0x198553: [0x1599, 2], + 0x198554: [0x1593, 2], + 0x198555: [0x1595, 2], + 0x198556: [0x1597, 2], + + 0x198557: [0x15AB, 3], + 0x198558: [0x15AD, 3], + 0x198559: [0x15AF, 3], + 0x19855A: [0x15A1, 3], + 0x19855B: [0x159B, 3], + 0x19855C: [0x159D, 3], + 0x19855D: [0x159F, 3], + 0x19855E: [0x15A9, 3], + 0x19855F: [0x15A3, 3], + 0x198560: [0x15A5, 3], + 0x198561: [0x15A7, 3], + 0x198562: [0x1589, 3], + 0x198563: [0x1583, 3], + 0x198564: [0x1585, 3], + 0x198565: [0x1587, 3], + 0x198566: [0x1591, 3], + 0x198567: [0x158B, 3], + 0x198568: [0x158D, 3], + 0x198569: [0x158F, 3], + 0x19856A: [0x1599, 3], + 0x19856B: [0x1593, 3], + 0x19856C: [0x1595, 3], + 0x19856D: [0x1597, 3], + + 0x19856E: [0x15AB, 4], + 0x19856F: [0x15AD, 4], + 0x198570: [0x15AF, 4], + 0x198571: [0x15A1, 4], + 0x198572: [0x159B, 4], + 0x198573: [0x159D, 4], + 0x198574: [0x159F, 4], + 0x198575: [0x15A9, 4], + 0x198576: [0x15A3, 4], + 0x198577: [0x15A5, 4], + 0x198578: [0x15A7, 4], + 0x198579: [0x1589, 4], + 0x19857A: [0x1583, 4], + 0x19857B: [0x1585, 4], + 0x19857C: [0x1587, 4], + 0x19857D: [0x1591, 4], + 0x19857E: [0x158B, 4], + 0x19857F: [0x158D, 4], + 0x198580: [0x158F, 4], + 0x198581: [0x1599, 4], + 0x198582: [0x1593, 4], + 0x198583: [0x1595, 4], + 0x198584: [0x1597, 4], + + 0x198585: [0x15AB, 5], + 0x198586: [0x15AD, 5], + 0x198587: [0x15AF, 5], + 0x198588: [0x15A1, 5], + 0x198589: [0x159B, 5], + 0x19858A: [0x159D, 5], + 0x19858B: [0x159F, 5], + 0x19858C: [0x15A9, 5], + 0x19858D: [0x15A3, 5], + 0x19858E: [0x15A5, 5], + 0x19858F: [0x15A7, 5], + 0x198590: [0x1589, 5], + 0x198591: [0x1583, 5], + 0x198592: [0x1585, 5], + 0x198593: [0x1587, 5], + 0x198594: [0x1591, 5], + 0x198595: [0x158B, 5], + 0x198596: [0x158D, 5], + 0x198597: [0x158F, 5], + 0x198598: [0x1599, 5], + 0x198599: [0x1593, 5], + 0x19859A: [0x1595, 5], + 0x19859B: [0x1597, 5], + + 0x19859C: [0x15AB, 6], + 0x19859D: [0x15AD, 6], + 0x19859E: [0x15AF, 6], + 0x19859F: [0x15A1, 6], + 0x1985A0: [0x159B, 6], + 0x1985A1: [0x159D, 6], + 0x1985A2: [0x159F, 6], + 0x1985A3: [0x15A9, 6], + 0x1985A4: [0x15A3, 6], + 0x1985A5: [0x15A5, 6], + 0x1985A6: [0x15A7, 6], + 0x1985A7: [0x1589, 6], + 0x1985A8: [0x1583, 6], + 0x1985A9: [0x1585, 6], + 0x1985AA: [0x1587, 6], + 0x1985AB: [0x1591, 6], + 0x1985AC: [0x158B, 6], + 0x1985AD: [0x158D, 6], + 0x1985AE: [0x158F, 6], + 0x1985AF: [0x1599, 6], + 0x1985B0: [0x1593, 6], + 0x1985B1: [0x1595, 6], + 0x1985B2: [0x1597, 6] +} + +class LocalRom(object): + + def __init__(self, file, vanillaRom=None, name=None): + self.name = name + 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): + self.buffer[address] = value + + def write_bytes(self, startaddress: int, values): + self.buffer[startaddress:startaddress + len(values)] = values + + def write_to_file(self, file): + with open(file, 'wb') as outfile: + outfile.write(self.buffer) + + def read_from_file(self, file): + with open(file, 'rb') as stream: + self.buffer = bytearray(stream.read()) + +def rom_code(rom): + rom.write_bytes(0x008510, bytearray([0x48, 0xa9, 0x69, 0x42, 0x8d, 0x45, 0x15, 0x68, 0x80, 0x22])) + rom.write_bytes(0x002FE3, bytearray([0x5c, 0x03, 0xff, 0x02])) + rom.write_bytes(0x00ACF5, bytearray([0x5c, 0x48, 0xff, 0x02])) + rom.write_bytes(0x0028FB, bytearray([0x5c, 0x70, 0xff, 0x02])) + rom.write_bytes(0x004EC8, bytearray([0x4C, 0x40, 0xCF])) + rom.write_bytes(0x009FBC, bytearray([0x80])) + rom.write_bytes(0x0057EA, bytearray([0xEA, 0xEA])) + rom.write_bytes(0x0057F2, bytearray([0x80])) + rom.write_bytes(0x005827, bytearray([0x5c, 0x5B, 0xFF, 0x08])) + rom.write_bytes(0x006C1C, bytearray([0x5c, 0x81, 0xFF, 0x02])) + rom.write_bytes(0x005808, bytearray([0xC9, 0x01, 0x00, 0x80, 0x11])) + rom.write_bytes(0x00AC75, bytearray([0x5c, 0x50, 0xFE, 0x08])) + rom.write_bytes(0x00ACFA, bytearray([0x08, 0x00, 0x10, 0x00, 0x20, 0x00])) + rom.write_bytes(0x0029AE, bytearray([0x5c, 0x80, 0xFE, 0x08])) + rom.write_bytes(0x002738, bytearray([0x80])) + rom.write_bytes(0x002945, bytearray([0x5c, 0xB3, 0xFE, 0x08])) + rom.write_bytes(0x00707C, bytearray([0x01, 0x02, 0x04, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20])) + rom.write_bytes(0x00F8C3, bytearray([0x5c, 0xE0, 0xFE, 0x12])) + rom.write_bytes(0x00F4AB, bytearray([0x5c, 0xEB, 0xFE, 0x08])) + rom.write_bytes(0x0064F5, bytearray([0x5c, 0xF8, 0xFE, 0x08])) + rom.write_bytes(0x0054CA, bytearray([0xA9, 0x00])) + rom.write_bytes(0x01088E, bytearray([0x5C, 0xA9, 0xFF, 0x08])) + rom.write_bytes(0x00A48E, bytearray([0x5C, 0xC6, 0xFF, 0x08])) + rom.write_bytes(0x00294E, bytearray([0xEA, 0xEA, 0xEA])) + rom.write_bytes(0x004ECB, bytearray([0xf8, 0xce, 0xfa, 0xce, 0xfc, 0xce, 0xfe, 0xce, 0xfc, 0xce, 0x00, 0xcf, 0x02, 0xcf, 0xfa, 0xce])) + rom.write_bytes(0x004EDB, bytearray([0x00, 0xcf, 0xfc, 0xce, 0x00, 0xcf, 0x00, 0xcf, 0x02, 0xcf, 0xfe, 0xce, 0xf8, 0xce, 0x2e, 0x32])) + rom.write_bytes(0x004EEB, bytearray([0x32, 0x2e, 0x32, 0x30, 0x30, 0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x2e, 0x2e, 0x32, 0x30, 0x30])) + rom.write_bytes(0x004EFB, bytearray([0x2e, 0x2e, 0x30, 0x30, 0x32, 0x2e, 0x32, 0x32, 0x2e])) + rom.write_bytes(0x001B35, bytearray([0x5C, 0x1D, 0xFF, 0x12])) + + + rom.write_bytes(0x017F03, bytearray([0x8b, 0xa9, 0x7e, 0x48, 0xab, 0xa9, 0x00, 0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x55, 0x15, 0x29])) + rom.write_bytes(0x017F13, bytearray([0x07, 0x8d, 0x0a, 0x05, 0xf0, 0x27, 0xad, 0x08, 0x05, 0xd0, 0x1a, 0xad, 0x0a, 0x05, 0x89, 0x01])) + rom.write_bytes(0x017F23, bytearray([0xf0, 0x07, 0xa9, 0x01, 0x8d, 0x08, 0x05, 0x80, 0x0c, 0x89, 0x02, 0xf0, 0x04, 0xa9, 0x02, 0x80])) + rom.write_bytes(0x017F33, bytearray([0xf3, 0xa9, 0x04, 0x80, 0xef, 0xad, 0x0a, 0x05, 0xab, 0x5c, 0xe8, 0xaf, 0x80, 0x9c, 0x08, 0x05])) + rom.write_bytes(0x017F43, bytearray([0xab, 0x5c, 0x09, 0xb0, 0x80, 0x8b, 0xda, 0xe2, 0x20, 0x48, 0xa9, 0x7e, 0x48, 0xab, 0xa9, 0x00])) + rom.write_bytes(0x017F53, bytearray([0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x55, 0x15, 0x8d, 0x53, 0x15, 0x68, 0x0c, 0x53, 0x15, 0xad])) + rom.write_bytes(0x017F63, bytearray([0x53, 0x15, 0x9d, 0x55, 0x15, 0xc2, 0x20, 0xfa, 0xab, 0x5c, 0xf9, 0xac, 0x81, 0xe2, 0x20, 0xee])) + rom.write_bytes(0x017F73, bytearray([0x54, 0x15, 0xc2, 0x20, 0xa9, 0x84, 0x03, 0x8d, 0x65, 0x05, 0x5c, 0x01, 0xa9, 0x80, 0xe2, 0x20])) + rom.write_bytes(0x017F83, bytearray([0x8b, 0xa9, 0x7e, 0x48, 0xab, 0xad, 0x39, 0x00, 0xc9, 0x04, 0xd0, 0x28, 0xad, 0x04, 0x05, 0xf0])) + rom.write_bytes(0x017F93, bytearray([0x23, 0xce, 0x04, 0x05, 0xa9, 0x05, 0x8d, 0x93, 0x05, 0x22, 0xa7, 0x82, 0x80, 0x68, 0x68, 0x68])) + rom.write_bytes(0x017FA3, bytearray([0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0xab, 0x28, 0xc2, 0x20, 0xa9, 0x93, 0x01, 0x8d, 0x95, 0x05])) + rom.write_bytes(0x017FB3, bytearray([0x5c, 0xa3, 0xd4, 0x80, 0xab, 0xc2, 0x20, 0xae, 0x85, 0x06, 0xbd, 0x65, 0x0d, 0x5c, 0x22, 0xec])) + rom.write_bytes(0x017FC3, bytearray([0x80])) + + rom.write_bytes(0x047E50, bytearray([0x22, 0x03, 0x92, 0x80, 0xe0, 0x28, 0x00, 0x90, 0x23, 0xda, 0xe2, 0x20, 0xbd, 0xd2, 0xac, 0x8f])) + rom.write_bytes(0x047E60, bytearray([0x53, 0x15, 0x7e, 0x8b, 0x20, 0x94, 0xff, 0xa9, 0x00, 0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x55])) + rom.write_bytes(0x047E70, bytearray([0x15, 0x18, 0x2c, 0x53, 0x15, 0xd0, 0x01, 0x38, 0xc2, 0x20, 0xab, 0xfa, 0x5c, 0x7c, 0xac, 0x81])) + rom.write_bytes(0x047E80, bytearray([0xe2, 0x20, 0x8b, 0xad, 0x53, 0x05, 0xaa, 0xbf, 0x7c, 0xf0, 0x00, 0x48, 0x20, 0x94, 0xff, 0x68])) + rom.write_bytes(0x047E90, bytearray([0x8d, 0x53, 0x15, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x64, 0x15, 0x2c, 0x53, 0x15, 0xf0, 0x07, 0xab])) + rom.write_bytes(0x047EA0, bytearray([0xc2, 0x20, 0x5c, 0xbc, 0xa9, 0x80, 0xab, 0xc2, 0x20, 0xae, 0x08, 0x05, 0xbd, 0x28, 0xaf, 0x5c])) + rom.write_bytes(0x047EB0, bytearray([0xb4, 0xa9, 0x80, 0xe2, 0x20, 0x8b, 0xae, 0x53, 0x05, 0xbf, 0x7c, 0xf0, 0x00, 0x48, 0x20, 0x94])) + rom.write_bytes(0x047EC0, bytearray([0xff, 0x68, 0x8d, 0x53, 0x15, 0xa9, 0x00, 0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x64, 0x15, 0x0c])) + rom.write_bytes(0x047ED0, bytearray([0x53, 0x15, 0xad, 0x53, 0x15, 0x9d, 0x64, 0x15, 0xee, 0x4f, 0x15, 0xc2, 0x20, 0xae, 0x51, 0x05])) + rom.write_bytes(0x047EE0, bytearray([0xab, 0xbd, 0x2d, 0xaf, 0x0d, 0x4f, 0x05, 0x5c, 0x4b, 0xa9, 0x80, 0x20, 0x05, 0xff, 0xad, 0x55])) + rom.write_bytes(0x047EF0, bytearray([0x08, 0xc9, 0x80, 0x00, 0x5c, 0xb1, 0xf4, 0x81, 0x20, 0x05, 0xff, 0xad, 0x55, 0x08, 0xc9, 0x60])) + rom.write_bytes(0x047F00, bytearray([0x00, 0x5c, 0xfb, 0xe4, 0x80, 0xa9, 0x00, 0x00, 0xda, 0x5a, 0x8b, 0xe2, 0x20, 0x20, 0x94, 0xff])) + rom.write_bytes(0x047F10, bytearray([0x48, 0xab, 0xad, 0x50, 0x15, 0xf0, 0x39, 0xa0, 0x00, 0x00, 0xc9, 0x2e, 0xf0, 0x38, 0xc9, 0x04])) + rom.write_bytes(0x047F20, bytearray([0x90, 0x06, 0x38, 0xe9, 0x03, 0xc8, 0x80, 0xf2, 0xaa, 0xbf, 0x7f, 0xf0, 0x00, 0x48, 0xb9, 0x55])) + rom.write_bytes(0x047F30, bytearray([0x15, 0x8d, 0x53, 0x15, 0x68, 0x0c, 0x53, 0x15, 0xad, 0x53, 0x15, 0x99, 0x55, 0x15, 0xa0, 0x01])) + rom.write_bytes(0x047F40, bytearray([0x00, 0x9c, 0x50, 0x15, 0xc2, 0x20, 0xa9, 0x04, 0x00, 0xab, 0x22, 0x03, 0x92, 0x80, 0x80, 0x03])) + rom.write_bytes(0x047F50, bytearray([0xc2, 0x20, 0xab, 0x7a, 0xfa, 0x60, 0xee, 0x4e, 0x15, 0x80, 0xe3, 0xda, 0x8b, 0xe0, 0x0a, 0x00])) + rom.write_bytes(0x047F60, bytearray([0xd0, 0x1d, 0xe2, 0x20, 0x20, 0x94, 0xff, 0xad, 0x04, 0x05, 0xc9, 0x02, 0xf0, 0x2b, 0xaa, 0xbd])) + rom.write_bytes(0x047F70, bytearray([0x40, 0x15, 0xd0, 0x0b, 0xad, 0x4e, 0x15, 0xf0, 0x14, 0xce, 0x4e, 0x15, 0xfe, 0x40, 0x15, 0xc2])) + rom.write_bytes(0x047F80, bytearray([0x20, 0xa9, 0x01, 0x00, 0xab, 0xfa, 0x8d, 0xc3, 0x0d, 0x5c, 0x2d, 0xd8, 0x80, 0xc2, 0x20, 0xa9])) + rom.write_bytes(0x047F90, bytearray([0x00, 0x00, 0xf0, 0xf0, 0xa9, 0x7e, 0x48, 0xab, 0x60, 0xad, 0x4f, 0x15, 0xcf, 0x10, 0xff, 0x1f])) + rom.write_bytes(0x047FA0, bytearray([0xb0, 0xdd, 0xc2, 0x20, 0xa9, 0x00, 0x00, 0x80, 0xdb, 0x48, 0xe2, 0x20, 0xad, 0x7b, 0x12, 0xc9])) + rom.write_bytes(0x047FB0, bytearray([0xea, 0xd0, 0x06, 0xa9, 0x69, 0x8f, 0x43, 0x15, 0x7e, 0xc2, 0x20, 0x68, 0x7d, 0x7b, 0x12, 0x9d])) + rom.write_bytes(0x047FC0, bytearray([0x7b, 0x12, 0x5c, 0x94, 0x88, 0x82, 0xad, 0x02, 0x05, 0xaa, 0xe2, 0x20, 0xbd, 0x64, 0x15, 0xda])) + rom.write_bytes(0x047FD0, bytearray([0x8d, 0x53, 0x15, 0xad, 0x53, 0x05, 0xaa, 0xbf, 0x83, 0xf0, 0x00, 0x0c, 0x53, 0x15, 0xad, 0x53])) + rom.write_bytes(0x047FE0, bytearray([0x15, 0xfa, 0x9d, 0x64, 0x15, 0xc2, 0x20, 0xad, 0x02, 0x05, 0x0a, 0x5c, 0x92, 0xa4, 0x81])) + + rom.write_bytes(0x097EE0, bytearray([0xae, 0x85, 0x06, 0xda, 0x8a, 0xe2, 0x20, 0xa2, 0x00, 0x00, 0xdd, 0x31, 0x15, 0xf0, 0x03, 0xe8])) + rom.write_bytes(0x097EF0, bytearray([0x80, 0xf8, 0xbf, 0x7c, 0xf0, 0x00, 0x8d, 0x30, 0x15, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x64, 0x15])) + rom.write_bytes(0x097F00, bytearray([0x29, 0x07, 0x0c, 0x30, 0x15, 0xf0, 0x0c, 0xa9, 0xff, 0x8d, 0x4f, 0x05, 0xc2, 0x20, 0xfa, 0x5c])) + rom.write_bytes(0x097F10, bytearray([0xce, 0xf8, 0x81, 0x9c, 0x4f, 0x05, 0xc2, 0x20, 0xfa, 0x5c, 0xcf, 0xf8, 0x81, 0xda, 0xb9, 0x5e])) + rom.write_bytes(0x097F20, bytearray([0x9b, 0x8d, 0x02, 0x05, 0xe2, 0x20, 0xeb, 0xa9, 0x00, 0xeb, 0x0a, 0xaa, 0xc2, 0x20, 0xbf, 0xcb])) + rom.write_bytes(0x097F30, bytearray([0xce, 0x80, 0xaa, 0xbd, 0x00, 0x00, 0x8d, 0x31, 0x15, 0xe2, 0x20, 0xae, 0x02, 0x05, 0xbf, 0xe9])) + rom.write_bytes(0x097F40, bytearray([0xce, 0x80, 0x8d, 0x33, 0x15, 0xc2, 0x20, 0xfa, 0x5c, 0x3b, 0x9b, 0x00, 0xc9, 0x10, 0xd0, 0x02])) + rom.write_bytes(0x097F50, bytearray([0xa9, 0x08, 0x8d, 0x73, 0x15, 0xe0, 0x0a, 0x00, 0xb0, 0x56, 0x48, 0x20, 0x80, 0xff, 0xeb, 0xa9])) + rom.write_bytes(0x097F60, bytearray([0x00, 0xeb, 0x20, 0x94, 0xff, 0x68, 0x20, 0x9f, 0xff, 0xad, 0x74, 0x15, 0x18, 0x6d, 0x75, 0x15])) + rom.write_bytes(0x097F70, bytearray([0xaa, 0xbd, 0x82, 0x15, 0xc2, 0x20, 0x0d, 0x80, 0x15, 0x9d, 0x82, 0x15, 0x5c, 0x12, 0xb5, 0x80])) + rom.write_bytes(0x097F80, bytearray([0xda, 0xc2, 0x20, 0xae, 0x02, 0x05, 0x8a, 0x0a, 0xaa, 0xbf, 0x04, 0xcf, 0x80, 0x8d, 0x80, 0x15])) + rom.write_bytes(0x097F90, bytearray([0xfa, 0xe2, 0x20, 0x60, 0x8a, 0x4a, 0xaa, 0xbf, 0x22, 0xcf, 0x80, 0x8d, 0x75, 0x15, 0x60, 0xa2])) + rom.write_bytes(0x097FA0, bytearray([0x00, 0x00, 0xc9, 0x01, 0xf0, 0x05, 0x4a, 0xe8, 0xe8, 0x80, 0xf7, 0x8a, 0x8d, 0x74, 0x15, 0x60])) + rom.write_bytes(0x097FB0, bytearray([0xa2, 0x00, 0x00, 0xad, 0x73, 0x15, 0xc9, 0x20, 0xf0, 0x04, 0x4a, 0xe8, 0x80, 0xf8, 0x8e, 0x74])) + rom.write_bytes(0x097FC0, bytearray([0x15, 0x20, 0x80, 0xff, 0xeb, 0xa9, 0x00, 0xeb, 0xad, 0x74, 0x15, 0x0a, 0xaa, 0xc2, 0x20, 0xbd])) + rom.write_bytes(0x097FD0, bytearray([0xaa, 0x15, 0x0d, 0x80, 0x15, 0x9d, 0xaa, 0x15, 0x5c, 0x12, 0xb5, 0x80])) + + rom.write_bytes(0x004F04, bytearray([0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00])) + rom.write_bytes(0x004F14, bytearray([0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x08])) + rom.write_bytes(0x004F24, bytearray([0x10, 0x18, 0x20])) + + +def patch_rom(world, rom, player: int, multiworld): + rom_code(rom) + if world.options.computer_sanity.value == 1: + rom.write_bytes(0x00350C, bytearray([0x5C, 0x4C, 0xFF, 0x12])) + rom.write_bytes(0x001B5E, bytearray(world.city_order)) + rom.write_byte(0x0FFF10, world.options.required_artifacts.value) + rom.write_byte(0x0FFF11, world.options.death_link.value) + + from Main import __version__ + rom.name = bytearray(f'MarioMissingAP{__version__.replace(".", "")[0:3]}_{player}_{multiworld.seed:11}\0', 'utf8')[:15] + rom.name.extend([0] * (15 - len(rom.name))) + rom.write_bytes(0x007FC0, rom.name) + +class MIMDeltaPatch(APDeltaPatch): + hash = USHASH + game: str = "Mario is Missing" + patch_file_ending = ".apmim" + + @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: + options: Utils.OptionsType = Utils.get_options() + if not file_name: + file_name = options["mariomissing_options"]["rom_file"] + if not os.path.exists(file_name): + file_name = Utils.user_path(file_name) + return file_name diff --git a/worlds/mariomissing/SetupGame.py b/worlds/mariomissing/SetupGame.py new file mode 100644 index 000000000000..4288eed7a3c8 --- /dev/null +++ b/worlds/mariomissing/SetupGame.py @@ -0,0 +1,27 @@ +import itertools + +def setup_gamevars(world): + world.city_order = [0x04, 0x0B, 0x08, 0x0C, 0x00, 0x01, 0x0E, 0x06, 0x0D, 0x05, 0x02, 0x0A, 0x07, 0x09, 0x03] + world.city_list = [] + if world.options.city_shuffle != 0: + world.random.shuffle(world.city_order) + + city_code = { + 0x00: "Rome", + 0x01: "Paris", + 0x02: "London", + 0x03: "New York", + 0x04: "San Francisco", + 0x05: "Athens", + 0x06: "Sydney", + 0x07: "Tokyo", + 0x08: "Nairobi", + 0x09: "Rio de Janeiro", + 0x0A: "Cairo", + 0x0B: "Moscow", + 0x0C: "Beijing", + 0x0D: "Buenos Aires", + 0x0E: "Mexico City", + } + world.city_list = [city_code[world.city_order[i]] for i in range(15)] + world.city_order = list(itertools.chain.from_iterable((x, 0x00) for x in world.city_order)) diff --git a/worlds/mariomissing/__init__.py b/worlds/mariomissing/__init__.py new file mode 100644 index 000000000000..b84e1f39c975 --- /dev/null +++ b/worlds/mariomissing/__init__.py @@ -0,0 +1,251 @@ +import os +import typing +import threading +import dataclasses + +from typing import Dict, List, Set, TextIO +from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification +from worlds.AutoWorld import World, WebWorld +from Options import PerGameCommonOptions +import Patch +import settings +from .Items import get_item_names_per_category, item_table, filler_items, artifacts +from .Locations import get_locations +from .Regions import create_regions +from .Options import MarioisMissingOptions +from .SetupGame import setup_gamevars +from .Client import MIMSNIClient +from .Rom import LocalRom, patch_rom, get_base_rom_path, MIMDeltaPatch, USHASH + +class MiMSettings(settings.Group): + class RomFile(settings.SNESRomPath): + """File name of the Mario is Missing US ROM""" + description = "Mario is Missing ROM File" + copy_to = "Mario Is Missing! (USA).sfc" + md5s = [USHASH] + + rom_file: RomFile = RomFile(RomFile.copy_to) + +class MiMWeb(WebWorld): + theme = "partyTime" + + setup_en = Tutorial( + "Multiworld Setup Guide", + "A guide to setting up the Mario is Missing randomizer" + "and connecting to an Archipelago server.", + "English", + "setup_en.md", + "setup/en", + ["Pink Switch"] + ) + + tutorials = [setup_en] + +class MarioisMissingWorld(World): + """Mario is Missing is a 2D edutainment game. As Luigi, save cities of the world from Bowser's terror while searching his castle for Mario.""" + game: str = "Mario is Missing" + option_definitions = MarioisMissingOptions + data_version = 1 + required_client_version = (0, 3, 5) + + 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, None, None)} + item_name_groups = get_item_names_per_category() + + web = MiMWeb() + settings: typing.ClassVar[MiMSettings] + #topology_present = True + + options_dataclass = MarioisMissingOptions + options: MarioisMissingOptions + + locked_locations: List[str] + location_cache: List[Location] + + def __init__(self, world: MultiWorld, player: int): + self.rom_name_available_event = threading.Event() + super().__init__(world, player) + + self.locked_locations= [] + self.location_cache= [] + + @classmethod + def stage_assert_generate(cls, multiworld): + rom_file = get_base_rom_path() + if not os.path.exists(rom_file): + raise FileNotFoundError(rom_file) + + def write_spoiler_header(self, spoiler_handle: TextIO) -> None: + spoiler_handle.write(f"Floor 1: {self.city_list[0:5]}\n") + spoiler_handle.write(f"Floor 2: {self.city_list[5:10]}\n") + spoiler_handle.write(f"Floor 3: {self.city_list[10:15]}\n") + + def create_item(self, name: str) -> Item: + data = item_table[name] + + if data.useful: + classification = ItemClassification.useful + elif data.progression: + classification = ItemClassification.progression + elif data.trap: + classification = ItemClassification.trap + else: + classification = ItemClassification.filler + + item = Item(name, classification, data.code, self.player) + + return item + + def create_regions(self): + create_regions(self.multiworld, self.player, get_locations(self.multiworld, self.player, self), + self.location_cache, self) + + def get_filler_item_name(self) -> str: + if self.options.computer_sanity.value == 1: + return self.random.choice(filler_items) + else: + return "Photograph" + + def set_rules(self): + self.multiworld.completion_condition[self.player] = lambda state: state.has('Mario', self.player) + self.multiworld.get_location("Bowser", self.player).place_locked_item(self.create_item("Mario")) + + self.multiworld.get_location("Colosseum - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Trevi Fountain - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Sistine Chapel - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Cathedral of Notre Dame - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Arc de Triomphe - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Eiffel Tower - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Tower of London - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Westminster Abbey - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Big Ben - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Empire State Building - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Statue of Liberty - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Rockefeller Center - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Golden Gate Bridge - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Coit Tower - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Transamerica Pyramid - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Erechtheion Temple - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Hadrian's Arch - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Parthenon - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Bondi Beach - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Taronga Zoo - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Sydney Opera - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Great Buddha of Kamakura - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Sensoji Temple - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Kokugikan Arena - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Nairobi National Park - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Maasai Village - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("National Museum of Kenya - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Christ the Redeemer Statue - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Copacabana Beach - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Sugar Loaf Mountain - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Great Pyramid - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Mosque of Mohammed - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Sphinx - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Kremlin - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("St. Basil's Cathedral - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Bolshoi Ballet - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Temple of Heaven - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Great Wall of China - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Forbidden City - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Teatro Colon - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Gaucho Museum - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Obelisk Monument - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Angel of Independence - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("National Palace - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + self.multiworld.get_location("Fine Arts Palace - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) + + def place_locked_item(self, excluded_items: Set[str], location: str, item: str) -> None: + excluded_items.add(item) + + item = self.create_item(item) + + self.multiworld.get_location(location, self.player).place_locked_item(item) + + def generate_early(self): + setup_gamevars(self) + + + def get_excluded_items(self) -> Set[str]: + excluded_items: Set[str] = set() + for item in self.multiworld.start_inventory[self.player]: + if item in artifacts: + excluded_items.add(item) + + return excluded_items + + def create_item_with_correct_settings(self, player: int, name: str) -> Item: + data = item_table[name] + if data.useful: + classification = ItemClassification.useful + elif data.progression: + classification = ItemClassification.progression + elif data.trap: + classification = ItemClassification.trap + else: + classification = ItemClassification.filler + item = Item(name, classification, data.code, player) + + if not item.advancement: + return item + + return item + + def generate_filler(self, multiworld: MultiWorld, player: int, + pool: List[Item]): + + for _ in range(len(multiworld.get_unfilled_locations(player)) - len(pool) - 46): + item = self.create_item_with_correct_settings(player, self.get_filler_item_name()) + pool.append(item) + + def get_item_pool(self, player: int, 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(player, name) + pool.append(item) + + return pool + + def create_items(self): + excluded_items = self.get_excluded_items() + + pool = self.get_item_pool(self.player, excluded_items) + + self.generate_filler(self.multiworld, self.player, pool) + + self.multiworld.itempool += pool + + def generate_output(self, output_directory: str): + + 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, self.multiworld) + + 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 = MIMDeltaPatch(os.path.splitext(rompath)[0]+MIMDeltaPatch.patch_file_ending, player=player, + player_name=world.player_name[player], patched_path=rompath) + patch.write() + finally: + self.rom_name_available_event.set() # make sure threading continues and errors are collected + if os.path.exists(rompath): + os.unlink(rompath) + + def modify_multidata(self, multidata: dict): + import base64 + # wait for self.rom_name to be available. + self.rom_name_available_event.wait() + rom_name = getattr(self, "rom_name", None) + # we skip in case of error, so that the original error in the output thread is the one that gets raised + 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]] From 814b145fe1dbf88c18cabbb8b1342fb61742a003 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:46:11 -0600 Subject: [PATCH 07/30] Delete worlds/mariomissing/d --- worlds/mariomissing/d | 1 - 1 file changed, 1 deletion(-) delete mode 100644 worlds/mariomissing/d diff --git a/worlds/mariomissing/d b/worlds/mariomissing/d deleted file mode 100644 index 8b137891791f..000000000000 --- a/worlds/mariomissing/d +++ /dev/null @@ -1 +0,0 @@ - From e45fd1c6cfb207bbf7731e9f632c7e78fb0a0883 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Sun, 24 Dec 2023 23:13:15 -0600 Subject: [PATCH 08/30] Delete worlds/mariomissing directory --- worlds/mariomissing/Client.py | 146 ------- worlds/mariomissing/Items.py | 105 ----- worlds/mariomissing/Locations.py | 535 ----------------------- worlds/mariomissing/Options.py | 24 -- worlds/mariomissing/Regions.py | 97 ----- worlds/mariomissing/Rom.py | 698 ------------------------------- worlds/mariomissing/SetupGame.py | 27 -- worlds/mariomissing/__init__.py | 251 ----------- 8 files changed, 1883 deletions(-) delete mode 100644 worlds/mariomissing/Client.py delete mode 100644 worlds/mariomissing/Items.py delete mode 100644 worlds/mariomissing/Locations.py delete mode 100644 worlds/mariomissing/Options.py delete mode 100644 worlds/mariomissing/Regions.py delete mode 100644 worlds/mariomissing/Rom.py delete mode 100644 worlds/mariomissing/SetupGame.py delete mode 100644 worlds/mariomissing/__init__.py diff --git a/worlds/mariomissing/Client.py b/worlds/mariomissing/Client.py deleted file mode 100644 index e89ee0036b7b..000000000000 --- a/worlds/mariomissing/Client.py +++ /dev/null @@ -1,146 +0,0 @@ -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 -else: - SNIContext = typing.Any - -snes_logger = logging.getLogger("SNES") - -GAME_MIM = "Mario is Missing" - -ROM_START = 0x000000 -WRAM_START = 0xF50000 -WRAM_SIZE = 0x20000 -SRAM_START = 0xE00000 - -MIM_ROMHASH_START = 0x007FC0 -ROMHASH_SIZE = 0x0F - -ITEM_RECEIVED = WRAM_START + 0x1550 -ITEM_LIST = WRAM_START + 0x1551 -DEATH_RECEIVED = WRAM_START + 0x1554 -GOAL_FLAG = WRAM_START + 0x1543 -VALIDATION_CHECK = WRAM_START + 0x1545 -VALIDATION_CHECK_2 = WRAM_START + 0x1546 -MIM_DEATHLINK_ENABLED = ROM_START + 0x0FFF11 - -class MIMSNIClient(SNIClient): - game = "Mario is Missing" - - async def deathlink_kill_player(self, ctx): - from SNIClient import DeathState, snes_buffered_write, snes_flush_writes, snes_read - validation_check_low = await snes_read(ctx, VALIDATION_CHECK, 0x1) - if validation_check_low[0] != 0x69: - return - - validation_check_high = await snes_read(ctx, VALIDATION_CHECK_2, 0x1) - if validation_check_high[0] != 0x42: - return - - snes_buffered_write(ctx, WRAM_START + 0x0565, bytes([0x84])) - snes_buffered_write(ctx, WRAM_START + 0x0566, bytes([0x03])) - await snes_flush_writes(ctx) - ctx.death_state = DeathState.dead - ctx.last_death_link = time.time() - - async def validate_rom(self, ctx): - from SNIClient import snes_buffered_write, snes_flush_writes, snes_read - - rom_name = await snes_read(ctx, MIM_ROMHASH_START, ROMHASH_SIZE) - if rom_name is None or rom_name == bytes([0] * ROMHASH_SIZE) or rom_name[:14] != b"MarioMissingAP": - return False - - ctx.game = self.game - ctx.items_handling = 0b111 # remote items - ctx.rom = rom_name - - death_link = await snes_read(ctx, MIM_DEATHLINK_ENABLED, 1) - if death_link: - await ctx.update_death_link(bool(death_link[0] & 0b1)) - return True - - async def game_watcher(self, ctx): - from SNIClient import snes_buffered_write, snes_flush_writes, snes_read - - - validation_check_low = await snes_read(ctx, VALIDATION_CHECK, 0x1) - validation_check_high = await snes_read(ctx, VALIDATION_CHECK_2, 0x1) - goal_done = await snes_read(ctx, GOAL_FLAG, 0x1) - current_item = await snes_read(ctx, ITEM_RECEIVED, 0x1) - is_dead = await snes_read(ctx, DEATH_RECEIVED, 0x1) - - if "DeathLink" in ctx.tags and ctx.last_death_link + 1 < time.time(): - currently_dead = is_dead[0] == 0x01 - await ctx.handle_deathlink_state(currently_dead) - if is_dead[0] != 0x00: - snes_buffered_write(ctx, WRAM_START + 0x1554, bytes([0x00])) - if validation_check_low is None: - return - - if validation_check_high is None: - return - if validation_check_low[0] != 0x69: - return - if validation_check_high[0] != 0x42: - return - if current_item[0] > 0x00: - return - if goal_done[0] == 0x69: - await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) - ctx.finished_game = True - - rom = await snes_read(ctx, MIM_ROMHASH_START, ROMHASH_SIZE) - if rom != ctx.rom: - ctx.rom = None - return - - new_checks = [] - from .Rom import location_table, item_values - - location_ram_data = await snes_read(ctx, WRAM_START + 0x1555, 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] - 0x1555] - 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] - snes_logger.info( - f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})') - await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) - - recv_count = await snes_read(ctx, ITEM_LIST, 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, ITEM_LIST, 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/mariomissing/Items.py b/worlds/mariomissing/Items.py deleted file mode 100644 index 3da72ca3a9c9..000000000000 --- a/worlds/mariomissing/Items.py +++ /dev/null @@ -1,105 +0,0 @@ -from typing import Dict, Set, Tuple, NamedTuple - -class ItemData(NamedTuple): - category: str - code: int - amount: int = 1 - progression: bool = False - progression_skip_balancing: bool = False - useful: bool = False - trap: bool = False - -item_table: Dict[str, ItemData] = { - #Rome - "Gladiator's Spear": ItemData('Artifacts', 0x198401, progression=True), - 'Coins from the Trevi Fountain': ItemData('Artifacts', 0x198402, progression=True), - 'Sistine Chapel Ceiling': ItemData('Artifacts', 0x198403, progression=True), - #Paris - 'Notre Dame Bell': ItemData('Artifacts', 0x198404, progression=True), - 'Eternal Flame': ItemData('Artifacts', 0x198405, progression=True), - 'Tricolor': ItemData('Artifacts', 0x198406, progression=True), - #London - 'Crown Jewels': ItemData('Artifacts', 0x198407, progression=True), - 'Bust of Shakespeare': ItemData('Artifacts', 0x198408, progression=True), - "Big Ben's Minute Hand": ItemData('Artifacts', 0x198409, progression=True), - #New York - 'King Kong': ItemData('Artifacts', 0x19840A, progression=True), - 'Statue of Liberty Torch': ItemData('Artifacts', 0x19840B, progression=True), - "Statue of Prometheus": ItemData('Artifacts', 0x19840C, progression=True), - #San Francisco - 'Golden Gate Bridge Foghorn': ItemData('Artifacts', 0x19840D, progression=True), - 'Window from Coit Tower': ItemData('Artifacts', 0x19840E, progression=True), - "Top of the Transamerica Pyramid": ItemData('Artifacts', 0x19840F, progression=True), - #Athens - 'Caryatid': ItemData('Artifacts', 0x198410, progression=True), - 'Brass Plaque': ItemData('Artifacts', 0x198411, progression=True), - "Parthenon Column": ItemData('Artifacts', 0x198412, progression=True), - #Sydney - 'Surfboard from Bondi Beach': ItemData('Artifacts', 0x198413, progression=True), - 'Taronga Zoo Koala': ItemData('Artifacts', 0x198414, progression=True), - "Sydney Opera Sheet Music": ItemData('Artifacts', 0x198415, progression=True), - #Tokyo - "Great Buddha's Orange": ItemData('Artifacts', 0x198416, progression=True), - 'Sensoji Temple Latern': ItemData('Artifacts', 0x198417, progression=True), - "Sumo Apron": ItemData('Artifacts', 0x198418, progression=True), - #Nairobi - 'Baby Elephant': ItemData('Artifacts', 0x198419, progression=True), - 'Maasai Headdress': ItemData('Artifacts', 0x19841A, progression=True), - "Human Skull": ItemData('Artifacts', 0x19841B, progression=True), - #Rio de Janeiro - 'Spotlight from Christ the Redeemer Statue': ItemData('Artifacts', 0x19841C, progression=True), - 'Copacabana Beach Seashell': ItemData('Artifacts', 0x19841D, progression=True), - "Sugar Loaf Mountain Cable Car": ItemData('Artifacts', 0x19841E, progression=True), - #Cairo - 'Top Brick of the Great Pyramid': ItemData('Artifacts', 0x19841F, progression=True), - 'Gingerbread Clock': ItemData('Artifacts', 0x198420, progression=True), - "Klaft of the Sphinx": ItemData('Artifacts', 0x198421, progression=True), - #Moscow - "Cannonball from the Emperor's Cannon": ItemData('Artifacts', 0x198422, progression=True), - 'Cathedral Dome': ItemData('Artifacts', 0x198423, progression=True), - "Bolshoi Ballet Slipper": ItemData('Artifacts', 0x198424, progression=True), - #Beijing - 'Hall of Good Harvest': ItemData('Artifacts', 0x198425, progression=True), - 'Stone from the Great Wall': ItemData('Artifacts', 0x198426, progression=True), - "Gate of Heavenly Peace": ItemData('Artifacts', 0x198427, progression=True), - #Buenos Aires - 'Flute from the Teatro Colon': ItemData('Artifacts', 0x198428, progression=True), - 'Boleadoras': ItemData('Artifacts', 0x198429, progression=True), - "Stone from the Obelisk": ItemData('Artifacts', 0x19842A, progression=True), - #Mexico City - 'Angel': ItemData('Artifacts', 0x19842B, progression=True), - 'Diego Rivera Mural': ItemData('Artifacts', 0x19842C, progression=True), - "Fine Arts Catalog": ItemData('Artifacts', 0x19842D, progression=True), - - "Castle Floor Key": ItemData('Other', 0x19842E, 2, progression=True), - "Newspaper": ItemData('Other', 0x19842F), - "Mario": ItemData('Events', None, 0, progression=True), - "Artifact Secured": ItemData('Events', None, 0, progression=True), - "Photograph": ItemData('Other', 0x198430), - "Advice": ItemData('Other', 0x198431) - -} - -filler_items: Tuple[str, ...] = ( - 'Photograph', - 'Newspaper', - 'Advice' -) - -artifacts: Tuple[str, ...] = ( - "Gladiator's Spear" - "Coins from the Trevi Fountain" - "Sistine Chapel Ceiling" - "Notre Dame Bell" - "Eternal Flame" - "Tricolor" -) - -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/mariomissing/Locations.py b/worlds/mariomissing/Locations.py deleted file mode 100644 index 05a30cc0845a..000000000000 --- a/worlds/mariomissing/Locations.py +++ /dev/null @@ -1,535 +0,0 @@ -from typing import List, Tuple, Optional, Callable, NamedTuple -from BaseClasses import MultiWorld - - -class LocationData(NamedTuple): - region: str - name: str - code: Optional[int] - rule: Callable = lambda state: True - - -def get_locations(multiworld: Optional[MultiWorld], player: Optional[int], world) -> Tuple[LocationData, ...]: - - location_table: List[LocationData] = [ - - LocationData('Rome', 'Rome - Koopa Treasure 1', 0x198400), - LocationData('Rome', 'Rome - Koopa Treasure 2', 0x198401), - LocationData('Rome', 'Rome - Koopa Treasure 3', 0x198402), - LocationData('Rome', 'Colosseum - Photograph', 0x198403, lambda state:state.has("Gladiator's Spear", player)), - LocationData('Rome', 'Trevi Fountain - Photograph', 0x198404, lambda state:state.has('Coins from the Trevi Fountain', player)), - LocationData('Rome', 'Sistine Chapel - Photograph', 0x198405, lambda state:state.has("Sistine Chapel Ceiling", player)), - - LocationData('Paris', 'Paris - Koopa Treasure 1', 0x198406), - LocationData('Paris', 'Paris - Koopa Treasure 2', 0x198407), - LocationData('Paris', 'Paris - Koopa Treasure 3', 0x198408), - LocationData('Paris', 'Cathedral of Notre Dame - Photograph', 0x198409, lambda state: state.has('Notre Dame Bell', player)), - LocationData('Paris', 'Arc de Triomphe - Photograph', 0x19840A, lambda state: state.has('Eternal Flame', player)), - LocationData('Paris', 'Eiffel Tower - Photograph', 0x19840B, lambda state: state.has('Tricolor', player)), - - LocationData('London', 'London - Koopa Treasure 1', 0x19840C), - LocationData('London', 'London - Koopa Treasure 2', 0x19840D), - LocationData('London', 'London - Koopa Treasure 3', 0x19840E), - LocationData('London', 'Tower of London - Photograph', 0x19840F, lambda state: state.has('Crown Jewels', player)), - LocationData('London', 'Westminster Abbey - Photograph', 0x198410, lambda state: state.has('Bust of Shakespeare', player)), - LocationData('London', 'Big Ben - Photograph', 0x198411, lambda state: state.has("Big Ben's Minute Hand", player)), - - LocationData('New York', 'New York - Koopa Treasure 1', 0x198412), - LocationData('New York', 'New York - Koopa Treasure 2', 0x198413), - LocationData('New York', 'New York - Koopa Treasure 3', 0x198414), - LocationData('New York', 'Empire State Building - Photograph', 0x198415, lambda state: state.has('King Kong', player)), - LocationData('New York', 'Statue of Liberty - Photograph', 0x198416, lambda state: state.has('Statue of Liberty Torch', player)), - LocationData('New York', 'Rockefeller Center - Photograph', 0x198417, lambda state: state.has('Statue of Prometheus', player)), - - LocationData('San Francisco', 'San Francisco - Koopa Treasure 1', 0x198418), - LocationData('San Francisco', 'San Francisco - Koopa Treasure 2', 0x198419), - LocationData('San Francisco', 'San Francisco - Koopa Treasure 3', 0x19841A), - LocationData('San Francisco', 'Golden Gate Bridge - Photograph', 0x19841B, lambda state: state.has('Golden Gate Bridge Foghorn', player)), - LocationData('San Francisco', 'Coit Tower - Photograph', 0x19841C, lambda state: state.has('Window from Coit Tower', player)), - LocationData('San Francisco', 'Transamerica Pyramid - Photograph', 0x1981D, lambda state: state.has('Top of the Transamerica Pyramid', player)), - - LocationData('Athens', 'Athens - Koopa Treasure 1', 0x19841E), - LocationData('Athens', 'Athens - Koopa Treasure 2', 0x19841F), - LocationData('Athens', 'Athens - Koopa Treasure 3', 0x198420), - LocationData('Athens', 'Erechtheion Temple - Photograph', 0x198421, lambda state: state.has('Caryatid', player)), - LocationData('Athens', "Hadrian's Arch - Photograph", 0x198422, lambda state: state.has('Brass Plaque', player)), - LocationData('Athens', 'Parthenon - Photograph', 0x198423, lambda state: state.has('Parthenon Column', player)), - - LocationData('Sydney', 'Sydney - Koopa Treasure 1', 0x198424), - LocationData('Sydney', 'Sydney - Koopa Treasure 2', 0x198425), - LocationData('Sydney', 'Sydney - Koopa Treasure 3', 0x198426), - LocationData('Sydney', 'Bondi Beach - Photograph', 0x198427, lambda state: state.has('Surfboard from Bondi Beach', player)), - LocationData('Sydney', 'Taronga Zoo - Photograph', 0x198428, lambda state: state.has('Taronga Zoo Koala', player)), - LocationData('Sydney', 'Sydney Opera - Photograph', 0x198429, lambda state: state.has('Sydney Opera Sheet Music', player)), - - LocationData('Tokyo', 'Tokyo - Koopa Treasure 1', 0x19842A), - LocationData('Tokyo', 'Tokyo - Koopa Treasure 2', 0x19842B), - LocationData('Tokyo', 'Tokyo - Koopa Treasure 3', 0x19842C), - LocationData('Tokyo', 'Great Buddha of Kamakura - Photograph', 0x19842D, lambda state: state.has("Great Buddha's Orange", player)), - LocationData('Tokyo', 'Sensoji Temple - Photograph', 0x19842E, lambda state: state.has('Sensoji Temple Latern', player)), - LocationData('Tokyo', 'Kokugikan Arena - Photograph', 0x19842F, lambda state: state.has('Sumo Apron', player)), - - LocationData('Nairobi', 'Nairobi - Koopa Treasure 1', 0x198430), - LocationData('Nairobi', 'Nairobi - Koopa Treasure 2', 0x198431), - LocationData('Nairobi', 'Nairobi - Koopa Treasure 3', 0x198432), - LocationData('Nairobi', 'Nairobi National Park - Photograph', 0x198433, lambda state: state.has('Baby Elephant', player)), - LocationData('Nairobi', 'Maasai Village - Photograph', 0x198434, lambda state: state.has('Maasai Headdress', player)), - LocationData('Nairobi', 'National Museum of Kenya - Photograph', 0x198435, lambda state: state.has('Human Skull', player)), - - LocationData('Rio de Janeiro', 'Rio de Janeiro - Koopa Treasure 1', 0x198436), - LocationData('Rio de Janeiro', 'Rio de Janeiro - Koopa Treasure 2', 0x198437), - LocationData('Rio de Janeiro', 'Rio de Janeiro - Koopa Treasure 3', 0x198438), - LocationData('Rio de Janeiro', 'Christ the Redeemer Statue - Photograph', 0x198439, lambda state: state.has('Spotlight from Christ the Redeemer Statue', player)), - LocationData('Rio de Janeiro', 'Copacabana Beach - Photograph', 0x19843A, lambda state: state.has('Copacabana Beach Seashell', player)), - LocationData('Rio de Janeiro', 'Sugar Loaf Mountain - Photograph', 0x19843B, lambda state: state.has('Sugar Loaf Mountain Cable Car', player)), - - LocationData('Cairo', 'Cairo - Koopa Treasure 1', 0x19843C), - LocationData('Cairo', 'Cairo - Koopa Treasure 2', 0x19843D), - LocationData('Cairo', 'Cairo - Koopa Treasure 3', 0x19843E), - LocationData('Cairo', 'Great Pyramid - Photograph', 0x19843F, lambda state: state.has('Top Brick of the Great Pyramid', player)), - LocationData('Cairo', 'Mosque of Mohammed - Photograph', 0x198440, lambda state: state.has('Gingerbread Clock', player)), - LocationData('Cairo', 'Sphinx - Photograph', 0x198441, lambda state: state.has('Klaft of the Sphinx', player)), - - LocationData('Moscow', 'Moscow - Koopa Treasure 1', 0x198442), - LocationData('Moscow', 'Moscow - Koopa Treasure 2', 0x198443), - LocationData('Moscow', 'Moscow - Koopa Treasure 3', 0x198444), - LocationData('Moscow', 'Kremlin - Photograph', 0x198445, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), - LocationData('Moscow', "St. Basil's Cathedral - Photograph", 0x198446, lambda state: state.has('Cathedral Dome', player)), - LocationData('Moscow', 'Bolshoi Ballet - Photograph', 0x198447, lambda state: state.has('Bolshoi Ballet Slipper', player)), - - LocationData('Beijing', 'Beijing - Koopa Treasure 1', 0x198448), - LocationData('Beijing', 'Beijing - Koopa Treasure 2', 0x198449), - LocationData('Beijing', 'Beijing - Koopa Treasure 3', 0x19844A), - LocationData('Beijing', 'Temple of Heaven - Photograph', 0x19844B, lambda state: state.has('Hall of Good Harvest', player)), - LocationData('Beijing', 'Great Wall of China - Photograph', 0x19844C, lambda state: state.has('Stone from the Great Wall', player)), - LocationData('Beijing', 'Forbidden City - Photograph', 0x19844D, lambda state: state.has('Gate of Heavenly Peace', player)), - - LocationData('Buenos Aires', 'Buenos Aires - Koopa Treasure 1', 0x19844E), - LocationData('Buenos Aires', 'Buenos Aires - Koopa Treasure 2', 0x19844F), - LocationData('Buenos Aires', 'Buenos Aires - Koopa Treasure 3', 0x198450), - LocationData('Buenos Aires', 'Teatro Colon - Photograph', 0x198451, lambda state: state.has('Flute from the Teatro Colon', player)), - LocationData('Buenos Aires', 'Gaucho Museum - Photograph', 0x198452, lambda state: state.has('Boleadoras', player)), - LocationData('Buenos Aires', 'Obelisk Monument - Photograph', 0x198453, lambda state: state.has('Stone from the Obelisk', player)), - - LocationData('Mexico City', 'Mexico City - Koopa Treasure 1', 0x198454), - LocationData('Mexico City', 'Mexico City - Koopa Treasure 2', 0x198455), - LocationData('Mexico City', 'Mexico City - Koopa Treasure 3', 0x198456), - LocationData('Mexico City', 'Angel of Independence - Photograph', 0x198457, lambda state: state.has('Angel', player)), - LocationData('Mexico City', 'National Palace - Photograph', 0x198458, lambda state: state.has('Diego Rivera Mural', player)), - LocationData('Mexico City', 'Fine Arts Palace - Photograph', 0x198459, lambda state: state.has('Fine Arts Catalog', player)), - - - LocationData('Rome', 'Colosseum - Return Artifact', None, lambda state:state.has("Gladiator's Spear", player)), - LocationData('Rome', 'Trevi Fountain - Return Artifact', None, lambda state:state.has('Coins from the Trevi Fountain', player)), - LocationData('Rome', 'Sistine Chapel - Return Artifact', None, lambda state:state.has("Sistine Chapel Ceiling", player)), - LocationData('Paris', 'Cathedral of Notre Dame - Return Artifact', None, lambda state: state.has('Notre Dame Bell', player)), - LocationData('Paris', 'Arc de Triomphe - Return Artifact', None, lambda state: state.has('Eternal Flame', player)), - LocationData('Paris', 'Eiffel Tower - Return Artifact', None, lambda state: state.has('Tricolor', player)), - LocationData('London', 'Tower of London - Return Artifact', None, lambda state: state.has('Crown Jewels', player)), - LocationData('London', 'Westminster Abbey - Return Artifact', None, lambda state: state.has('Bust of Shakespeare', player)), - LocationData('London', 'Big Ben - Return Artifact', None, lambda state: state.has("Big Ben's Minute Hand", player)), - LocationData('New York', 'Empire State Building - Return Artifact', None, lambda state: state.has('King Kong', player)), - LocationData('New York', 'Statue of Liberty - Return Artifact', None, lambda state: state.has('Statue of Liberty Torch', player)), - LocationData('New York', 'Rockefeller Center - Return Artifact', None, lambda state: state.has('Statue of Prometheus', player)), - LocationData('San Francisco', 'Golden Gate Bridge - Return Artifact', None, lambda state: state.has('Golden Gate Bridge Foghorn', player)), - LocationData('San Francisco', 'Coit Tower - Return Artifact', None, lambda state: state.has('Window from Coit Tower', player)), - LocationData('San Francisco', 'Transamerica Pyramid - Return Artifact', None, lambda state: state.has('Top of the Transamerica Pyramid', player)), - LocationData('Athens', 'Erechtheion Temple - Return Artifact', None, lambda state: state.has('Caryatid', player)), - LocationData('Athens', "Hadrian's Arch - Return Artifact", None, lambda state: state.has('Brass Plaque', player)), - LocationData('Athens', 'Parthenon - Return Artifact', None, lambda state: state.has('Parthenon Column', player)), - LocationData('Sydney', 'Bondi Beach - Return Artifact', None, lambda state: state.has('Surfboard from Bondi Beach', player)), - LocationData('Sydney', 'Taronga Zoo - Return Artifact', None, lambda state: state.has('Taronga Zoo Koala', player)), - LocationData('Sydney', 'Sydney Opera - Return Artifact', None, lambda state: state.has('Sydney Opera Sheet Music', player)), - LocationData('Tokyo', 'Great Buddha of Kamakura - Return Artifact', None, lambda state: state.has("Great Buddha's Orange", player)), - LocationData('Tokyo', 'Sensoji Temple - Return Artifact', None, lambda state: state.has('Sensoji Temple Latern', player)), - LocationData('Tokyo', 'Kokugikan Arena - Return Artifact', None, lambda state: state.has('Sumo Apron', player)), - LocationData('Nairobi', 'Nairobi National Park - Return Artifact', None, lambda state: state.has('Baby Elephant', player)), - LocationData('Nairobi', 'Maasai Village - Return Artifact', None, lambda state: state.has('Maasai Headdress', player)), - LocationData('Nairobi', 'National Museum of Kenya - Return Artifact', None, lambda state: state.has('Human Skull', player)), - LocationData('Rio de Janeiro', 'Christ the Redeemer Statue - Return Artifact', None, lambda state: state.has('Spotlight from Christ the Redeemer Statue', player)), - LocationData('Rio de Janeiro', 'Copacabana Beach - Return Artifact', None, lambda state: state.has('Copacabana Beach Seashell', player)), - LocationData('Rio de Janeiro', 'Sugar Loaf Mountain - Return Artifact', None, lambda state: state.has('Sugar Loaf Mountain Cable Car', player)), - LocationData('Cairo', 'Great Pyramid - Return Artifact', None, lambda state: state.has('Top Brick of the Great Pyramid', player)), - LocationData('Cairo', 'Mosque of Mohammed - Return Artifact', None, lambda state: state.has('Gingerbread Clock', player)), - LocationData('Cairo', 'Sphinx - Return Artifact', None, lambda state: state.has('Klaft of the Sphinx', player)), - LocationData('Moscow', 'Kremlin - Return Artifact', None, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), - LocationData('Moscow', "St. Basil's Cathedral - Return Artifact", None, lambda state: state.has('Cathedral Dome', player)), - LocationData('Moscow', 'Bolshoi Ballet - Return Artifact', None, lambda state: state.has('Bolshoi Ballet Slipper', player)), - LocationData('Beijing', 'Temple of Heaven - Return Artifact', None, lambda state: state.has('Hall of Good Harvest', player)), - LocationData('Beijing', 'Great Wall of China - Return Artifact', None, lambda state: state.has('Stone from the Great Wall', player)), - LocationData('Beijing', 'Forbidden City - Return Artifact', None, lambda state: state.has('Gate of Heavenly Peace', player)), - LocationData('Buenos Aires', 'Teatro Colon - Return Artifact', None, lambda state: state.has('Flute from the Teatro Colon', player)), - LocationData('Buenos Aires', 'Gaucho Museum - Return Artifact', None, lambda state: state.has('Boleadoras', player)), - LocationData('Buenos Aires', 'Obelisk Monument - Return Artifact', None, lambda state: state.has('Stone from the Obelisk', player)), - LocationData('Mexico City', 'Angel of Independence - Return Artifact', None, lambda state: state.has('Angel', player)), - LocationData('Mexico City', 'National Palace - Return Artifact', None, lambda state: state.has('Diego Rivera Mural', player)), - LocationData('Mexico City', 'Fine Arts Palace - Return Artifact', None, lambda state: state.has('Fine Arts Catalog', player)), - - LocationData('Castle Floor 4', 'Bowser', None) - ] - - if not multiworld or world.options.computer_sanity.value == 1: - location_table += ( - LocationData("Rome", "Rome - Colosseum - Newspaper Article", 0x19845A), - LocationData("Rome", "Rome - Trevi Fountain - Newspaper Article", 0x19845B), - LocationData("Rome", "Rome - Sistine Chapel - Newspaper Article", 0x19845C), - LocationData("Rome", "Rome - Scientist - Location Advice", 0x19845D), - LocationData("Rome", "Rome - Scientist - Artifact 1 Advice", 0x19845E, lambda state: state.has("Gladiator's Spear", player)), - LocationData("Rome", "Rome - Scientist - Artifact 2 Advice", 0x19845F, lambda state: state.has("Coins from the Trevi Fountain", player)), - LocationData("Rome", "Rome - Scientist - Artifact 3 Advice", 0x198460, lambda state: state.has("Sistine Chapel Ceiling", player)), - LocationData("Rome", "Rome - Officer - Location Advice", 0x198461), - LocationData("Rome", "Rome - Officer - Artifact 1 Advice", 0x198462, lambda state: state.has("Gladiator's Spear", player)), - LocationData("Rome", "Rome - Officer - Artifact 2 Advice", 0x198463, lambda state: state.has("Coins from the Trevi Fountain", player)), - LocationData("Rome", "Rome - Officer - Artifact 3 Advice", 0x198464, lambda state: state.has("Sistine Chapel Ceiling", player)), - LocationData("Rome", "Rome - Child - Location Advice", 0x198465), - LocationData("Rome", "Rome - Child - Artifact 1 Advice", 0x198466, lambda state: state.has("Gladiator's Spear", player)), - LocationData("Rome", "Rome - Child - Artifact 2 Advice", 0x198467, lambda state: state.has("Coins from the Trevi Fountain", player)), - LocationData("Rome", "Rome - Child - Artifact 3 Advice", 0x198468, lambda state: state.has("Sistine Chapel Ceiling", player)), - LocationData("Rome", "Rome - Tourist - Location Advice", 0x198469), - LocationData("Rome", "Rome - Tourist - Artifact 1 Advice", 0x19846A, lambda state: state.has("Gladiator's Spear", player)), - LocationData("Rome", "Rome - Tourist - Artifact 2 Advice", 0x19846B, lambda state: state.has("Coins from the Trevi Fountain", player)), - LocationData("Rome", "Rome - Tourist - Artifact 3 Advice", 0x19846C, lambda state: state.has("Sistine Chapel Ceiling", player)), - LocationData("Rome", "Rome - Businesswoman - Location Advice", 0x19846D), - LocationData("Rome", "Rome - Businesswoman - Artifact 1 Advice", 0x19846E, lambda state: state.has("Gladiator's Spear", player)), - LocationData("Rome", "Rome - Businesswoman - Artifact 2 Advice", 0x19846F, lambda state: state.has("Coins from the Trevi Fountain", player)), - LocationData("Rome", "Rome - Businesswoman - Artifact 3 Advice", 0x198470, lambda state: state.has("Sistine Chapel Ceiling", player)), - - LocationData("Paris", "Paris - Cathedral of Notre Dame - Newspaper Article", 0x198471), - LocationData("Paris", "Paris - Arc de Triomphe - Newspaper Article", 0x198472), - LocationData("Paris", "Paris - Eiffel Tower - Newspaper Article", 0x198473), - LocationData("Paris", "Paris - Scientist - Location Advice", 0x198474), - LocationData("Paris", "Paris - Scientist - Artifact 1 Advice", 0x198475, lambda state: state.has("Notre Dame Bell", player)), - LocationData("Paris", "Paris - Scientist - Artifact 2 Advice", 0x198476, lambda state: state.has("Eternal Flame", player)), - LocationData("Paris", "Paris - Scientist - Artifact 3 Advice", 0x198477, lambda state: state.has("Tricolor", player)), - LocationData("Paris", "Paris - Officer - Location Advice", 0x198478), - LocationData("Paris", "Paris - Officer - Artifact 1 Advice", 0x198479, lambda state: state.has("Notre Dame Bell", player)), - LocationData("Paris", "Paris - Officer - Artifact 2 Advice", 0x19847A, lambda state: state.has("Eternal Flame", player)), - LocationData("Paris", "Paris - Officer - Artifact 3 Advice", 0x19847B, lambda state: state.has("Tricolor", player)), - LocationData("Paris", "Paris - Child - Location Advice", 0x19847C), - LocationData("Paris", "Paris - Child - Artifact 1 Advice", 0x19847D, lambda state: state.has("Notre Dame Bell", player)), - LocationData("Paris", "Paris - Child - Artifact 2 Advice", 0x19847E, lambda state: state.has("Eternal Flame", player)), - LocationData("Paris", "Paris - Child - Artifact 3 Advice", 0x19847F, lambda state: state.has("Tricolor", player)), - LocationData("Paris", "Paris - Tourist - Location Advice", 0x198480), - LocationData("Paris", "Paris - Tourist - Artifact 1 Advice", 0x198481, lambda state: state.has("Notre Dame Bell", player)), - LocationData("Paris", "Paris - Tourist - Artifact 2 Advice", 0x198482, lambda state: state.has("Eternal Flame", player)), - LocationData("Paris", "Paris - Tourist - Artifact 3 Advice", 0x198483, lambda state: state.has("Tricolor", player)), - LocationData("Paris", "Paris - Businesswoman - Location Advice", 0x198484), - LocationData("Paris", "Paris - Businesswoman - Artifact 1 Advice", 0x198485, lambda state: state.has("Notre Dame Bell", player)), - LocationData("Paris", "Paris - Businesswoman - Artifact 2 Advice", 0x198486, lambda state: state.has("Eternal Flame", player)), - LocationData("Paris", "Paris - Businesswoman - Artifact 3 Advice", 0x198487, lambda state: state.has("Tricolor", player)), - - LocationData("London", "London - Tower of London - Newspaper Article", 0x198488), - LocationData("London", "London - Westminster Abbey - Newspaper Article", 0x198489), - LocationData("London", "London - Big Ben - Newspaper Article", 0x19848A), - LocationData("London", "London - Scientist - Location Advice", 0x19848B), - LocationData("London", "London - Scientist - Artifact 1 Advice", 0x19848C, lambda state: state.has("Crown Jewels", player)), - LocationData("London", "London - Scientist - Artifact 2 Advice", 0x19848D, lambda state: state.has("Bust of Shakespeare", player)), - LocationData("London", "London - Scientist - Artifact 3 Advice", 0x19848E, lambda state: state.has("Big Ben's Minute Hand", player)), - LocationData("London", "London - Officer - Location Advice", 0x19848F), - LocationData("London", "London - Officer - Artifact 1 Advice", 0x198490, lambda state: state.has("Crown Jewels", player)), - LocationData("London", "London - Officer - Artifact 2 Advice", 0x198491, lambda state: state.has("Bust of Shakespeare", player)), - LocationData("London", "London - Officer - Artifact 3 Advice", 0x198492, lambda state: state.has("Big Ben's Minute Hand", player)), - LocationData("London", "London - Child - Location Advice", 0x198493), - LocationData("London", "London - Child - Artifact 1 Advice", 0x198494, lambda state: state.has("Crown Jewels", player)), - LocationData("London", "London - Child - Artifact 2 Advice", 0x198495, lambda state: state.has("Bust of Shakespeare", player)), - LocationData("London", "London - Child - Artifact 3 Advice", 0x198496, lambda state: state.has("Big Ben's Minute Hand", player)), - LocationData("London", "London - Tourist - Location Advice", 0x198497), - LocationData("London", "London - Tourist - Artifact 1 Advice", 0x198498, lambda state: state.has("Crown Jewels", player)), - LocationData("London", "London - Tourist - Artifact 2 Advice", 0x198499, lambda state: state.has("Bust of Shakespeare", player)), - LocationData("London", "London - Tourist - Artifact 3 Advice", 0x19849A, lambda state: state.has("Big Ben's Minute Hand", player)), - LocationData("London", "London - Businesswoman - Location Advice", 0x19849B), - LocationData("London", "London - Businesswoman - Artifact 1 Advice", 0x19849C, lambda state: state.has("Crown Jewels", player)), - LocationData("London", "London - Businesswoman - Artifact 2 Advice", 0x19849D, lambda state: state.has("Eternal Flame", player)), - LocationData("London", "London - Businesswoman - Artifact 3 Advice", 0x19849E, lambda state: state.has("Big Ben's Minute Hand", player)), - - LocationData("New York", "New York - Empire State Building - Newspaper Article", 0x19849F), - LocationData("New York", "New York - Statue of Liberty - Newspaper Article", 0x1984A0), - LocationData("New York", "New York - Rockefeller Center - Newspaper Article", 0x1984A1), - LocationData("New York", "New York - Scientist - Location Advice", 0x1984A2), - LocationData("New York", "New York - Scientist - Artifact 1 Advice", 0x1984A3, lambda state: state.has("King Kong", player)), - LocationData("New York", "New York - Scientist - Artifact 2 Advice", 0x1984A4, lambda state: state.has("Statue of Liberty Torch", player)), - LocationData("New York", "New York - Scientist - Artifact 3 Advice", 0x1984A5, lambda state: state.has("Statue of Prometheus", player)), - LocationData("New York", "New York - Officer - Location Advice", 0x1984A6), - LocationData("New York", "New York - Officer - Artifact 1 Advice", 0x1984A7, lambda state: state.has("King Kong", player)), - LocationData("New York", "New York - Officer - Artifact 2 Advice", 0x1984A8, lambda state: state.has("Statue of Liberty Torch", player)), - LocationData("New York", "New York - Officer - Artifact 3 Advice", 0x1984A9, lambda state: state.has("Statue of Prometheus", player)), - LocationData("New York", "New York - Child - Location Advice", 0x1984AA), - LocationData("New York", "New York - Child - Artifact 1 Advice", 0x1984AB, lambda state: state.has("King Kong", player)), - LocationData("New York", "New York - Child - Artifact 2 Advice", 0x1984AC, lambda state: state.has("Statue of Liberty Torch", player)), - LocationData("New York", "New York - Child - Artifact 3 Advice", 0x1984AD, lambda state: state.has("Statue of Prometheus", player)), - LocationData("New York", "New York - Tourist - Location Advice", 0x1984AE), - LocationData("New York", "New York - Tourist - Artifact 1 Advice", 0x1984AF, lambda state: state.has("King Kong", player)), - LocationData("New York", "New York - Tourist - Artifact 2 Advice", 0x1984B0, lambda state: state.has("Statue of Liberty Torch", player)), - LocationData("New York", "New York - Tourist - Artifact 3 Advice", 0x1984B1, lambda state: state.has("Statue of Prometheus", player)), - LocationData("New York", "New York - Businesswoman - Location Advice", 0x1984B2), - LocationData("New York", "New York - Businesswoman - Artifact 1 Advice", 0x1984B3, lambda state: state.has("King Kong", player)), - LocationData("New York", "New York - Businesswoman - Artifact 2 Advice", 0x1984B4, lambda state: state.has("Statue of Liberty Torch", player)), - LocationData("New York", "New York - Businesswoman - Artifact 3 Advice", 0x1984B5, lambda state: state.has("Statue of Prometheus", player)), - - LocationData("San Francisco", "San Francisco - Golden Gate Bridge - Newspaper Article", 0x1984B6), - LocationData("San Francisco", "San Francisco - Coit Tower - Newspaper Article", 0x1984B7), - LocationData("San Francisco", "San Francisco - Transamerica Pyramid - Newspaper Article", 0x1984B8), - LocationData("San Francisco", "San Francisco - Scientist - Location Advice", 0x1984B9), - LocationData("San Francisco", "San Francisco - Scientist - Artifact 1 Advice", 0x1984BA, lambda state: state.has("Golden Gate Bridge Foghorn", player)), - LocationData("San Francisco", "San Francisco - Scientist - Artifact 2 Advice", 0x1984BB, lambda state: state.has("Window from Coit Tower", player)), - LocationData("San Francisco", "San Francisco - Scientist - Artifact 3 Advice", 0x1984BC, lambda state: state.has("Top of the Transamerica Pyramid", player)), - LocationData("San Francisco", "San Francisco - Officer - Location Advice", 0x1984BD), - LocationData("San Francisco", "San Francisco - Officer - Artifact 1 Advice", 0x1984BE, lambda state: state.has("Golden Gate Bridge Foghorn", player)), - LocationData("San Francisco", "San Francisco - Officer - Artifact 2 Advice", 0x1984BF, lambda state: state.has("Window from Coit Tower", player)), - LocationData("San Francisco", "San Francisco - Officer - Artifact 3 Advice", 0x1984C0, lambda state: state.has("Top of the Transamerica Pyramid", player)), - LocationData("San Francisco", "San Francisco - Child - Location Advice", 0x1984C1), - LocationData("San Francisco", "San Francisco - Child - Artifact 1 Advice", 0x1984C2, lambda state: state.has("Golden Gate Bridge Foghorn", player)), - LocationData("San Francisco", "San Francisco - Child - Artifact 2 Advice", 0x1984C3, lambda state: state.has("Window from Coit Tower", player)), - LocationData("San Francisco", "San Francisco - Child - Artifact 3 Advice", 0x1984C4, lambda state: state.has("Top of the Transamerica Pyramid", player)), - LocationData("San Francisco", "San Francisco - Tourist - Location Advice", 0x1984C5), - LocationData("San Francisco", "San Francisco - Tourist - Artifact 1 Advice", 0x1984C6, lambda state: state.has("Golden Gate Bridge Foghorn", player)), - LocationData("San Francisco", "San Francisco - Tourist - Artifact 2 Advice", 0x1984C7, lambda state: state.has("Window from Coit Tower", player)), - LocationData("San Francisco", "San Francisco - Tourist - Artifact 3 Advice", 0x1984C8, lambda state: state.has("Top of the Transamerica Pyramid", player)), - LocationData("San Francisco", "San Francisco - Businesswoman - Location Advice", 0x1984C9), - LocationData("San Francisco", "San Francisco - Businesswoman - Artifact 1 Advice", 0x1984CA, lambda state: state.has("Golden Gate Bridge Foghorn", player)), - LocationData("San Francisco", "San Francisco - Businesswoman - Artifact 2 Advice", 0x1984CB, lambda state: state.has("Window from Coit Tower", player)), - LocationData("San Francisco", "San Francisco - Businesswoman - Artifact 3 Advice", 0x1984CC, lambda state: state.has("Top of the Transamerica Pyramid", player)), - - LocationData("Athens", "Athens - Erechtheion Temple - Newspaper Article", 0x1984CD), - LocationData("Athens", "Athens - Hadrian's Arch - Newspaper Article", 0x1984CE), - LocationData("Athens", "Athens - Sydney Opera - Newspaper Article", 0x1984CF), - LocationData("Athens", "Athens - Scientist - Location Advice", 0x1984D0), - LocationData("Athens", "Athens - Scientist - Artifact 1 Advice", 0x1984D1, lambda state: state.has("Caryatid", player)), - LocationData("Athens", "Athens - Scientist - Artifact 2 Advice", 0x1984D2, lambda state: state.has("Brass Plaque", player)), - LocationData("Athens", "Athens - Scientist - Artifact 3 Advice", 0x1984D3, lambda state: state.has("Parthenon Column", player)), - LocationData("Athens", "Athens - Officer - Location Advice", 0x1984D4), - LocationData("Athens", "Athens - Officer - Artifact 1 Advice", 0x1984D5, lambda state: state.has("Caryatid", player)), - LocationData("Athens", "Athens - Officer - Artifact 2 Advice", 0x1984D6, lambda state: state.has("Brass Plaque", player)), - LocationData("Athens", "Athens - Officer - Artifact 3 Advice", 0x1984D7, lambda state: state.has("Parthenon Column", player)), - LocationData("Athens", "Athens - Child - Location Advice", 0x1984D8), - LocationData("Athens", "Athens - Child - Artifact 1 Advice", 0x1984D9, lambda state: state.has("Caryatid", player)), - LocationData("Athens", "Athens - Child - Artifact 2 Advice", 0x1984DA, lambda state: state.has("Brass Plaque", player)), - LocationData("Athens", "Athens - Child - Artifact 3 Advice", 0x1984DB, lambda state: state.has("Parthenon Column", player)), - LocationData("Athens", "Athens - Tourist - Location Advice", 0x1984DC), - LocationData("Athens", "Athens - Tourist - Artifact 1 Advice", 0x1984DD, lambda state: state.has("Caryatid", player)), - LocationData("Athens", "Athens - Tourist - Artifact 2 Advice", 0x1984DE, lambda state: state.has("Brass Plaque", player)), - LocationData("Athens", "Athens - Tourist - Artifact 3 Advice", 0x1984DF, lambda state: state.has("Parthenon Column", player)), - LocationData("Athens", "Athens - Businesswoman - Location Advice", 0x1984E0), - LocationData("Athens", "Athens - Businesswoman - Artifact 1 Advice", 0x1984E1, lambda state: state.has("Caryatid", player)), - LocationData("Athens", "Athens - Businesswoman - Artifact 2 Advice", 0x1984E2, lambda state: state.has("Brass Plaque", player)), - LocationData("Athens", "Athens - Businesswoman - Artifact 3 Advice", 0x1984E3, lambda state: state.has("Parthenon Column", player)), - - LocationData("Sydney", "Sydney - Bondi Beach - Newspaper Article", 0x1984E4), - LocationData("Sydney", "Sydney - Taronga Zoo - Newspaper Article", 0x1984E5), - LocationData("Sydney", "Sydney - Parthenon - Newspaper Article", 0x1984E6), - LocationData("Sydney", "Sydney - Scientist - Location Advice", 0x1984E7), - LocationData("Sydney", "Sydney - Scientist - Artifact 1 Advice", 0x1984E8, lambda state: state.has("Surfboard from Bondi Beach", player)), - LocationData("Sydney", "Sydney - Scientist - Artifact 2 Advice", 0x1984E9, lambda state: state.has("Taronga Zoo Koala", player)), - LocationData("Sydney", "Sydney - Scientist - Artifact 3 Advice", 0x1984EA, lambda state: state.has("Sydney Opera Sheet Music", player)), - LocationData("Sydney", "Sydney - Officer - Location Advice", 0x1984EB), - LocationData("Sydney", "Sydney - Officer - Artifact 1 Advice", 0x1984EC, lambda state: state.has("Surfboard from Bondi Beach", player)), - LocationData("Sydney", "Sydney - Officer - Artifact 2 Advice", 0x1984ED, lambda state: state.has("Taronga Zoo Koala", player)), - LocationData("Sydney", "Sydney - Officer - Artifact 3 Advice", 0x1984EE, lambda state: state.has("Sydney Opera Sheet Music", player)), - LocationData("Sydney", "Sydney - Child - Location Advice", 0x1984EF), - LocationData("Sydney", "Sydney - Child - Artifact 1 Advice", 0x1984F0, lambda state: state.has("Surfboard from Bondi Beach", player)), - LocationData("Sydney", "Sydney - Child - Artifact 2 Advice", 0x1984F1, lambda state: state.has("Taronga Zoo Koala", player)), - LocationData("Sydney", "Sydney - Child - Artifact 3 Advice", 0x1984F2, lambda state: state.has("Sydney Opera Sheet Music", player)), - LocationData("Sydney", "Sydney - Tourist - Location Advice", 0x1984F3), - LocationData("Sydney", "Sydney - Tourist - Artifact 1 Advice", 0x1984F4, lambda state: state.has("Surfboard from Bondi Beach", player)), - LocationData("Sydney", "Sydney - Tourist - Artifact 2 Advice", 0x1984F5, lambda state: state.has("Taronga Zoo Koala", player)), - LocationData("Sydney", "Sydney - Tourist - Artifact 3 Advice", 0x1984F6, lambda state: state.has("Sydney Opera Sheet Music", player)), - LocationData("Sydney", "Sydney - Businesswoman - Location Advice", 0x1984F7), - LocationData("Sydney", "Sydney - Businesswoman - Artifact 1 Advice", 0x1984F8, lambda state: state.has("Surfboard from Bondi Beach", player)), - LocationData("Sydney", "Sydney - Businesswoman - Artifact 2 Advice", 0x1984F9, lambda state: state.has("Taronga Zoo Koala", player)), - LocationData("Sydney", "Sydney - Businesswoman - Artifact 3 Advice", 0x1984FA, lambda state: state.has("Sydney Opera Sheet Music", player)), - - LocationData("Tokyo", "Tokyo - Great Buddha of Kamakura - Newspaper Article", 0x1984FB), - LocationData("Tokyo", "Tokyo - Sensoji Temple - Newspaper Article", 0x1984FC), - LocationData("Tokyo", "Tokyo - Kokugikan Arena - Newspaper Article", 0x1984FD), - LocationData("Tokyo", "Tokyo - Scientist - Location Advice", 0x1984FE), - LocationData("Tokyo", "Tokyo - Scientist - Artifact 1 Advice", 0x1984FF, lambda state: state.has("Great Buddha's Orange", player)), - LocationData("Tokyo", "Tokyo - Scientist - Artifact 2 Advice", 0x198500, lambda state: state.has("Sensoji Temple Latern", player)), - LocationData("Tokyo", "Tokyo - Scientist - Artifact 3 Advice", 0x198501, lambda state: state.has("Sumo Apron", player)), - LocationData("Tokyo", "Tokyo - Officer - Location Advice", 0x198502), - LocationData("Tokyo", "Tokyo - Officer - Artifact 1 Advice", 0x198503, lambda state: state.has("Great Buddha's Orange", player)), - LocationData("Tokyo", "Tokyo - Officer - Artifact 2 Advice", 0x198504, lambda state: state.has("Sensoji Temple Latern", player)), - LocationData("Tokyo", "Tokyo - Officer - Artifact 3 Advice", 0x198505, lambda state: state.has("Sumo Apron", player)), - LocationData("Tokyo", "Tokyo - Child - Location Advice", 0x198506), - LocationData("Tokyo", "Tokyo - Child - Artifact 1 Advice", 0x198507, lambda state: state.has("Great Buddha's Orange", player)), - LocationData("Tokyo", "Tokyo - Child - Artifact 2 Advice", 0x198508, lambda state: state.has("Sensoji Temple Latern", player)), - LocationData("Tokyo", "Tokyo - Child - Artifact 3 Advice", 0x198509, lambda state: state.has("Sumo Apron", player)), - LocationData("Tokyo", "Tokyo - Tourist - Location Advice", 0x19850A), - LocationData("Tokyo", "Tokyo - Tourist - Artifact 1 Advice", 0x19850B, lambda state: state.has("Great Buddha's Orange", player)), - LocationData("Tokyo", "Tokyo - Tourist - Artifact 2 Advice", 0x19850C, lambda state: state.has("Sensoji Temple Latern", player)), - LocationData("Tokyo", "Tokyo - Tourist - Artifact 3 Advice", 0x19850D, lambda state: state.has("Sumo Apron", player)), - LocationData("Tokyo", "Tokyo - Businesswoman - Location Advice", 0x19850E), - LocationData("Tokyo", "Tokyo - Businesswoman - Artifact 1 Advice", 0x19850F, lambda state: state.has("Great Buddha's Orange", player)), - LocationData("Tokyo", "Tokyo - Businesswoman - Artifact 2 Advice", 0x198510, lambda state: state.has("Sensoji Temple Latern", player)), - LocationData("Tokyo", "Tokyo - Businesswoman - Artifact 3 Advice", 0x198511, lambda state: state.has("Sumo Apron", player)), - - LocationData("Nairobi", "Nairobi - Nairobi National Park - Newspaper Article", 0x198512), - LocationData("Nairobi", "Nairobi - Maasai Village - Newspaper Article", 0x198513), - LocationData("Nairobi", "Nairobi - National Museum of Kenya - Newspaper Article", 0x198514), - LocationData("Nairobi", "Nairobi - Scientist - Location Advice", 0x198515), - LocationData("Nairobi", "Nairobi - Scientist - Artifact 1 Advice", 0x198516, lambda state: state.has("Baby Elephant", player)), - LocationData("Nairobi", "Nairobi - Scientist - Artifact 2 Advice", 0x198517, lambda state: state.has("Maasai Headdress", player)), - LocationData("Nairobi", "Nairobi - Scientist - Artifact 3 Advice", 0x198518, lambda state: state.has("Human Skull", player)), - LocationData("Nairobi", "Nairobi - Officer - Location Advice", 0x198519), - LocationData("Nairobi", "Nairobi - Officer - Artifact 1 Advice", 0x19851A, lambda state: state.has("Baby Elephant", player)), - LocationData("Nairobi", "Nairobi - Officer - Artifact 2 Advice", 0x19851B, lambda state: state.has("Maasai Headdress", player)), - LocationData("Nairobi", "Nairobi - Officer - Artifact 3 Advice", 0x19851C, lambda state: state.has("Human Skull", player)), - LocationData("Nairobi", "Nairobi - Child - Location Advice", 0x19851D), - LocationData("Nairobi", "Nairobi - Child - Artifact 1 Advice", 0x19851E, lambda state: state.has("Baby Elephant", player)), - LocationData("Nairobi", "Nairobi - Child - Artifact 2 Advice", 0x19851F, lambda state: state.has("Maasai Headdress", player)), - LocationData("Nairobi", "Nairobi - Child - Artifact 3 Advice", 0x198520, lambda state: state.has("Human Skull", player)), - LocationData("Nairobi", "Nairobi - Tourist - Location Advice", 0x198521), - LocationData("Nairobi", "Nairobi - Tourist - Artifact 1 Advice", 0x198522, lambda state: state.has("Baby Elephant", player)), - LocationData("Nairobi", "Nairobi - Tourist - Artifact 2 Advice", 0x198523, lambda state: state.has("Maasai Headdress", player)), - LocationData("Nairobi", "Nairobi - Tourist - Artifact 3 Advice", 0x198524, lambda state: state.has("Human Skull", player)), - LocationData("Nairobi", "Nairobi - Businesswoman - Location Advice", 0x198525), - LocationData("Nairobi", "Nairobi - Businesswoman - Artifact 1 Advice", 0x198526, lambda state: state.has("Baby Elephant", player)), - LocationData("Nairobi", "Nairobi - Businesswoman - Artifact 2 Advice", 0x198527, lambda state: state.has("Maasai Headdress", player)), - LocationData("Nairobi", "Nairobi - Businesswoman - Artifact 3 Advice", 0x198528, lambda state: state.has("Human Skull", player)), - - LocationData("Rio de Janeiro", "Rio de Janeiro - Christ the Redeemer Statue - Newspaper Article", 0x198529), - LocationData("Rio de Janeiro", "Rio de Janeiro - Copacabana Beach - Newspaper Article", 0x19852A), - LocationData("Rio de Janeiro", "Rio de Janeiro - Sugar Loaf Mountain - Newspaper Article", 0x19852B), - LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Location Advice", 0x19852C), - LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Artifact 1 Advice", 0x19852D, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Artifact 2 Advice", 0x19852E, lambda state: state.has("Copacabana Beach Seashell", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Scientist - Artifact 3 Advice", 0x19852F, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Location Advice", 0x198530), - LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Artifact 1 Advice", 0x198531, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Artifact 2 Advice", 0x198532, lambda state: state.has("Copacabana Beach Seashell", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Officer - Artifact 3 Advice", 0x198533, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Location Advice", 0x198534), - LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Artifact 1 Advice", 0x198535, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Artifact 2 Advice", 0x198536, lambda state: state.has("Copacabana Beach Seashell", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Child - Artifact 3 Advice", 0x198537, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Location Advice", 0x198538), - LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Artifact 1 Advice", 0x198539, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Artifact 2 Advice", 0x19853A, lambda state: state.has("Copacabana Beach Seashell", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Tourist - Artifact 3 Advice", 0x19853B, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Location Advice", 0x19853C), - LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Artifact 1 Advice", 0x19853D, lambda state: state.has("Spotlight from Christ the Redeemer Statue", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Artifact 2 Advice", 0x19853E, lambda state: state.has("Copacabana Beach Seashell", player)), - LocationData("Rio de Janeiro", "Rio de Janeiro - Businesswoman - Artifact 3 Advice", 0x19853F, lambda state: state.has("Sugar Loaf Mountain Cable Car", player)), - - LocationData("Cairo", "Cairo - Great Pyramid - Newspaper Article", 0x198540), - LocationData("Cairo", "Cairo - Mosque of Mohammed - Newspaper Article", 0x198541), - LocationData("Cairo", "Cairo - Sphinx - Newspaper Article", 0x198542), - LocationData("Cairo", "Cairo - Scientist - Location Advice", 0x198543), - LocationData("Cairo", "Cairo - Scientist - Artifact 1 Advice", 0x198544, lambda state: state.has("Top Brick of the Great Pyramid", player)), - LocationData("Cairo", "Cairo - Scientist - Artifact 2 Advice", 0x198545, lambda state: state.has("Gingerbread Clock", player)), - LocationData("Cairo", "Cairo - Scientist - Artifact 3 Advice", 0x198546, lambda state: state.has("Klaft of the Sphinx", player)), - LocationData("Cairo", "Cairo - Officer - Location Advice", 0x198547), - LocationData("Cairo", "Cairo - Officer - Artifact 1 Advice", 0x198548, lambda state: state.has("Top Brick of the Great Pyramid", player)), - LocationData("Cairo", "Cairo - Officer - Artifact 2 Advice", 0x198549, lambda state: state.has("Gingerbread Clock", player)), - LocationData("Cairo", "Cairo - Officer - Artifact 3 Advice", 0x19854A, lambda state: state.has("Klaft of the Sphinx", player)), - LocationData("Cairo", "Cairo - Child - Location Advice", 0x19854B), - LocationData("Cairo", "Cairo - Child - Artifact 1 Advice", 0x19854C, lambda state: state.has("Top Brick of the Great Pyramid", player)), - LocationData("Cairo", "Cairo - Child - Artifact 2 Advice", 0x19854D, lambda state: state.has("Gingerbread Clock", player)), - LocationData("Cairo", "Cairo - Child - Artifact 3 Advice", 0x19854E, lambda state: state.has("Klaft of the Sphinx", player)), - LocationData("Cairo", "Cairo - Tourist - Location Advice", 0x19854F), - LocationData("Cairo", "Cairo - Tourist - Artifact 1 Advice", 0x198550, lambda state: state.has("Top Brick of the Great Pyramid", player)), - LocationData("Cairo", "Cairo - Tourist - Artifact 2 Advice", 0x198551, lambda state: state.has("Gingerbread Clock", player)), - LocationData("Cairo", "Cairo - Tourist - Artifact 3 Advice", 0x198552, lambda state: state.has("Klaft of the Sphinx", player)), - LocationData("Cairo", "Cairo - Businesswoman - Location Advice", 0x198553), - LocationData("Cairo", "Cairo - Businesswoman - Artifact 1 Advice", 0x198554, lambda state: state.has("Top Brick of the Great Pyramid", player)), - LocationData("Cairo", "Cairo - Businesswoman - Artifact 2 Advice", 0x198555, lambda state: state.has("Gingerbread Clock", player)), - LocationData("Cairo", "Cairo - Businesswoman - Artifact 3 Advice", 0x198556, lambda state: state.has("Klaft of the Sphinx", player)), - - LocationData("Moscow", "Moscow - Kremlin - Newspaper Article", 0x198557), - LocationData("Moscow", "Moscow - St. Basil's Cathedral - Newspaper Article", 0x198558), - LocationData("Moscow", "Moscow - Bolshoi Ballet - Newspaper Article", 0x198559), - LocationData("Moscow", "Moscow - Scientist - Location Advice", 0x19855A), - LocationData("Moscow", "Moscow - Scientist - Artifact 1 Advice", 0x19855B, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), - LocationData("Moscow", "Moscow - Scientist - Artifact 2 Advice", 0x19855C, lambda state: state.has("Cathedral Dome", player)), - LocationData("Moscow", "Moscow - Scientist - Artifact 3 Advice", 0x19855D, lambda state: state.has("Bolshoi Ballet Slipper", player)), - LocationData("Moscow", "Moscow - Officer - Location Advice", 0x19855E), - LocationData("Moscow", "Moscow - Officer - Artifact 1 Advice", 0x19855F, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), - LocationData("Moscow", "Moscow - Officer - Artifact 2 Advice", 0x198560, lambda state: state.has("Cathedral Dome", player)), - LocationData("Moscow", "Moscow - Officer - Artifact 3 Advice", 0x198561, lambda state: state.has("Bolshoi Ballet Slipper", player)), - LocationData("Moscow", "Moscow - Child - Location Advice", 0x198562), - LocationData("Moscow", "Moscow - Child - Artifact 1 Advice", 0x198563, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), - LocationData("Moscow", "Moscow - Child - Artifact 2 Advice", 0x198564, lambda state: state.has("Cathedral Dome", player)), - LocationData("Moscow", "Moscow - Child - Artifact 3 Advice", 0x198565, lambda state: state.has("Bolshoi Ballet Slipper", player)), - LocationData("Moscow", "Moscow - Tourist - Location Advice", 0x198566), - LocationData("Moscow", "Moscow - Tourist - Artifact 1 Advice", 0x198567, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), - LocationData("Moscow", "Moscow - Tourist - Artifact 2 Advice", 0x198568, lambda state: state.has("Cathedral Dome", player)), - LocationData("Moscow", "Moscow - Tourist - Artifact 3 Advice", 0x198569, lambda state: state.has("Bolshoi Ballet Slipper", player)), - LocationData("Moscow", "Moscow - Businesswoman - Location Advice", 0x19856A), - LocationData("Moscow", "Moscow - Businesswoman - Artifact 1 Advice", 0x19856B, lambda state: state.has("Cannonball from the Emperor's Cannon", player)), - LocationData("Moscow", "Moscow - Businesswoman - Artifact 2 Advice", 0x19856C, lambda state: state.has("Cathedral Dome", player)), - LocationData("Moscow", "Moscow - Businesswoman - Artifact 3 Advice", 0x19856D, lambda state: state.has("Bolshoi Ballet Slipper", player)), - - LocationData("Beijing", "Beijing - Temple of Heaven - Newspaper Article", 0x19856E), - LocationData("Beijing", "Beijing - Great Wall of China - Newspaper Article", 0x19856F), - LocationData("Beijing", "Beijing - Forbidden City - Newspaper Article", 0x198570), - LocationData("Beijing", "Beijing - Scientist - Location Advice", 0x198571), - LocationData("Beijing", "Beijing - Scientist - Artifact 1 Advice", 0x198572, lambda state: state.has("Hall of Good Harvest", player)), - LocationData("Beijing", "Beijing - Scientist - Artifact 2 Advice", 0x198573, lambda state: state.has("Stone from the Great Wall", player)), - LocationData("Beijing", "Beijing - Scientist - Artifact 3 Advice", 0x198574, lambda state: state.has("Gate of Heavenly Peace", player)), - LocationData("Beijing", "Beijing - Officer - Location Advice", 0x198575), - LocationData("Beijing", "Beijing - Officer - Artifact 1 Advice", 0x198576, lambda state: state.has("Hall of Good Harvest", player)), - LocationData("Beijing", "Beijing - Officer - Artifact 2 Advice", 0x198577, lambda state: state.has("Stone from the Great Wall", player)), - LocationData("Beijing", "Beijing - Officer - Artifact 3 Advice", 0x198578, lambda state: state.has("Gate of Heavenly Peace", player)), - LocationData("Beijing", "Beijing - Child - Location Advice", 0x198579), - LocationData("Beijing", "Beijing - Child - Artifact 1 Advice", 0x19857A, lambda state: state.has("Hall of Good Harvest", player)), - LocationData("Beijing", "Beijing - Child - Artifact 2 Advice", 0x19857B, lambda state: state.has("Stone from the Great Wall", player)), - LocationData("Beijing", "Beijing - Child - Artifact 3 Advice", 0x19857C, lambda state: state.has("Gate of Heavenly Peace", player)), - LocationData("Beijing", "Beijing - Tourist - Location Advice", 0x19857D), - LocationData("Beijing", "Beijing - Tourist - Artifact 1 Advice", 0x19857E, lambda state: state.has("Hall of Good Harvest", player)), - LocationData("Beijing", "Beijing - Tourist - Artifact 2 Advice", 0x19857F, lambda state: state.has("Stone from the Great Wall", player)), - LocationData("Beijing", "Beijing - Tourist - Artifact 3 Advice", 0x198580, lambda state: state.has("Gate of Heavenly Peace", player)), - LocationData("Beijing", "Beijing - Businesswoman - Location Advice", 0x198581), - LocationData("Beijing", "Beijing - Businesswoman - Artifact 1 Advice", 0x198582, lambda state: state.has("Hall of Good Harvest", player)), - LocationData("Beijing", "Beijing - Businesswoman - Artifact 2 Advice", 0x198583, lambda state: state.has("Stone from the Great Wall", player)), - LocationData("Beijing", "Beijing - Businesswoman - Artifact 3 Advice", 0x198584, lambda state: state.has("Gate of Heavenly Peace", player)), - - LocationData("Buenos Aires", "Buenos Aires - Teatro Colon - Newspaper Article", 0x198585), - LocationData("Buenos Aires", "Buenos Aires - Gaucho Museum - Newspaper Article", 0x198586), - LocationData("Buenos Aires", "Buenos Aires - Obelisk Monument - Newspaper Article", 0x198587), - LocationData("Buenos Aires", "Buenos Aires - Scientist - Location Advice", 0x19858A), - LocationData("Buenos Aires", "Buenos Aires - Scientist - Artifact 1 Advice", 0x19858B, lambda state: state.has("Flute from the Teatro Colon", player)), - LocationData("Buenos Aires", "Buenos Aires - Scientist - Artifact 2 Advice", 0x19858C, lambda state: state.has("Boleadoras", player)), - LocationData("Buenos Aires", "Buenos Aires - Scientist - Artifact 3 Advice", 0x19858D, lambda state: state.has("Stone from the Obelisk", player)), - LocationData("Buenos Aires", "Buenos Aires - Officer - Location Advice", 0x19858E), - LocationData("Buenos Aires", "Buenos Aires - Officer - Artifact 1 Advice", 0x19858F, lambda state: state.has("Flute from the Teatro Colon", player)), - LocationData("Buenos Aires", "Buenos Aires - Officer - Artifact 2 Advice", 0x198590, lambda state: state.has("Boleadoras", player)), - LocationData("Buenos Aires", "Buenos Aires - Officer - Artifact 3 Advice", 0x198591, lambda state: state.has("Stone from the Obelisk", player)), - LocationData("Buenos Aires", "Buenos Aires - Child - Location Advice", 0x198592), - LocationData("Buenos Aires", "Buenos Aires - Child - Artifact 1 Advice", 0x198593, lambda state: state.has("Flute from the Teatro Colon", player)), - LocationData("Buenos Aires", "Buenos Aires - Child - Artifact 2 Advice", 0x198594, lambda state: state.has("Boleadoras", player)), - LocationData("Buenos Aires", "Buenos Aires - Child - Artifact 3 Advice", 0x198595, lambda state: state.has("Stone from the Obelisk", player)), - LocationData("Buenos Aires", "Buenos Aires - Tourist - Location Advice", 0x198596), - LocationData("Buenos Aires", "Buenos Aires - Tourist - Artifact 1 Advice", 0x198597, lambda state: state.has("Flute from the Teatro Colon", player)), - LocationData("Buenos Aires", "Buenos Aires - Tourist - Artifact 2 Advice", 0x198598, lambda state: state.has("Boleadoras", player)), - LocationData("Buenos Aires", "Buenos Aires - Tourist - Artifact 3 Advice", 0x198599, lambda state: state.has("Stone from the Obelisk", player)), - LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Location Advice", 0x19859A), - LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Artifact 1 Advice", 0x19859B, lambda state: state.has("Flute from the Teatro Colon", player)), - LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Artifact 2 Advice", 0x19859C, lambda state: state.has("Boleadoras", player)), - LocationData("Buenos Aires", "Buenos Aires - Businesswoman - Artifact 3 Advice", 0x19859D, lambda state: state.has("Stone from the Obelisk", player)), - - LocationData("Mexico City", "Mexico City - Angel of Independence - Newspaper Article", 0x19859E), - LocationData("Mexico City", "Mexico City - National Palace - Newspaper Article", 0x19859F), - LocationData("Mexico City", "Mexico City - Fine Arts Palace - Newspaper Article", 0x1985A0), - LocationData("Mexico City", "Mexico City - Scientist - Location Advice", 0x1985A1), - LocationData("Mexico City", "Mexico City - Scientist - Artifact 1 Advice", 0x1985A2, lambda state: state.has("Angel", player)), - LocationData("Mexico City", "Mexico City - Scientist - Artifact 2 Advice", 0x1985A3, lambda state: state.has("Diego Rivera Mural", player)), - LocationData("Mexico City", "Mexico City - Scientist - Artifact 3 Advice", 0x1985A4, lambda state: state.has("Fine Arts Catalog", player)), - LocationData("Mexico City", "Mexico City - Officer - Location Advice", 0x1985A5), - LocationData("Mexico City", "Mexico City - Officer - Artifact 1 Advice", 0x1985A6, lambda state: state.has("Angel", player)), - LocationData("Mexico City", "Mexico City - Officer - Artifact 2 Advice", 0x1985A7, lambda state: state.has("Diego Rivera Mural", player)), - LocationData("Mexico City", "Mexico City - Officer - Artifact 3 Advice", 0x1985A8, lambda state: state.has("Fine Arts Catalog", player)), - LocationData("Mexico City", "Mexico City - Child - Location Advice", 0x1985A9), - LocationData("Mexico City", "Mexico City - Child - Artifact 1 Advice", 0x1985AA, lambda state: state.has("Angel", player)), - LocationData("Mexico City", "Mexico City - Child - Artifact 2 Advice", 0x1985AB, lambda state: state.has("Diego Rivera Mural", player)), - LocationData("Mexico City", "Mexico City - Child - Artifact 3 Advice", 0x1985AC, lambda state: state.has("Fine Arts Catalog", player)), - LocationData("Mexico City", "Mexico City - Tourist - Location Advice", 0x1985AD), - LocationData("Mexico City", "Mexico City - Tourist - Artifact 1 Advice", 0x1985AE, lambda state: state.has("Angel", player)), - LocationData("Mexico City", "Mexico City - Tourist - Artifact 2 Advice", 0x1985AF, lambda state: state.has("Diego Rivera Mural", player)), - LocationData("Mexico City", "Mexico City - Tourist - Artifact 3 Advice", 0x1985B0, lambda state: state.has("Fine Arts Catalog", player)), - LocationData("Mexico City", "Mexico City - Businesswoman - Location Advice", 0x1985B1), - LocationData("Mexico City", "Mexico City - Businesswoman - Artifact 1 Advice", 0x1985B2, lambda state: state.has("Angel", player)), - LocationData("Mexico City", "Mexico City - Businesswoman - Artifact 2 Advice", 0x1985B3, lambda state: state.has("Diego Rivera Mural", player)), - LocationData("Mexico City", "Mexico City - Businesswoman - Artifact 3 Advice", 0x1985B4, lambda state: state.has("Fine Arts Catalog", player)) - - - ) - return list(location_table) diff --git a/worlds/mariomissing/Options.py b/worlds/mariomissing/Options.py deleted file mode 100644 index 84e7a7cf7c81..000000000000 --- a/worlds/mariomissing/Options.py +++ /dev/null @@ -1,24 +0,0 @@ -from dataclasses import dataclass -from Options import Toggle, DeathLink, Range, PerGameCommonOptions - -class RequiredArtifacts(Range): - """How many Artifacts are required to finish""" - display_name = "Required Artifacts" - range_start = 0 - range_end = 45 - default = 25 - -class ComputerChecks(Toggle): - """If enabled, places checks on the Computer data locations""" - display_name = "Computer Checks" - -class CityShuffle(Toggle): - """Shuffles which doors lead to which cities""" - display_name = "City Shuffle" - -@dataclass -class MarioisMissingOptions(PerGameCommonOptions): - required_artifacts: RequiredArtifacts - computer_sanity: ComputerChecks - city_shuffle: CityShuffle - death_link: DeathLink diff --git a/worlds/mariomissing/Regions.py b/worlds/mariomissing/Regions.py deleted file mode 100644 index c8ae032ec485..000000000000 --- a/worlds/mariomissing/Regions.py +++ /dev/null @@ -1,97 +0,0 @@ -from typing import List, Dict, Tuple -from BaseClasses import MultiWorld, Region, Location -from .Locations import LocationData - -class YILocation(Location): - game: str = "Mario is Missing" - -def __init__(player: int, name: str = " ", address: int = None, parent=None): - super().__init__(player, name, address, parent) - - -def create_regions(multiworld: MultiWorld, player: int, locations: Tuple[LocationData, ...], location_cache: List[Location], world): - - locations_per_region = get_locations_per_region(locations) - - regions = [ - create_region(multiworld, player, locations_per_region, location_cache, 'Menu'), - create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 1'), - create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 2'), - create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 3'), - create_region(multiworld, player, locations_per_region, location_cache, 'Castle Floor 4'), - - create_region(multiworld, player, locations_per_region, location_cache, 'Rome'), - create_region(multiworld, player, locations_per_region, location_cache, 'Paris'), - create_region(multiworld, player, locations_per_region, location_cache, 'London'), - create_region(multiworld, player, locations_per_region, location_cache, 'New York'), - create_region(multiworld, player, locations_per_region, location_cache, 'San Francisco'), - create_region(multiworld, player, locations_per_region, location_cache, 'Athens'), - create_region(multiworld, player, locations_per_region, location_cache, 'Sydney'), - create_region(multiworld, player, locations_per_region, location_cache, 'Tokyo'), - create_region(multiworld, player, locations_per_region, location_cache, 'Nairobi'), - create_region(multiworld, player, locations_per_region, location_cache, 'Rio de Janeiro'), - create_region(multiworld, player, locations_per_region, location_cache, 'Cairo'), - create_region(multiworld, player, locations_per_region, location_cache, 'Moscow'), - create_region(multiworld, player, locations_per_region, location_cache, 'Beijing'), - create_region(multiworld, player, locations_per_region, location_cache, 'Buenos Aires'), - create_region(multiworld, player, locations_per_region, location_cache, 'Mexico City') - - ] - multiworld.regions += regions - multiworld.get_region('Menu', player).add_exits(["Castle Floor 1"]) - multiworld.get_region('Castle Floor 1', player).add_exits(["Castle Floor 2"], - {"Castle Floor 2": lambda state: state.has_any({'Castle Floor Key'}, player)}) - multiworld.get_region('Castle Floor 2', player).add_exits(["Castle Floor 3"], - {"Castle Floor 3": lambda state: state.has('Castle Floor Key', player, 2)}) - multiworld.get_region('Castle Floor 3', player).add_exits(["Castle Floor 4"], - {"Castle Floor 4": lambda state: state.has('Artifact Secured', player, world.options.required_artifacts.value)}) - - multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[0]]) - multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[1]]) - multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[2]]) - multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[3]]) - multiworld.get_region('Castle Floor 1', player).add_exits([world.city_list[4]]) - - multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[5]]) - multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[6]]) - multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[7]]) - multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[8]]) - multiworld.get_region('Castle Floor 2', player).add_exits([world.city_list[9]]) - - multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[10]]) - multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[11]]) - multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[12]]) - multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[13]]) - multiworld.get_region('Castle Floor 3', player).add_exits([world.city_list[14]]) - -def create_location(player: int, location_data: LocationData, region: Region, location_cache: List[Location]) -> Location: - location = YILocation(player, location_data.name, location_data.code, region) - location.access_rule = location_data.rule - - if id is None: - location.event = True - location.locked = True - - location_cache.append(location) - - return location - -def create_region(multiworld: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], location_cache: List[Location], name: str) -> Region: - region = Region(name, player, multiworld) - region.world = multiworld - - if name in locations_per_region: - for location_data in locations_per_region[name]: - location = create_location(player, location_data, region, location_cache) - region.locations.append(location) - - return region - - -def get_locations_per_region(locations: Tuple[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/mariomissing/Rom.py b/worlds/mariomissing/Rom.py deleted file mode 100644 index 5da09d216d4e..000000000000 --- a/worlds/mariomissing/Rom.py +++ /dev/null @@ -1,698 +0,0 @@ -import hashlib -import os -import Utils -from worlds.Files import APDeltaPatch -USHASH = '2a2152976e503eaacd9815f44c262d73' -ROM_PLAYER_LIMIT = 65535 - -item_values = { - 0x198401: [0x1550, 0x01], - 0x198402: [0x1550, 0x02], - 0x198403: [0x1550, 0x03], - 0x198404: [0x1550, 0x04], - 0x198405: [0x1550, 0x05], - 0x198406: [0x1550, 0x06], - 0x198407: [0x1550, 0x07], - 0x198408: [0x1550, 0x08], - 0x198409: [0x1550, 0x09], - 0x19840A: [0x1550, 0x0A], - 0x19840B: [0x1550, 0x0B], - 0x19840C: [0x1550, 0x0C], - 0x19840D: [0x1550, 0x0D], - 0x19840E: [0x1550, 0x0E], - 0x19840F: [0x1550, 0x0F], - 0x198410: [0x1550, 0x10], - 0x198411: [0x1550, 0x11], - 0x198412: [0x1550, 0x12], - 0x198413: [0x1550, 0x13], - 0x198414: [0x1550, 0x14], - 0x198415: [0x1550, 0x15], - 0x198416: [0x1550, 0x16], - 0x198417: [0x1550, 0x17], - 0x198418: [0x1550, 0x18], - 0x198419: [0x1550, 0x19], - 0x19841A: [0x1550, 0x1A], - 0x19841B: [0x1550, 0x1B], - 0x19841C: [0x1550, 0x1C], - 0x19841D: [0x1550, 0x1D], - 0x19841E: [0x1550, 0x1E], - 0x19841F: [0x1550, 0x1F], - 0x198420: [0x1550, 0x20], - 0x198421: [0x1550, 0x21], - 0x198422: [0x1550, 0x22], - 0x198423: [0x1550, 0x23], - 0x198424: [0x1550, 0x24], - 0x198425: [0x1550, 0x25], - 0x198426: [0x1550, 0x26], - 0x198427: [0x1550, 0x27], - 0x198428: [0x1550, 0x28], - 0x198429: [0x1550, 0x29], - 0x19842A: [0x1550, 0x2A], - 0x19842B: [0x1550, 0x2B], - 0x19842C: [0x1550, 0x2C], - 0x19842D: [0x1550, 0x2D], - 0x19842E: [0x1550, 0x2E] - -} - -location_table = { - 0x198400: [0x1555, 3], - 0x198401: [0x1555, 4], - 0x198402: [0x1555, 5], - 0x198403: [0x1564, 3], - 0x198404: [0x1564, 4], - 0x198405: [0x1564, 5], - - 0x198406: [0x1556, 3], - 0x198407: [0x1556, 4], - 0x198408: [0x1556, 5], - 0x198409: [0x1565, 3], - 0x19840A: [0x1565, 4], - 0x19840B: [0x1565, 5], - - 0x19840C: [0x1557, 3], - 0x19840D: [0x1557, 4], - 0x19840E: [0x1557, 5], - 0x19840F: [0x1566, 3], - 0x198410: [0x1566, 4], - 0x198411: [0x1566, 5], - - 0x198412: [0x1558, 3], - 0x198413: [0x1558, 4], - 0x198414: [0x1558, 5], - 0x198415: [0x1567, 3], - 0x198416: [0x1567, 4], - 0x198417: [0x1567, 5], - - 0x198418: [0x1559, 3], - 0x198419: [0x1559, 4], - 0x19841A: [0x1559, 5], - 0x19841B: [0x1568, 3], - 0x19841C: [0x1568, 4], - 0x19841D: [0x1568, 5], - - 0x19841E: [0x155A, 3], - 0x19841F: [0x155A, 4], - 0x198420: [0x155A, 5], - 0x198421: [0x1569, 3], - 0x198422: [0x1569, 4], - 0x198423: [0x1569, 5], - - 0x198424: [0x155B, 3], - 0x198425: [0x155B, 4], - 0x198426: [0x155B, 5], - 0x198427: [0x156A, 3], - 0x198428: [0x156A, 4], - 0x198429: [0x156A, 5], - - 0x19842A: [0x155C, 3], - 0x19842B: [0x155C, 4], - 0x19842C: [0x155C, 5], - 0x19842D: [0x156B, 3], - 0x19842E: [0x156B, 4], - 0x19842F: [0x156B, 5], - - 0x198430: [0x155D, 3], - 0x198431: [0x155D, 4], - 0x198432: [0x155D, 5], - 0x198433: [0x156C, 3], - 0x198434: [0x156C, 4], - 0x198435: [0x156C, 5], - - 0x198436: [0x155E, 3], - 0x198437: [0x155E, 4], - 0x198438: [0x155E, 5], - 0x198439: [0x156D, 3], - 0x19843A: [0x156D, 4], - 0x19843B: [0x156D, 5], - - 0x19843C: [0x155F, 3], - 0x19843D: [0x155F, 4], - 0x19843E: [0x155F, 5], - 0x19843F: [0x156E, 3], - 0x198440: [0x156E, 4], - 0x198441: [0x156E, 5], - - 0x198442: [0x1560, 3], - 0x198443: [0x1560, 4], - 0x198444: [0x1560, 5], - 0x198445: [0x156F, 3], - 0x198446: [0x156F, 4], - 0x198447: [0x156F, 5], - - 0x198448: [0x1561, 3], - 0x198449: [0x1561, 4], - 0x19844A: [0x1561, 5], - 0x19844B: [0x1570, 3], - 0x19844C: [0x1570, 4], - 0x19844D: [0x1570, 5], - - 0x19844E: [0x1562, 3], - 0x19844F: [0x1562, 4], - 0x198450: [0x1562, 5], - 0x198451: [0x1571, 3], - 0x198452: [0x1571, 4], - 0x198453: [0x1571, 5], - - 0x198454: [0x1563, 3], - 0x198455: [0x1563, 4], - 0x198456: [0x1563, 5], - 0x198457: [0x1572, 3], - 0x198458: [0x1572, 4], - 0x198459: [0x1572, 5], - - 0x19845A: [0x15AA, 0], - 0x19845B: [0x15AC, 0], - 0x19845C: [0x15AE, 0], - 0x19845D: [0x15A0, 0], - 0x19845E: [0x159A, 0], - 0x19845F: [0x159C, 0], - 0x198460: [0x159E, 0], - 0x198461: [0x15A8, 0], - 0x198462: [0x15A2, 0], - 0x198463: [0x15A4, 0], - 0x198464: [0x15A6, 0], - 0x198465: [0x1588, 0], - 0x198466: [0x1582, 0], - 0x198467: [0x1584, 0], - 0x198468: [0x1586, 0], - 0x198469: [0x1590, 0], - 0x19846A: [0x158A, 0], - 0x19846B: [0x158C, 0], - 0x19846C: [0x158E, 0], - 0x19846D: [0x1598, 0], - 0x19846E: [0x1592, 0], - 0x19846F: [0x1594, 0], - 0x198470: [0x1596, 0], - - 0x198471: [0x15AA, 1], - 0x198472: [0x15AC, 1], - 0x198473: [0x15AE, 1], - 0x198474: [0x15A0, 1], - 0x198475: [0x159A, 1], - 0x198476: [0x159C, 1], - 0x198477: [0x159E, 1], - 0x198478: [0x15A8, 1], - 0x198479: [0x15A2, 1], - 0x19847A: [0x15A4, 1], - 0x19847B: [0x15A6, 1], - 0x19847C: [0x1588, 1], - 0x19847D: [0x1582, 1], - 0x19847E: [0x1584, 1], - 0x19847F: [0x1586, 1], - 0x198480: [0x1590, 1], - 0x198481: [0x158A, 1], - 0x198482: [0x158C, 1], - 0x198483: [0x158E, 1], - 0x198484: [0x1598, 1], - 0x198485: [0x1592, 1], - 0x198486: [0x1594, 1], - 0x198487: [0x1596, 1], - - 0x198488: [0x15AA, 2], - 0x198489: [0x15AC, 2], - 0x19848A: [0x15AE, 2], - 0x19848B: [0x15A0, 2], - 0x19848C: [0x159A, 2], - 0x19848D: [0x159C, 2], - 0x19848E: [0x159E, 2], - 0x19848F: [0x15A8, 2], - 0x198490: [0x15A2, 2], - 0x198491: [0x15A4, 2], - 0x198492: [0x15A6, 2], - 0x198493: [0x1588, 2], - 0x198494: [0x1582, 2], - 0x198495: [0x1584, 2], - 0x198496: [0x1586, 2], - 0x198497: [0x1590, 2], - 0x198498: [0x158A, 2], - 0x198499: [0x158C, 2], - 0x19849A: [0x158E, 2], - 0x19849B: [0x1598, 2], - 0x19849C: [0x1592, 2], - 0x19849D: [0x1594, 2], - 0x19849E: [0x1596, 2], - - 0x19849F: [0x15AA, 3], - 0x1984A0: [0x15AC, 3], - 0x1984A1: [0x15AE, 3], - 0x1984A2: [0x15A0, 3], - 0x1984A3: [0x159A, 3], - 0x1984A4: [0x159C, 3], - 0x1984A5: [0x159E, 3], - 0x1984A6: [0x15A8, 3], - 0x1984A7: [0x15A2, 3], - 0x1984A8: [0x15A4, 3], - 0x1984A9: [0x15A6, 3], - 0x1984AA: [0x1588, 3], - 0x1984AB: [0x1582, 3], - 0x1984AC: [0x1584, 3], - 0x1984AD: [0x1586, 3], - 0x1984AE: [0x1590, 3], - 0x1984AF: [0x158A, 3], - 0x1984B0: [0x158C, 3], - 0x1984B1: [0x158E, 3], - 0x1984B2: [0x1598, 3], - 0x1984B3: [0x1592, 3], - 0x1984B4: [0x1594, 3], - 0x1984B5: [0x1596, 3], - - 0x1984B6: [0x15AA, 4], - 0x1984B7: [0x15AC, 4], - 0x1984B8: [0x15AE, 4], - 0x1984B9: [0x15A0, 4], - 0x1984BA: [0x159A, 4], - 0x1984BB: [0x159C, 4], - 0x1984BC: [0x159E, 4], - 0x1984BD: [0x15A8, 4], - 0x1984BE: [0x15A2, 4], - 0x1984BF: [0x15A4, 4], - 0x1984C0: [0x15A6, 4], - 0x1984c1: [0x1588, 4], - 0x1984c2: [0x1582, 4], - 0x1984C3: [0x1584, 4], - 0x1984C4: [0x1586, 4], - 0x1984C5: [0x1590, 4], - 0x1984C6: [0x158A, 4], - 0x1984C7: [0x158C, 4], - 0x1984C8: [0x158E, 4], - 0x1984C9: [0x1598, 4], - 0x1984CA: [0x1592, 4], - 0x1984CB: [0x1594, 4], - 0x1984CC: [0x1596, 4], - - 0x1984CD: [0x15AA, 5], - 0x1984CE: [0x15AC, 5], - 0x1984CF: [0x15AE, 5], - 0x1984D0: [0x15A0, 5], - 0x1984D1: [0x159A, 5], - 0x1984D2: [0x159C, 5], - 0x1984D3: [0x159E, 5], - 0x1984D4: [0x15A8, 5], - 0x1984D5: [0x15A2, 5], - 0x1984D6: [0x15A4, 5], - 0x1984D7: [0x15A6, 5], - 0x1984D8: [0x1588, 5], - 0x1984D9: [0x1582, 5], - 0x1984DA: [0x1584, 5], - 0x1984DB: [0x1586, 5], - 0x1984DC: [0x1590, 5], - 0x1984DD: [0x158A, 5], - 0x1984DE: [0x158C, 5], - 0x1984DF: [0x158E, 5], - 0x1984E0: [0x1598, 5], - 0x1984E1: [0x1592, 5], - 0x1984E2: [0x1594, 5], - 0x1984E3: [0x1596, 5], - - 0x1984E4: [0x15AA, 6], - 0x1984E5: [0x15AC, 6], - 0x1984E6: [0x15AE, 6], - 0x1984E7: [0x15A0, 6], - 0x1984E8: [0x159A, 6], - 0x1984E9: [0x159C, 6], - 0x1984EA: [0x159E, 6], - 0x1984EB: [0x15A8, 6], - 0x1984EC: [0x15A2, 6], - 0x1984ED: [0x15A4, 6], - 0x1984EE: [0x15A6, 6], - 0x1984EF: [0x1588, 6], - 0x1984F0: [0x1582, 6], - 0x1984F1: [0x1584, 6], - 0x1984F2: [0x1586, 6], - 0x1984F3: [0x1590, 6], - 0x1984F4: [0x158A, 6], - 0x1984F5: [0x158C, 6], - 0x1984F6: [0x158E, 6], - 0x1984F7: [0x1598, 6], - 0x1984F8: [0x1592, 6], - 0x1984F9: [0x1594, 6], - 0x1984FA: [0x1596, 6], - - 0x1984FB: [0x15AA, 7], - 0x1984FC: [0x15AC, 7], - 0x1984FD: [0x15AE, 7], - 0x1984FE: [0x15A0, 7], - 0x1984FF: [0x159A, 7], - 0x198500: [0x159C, 7], - 0x198501: [0x159E, 7], - 0x198502: [0x15A8, 7], - 0x198503: [0x15A2, 7], - 0x198504: [0x15A4, 7], - 0x198505: [0x15A6, 7], - 0x198506: [0x1588, 7], - 0x198507: [0x1582, 7], - 0x198508: [0x1584, 7], - 0x198509: [0x1586, 7], - 0x19850A: [0x1590, 7], - 0x19850B: [0x158A, 7], - 0x19850C: [0x158C, 7], - 0x19850D: [0x158E, 7], - 0x19850E: [0x1598, 7], - 0x19850F: [0x1592, 7], - 0x198510: [0x1594, 7], - 0x198511: [0x1596, 7], - - 0x198512: [0x15AB, 0], - 0x198513: [0x15AD, 0], - 0x198514: [0x15AF, 0], - 0x198515: [0x15A1, 0], - 0x198516: [0x159B, 0], - 0x198517: [0x159D, 0], - 0x198518: [0x159F, 0], - 0x198519: [0x15A9, 0], - 0x19851A: [0x15A3, 0], - 0x19851B: [0x15A5, 0], - 0x19851C: [0x15A7, 0], - 0x19851D: [0x1589, 0], - 0x19851E: [0x1583, 0], - 0x19851F: [0x1585, 0], - 0x198520: [0x1587, 0], - 0x198521: [0x1591, 0], - 0x198522: [0x158B, 0], - 0x198523: [0x158D, 0], - 0x198524: [0x158F, 0], - 0x198525: [0x1599, 0], - 0x198526: [0x1593, 0], - 0x198527: [0x1595, 0], - 0x198528: [0x1597, 0], - - 0x198529: [0x15AB, 1], - 0x19852A: [0x15AD, 1], - 0x19852B: [0x15AF, 1], - 0x19852C: [0x15A1, 1], - 0x19852D: [0x159B, 1], - 0x19852E: [0x159D, 1], - 0x19852F: [0x159F, 1], - 0x198530: [0x15A9, 1], - 0x198531: [0x15A3, 1], - 0x198532: [0x15A5, 1], - 0x198533: [0x15A7, 1], - 0x198534: [0x1589, 1], - 0x198535: [0x1583, 1], - 0x198536: [0x1585, 1], - 0x198537: [0x1587, 1], - 0x198538: [0x1591, 1], - 0x198539: [0x158B, 1], - 0x19853A: [0x158D, 1], - 0x19853B: [0x158F, 1], - 0x19853C: [0x1599, 1], - 0x19853D: [0x1593, 1], - 0x19853E: [0x1595, 1], - 0x19853F: [0x1597, 1], - - 0x198540: [0x15AB, 2], - 0x198541: [0x15AD, 2], - 0x198542: [0x15AF, 2], - 0x198543: [0x15A1, 2], - 0x198544: [0x159B, 2], - 0x198545: [0x159D, 2], - 0x198546: [0x159F, 2], - 0x198547: [0x15A9, 2], - 0x198548: [0x15A3, 2], - 0x198549: [0x15A5, 2], - 0x19854A: [0x15A7, 2], - 0x19854B: [0x1589, 2], - 0x19854C: [0x1583, 2], - 0x19854D: [0x1585, 2], - 0x19854E: [0x1587, 2], - 0x19854F: [0x1591, 2], - 0x198550: [0x158B, 2], - 0x198551: [0x158D, 2], - 0x198552: [0x158F, 2], - 0x198553: [0x1599, 2], - 0x198554: [0x1593, 2], - 0x198555: [0x1595, 2], - 0x198556: [0x1597, 2], - - 0x198557: [0x15AB, 3], - 0x198558: [0x15AD, 3], - 0x198559: [0x15AF, 3], - 0x19855A: [0x15A1, 3], - 0x19855B: [0x159B, 3], - 0x19855C: [0x159D, 3], - 0x19855D: [0x159F, 3], - 0x19855E: [0x15A9, 3], - 0x19855F: [0x15A3, 3], - 0x198560: [0x15A5, 3], - 0x198561: [0x15A7, 3], - 0x198562: [0x1589, 3], - 0x198563: [0x1583, 3], - 0x198564: [0x1585, 3], - 0x198565: [0x1587, 3], - 0x198566: [0x1591, 3], - 0x198567: [0x158B, 3], - 0x198568: [0x158D, 3], - 0x198569: [0x158F, 3], - 0x19856A: [0x1599, 3], - 0x19856B: [0x1593, 3], - 0x19856C: [0x1595, 3], - 0x19856D: [0x1597, 3], - - 0x19856E: [0x15AB, 4], - 0x19856F: [0x15AD, 4], - 0x198570: [0x15AF, 4], - 0x198571: [0x15A1, 4], - 0x198572: [0x159B, 4], - 0x198573: [0x159D, 4], - 0x198574: [0x159F, 4], - 0x198575: [0x15A9, 4], - 0x198576: [0x15A3, 4], - 0x198577: [0x15A5, 4], - 0x198578: [0x15A7, 4], - 0x198579: [0x1589, 4], - 0x19857A: [0x1583, 4], - 0x19857B: [0x1585, 4], - 0x19857C: [0x1587, 4], - 0x19857D: [0x1591, 4], - 0x19857E: [0x158B, 4], - 0x19857F: [0x158D, 4], - 0x198580: [0x158F, 4], - 0x198581: [0x1599, 4], - 0x198582: [0x1593, 4], - 0x198583: [0x1595, 4], - 0x198584: [0x1597, 4], - - 0x198585: [0x15AB, 5], - 0x198586: [0x15AD, 5], - 0x198587: [0x15AF, 5], - 0x198588: [0x15A1, 5], - 0x198589: [0x159B, 5], - 0x19858A: [0x159D, 5], - 0x19858B: [0x159F, 5], - 0x19858C: [0x15A9, 5], - 0x19858D: [0x15A3, 5], - 0x19858E: [0x15A5, 5], - 0x19858F: [0x15A7, 5], - 0x198590: [0x1589, 5], - 0x198591: [0x1583, 5], - 0x198592: [0x1585, 5], - 0x198593: [0x1587, 5], - 0x198594: [0x1591, 5], - 0x198595: [0x158B, 5], - 0x198596: [0x158D, 5], - 0x198597: [0x158F, 5], - 0x198598: [0x1599, 5], - 0x198599: [0x1593, 5], - 0x19859A: [0x1595, 5], - 0x19859B: [0x1597, 5], - - 0x19859C: [0x15AB, 6], - 0x19859D: [0x15AD, 6], - 0x19859E: [0x15AF, 6], - 0x19859F: [0x15A1, 6], - 0x1985A0: [0x159B, 6], - 0x1985A1: [0x159D, 6], - 0x1985A2: [0x159F, 6], - 0x1985A3: [0x15A9, 6], - 0x1985A4: [0x15A3, 6], - 0x1985A5: [0x15A5, 6], - 0x1985A6: [0x15A7, 6], - 0x1985A7: [0x1589, 6], - 0x1985A8: [0x1583, 6], - 0x1985A9: [0x1585, 6], - 0x1985AA: [0x1587, 6], - 0x1985AB: [0x1591, 6], - 0x1985AC: [0x158B, 6], - 0x1985AD: [0x158D, 6], - 0x1985AE: [0x158F, 6], - 0x1985AF: [0x1599, 6], - 0x1985B0: [0x1593, 6], - 0x1985B1: [0x1595, 6], - 0x1985B2: [0x1597, 6] -} - -class LocalRom(object): - - def __init__(self, file, vanillaRom=None, name=None): - self.name = name - 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): - self.buffer[address] = value - - def write_bytes(self, startaddress: int, values): - self.buffer[startaddress:startaddress + len(values)] = values - - def write_to_file(self, file): - with open(file, 'wb') as outfile: - outfile.write(self.buffer) - - def read_from_file(self, file): - with open(file, 'rb') as stream: - self.buffer = bytearray(stream.read()) - -def rom_code(rom): - rom.write_bytes(0x008510, bytearray([0x48, 0xa9, 0x69, 0x42, 0x8d, 0x45, 0x15, 0x68, 0x80, 0x22])) - rom.write_bytes(0x002FE3, bytearray([0x5c, 0x03, 0xff, 0x02])) - rom.write_bytes(0x00ACF5, bytearray([0x5c, 0x48, 0xff, 0x02])) - rom.write_bytes(0x0028FB, bytearray([0x5c, 0x70, 0xff, 0x02])) - rom.write_bytes(0x004EC8, bytearray([0x4C, 0x40, 0xCF])) - rom.write_bytes(0x009FBC, bytearray([0x80])) - rom.write_bytes(0x0057EA, bytearray([0xEA, 0xEA])) - rom.write_bytes(0x0057F2, bytearray([0x80])) - rom.write_bytes(0x005827, bytearray([0x5c, 0x5B, 0xFF, 0x08])) - rom.write_bytes(0x006C1C, bytearray([0x5c, 0x81, 0xFF, 0x02])) - rom.write_bytes(0x005808, bytearray([0xC9, 0x01, 0x00, 0x80, 0x11])) - rom.write_bytes(0x00AC75, bytearray([0x5c, 0x50, 0xFE, 0x08])) - rom.write_bytes(0x00ACFA, bytearray([0x08, 0x00, 0x10, 0x00, 0x20, 0x00])) - rom.write_bytes(0x0029AE, bytearray([0x5c, 0x80, 0xFE, 0x08])) - rom.write_bytes(0x002738, bytearray([0x80])) - rom.write_bytes(0x002945, bytearray([0x5c, 0xB3, 0xFE, 0x08])) - rom.write_bytes(0x00707C, bytearray([0x01, 0x02, 0x04, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20])) - rom.write_bytes(0x00F8C3, bytearray([0x5c, 0xE0, 0xFE, 0x12])) - rom.write_bytes(0x00F4AB, bytearray([0x5c, 0xEB, 0xFE, 0x08])) - rom.write_bytes(0x0064F5, bytearray([0x5c, 0xF8, 0xFE, 0x08])) - rom.write_bytes(0x0054CA, bytearray([0xA9, 0x00])) - rom.write_bytes(0x01088E, bytearray([0x5C, 0xA9, 0xFF, 0x08])) - rom.write_bytes(0x00A48E, bytearray([0x5C, 0xC6, 0xFF, 0x08])) - rom.write_bytes(0x00294E, bytearray([0xEA, 0xEA, 0xEA])) - rom.write_bytes(0x004ECB, bytearray([0xf8, 0xce, 0xfa, 0xce, 0xfc, 0xce, 0xfe, 0xce, 0xfc, 0xce, 0x00, 0xcf, 0x02, 0xcf, 0xfa, 0xce])) - rom.write_bytes(0x004EDB, bytearray([0x00, 0xcf, 0xfc, 0xce, 0x00, 0xcf, 0x00, 0xcf, 0x02, 0xcf, 0xfe, 0xce, 0xf8, 0xce, 0x2e, 0x32])) - rom.write_bytes(0x004EEB, bytearray([0x32, 0x2e, 0x32, 0x30, 0x30, 0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x2e, 0x2e, 0x32, 0x30, 0x30])) - rom.write_bytes(0x004EFB, bytearray([0x2e, 0x2e, 0x30, 0x30, 0x32, 0x2e, 0x32, 0x32, 0x2e])) - rom.write_bytes(0x001B35, bytearray([0x5C, 0x1D, 0xFF, 0x12])) - - - rom.write_bytes(0x017F03, bytearray([0x8b, 0xa9, 0x7e, 0x48, 0xab, 0xa9, 0x00, 0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x55, 0x15, 0x29])) - rom.write_bytes(0x017F13, bytearray([0x07, 0x8d, 0x0a, 0x05, 0xf0, 0x27, 0xad, 0x08, 0x05, 0xd0, 0x1a, 0xad, 0x0a, 0x05, 0x89, 0x01])) - rom.write_bytes(0x017F23, bytearray([0xf0, 0x07, 0xa9, 0x01, 0x8d, 0x08, 0x05, 0x80, 0x0c, 0x89, 0x02, 0xf0, 0x04, 0xa9, 0x02, 0x80])) - rom.write_bytes(0x017F33, bytearray([0xf3, 0xa9, 0x04, 0x80, 0xef, 0xad, 0x0a, 0x05, 0xab, 0x5c, 0xe8, 0xaf, 0x80, 0x9c, 0x08, 0x05])) - rom.write_bytes(0x017F43, bytearray([0xab, 0x5c, 0x09, 0xb0, 0x80, 0x8b, 0xda, 0xe2, 0x20, 0x48, 0xa9, 0x7e, 0x48, 0xab, 0xa9, 0x00])) - rom.write_bytes(0x017F53, bytearray([0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x55, 0x15, 0x8d, 0x53, 0x15, 0x68, 0x0c, 0x53, 0x15, 0xad])) - rom.write_bytes(0x017F63, bytearray([0x53, 0x15, 0x9d, 0x55, 0x15, 0xc2, 0x20, 0xfa, 0xab, 0x5c, 0xf9, 0xac, 0x81, 0xe2, 0x20, 0xee])) - rom.write_bytes(0x017F73, bytearray([0x54, 0x15, 0xc2, 0x20, 0xa9, 0x84, 0x03, 0x8d, 0x65, 0x05, 0x5c, 0x01, 0xa9, 0x80, 0xe2, 0x20])) - rom.write_bytes(0x017F83, bytearray([0x8b, 0xa9, 0x7e, 0x48, 0xab, 0xad, 0x39, 0x00, 0xc9, 0x04, 0xd0, 0x28, 0xad, 0x04, 0x05, 0xf0])) - rom.write_bytes(0x017F93, bytearray([0x23, 0xce, 0x04, 0x05, 0xa9, 0x05, 0x8d, 0x93, 0x05, 0x22, 0xa7, 0x82, 0x80, 0x68, 0x68, 0x68])) - rom.write_bytes(0x017FA3, bytearray([0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0xab, 0x28, 0xc2, 0x20, 0xa9, 0x93, 0x01, 0x8d, 0x95, 0x05])) - rom.write_bytes(0x017FB3, bytearray([0x5c, 0xa3, 0xd4, 0x80, 0xab, 0xc2, 0x20, 0xae, 0x85, 0x06, 0xbd, 0x65, 0x0d, 0x5c, 0x22, 0xec])) - rom.write_bytes(0x017FC3, bytearray([0x80])) - - rom.write_bytes(0x047E50, bytearray([0x22, 0x03, 0x92, 0x80, 0xe0, 0x28, 0x00, 0x90, 0x23, 0xda, 0xe2, 0x20, 0xbd, 0xd2, 0xac, 0x8f])) - rom.write_bytes(0x047E60, bytearray([0x53, 0x15, 0x7e, 0x8b, 0x20, 0x94, 0xff, 0xa9, 0x00, 0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x55])) - rom.write_bytes(0x047E70, bytearray([0x15, 0x18, 0x2c, 0x53, 0x15, 0xd0, 0x01, 0x38, 0xc2, 0x20, 0xab, 0xfa, 0x5c, 0x7c, 0xac, 0x81])) - rom.write_bytes(0x047E80, bytearray([0xe2, 0x20, 0x8b, 0xad, 0x53, 0x05, 0xaa, 0xbf, 0x7c, 0xf0, 0x00, 0x48, 0x20, 0x94, 0xff, 0x68])) - rom.write_bytes(0x047E90, bytearray([0x8d, 0x53, 0x15, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x64, 0x15, 0x2c, 0x53, 0x15, 0xf0, 0x07, 0xab])) - rom.write_bytes(0x047EA0, bytearray([0xc2, 0x20, 0x5c, 0xbc, 0xa9, 0x80, 0xab, 0xc2, 0x20, 0xae, 0x08, 0x05, 0xbd, 0x28, 0xaf, 0x5c])) - rom.write_bytes(0x047EB0, bytearray([0xb4, 0xa9, 0x80, 0xe2, 0x20, 0x8b, 0xae, 0x53, 0x05, 0xbf, 0x7c, 0xf0, 0x00, 0x48, 0x20, 0x94])) - rom.write_bytes(0x047EC0, bytearray([0xff, 0x68, 0x8d, 0x53, 0x15, 0xa9, 0x00, 0xeb, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x64, 0x15, 0x0c])) - rom.write_bytes(0x047ED0, bytearray([0x53, 0x15, 0xad, 0x53, 0x15, 0x9d, 0x64, 0x15, 0xee, 0x4f, 0x15, 0xc2, 0x20, 0xae, 0x51, 0x05])) - rom.write_bytes(0x047EE0, bytearray([0xab, 0xbd, 0x2d, 0xaf, 0x0d, 0x4f, 0x05, 0x5c, 0x4b, 0xa9, 0x80, 0x20, 0x05, 0xff, 0xad, 0x55])) - rom.write_bytes(0x047EF0, bytearray([0x08, 0xc9, 0x80, 0x00, 0x5c, 0xb1, 0xf4, 0x81, 0x20, 0x05, 0xff, 0xad, 0x55, 0x08, 0xc9, 0x60])) - rom.write_bytes(0x047F00, bytearray([0x00, 0x5c, 0xfb, 0xe4, 0x80, 0xa9, 0x00, 0x00, 0xda, 0x5a, 0x8b, 0xe2, 0x20, 0x20, 0x94, 0xff])) - rom.write_bytes(0x047F10, bytearray([0x48, 0xab, 0xad, 0x50, 0x15, 0xf0, 0x39, 0xa0, 0x00, 0x00, 0xc9, 0x2e, 0xf0, 0x38, 0xc9, 0x04])) - rom.write_bytes(0x047F20, bytearray([0x90, 0x06, 0x38, 0xe9, 0x03, 0xc8, 0x80, 0xf2, 0xaa, 0xbf, 0x7f, 0xf0, 0x00, 0x48, 0xb9, 0x55])) - rom.write_bytes(0x047F30, bytearray([0x15, 0x8d, 0x53, 0x15, 0x68, 0x0c, 0x53, 0x15, 0xad, 0x53, 0x15, 0x99, 0x55, 0x15, 0xa0, 0x01])) - rom.write_bytes(0x047F40, bytearray([0x00, 0x9c, 0x50, 0x15, 0xc2, 0x20, 0xa9, 0x04, 0x00, 0xab, 0x22, 0x03, 0x92, 0x80, 0x80, 0x03])) - rom.write_bytes(0x047F50, bytearray([0xc2, 0x20, 0xab, 0x7a, 0xfa, 0x60, 0xee, 0x4e, 0x15, 0x80, 0xe3, 0xda, 0x8b, 0xe0, 0x0a, 0x00])) - rom.write_bytes(0x047F60, bytearray([0xd0, 0x1d, 0xe2, 0x20, 0x20, 0x94, 0xff, 0xad, 0x04, 0x05, 0xc9, 0x02, 0xf0, 0x2b, 0xaa, 0xbd])) - rom.write_bytes(0x047F70, bytearray([0x40, 0x15, 0xd0, 0x0b, 0xad, 0x4e, 0x15, 0xf0, 0x14, 0xce, 0x4e, 0x15, 0xfe, 0x40, 0x15, 0xc2])) - rom.write_bytes(0x047F80, bytearray([0x20, 0xa9, 0x01, 0x00, 0xab, 0xfa, 0x8d, 0xc3, 0x0d, 0x5c, 0x2d, 0xd8, 0x80, 0xc2, 0x20, 0xa9])) - rom.write_bytes(0x047F90, bytearray([0x00, 0x00, 0xf0, 0xf0, 0xa9, 0x7e, 0x48, 0xab, 0x60, 0xad, 0x4f, 0x15, 0xcf, 0x10, 0xff, 0x1f])) - rom.write_bytes(0x047FA0, bytearray([0xb0, 0xdd, 0xc2, 0x20, 0xa9, 0x00, 0x00, 0x80, 0xdb, 0x48, 0xe2, 0x20, 0xad, 0x7b, 0x12, 0xc9])) - rom.write_bytes(0x047FB0, bytearray([0xea, 0xd0, 0x06, 0xa9, 0x69, 0x8f, 0x43, 0x15, 0x7e, 0xc2, 0x20, 0x68, 0x7d, 0x7b, 0x12, 0x9d])) - rom.write_bytes(0x047FC0, bytearray([0x7b, 0x12, 0x5c, 0x94, 0x88, 0x82, 0xad, 0x02, 0x05, 0xaa, 0xe2, 0x20, 0xbd, 0x64, 0x15, 0xda])) - rom.write_bytes(0x047FD0, bytearray([0x8d, 0x53, 0x15, 0xad, 0x53, 0x05, 0xaa, 0xbf, 0x83, 0xf0, 0x00, 0x0c, 0x53, 0x15, 0xad, 0x53])) - rom.write_bytes(0x047FE0, bytearray([0x15, 0xfa, 0x9d, 0x64, 0x15, 0xc2, 0x20, 0xad, 0x02, 0x05, 0x0a, 0x5c, 0x92, 0xa4, 0x81])) - - rom.write_bytes(0x097EE0, bytearray([0xae, 0x85, 0x06, 0xda, 0x8a, 0xe2, 0x20, 0xa2, 0x00, 0x00, 0xdd, 0x31, 0x15, 0xf0, 0x03, 0xe8])) - rom.write_bytes(0x097EF0, bytearray([0x80, 0xf8, 0xbf, 0x7c, 0xf0, 0x00, 0x8d, 0x30, 0x15, 0xad, 0x02, 0x05, 0xaa, 0xbd, 0x64, 0x15])) - rom.write_bytes(0x097F00, bytearray([0x29, 0x07, 0x0c, 0x30, 0x15, 0xf0, 0x0c, 0xa9, 0xff, 0x8d, 0x4f, 0x05, 0xc2, 0x20, 0xfa, 0x5c])) - rom.write_bytes(0x097F10, bytearray([0xce, 0xf8, 0x81, 0x9c, 0x4f, 0x05, 0xc2, 0x20, 0xfa, 0x5c, 0xcf, 0xf8, 0x81, 0xda, 0xb9, 0x5e])) - rom.write_bytes(0x097F20, bytearray([0x9b, 0x8d, 0x02, 0x05, 0xe2, 0x20, 0xeb, 0xa9, 0x00, 0xeb, 0x0a, 0xaa, 0xc2, 0x20, 0xbf, 0xcb])) - rom.write_bytes(0x097F30, bytearray([0xce, 0x80, 0xaa, 0xbd, 0x00, 0x00, 0x8d, 0x31, 0x15, 0xe2, 0x20, 0xae, 0x02, 0x05, 0xbf, 0xe9])) - rom.write_bytes(0x097F40, bytearray([0xce, 0x80, 0x8d, 0x33, 0x15, 0xc2, 0x20, 0xfa, 0x5c, 0x3b, 0x9b, 0x00, 0xc9, 0x10, 0xd0, 0x02])) - rom.write_bytes(0x097F50, bytearray([0xa9, 0x08, 0x8d, 0x73, 0x15, 0xe0, 0x0a, 0x00, 0xb0, 0x56, 0x48, 0x20, 0x80, 0xff, 0xeb, 0xa9])) - rom.write_bytes(0x097F60, bytearray([0x00, 0xeb, 0x20, 0x94, 0xff, 0x68, 0x20, 0x9f, 0xff, 0xad, 0x74, 0x15, 0x18, 0x6d, 0x75, 0x15])) - rom.write_bytes(0x097F70, bytearray([0xaa, 0xbd, 0x82, 0x15, 0xc2, 0x20, 0x0d, 0x80, 0x15, 0x9d, 0x82, 0x15, 0x5c, 0x12, 0xb5, 0x80])) - rom.write_bytes(0x097F80, bytearray([0xda, 0xc2, 0x20, 0xae, 0x02, 0x05, 0x8a, 0x0a, 0xaa, 0xbf, 0x04, 0xcf, 0x80, 0x8d, 0x80, 0x15])) - rom.write_bytes(0x097F90, bytearray([0xfa, 0xe2, 0x20, 0x60, 0x8a, 0x4a, 0xaa, 0xbf, 0x22, 0xcf, 0x80, 0x8d, 0x75, 0x15, 0x60, 0xa2])) - rom.write_bytes(0x097FA0, bytearray([0x00, 0x00, 0xc9, 0x01, 0xf0, 0x05, 0x4a, 0xe8, 0xe8, 0x80, 0xf7, 0x8a, 0x8d, 0x74, 0x15, 0x60])) - rom.write_bytes(0x097FB0, bytearray([0xa2, 0x00, 0x00, 0xad, 0x73, 0x15, 0xc9, 0x20, 0xf0, 0x04, 0x4a, 0xe8, 0x80, 0xf8, 0x8e, 0x74])) - rom.write_bytes(0x097FC0, bytearray([0x15, 0x20, 0x80, 0xff, 0xeb, 0xa9, 0x00, 0xeb, 0xad, 0x74, 0x15, 0x0a, 0xaa, 0xc2, 0x20, 0xbd])) - rom.write_bytes(0x097FD0, bytearray([0xaa, 0x15, 0x0d, 0x80, 0x15, 0x9d, 0xaa, 0x15, 0x5c, 0x12, 0xb5, 0x80])) - - rom.write_bytes(0x004F04, bytearray([0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00])) - rom.write_bytes(0x004F14, bytearray([0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x08])) - rom.write_bytes(0x004F24, bytearray([0x10, 0x18, 0x20])) - - -def patch_rom(world, rom, player: int, multiworld): - rom_code(rom) - if world.options.computer_sanity.value == 1: - rom.write_bytes(0x00350C, bytearray([0x5C, 0x4C, 0xFF, 0x12])) - rom.write_bytes(0x001B5E, bytearray(world.city_order)) - rom.write_byte(0x0FFF10, world.options.required_artifacts.value) - rom.write_byte(0x0FFF11, world.options.death_link.value) - - from Main import __version__ - rom.name = bytearray(f'MarioMissingAP{__version__.replace(".", "")[0:3]}_{player}_{multiworld.seed:11}\0', 'utf8')[:15] - rom.name.extend([0] * (15 - len(rom.name))) - rom.write_bytes(0x007FC0, rom.name) - -class MIMDeltaPatch(APDeltaPatch): - hash = USHASH - game: str = "Mario is Missing" - patch_file_ending = ".apmim" - - @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: - options: Utils.OptionsType = Utils.get_options() - if not file_name: - file_name = options["mariomissing_options"]["rom_file"] - if not os.path.exists(file_name): - file_name = Utils.user_path(file_name) - return file_name diff --git a/worlds/mariomissing/SetupGame.py b/worlds/mariomissing/SetupGame.py deleted file mode 100644 index 4288eed7a3c8..000000000000 --- a/worlds/mariomissing/SetupGame.py +++ /dev/null @@ -1,27 +0,0 @@ -import itertools - -def setup_gamevars(world): - world.city_order = [0x04, 0x0B, 0x08, 0x0C, 0x00, 0x01, 0x0E, 0x06, 0x0D, 0x05, 0x02, 0x0A, 0x07, 0x09, 0x03] - world.city_list = [] - if world.options.city_shuffle != 0: - world.random.shuffle(world.city_order) - - city_code = { - 0x00: "Rome", - 0x01: "Paris", - 0x02: "London", - 0x03: "New York", - 0x04: "San Francisco", - 0x05: "Athens", - 0x06: "Sydney", - 0x07: "Tokyo", - 0x08: "Nairobi", - 0x09: "Rio de Janeiro", - 0x0A: "Cairo", - 0x0B: "Moscow", - 0x0C: "Beijing", - 0x0D: "Buenos Aires", - 0x0E: "Mexico City", - } - world.city_list = [city_code[world.city_order[i]] for i in range(15)] - world.city_order = list(itertools.chain.from_iterable((x, 0x00) for x in world.city_order)) diff --git a/worlds/mariomissing/__init__.py b/worlds/mariomissing/__init__.py deleted file mode 100644 index b84e1f39c975..000000000000 --- a/worlds/mariomissing/__init__.py +++ /dev/null @@ -1,251 +0,0 @@ -import os -import typing -import threading -import dataclasses - -from typing import Dict, List, Set, TextIO -from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification -from worlds.AutoWorld import World, WebWorld -from Options import PerGameCommonOptions -import Patch -import settings -from .Items import get_item_names_per_category, item_table, filler_items, artifacts -from .Locations import get_locations -from .Regions import create_regions -from .Options import MarioisMissingOptions -from .SetupGame import setup_gamevars -from .Client import MIMSNIClient -from .Rom import LocalRom, patch_rom, get_base_rom_path, MIMDeltaPatch, USHASH - -class MiMSettings(settings.Group): - class RomFile(settings.SNESRomPath): - """File name of the Mario is Missing US ROM""" - description = "Mario is Missing ROM File" - copy_to = "Mario Is Missing! (USA).sfc" - md5s = [USHASH] - - rom_file: RomFile = RomFile(RomFile.copy_to) - -class MiMWeb(WebWorld): - theme = "partyTime" - - setup_en = Tutorial( - "Multiworld Setup Guide", - "A guide to setting up the Mario is Missing randomizer" - "and connecting to an Archipelago server.", - "English", - "setup_en.md", - "setup/en", - ["Pink Switch"] - ) - - tutorials = [setup_en] - -class MarioisMissingWorld(World): - """Mario is Missing is a 2D edutainment game. As Luigi, save cities of the world from Bowser's terror while searching his castle for Mario.""" - game: str = "Mario is Missing" - option_definitions = MarioisMissingOptions - data_version = 1 - required_client_version = (0, 3, 5) - - 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, None, None)} - item_name_groups = get_item_names_per_category() - - web = MiMWeb() - settings: typing.ClassVar[MiMSettings] - #topology_present = True - - options_dataclass = MarioisMissingOptions - options: MarioisMissingOptions - - locked_locations: List[str] - location_cache: List[Location] - - def __init__(self, world: MultiWorld, player: int): - self.rom_name_available_event = threading.Event() - super().__init__(world, player) - - self.locked_locations= [] - self.location_cache= [] - - @classmethod - def stage_assert_generate(cls, multiworld): - rom_file = get_base_rom_path() - if not os.path.exists(rom_file): - raise FileNotFoundError(rom_file) - - def write_spoiler_header(self, spoiler_handle: TextIO) -> None: - spoiler_handle.write(f"Floor 1: {self.city_list[0:5]}\n") - spoiler_handle.write(f"Floor 2: {self.city_list[5:10]}\n") - spoiler_handle.write(f"Floor 3: {self.city_list[10:15]}\n") - - def create_item(self, name: str) -> Item: - data = item_table[name] - - if data.useful: - classification = ItemClassification.useful - elif data.progression: - classification = ItemClassification.progression - elif data.trap: - classification = ItemClassification.trap - else: - classification = ItemClassification.filler - - item = Item(name, classification, data.code, self.player) - - return item - - def create_regions(self): - create_regions(self.multiworld, self.player, get_locations(self.multiworld, self.player, self), - self.location_cache, self) - - def get_filler_item_name(self) -> str: - if self.options.computer_sanity.value == 1: - return self.random.choice(filler_items) - else: - return "Photograph" - - def set_rules(self): - self.multiworld.completion_condition[self.player] = lambda state: state.has('Mario', self.player) - self.multiworld.get_location("Bowser", self.player).place_locked_item(self.create_item("Mario")) - - self.multiworld.get_location("Colosseum - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Trevi Fountain - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Sistine Chapel - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Cathedral of Notre Dame - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Arc de Triomphe - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Eiffel Tower - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Tower of London - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Westminster Abbey - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Big Ben - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Empire State Building - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Statue of Liberty - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Rockefeller Center - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Golden Gate Bridge - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Coit Tower - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Transamerica Pyramid - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Erechtheion Temple - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Hadrian's Arch - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Parthenon - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Bondi Beach - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Taronga Zoo - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Sydney Opera - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Great Buddha of Kamakura - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Sensoji Temple - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Kokugikan Arena - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Nairobi National Park - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Maasai Village - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("National Museum of Kenya - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Christ the Redeemer Statue - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Copacabana Beach - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Sugar Loaf Mountain - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Great Pyramid - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Mosque of Mohammed - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Sphinx - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Kremlin - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("St. Basil's Cathedral - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Bolshoi Ballet - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Temple of Heaven - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Great Wall of China - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Forbidden City - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Teatro Colon - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Gaucho Museum - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Obelisk Monument - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Angel of Independence - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("National Palace - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - self.multiworld.get_location("Fine Arts Palace - Return Artifact", self.player).place_locked_item(self.create_item("Artifact Secured")) - - def place_locked_item(self, excluded_items: Set[str], location: str, item: str) -> None: - excluded_items.add(item) - - item = self.create_item(item) - - self.multiworld.get_location(location, self.player).place_locked_item(item) - - def generate_early(self): - setup_gamevars(self) - - - def get_excluded_items(self) -> Set[str]: - excluded_items: Set[str] = set() - for item in self.multiworld.start_inventory[self.player]: - if item in artifacts: - excluded_items.add(item) - - return excluded_items - - def create_item_with_correct_settings(self, player: int, name: str) -> Item: - data = item_table[name] - if data.useful: - classification = ItemClassification.useful - elif data.progression: - classification = ItemClassification.progression - elif data.trap: - classification = ItemClassification.trap - else: - classification = ItemClassification.filler - item = Item(name, classification, data.code, player) - - if not item.advancement: - return item - - return item - - def generate_filler(self, multiworld: MultiWorld, player: int, - pool: List[Item]): - - for _ in range(len(multiworld.get_unfilled_locations(player)) - len(pool) - 46): - item = self.create_item_with_correct_settings(player, self.get_filler_item_name()) - pool.append(item) - - def get_item_pool(self, player: int, 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(player, name) - pool.append(item) - - return pool - - def create_items(self): - excluded_items = self.get_excluded_items() - - pool = self.get_item_pool(self.player, excluded_items) - - self.generate_filler(self.multiworld, self.player, pool) - - self.multiworld.itempool += pool - - def generate_output(self, output_directory: str): - - 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, self.multiworld) - - 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 = MIMDeltaPatch(os.path.splitext(rompath)[0]+MIMDeltaPatch.patch_file_ending, player=player, - player_name=world.player_name[player], patched_path=rompath) - patch.write() - finally: - self.rom_name_available_event.set() # make sure threading continues and errors are collected - if os.path.exists(rompath): - os.unlink(rompath) - - def modify_multidata(self, multidata: dict): - import base64 - # wait for self.rom_name to be available. - self.rom_name_available_event.wait() - rom_name = getattr(self, "rom_name", None) - # we skip in case of error, so that the original error in the output thread is the one that gets raised - 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]] From 4310e100ce29f3826935c59a861884611f591133 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Tue, 23 Apr 2024 01:03:44 -0500 Subject: [PATCH 09/30] Add files via upload --- worlds/sai2/Client.py | 225 +++++++++ worlds/sai2/Items.py | 99 ++++ worlds/sai2/Locations.py | 118 +++++ worlds/sai2/Options.py | 93 ++++ worlds/sai2/Regions.py | 143 ++++++ worlds/sai2/Rom.py | 874 ++++++++++++++++++++++++++++++++++ worlds/sai2/Rules.py | 99 ++++ worlds/sai2/__init__.py | 293 ++++++++++++ worlds/sai2/extended_logic.py | 99 ++++ worlds/sai2/local_data.py | 546 +++++++++++++++++++++ worlds/sai2/setup_game.py | 88 ++++ 11 files changed, 2677 insertions(+) create mode 100644 worlds/sai2/Client.py create mode 100644 worlds/sai2/Items.py create mode 100644 worlds/sai2/Locations.py create mode 100644 worlds/sai2/Options.py create mode 100644 worlds/sai2/Regions.py create mode 100644 worlds/sai2/Rom.py create mode 100644 worlds/sai2/Rules.py create mode 100644 worlds/sai2/__init__.py create mode 100644 worlds/sai2/extended_logic.py create mode 100644 worlds/sai2/local_data.py create mode 100644 worlds/sai2/setup_game.py diff --git a/worlds/sai2/Client.py b/worlds/sai2/Client.py new file mode 100644 index 000000000000..fdd3a91df370 --- /dev/null +++ b/worlds/sai2/Client.py @@ -0,0 +1,225 @@ +import logging +import struct +import typing +import time +from struct import pack +from .local_data import location_list, scout_location_map, plain_encoding_table, shop_scouts, special_chests, hud_encoding_table, sprite_visuals + +from NetUtils import ClientStatus, color +from worlds.AutoSNIClient import SNIClient + +if typing.TYPE_CHECKING: + from SNIClient import SNIContext +else: + SNIContext = typing.Any + +snes_logger = logging.getLogger("SNES") + +ROM_START = 0x000000 +WRAM_START = 0xF50000 +WRAM_SIZE = 0x20000 +SRAM_START = 0xE00000 + +SAI2_ROMHASH_START = 0x00FFC0 +ROMHASH_SIZE = 0x15 + +ITEMQUEUE_HIGH = WRAM_START + 0x4D6 +ITEM_RECEIVED = WRAM_START + 0x0485 +DEMO_FLAG = WRAM_START + 0x03F5 +CHEST_SCOUT_MODE = WRAM_START + 0x04F9 +SPECIAL_CHEST_SCOUT = SRAM_START + 0x7DE7 +LOCATIONS_SCOUTED_FLAG = WRAM_START + 0x04C4 +IN_GAME = WRAM_START + 0x045A +GOALFLAG = WRAM_START + 0x0034 + +SHOP_SCOUTS = [0xA7D7, 0xA82D, 0xA883] + +class SAI2SNIClient(SNIClient): + game = "Super Adventure Island II" + + async def validate_rom(self, ctx): + from SNIClient import snes_buffered_write, snes_flush_writes, snes_read + + rom_name = await snes_read(ctx, SAI2_ROMHASH_START, ROMHASH_SIZE) + if rom_name is None or rom_name[:6] != b"SAI2AP": + return False + + ctx.game = self.game + ctx.items_handling = 0b001 + ctx.rom = rom_name + return True + + async def game_watcher(self, ctx): + from SNIClient import snes_buffered_write, snes_flush_writes, snes_read + item_received = await snes_read(ctx, ITEM_RECEIVED, 0x1) + goal_flag = await snes_read(ctx, GOALFLAG, 0x1) + scout_flag = await snes_read(ctx, CHEST_SCOUT_MODE, 2) + scout_id = struct.unpack("H", scout_flag)[0] + special_scout_flag = await snes_read(ctx, SPECIAL_CHEST_SCOUT, 2) + special_scout_id = struct.unpack("H", special_scout_flag)[0] + in_game = await snes_read(ctx, IN_GAME, 0x1) + locations_scouted_flag = await snes_read(ctx, LOCATIONS_SCOUTED_FLAG, 0x1) + + if in_game is None: + return + + elif in_game[0] != 0x01: + return + + elif item_received[0] > 0x00: + return + + from .Rom import input_item_ids + rom = await snes_read(ctx, SAI2_ROMHASH_START, ROMHASH_SIZE) + if rom != ctx.rom: + ctx.rom = None + return + + if goal_flag[0] != 0x00: + await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) + ctx.finished_game = True + + if locations_scouted_flag[0] == 0x00: + for location in location_list: + await ctx.send_msgs([{"cmd": 'LocationScouts', "locations": location_list, "create_as_hint": 0}]) + snes_buffered_write(ctx, WRAM_START + 0x04C4, bytes([0x01])) + + if scout_id != 0x0000: + scout_id = hex(scout_id) + scout_id = scout_id[2:] + scout_id = int(scout_id, 16) + if scout_id in scout_location_map: + location = ctx.locations_info[scout_location_map[scout_id]] #convert the stored internal ID to the corresponding AP location id + item = ctx.item_names[location.item] + if item in sprite_visuals: + local_sprite = bytearray(0) + local_sprite.extend(sprite_visuals[item]) + snes_buffered_write(ctx, WRAM_START + 0x04FC, local_sprite)#If the item is a nonlocal SAI2 item, use its in-game sprite but act like an ap item + snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x01])) + else: + snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x00])) + item = item.upper() + sai2_item = bytearray(0) + for char in item: + if char in hud_encoding_table: + sai2_item.extend (hud_encoding_table[char]) + else: + sai2_item.extend ([0x8F, 0x2C]) + if len(item) <= 16: + for _ in range(16 - len(item)): + sai2_item.extend([0x90, 0x28]) + snes_buffered_write(ctx, SRAM_START + 0x7E4D, sai2_item)#write item name as ingame text + snes_buffered_write(ctx, CHEST_SCOUT_MODE, bytes([0x00])) + snes_buffered_write(ctx, CHEST_SCOUT_MODE + 1, bytes([0x00])) + + if special_scout_id != 0x000: + special_scout_id = hex(special_scout_id) + special_scout_id = special_scout_id[2:] + special_scout_id = int(special_scout_id, 16) + print(special_scout_id) + if special_scout_id in shop_scouts: + location = ctx.locations_info[shop_scouts[special_scout_id]] #I can probably make a function out of this and the normal one + item = ctx.item_names[location.item] + item = item[:21] + player = ctx.player_names[location.player] + player = player[:21] + sai2_item = bytearray(0) + sai2_player = bytearray(0) + for char in item: #I can probably make a function out of this + if char in plain_encoding_table: + sai2_item.extend (plain_encoding_table[char]) + else: + sai2_item.extend ([0x8F, 0x2C]) + sai2_item.extend([0xFF, 0x03]) + for char in player: #I can probably make a function out of this + if char in plain_encoding_table: + sai2_player.extend (plain_encoding_table[char]) + else: + sai2_player.extend ([0x8F, 0x2C]) + + sai2_player.extend([0xFF, 0x03]) + snes_buffered_write(ctx, SRAM_START + 0x7DF0, sai2_item)#write item name as ingame text + snes_buffered_write(ctx, SRAM_START + 0x7E44, sai2_player)#write item name as ingame text + elif special_scout_id in special_chests: + location = ctx.locations_info[special_chests[special_scout_id]] #I can probably make a function out of this and the normal one + print(location) + item = ctx.item_names[location.item] + if item in sprite_visuals: + print(item) + local_sprite = bytearray(0) + local_sprite.extend(sprite_visuals[item]) + print(local_sprite) + snes_buffered_write(ctx, WRAM_START + 0x04FC, local_sprite)#If the item is a nonlocal SAI2 item, use its in-game sprite but act like an ap item + snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x01])) + else: + snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x00])) + item = item.upper() + sai2_item = bytearray(0) + for char in item: + if char in hud_encoding_table: + sai2_item.extend (hud_encoding_table[char]) + else: + sai2_item.extend ([0x8F, 0x2C]) + if len(item) <= 16: + for _ in range(16 - len(item)): + sai2_item.extend([0x90, 0x28]) + snes_buffered_write(ctx, SRAM_START + 0x7E4D, sai2_item)#write item name as ingame text + snes_buffered_write(ctx, SPECIAL_CHEST_SCOUT, bytes([0x00])) + snes_buffered_write(ctx, SPECIAL_CHEST_SCOUT + 1, bytes([0x00])) + + new_checks = [] + from .Rom import location_flag_table + + location_ram_data = await snes_read(ctx, WRAM_START + 0x460, 0xF0) + for loc_id, loc_data in location_flag_table.items(): + if loc_id not in ctx.locations_checked: + data = location_ram_data[loc_data[0] - 0x460] + 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] + snes_logger.info( + f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})') + await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) + + 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 input_item_ids: + item_count = await snes_read(ctx, WRAM_START + input_item_ids[item.item][0], 0x1) + increment = input_item_ids[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 + input_item_ids[item.item][0], bytes([new_item_count])) + await snes_flush_writes(ctx) + +def get_shop_text(special_id, ctx, SRAM_START): + location = ctx.locations_info[shop_scouts[special_id]] + item = ctx.item_names[location.item] + player = ctx.player_names[location.player] + sai2_item = bytearray(0) + for char in item: + if char in hud_encoding_table: + sai2_item.extend (hud_encoding_table[char]) + else: + sai2_item.extend ([0x8F, 0x2C]) + if len(item) <= 16: + for _ in range(16 - len(item)): + sai2_item.extend([0x90, 0x28]) + snes_buffered_write(ctx, SRAM_START + 0x7E4D, sai2_item)#write item name as ingame text \ No newline at end of file diff --git a/worlds/sai2/Items.py b/worlds/sai2/Items.py new file mode 100644 index 000000000000..c65b8358822f --- /dev/null +++ b/worlds/sai2/Items.py @@ -0,0 +1,99 @@ +from typing import Dict, Set, Tuple, NamedTuple, Optional + +class ItemData(NamedTuple): + category: str + code: int + classification: str + amount: Optional[int] = 1 + +item_table: Dict[str, ItemData] = { + 'Silver Sword': ItemData('Swords', 0x5A1000, "progression"), + 'Fire Sword': ItemData('Swords', 0x5A1001, "progression"), + 'Ice Sword': ItemData('Swords', 0x5A1002, "progression"), + 'Thunder Sword': ItemData('Swords', 0x5A1003, "progression"), + 'Crystal Sword': ItemData('Swords', 0x5A1004, "progression"), + 'Power Sword': ItemData('Swords', 0x5A1005, "progression"), + 'Light Sword': ItemData('Swords', 0x5A1006, "progression", 0), + 'Dagger': ItemData('Projectiles', 0x5A1007, "progression"), + 'Fireballs': ItemData('Projectiles', 0x5A1008, "progression"), + 'Boomerang': ItemData('Projectiles', 0x5A1009, "progression", 0), + 'Ax': ItemData('Projectiles', 0x5A100A, "progression"), + 'Shovel': ItemData('Items', 0x5A100B, "progression"), + + 'Fire Armor': ItemData('Armor', 0x5A100C, "progression"), + 'Ice Armor': ItemData('Armor', 0x5A100D, "progression"), + 'Aqua Armor': ItemData('Armor', 0x5A100E, "progression"), + 'Light Armor': ItemData('Armor', 0x5A100F, "progression", 0), + + 'Fire Shield': ItemData('Shields', 0x5A1010, "useful"), + 'Ice Shield': ItemData('Shields', 0x5A1011, "useful"), + 'Aqua Shield': ItemData('Shields', 0x5A1012, "useful"), + 'Light Shield': ItemData('Shields', 0x5A1013, "useful", 0), + + 'Wand': ItemData('Equipment', 0x5A1014, "progression"), + 'Ice Bell': ItemData('Equipment', 0x5A1015, "progression"), + 'Sun Ring': ItemData('Equipment', 0x5A1016, "progression"), + 'Power Fan': ItemData('Equipment', 0x5A1017, "progression"), + 'Elven Flute': ItemData('Equipment', 0x5A1018, "progression"), + 'Sky Bell': ItemData('Equipment', 0x5A1019, "progression"), + 'Light Stone': ItemData('Equipment', 0x5A101A, "progression"), + 'Sun Stone': ItemData('Equipment', 0x5A101B, "progression"), + 'Star Stone': ItemData('Equipment', 0x5A101C, "progression"), + 'Aqua Stone': ItemData('Equipment', 0x5A101D, "progression"), + 'Moon Stone': ItemData('Equipment', 0x5A101E, "progression"), + + 'Light Spell': ItemData('Spells', 0x5A101F, "progression"), + 'Star Spell': ItemData('Spells', 0x5A1020, "progression"), + 'Sun Spell': ItemData('Spells', 0x5A1021, "progression"), + 'Aqua Spell': ItemData('Spells', 0x5A1022, "progression"), + 'Moon Spell': ItemData('Spells', 0x5A1023, "progression"), + + 'Shove': ItemData('Skills', 0x5A1024, "progression"), + 'Up Jab': ItemData('Skills', 0x5A1025, "progression"), + 'Down Jab': ItemData('Skills', 0x5A1026, "progression"), + + 'Life Bottle': ItemData('Upgrades', 0x5A1027, "progression", 9), + 'Magic Bottle': ItemData('Upgrades', 0x5A1028, "useful", 13), + + '500 Coins': ItemData('Coins', 0x5A1029, "progression", 2), + '1000 Coins': ItemData('Coins', 0x5A102A, "progression", 5), + '2000 Coins': ItemData('Coins', 0x5A102B, "progression", 3), + '5000 Coins': ItemData('Coins', 0x5A102C, "progression", 1), + + 'Light Switch': ItemData('Events', None, "progression", 0), + 'Sun Switch': ItemData('Events', None, "progression", 0), + 'Star Switch': ItemData('Events', None, "progression", 0), + 'Aqua Switch': ItemData('Events', None, "progression", 0), + 'Moon Switch': ItemData('Events', None, "progression", 0), + 'Puka-Puka Drained': ItemData('Events', None, "progression", 0), + 'Tina': ItemData('Events', None, "progression", 0), + 'Boa-Hiya Shortcut Open': ItemData('Events', None, "progression", 0), + 'Sala-Hiya Shortcut Open': ItemData('Events', None, "progression", 0), + 'Sala-Puka Shortcut Open': ItemData('Events', None, "progression", 0), + 'Fuwa-Poka Shortcut Open': ItemData('Events', None, "progression", 0), + 'Fuwa-Puka Shortcut Open': ItemData('Events', None, "progression", 0), + + 'Light Gate Lowered': ItemData('Events', None, "progression", 0), + 'Sun Gate Lowered': ItemData('Events', None, "progression", 0), + 'Star Gate Lowered': ItemData('Events', None, "progression", 0), + 'Aqua Gate Lowered': ItemData('Events', None, "progression", 0), + 'Moon Gate Lowered': ItemData('Events', None, "progression", 0), +} + +filler_items: Tuple[str, ...] = ( + '500 Coins', + '1000 Coins', + '2000 Coins', + '5000 Coins', + 'Life Bottle', + 'Magic Bottle' +) + +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/sai2/Locations.py b/worlds/sai2/Locations.py new file mode 100644 index 000000000000..170a519fd495 --- /dev/null +++ b/worlds/sai2/Locations.py @@ -0,0 +1,118 @@ +from typing import List, Tuple, Optional, Callable, NamedTuple +from BaseClasses import MultiWorld + + +class LocationData(NamedTuple): + region: str + name: str + code: Optional[int] + rule: Callable = lambda state: True + + +def get_locations(world) -> Tuple[LocationData, ...]: + + location_table: Tuple[LocationData, ...] = [ + + LocationData('Poka-Poka Island', 'Poka-Poka Lake Chest', 0x5A1000), + LocationData('Poka-Poka East', 'Poka-Poka Tree Chest', 0x5A1001), + LocationData('Poka-Poka Island', 'Poka-Poka Digging Chest', 0x5A1002), + LocationData('Poka-Poka East', 'Poka-Poka Pushable Rock Chest', 0x5A1003), + LocationData('Poka-Poka East', 'Poka-Poka Sun Blocks Chest', 0x5A1004), + LocationData('Poka-Poka East', 'Poka-Poka East Cave Chest', 0x5A1005), + LocationData('Poka-Poka Island', 'Poka-Poka West Cave Chest', 0x5A1006), + LocationData('Poka-Poka East', 'Poka-Poka Moon Alcove Chest', 0x5A1007), + LocationData('Poka-Poka East', 'Poka-Poka Down Blocks Chest', 0x5A1008), + LocationData('Poka-Poka East', 'Poka-Poka Shrine Chest', 0x5A1009), + LocationData('Poka-Poka East', 'Evil Tree Chest', 0x5A100A), + + LocationData('Boa-Boa Island', 'Boa-Boa Clouds Chest', 0x5A100B), + LocationData('Boa-Boa Island', 'Boa-Boa Sun Alcove Chest', 0x5A100C), + LocationData('Boa-Boa Island', 'Boa-Boa Sun Block Chest', 0x5A100D), + LocationData('Boa-Boa Island', 'Boa-Boa Lava Lake West Chest', 0x5A100E), + LocationData('Boa-Boa Island', 'Boa-Boa Lava Lake East Chest', 0x5A100F), + LocationData('Boa-Boa Island', 'Boa-Boa Western Shaft Chest', 0x5A1010), + LocationData('Boa-Boa Island', 'Boa-Boa Eastern Shaft Chest', 0x5A1011), + LocationData('Boa-Boa Island', 'Boa-Boa Shrine Chest', 0x5A1012), + LocationData('Boa-Boa Island', 'Tortoise Chest', 0x5A1013), + + LocationData('Hiya-Hiya Entrance', 'Hiya-Hiya Clouds Chest', 0x5A1014), + LocationData('Hiya-Hiya Underside', 'Hiya-Hiya Underground Chest', 0x5A1015), + LocationData('Hiya-Hiya Entrance', 'Hiya-Hiya Sun Blocks Chest', 0x5A1016), + LocationData('Hiya-Hiya Main', 'Hiya-Hiya Hidden Alcove Chest', 0x5A1017), + LocationData('Hiya-Hiya Main', 'Hiya-Hiya Up Block Alcove Chest', 0x5A1018), + LocationData('Hiya-Hiya Main', 'Hiya-Hiya Trapped Chest', 0x5A1019), + LocationData('Hiya-Hiya Main', 'Hiya-Hiya Ice Cubes Chest', 0x5A101A), + LocationData('Hiya-Hiya Main', 'Hiya-Hiya Long Fall Chest', 0x5A101B), + LocationData('Hiya-Hiya Back', 'Hiya-Hiya Vines Chest', 0x5A101C), + LocationData('Hiya-Hiya Back', 'Hiya-Hiya Shrine Chest', 0x5A101D), + LocationData('Hiya-Hiya Main', 'Mammoth Chest', 0x5A101E), + + LocationData('Puka-Puka Island', 'Puka-Puka Light Blocks Chest', 0x5A101F), + LocationData('Puka-Puka Island', 'Puka-Puka Down Jab Chest', 0x5A1020), + LocationData('Puka-Puka Island', 'Puka-Puka Star Blocks Chest', 0x5A1021), + LocationData('Puka-Puka Island', 'Puka-Puka Up Jab Chest', 0x5A1022), + LocationData('Puka-Puka Island', 'Puka-Puka Underwater Chest', 0x5A1023), + LocationData('Puka-Puka Island', 'Puka-Puka Aqua Blocks Chest', 0x5A1024), + LocationData('Puka-Puka Island', 'Puka-Puka Spike Maze Upper Chest', 0x5A1025), + LocationData('Puka-Puka Island', 'Puka-Puka Spike Maze Lower Chest', 0x5A1026), + LocationData('Puka-Puka Island', 'Puka-Puka Moving Platforms Chest', 0x5A1027), + LocationData('Puka-Puka Island', 'Puka-Puka Springs Chest', 0x5A1028), + LocationData('Puka-Puka Island', 'Puka-Puka Shrine Chest', 0x5A1029), + LocationData('Puka-Puka Island', 'Octopus Chest', 0x5A102A), + + LocationData('Sala-Sala Island', 'Sala-Sala Near Entrance Chest', 0x5A102B), + LocationData('Sala-Sala Island', 'Sala-Sala Up Jab Chest', 0x5A102C), + LocationData('Sala-Sala Island', 'Sala-Sala Star Alcove Chest', 0x5A102D), + LocationData('Sala-Sala Island', 'Sala-Sala Top of the Pyramid Chest', 0x5A102E), + LocationData('Sala-Sala Backside', 'Sala-Sala All Blocks Chest', 0x5A102F), + LocationData('Sala-Sala Backside', 'Sala-Sala Farthest Chest', 0x5A1030), + LocationData('Sala-Sala Island', 'Sala-Sala Pyramid Center Chest', 0x5A1031), + LocationData('Sala-Sala Backside', 'Sala-Sala Elevator Chest', 0x5A1032), + LocationData('Sala-Sala Backside', 'Sala-Sala Shrine Chest', 0x5A1033), + LocationData('Sala-Sala Backside', 'Mummy Chest', 0x5A1034), + + LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Block Maze Chest', 0x5A1035), + LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Moon Block Chest', 0x5A1036), + LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Light Block Chest', 0x5A1037), + LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Bridge Room Chest', 0x5A1038), + LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Balance Platforms Chest', 0x5A1039), + LocationData('Fuwa-Fuwa Island', 'Hawk Chest', 0x5A103A), + + LocationData('Western Sea', 'Muscle Lizard Chest', 0x5A103B), + LocationData('Northwestern Sea', 'Ice Cave Chest', 0x5A103C), + LocationData('Northwestern Sea', '100 Coin Shop', 0x5A103D), + LocationData('Northeastern Sea', 'Desert Island Chest', 0x5A103E), + LocationData('Northeastern Sea', 'Overworld Tomb Chest', 0x5A103F), + LocationData('Eastern Sea', 'Saber Tooth Chest', 0x5A1040), + LocationData('Eastern Sea', 'Northern Cave Chest', 0x5A1041), + LocationData('Eastern Sea', '300 Coin Shop', 0x5A1042), + LocationData('Eastern Sea', '500 Coin Shop', 0x5A1043), + #LocationData('Southern Sea', "Waku-Waku King's Gift", 0x5A1044), + LocationData("Curly's Casino", "Casino 500 Coin Purchase", 0x5A1045), + LocationData("Curly's Casino", "Casino 1000 Coin Purchase", 0x5A1046), + LocationData("Curly's Casino", "Casino 2000 Coin Purchase", 0x5A1047), + LocationData("Curly's Casino", "Casino 3000 Coin Purchase", 0x5A1048), + LocationData("Curly's Casino", "Casino 5000 Coin Purchase", 0x5A1049), + + LocationData("Poka-Poka Island", 'Poka-Poka First Cave', None), + LocationData("Boa-Boa Island", 'Boa-Boa Hidden Wall', None), + LocationData("Hiya-Hiya Main", 'Hiya-Hiya Top Level', None), + LocationData("Puka-Puka Switch Room", 'Puka-Puka Switch Room', None), + LocationData("Sala-Sala Island", 'Sala-Sala Switch Room', None), + LocationData("Puka-Puka Island", 'Puka-Puka Water Control', None), + LocationData("Fuwa-Fuwa Island", 'Phantom Defeat', None), + + LocationData("Boa-Boa Island", 'Boa-Hiya Shortcut Room', None), + LocationData("Sala-Sala Backside", 'Sala-Hiya Shortcut Room', None), + LocationData("Sala-Sala Island", 'Sala-Puka Shortcut Room', None), + LocationData("Fuwa-Fuwa Island", 'Fuwa-Puka Shortcut Room', None), + LocationData("Fuwa-Fuwa Island", 'Fuwa-Poka Shortcut Room', None), + + LocationData("Southern Sea", 'Light Gate', None), + LocationData("Western Sea", 'Sun Gate', None), + LocationData("Northwestern Sea", 'Star Gate', None), + LocationData("Southern Sea", 'Aqua Gate', None), + LocationData("Southeastern Sea", 'Moon Gate', None) + ] + + return location_table \ No newline at end of file diff --git a/worlds/sai2/Options.py b/worlds/sai2/Options.py new file mode 100644 index 000000000000..3f59f0278bc0 --- /dev/null +++ b/worlds/sai2/Options.py @@ -0,0 +1,93 @@ +from dataclasses import dataclass +from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, PerGameCommonOptions + +class WorldState(Choice): + """Closed: All 5 gates start closed. + Random Open: Opens 5 random gates by default. + Open: All 5 gates start open. + If not open, you will start with 1 random progression item.""" + display_name = "World State" + option_closed = 0 + option_open = 1 + option_random_open = 2 + default = 0 + +class ExtraStartingHealth(DefaultOnToggle): + """If enabled, you will start with two hearts rather than one.""" + display_name = "Extra Starting Health" + +class DisableRandomEncounters(DefaultOnToggle): + """Disables random encounters on the overworld map.""" + display_name = "No Random Encounters" + +class FastShovel(DefaultOnToggle): + """Allows easily swapping to the Shovel and back by pressing Select on the menu.""" + display_name = "Fast Shovel" + +class MagicQuickswap(DefaultOnToggle): + """Allows swapping between magic spells by pressing L and R.""" + display_name = "Magic Quickswap" + +class DefaultSwitchStates(Choice): + """Define the default state the Switches will be found in.""" + display_name = "Switch States" + option_normal = 0 + option_inverted = 1 + option_random_set = 2 + +class ShortcutStates(Choice): + """All Closed: All shortcuts start closed. + All Open: All Shortcuts start open. + Random Open: Ranom shortcuts start open. + Exclude Fuwa: Fuwa-Fuwa shortcuts will start closed regardless. + + Shortcuts that start open can be entered from their opposite side.""" + display_name = "Shortcuts" + option_all_closed = 0 + option_all_open = 1 + option_random_open = 2 + option_random_exclude_fuwa = 3 + option_all_exclude_fuwa = 4 + default = 0 + +class ForceSpells(Toggle): + """If enabled, the 5 island bosses will each lock 1 of the 5 Spells.""" + display_name = "Force Spells on Bosses" + +class CasinoChecks(Toggle): + """If enabled, will place the 5 items normally found in the Casino into the pool, + and add checks on their purchases. The prices have been severly reduced to reduce the amount of grinding, + but some may still be required.""" + display_name = "Casino Checks" + +class OpenFuwa(Toggle): + """If enabled, you will be able to access Fuwa-Fuwa Island without needing the 5 spells.""" + display_name = "Early Fuwa-Fuwa" + +class ShuffleSkills(Choice): + """Determines if the 3 techniques are in their normal location, shuffled amongst the 3 shops, or anywhere.""" + display_name = "Skills" + option_normal = 0 + option_shuffled = 1 + option_in_pool = 2 + +class SpellLockEnding(Toggle): + """If enabled, you will need to have the 5 Spells in order to use the Sky Bell and fight Phantom. Recommended to be used with 'Early Fuwa-Fuwa'.""" + display_name = "Locked Phantom" + + + +@dataclass +class SAI2Options(PerGameCommonOptions): + world_state: WorldState + switch_states: DefaultSwitchStates + shortcut_states: ShortcutStates + phantom_spells: SpellLockEnding + early_fuwa: OpenFuwa + shuffle_skills: ShuffleSkills + boss_spells: ForceSpells + casino_checks: CasinoChecks + extra_health: ExtraStartingHealth + disable_encounters: DisableRandomEncounters + fast_shovel: FastShovel + magic_swap: MagicQuickswap diff --git a/worlds/sai2/Regions.py b/worlds/sai2/Regions.py new file mode 100644 index 000000000000..c67e558456e3 --- /dev/null +++ b/worlds/sai2/Regions.py @@ -0,0 +1,143 @@ +from typing import List, Dict, Tuple +from BaseClasses import MultiWorld, Region, Entrance, Location +from .Locations import LocationData +from .extended_logic import logic_helpers + +class SAI2Location(Location): + game: str = "Super Adventure Island II" + +def __init__(self, player: int, name: str = " ", address: int = None, parent=None): + super().__init__(player, name, address, parent) + + +def init_areas(world, locations: Tuple[LocationData, ...]): + multiworld = world.multiworld + player = world.player + location_cache = world.location_cache + logic = logic_helpers(world) + + locations_per_region = get_locations_per_region(locations) + + regions = [ + create_region(multiworld, player, locations_per_region, location_cache, 'Menu'), + create_region(multiworld, player, locations_per_region, location_cache, 'Southern Sea'), + create_region(multiworld, player, locations_per_region, location_cache, 'Western Sea'), + create_region(multiworld, player, locations_per_region, location_cache, 'Northwestern Sea'), + create_region(multiworld, player, locations_per_region, location_cache, 'Northeastern Sea'), + create_region(multiworld, player, locations_per_region, location_cache, 'Southeastern Sea'), + create_region(multiworld, player, locations_per_region, location_cache, 'Eastern Sea'), + create_region(multiworld, player, locations_per_region, location_cache, 'Poka-Poka Island'), + create_region(multiworld, player, locations_per_region, location_cache, 'Poka-Poka East'), + create_region(multiworld, player, locations_per_region, location_cache, 'Boa-Boa Island'), + create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Entrance'), + create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Underside'), + create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Main'), + create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Back'), + create_region(multiworld, player, locations_per_region, location_cache, 'Puka-Puka Island'), + create_region(multiworld, player, locations_per_region, location_cache, 'Puka-Puka Switch Room'), + create_region(multiworld, player, locations_per_region, location_cache, "Curly's Casino"), + create_region(multiworld, player, locations_per_region, location_cache, "Sala-Sala Island"), + create_region(multiworld, player, locations_per_region, location_cache, "Sala-Sala Backside"), + create_region(multiworld, player, locations_per_region, location_cache, "Fuwa-Fuwa Island") + + ] + multiworld.regions += regions + + multiworld.get_region('Menu', player).add_exits(["Southern Sea"]) + + multiworld.get_region('Southern Sea', player).add_exits(['Poka-Poka Island', 'Fuwa-Fuwa Island', 'Western Sea', 'Southeastern Sea'], + {'Fuwa-Fuwa Island': lambda state: logic.fuwa_access(state), #Fuwa island is in the south sea + 'Western Sea': lambda state: state.has("Light Gate Lowered", player), #Light gate + 'Southeastern Sea': lambda state: state.has("Aqua Gate Lowered", player)}) #Aqua gate + multiworld.get_region('Poka-Poka Island', player).add_exits(["Poka-Poka East"],{"Poka-Poka East": lambda state: state.has("Silver Sword", player)}) #Breakable rocks leading from the start to the back + multiworld.get_region('Poka-Poka East', player).add_exits(["Fuwa-Fuwa Island", "Poka-Poka Island"],{"Fuwa-Fuwa Island": lambda state: state.has_all({"Shovel", "Fuwa-Poka Shortcut Open"}, player)}) #Shortcut to Fuwa-Fuwa, poka can be reached always + multiworld.get_region('Western Sea', player).add_exits(['Boa-Boa Island', 'Northwestern Sea'], + {'Boa-Boa Island': lambda state: state.has("Sun Ring", player), #Sun ring opens island + 'Northwestern Sea': lambda state: state.has("Sun Gate Lowered", player)}) #Sun Gate + + multiworld.get_region('Boa-Boa Island', player).add_exits(['Western Sea', 'Hiya-Hiya Underside', 'Northwestern Sea', 'Hiya-Hiya Entrance'], + {'Western Sea': lambda state: state.has("Wand", player), #May not need wand. + 'Hiya-Hiya Underside': lambda state: state.has_all({"Shovel", "Fire Sword", "Boa-Hiya Shortcut Open"}, player),#Shortcut leads to this but blocked by an ice wall + 'Hiya-Hiya Entrance': lambda state: state.has_all({"Wand", "Shovel", "Shove", "Boa-Hiya Shortcut Open"}, player),#Same as above, but needs Wand to warp to the start + 'Northwestern Sea': lambda state: state.has_all({"Wand", "Shovel", "Boa-Hiya Shortcut Open"}, player)})#Same as above but doesn't need shove + multiworld.get_region('Northwestern Sea', player).add_exits(['Hiya-Hiya Entrance', 'Western Sea', 'Northeastern Sea'], + {'Hiya-Hiya Entrance': lambda state: state.has_all({"Ice Bell", "Shove"}, player), #Intended access + 'Western Sea': lambda state: state.has("Sun Gate Lowered", player),#Sun Gate + 'Northeastern Sea': lambda state: state.has("Star Gate Lowered", player)})#Star Gate + multiworld.get_region('Hiya-Hiya Entrance', player).add_exits(['Hiya-Hiya Underside', 'Hiya-Hiya Main', 'Northwestern Sea'], + {'Northwestern Sea': lambda state: state.has("Wand", player), + 'Hiya-Hiya Underside': lambda state: state.has("Shovel", player), + 'Hiya-Hiya Main': lambda state: state.has("Fire Sword", player)}) + multiworld.get_region('Hiya-Hiya Underside', player).add_exits(['Boa-Boa Island'], + {'Boa-Boa Island': lambda state: state.has_all({"Boa-Hiya Shortcut Open", "Fire Sword"}, player)}) + multiworld.get_region('Hiya-Hiya Main', player).add_exits(['Hiya-Hiya Entrance', "Sala-Sala Backside", "Sala-Sala Island", "Hiya-Hiya Back", "Northwestern Sea"],#Northwestern sea? + {'Hiya-Hiya Entrance': lambda state: (state.has("Fire Sword", player)) or (state.has_all({"Wand", "Shove"}, player)), + 'Hiya-Hiya Back': lambda state: state.has("Shove", player), + "Sala-Sala Backside": lambda state: (state.has_all({"Shove", "Sala-Hiya Shortcut Open", "Down Jab"}, player) and logic.star_switch_on(state) and state.has_group("Swords", player, 1)), + "Sala-Sala Island": lambda state: (state.has_all({"Shove", "Sala-Hiya Shortcut Open", "Wand", "Down Jab"}, player) and logic.star_switch_on(state) and state.has_group("Swords", player, 1) and logic.has_early_health(state)), + "Northwestern Sea": lambda state: state.has("Wand", player)}) + multiworld.get_region('Hiya-Hiya Back', player).add_exits(['Hiya-Hiya Main', "Hiya-Hiya Entrance"], + {'Hiya-Hiya Main': lambda state: state.has("Shove", player), + 'Hiya-Hiya Entrance': lambda state: state.has("Wand", player)}) + multiworld.get_region('Southeastern Sea', player).add_exits(['Southern Sea', 'Eastern Sea', 'Northeastern Sea', "Curly's Casino"], + {'Southern Sea': lambda state: state.has("Aqua Gate Lowered", player), + 'Northeastern Sea': lambda state: state.has("Moon Gate Lowered", player), + 'Eastern Sea': lambda state: state.has("Moon Gate Lowered", player), + "Curly's Casino": lambda state: state.has("Power Fan", player)}) + multiworld.get_region("Curly's Casino", player).add_exits(['Southeastern Sea', "Puka-Puka Island"], + {'Puka-Puka Island': lambda state: state.has("Shovel", player)}) + multiworld.get_region("Puka-Puka Island", player).add_exits(["Curly's Casino", "Puka-Puka Switch Room", "Fuwa-Fuwa Island"], + {"Curly's Casino": lambda state: state.has("Shovel", player), + "Puka-Puka Switch Room": lambda state: state.has("Puka-Puka Drained", player), + "Fuwa-Fuwa Island": lambda state: state.has_all({"Fuwa-Puka Shortcut Open", "Puka-Puka Drained"}, player) and ((state.has_group("Swords", player, 1) and state.has("Down Jab", player)) or state.has("Wand", player))}) + multiworld.get_region("Puka-Puka Switch Room", player).add_exits(["Curly's Casino", "Sala-Sala Island", "Puka-Puka Island"], + {"Curly's Casino": lambda state: state.has("Wand", player), + "Sala-Sala Island": lambda state: state.has("Sala-Puka Shortcut Open", player) and logic.has_early_health(state), + "Puka-Puka Island": lambda state: state.has("Puka-Puka Drained", player)}) + multiworld.get_region("Eastern Sea", player).add_exits(['Southeastern Sea', "Sala-Sala Island"], + {'Southeastern Sea': lambda state: state.has("Moon Gate Lowered", player), + "Sala-Sala Island": lambda state: logic.has_early_health(state)}) + multiworld.get_region("Sala-Sala Island", player).add_exits(['Eastern Sea', "Sala-Sala Backside", "Puka-Puka Switch Room"], + {'Sala-Sala Backside': lambda state: logic.moon_switch_on(state) and state.has_all({"Shovel", "Shove"}, player), + 'Pula-Puka Switch Room': lambda state: logic.moon_switch_on(state) and state.has_all({"Shovel", "Shove"}, player)}) + multiworld.get_region("Sala-Sala Backside", player).add_exits(['Sala-Sala Island', "Hiya-Hiya Back"], + {'Hiya-Hiya Back': lambda state: state.has("Sala-Hiya Shortcut Open", player)}) + multiworld.get_region('Fuwa-Fuwa Island', player).add_exits(['Southern Sea', 'Poka-Poka East', "Puka-Puka Island", "Curly's Casino"], + {'Poka-Poka East': lambda state: state.has_all({"Shovel", "Fuwa-Poka Shortcut Open"}, player), #CHECK THIS!!!! + 'Puka-Puka Island': lambda state: state.has_all({"Down Jab", "Power Sword", "Fuwa-Puka Shortcut Open", "Puka-Puka Drained"}, player), + "Curly's Casino": lambda state: state.has_all({"Down Jab", "Power Sword", "Fuwa-Puka Shortcut Open", "Wand"}, player)}) + multiworld.get_region('Northeastern Sea', player).add_exits(['Northwestern Sea', 'Southeastern Sea'], #Irrelevant except with random open gates + {'Northwestern Sea': lambda state: state.has("Star Gate Lowered", player), + 'Southeastern Sea': lambda state: state.has("Moon Gate Lowered", player)}) + +def create_location(player: int, location_data: LocationData, region: Region, location_cache: List[Location]) -> Location: + location = SAI2Location(player, location_data.name, location_data.code, region) + location.access_rule = location_data.rule + + if id is None: + location.event = True + location.locked = True + + location_cache.append(location) + + return location + +def create_region(multiworld: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], location_cache: List[Location], name: str) -> Region: + region = Region(name, player, multiworld) + region.world = multiworld + + if name in locations_per_region: + for location_data in locations_per_region[name]: + location = create_location(player, location_data, region, location_cache) + region.locations.append(location) + + return region + + +def get_locations_per_region(locations: Tuple[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/sai2/Rom.py b/worlds/sai2/Rom.py new file mode 100644 index 000000000000..fb0a3e9c5073 --- /dev/null +++ b/worlds/sai2/Rom.py @@ -0,0 +1,874 @@ +import hashlib +import os +import typing +import Utils +from BaseClasses import ItemClassification +from worlds.Files import APProcedurePatch, APTokenMixin, APTokenTypes +from .local_data import local_locations, local_items, shop_items +USHASH = 'b4e732b3d742af1791605bcd7aa4a1c4' + +input_item_ids = { + 0x5A1000: [0x0485, 0x01], #Silver Sword + 0x5A1001: [0x0485, 0x02], #Fire Sword + 0x5A1002: [0x0485, 0x03], #Ice Sword + 0x5A1003: [0x0485, 0x04], #Thunder Sword + 0x5A1004: [0x0485, 0x05], #Crystal Sword + 0x5A1005: [0x0485, 0x06], #Power Sword + 0x5A1006: [0x0485, 0x07], #Light Sword + 0x5A1007: [0x0485, 0x08], #Dagger + 0x5A1008: [0x0485, 0x09], #Fireballs + 0x5A1009: [0x0485, 0x0A], #Boomerang + 0x5A100A: [0x0485, 0x0B], #Ax + 0x5A100B: [0x0485, 0x0C], #Shovel + 0x5A100C: [0x0485, 0x0D], #Fire Armor + 0x5A100D: [0x0485, 0x0E], #Ice Armor + 0x5A100E: [0x0485, 0x0F], #Aqua Armor + 0x5A100F: [0x0485, 0x10], #Light Armor + 0x5A1010: [0x0485, 0x11], #Fire Shield + 0x5A1011: [0x0485, 0x12], #Ice Shield + 0x5A1012: [0x0485, 0x13], #Aqua Shield + 0x5A1013: [0x0485, 0x14], #Light Shield + 0x5A1014: [0x0485, 0x15], #Magic Wand + 0x5A1015: [0x0485, 0x16], #Ice Bell + 0x5A1016: [0x0485, 0x17], #Sun Ring + 0x5A1017: [0x0485, 0x18], #Power Fan + 0x5A1018: [0x0485, 0x19], #Elven Flute + 0x5A1019: [0x0485, 0x1A], #Sky Bell + 0x5A101A: [0x0485, 0x1B], #Light Stone + 0x5A101B: [0x0485, 0x1C], #Sun Stone + 0x5A101C: [0x0485, 0x1D], #Star Stone + 0x5A101D: [0x0485, 0x1E], #Aqua Stone + 0x5A101E: [0x0485, 0x1F], #Moon Stone + 0x5A101F: [0x0485, 0x20], #Light Spell + 0x5A1020: [0x0485, 0x22], #Sun Spell + 0x5A1021: [0x0485, 0x23], #Star Spell + 0x5A1022: [0x0485, 0x23], #Aqua Spell + 0x5A1023: [0x0485, 0x24], #Moon Spell + + 0x5A1024: [0x0485, 0x26], #Shove + 0x5A1025: [0x0485, 0x27], #Up Jab + 0x5A1026: [0x0485, 0x28], #Down Jab + + 0x5A1027: [0x0485, 0xE0], #Life Bottle + 0x5A1028: [0x0485, 0xE1], #Magic Bottle + + 0x5A1029: [0x0485, 0xE2], #500 Coins + 0x5A102A: [0x0485, 0xE3], #1000 Coins + 0x5A102B: [0x0485, 0xE4], #2000 Coins + 0x5A102C: [0x0485, 0xE5], #5000 Coins + +} + +location_flag_table = { + #Poka-Poka + 0x5A1000: [0x491, 0], #Poka-Poka Lake + 0x5A1001: [0x497, 0], #Poka-Poka Tree Chest + 0x5A1002: [0x492, 0], #Poka-Poka Digging Chest + 0x5A1003: [0x493, 0], #Poka-Poka Shove + 0x5A1004: [0x496, 0], #Sun Chest + 0x5A1005: [0x53E, 0], #Poka-Poka Elven Flute 1 + 0x5A1006: [0x490, 0], #First Chest + 0x5A1007: [0x494, 0], #Moon Chest + 0x5A1008: [0x495, 0], #Poka-Poka Down Stab + 0x5A1009: [0x480, 0], #Poka-Poka Elven Flute 2 + 0x5A100A: [0x487, 0], #Poka-Poka Boss + ################################################### + #Boa-Boa + 0x5A100B: [0x53D, 0], #First room clouds + 0x5A100C: [0x4EE, 0], #First room sun bridge + 0x5A100D: [0x4EF, 0], #Elven Flute 1 + 0x5A100E: [0x4F0, 0], #Dig Chest + 0x5A100F: [0x4F1, 0], #Lava Lake + 0x5A1010: [0x4F2, 0], #West Shaft + 0x5A1011: [0x4F3, 0], #East Shaft + 0x5A1012: [0x488, 0], #Elven Flute 2 + 0x5A1013: [0x48A, 0], #Boss + ################################################## + #Hiya-Hiya + 0x5A1014: [0x4A9, 0], #Cloud Chest + 0x5A1015: [0x4AA, 0], #Dig Chest + 0x5A1016: [0x4AB, 0], #Sun Chest + 0x5A1017: [0x4AC, 0], #West Tower Fall + 0x5A1018: [0x4AD, 0], #Up Block Chest + 0x5A1019: [0x4AE, 0], #Trap Chest + 0x5A101A: [0x4AF, 0], #Ice Cube Chest + 0x5A101B: [0x4B0, 0], #East Tower Fall + 0x5A101C: [0x53F, 0], #Elven Flute 1 + 0x5A101D: [0x48D, 0], #Elven Flute 2 + 0x5A101E: [0x48B, 0], #Boss + ################################################### + #Puka-Puka + 0x5A101F: [0x4C6, 0], #Light Block Chest + 0x5A1020: [0x4C7, 0], #Down Jab Chest + 0x5A1021: [0x4C8, 0], #Star Block Chest + 0x5A1022: [0x4C9, 0], #Up Jab Chest + 0x5A1023: [0x4CA, 0], #Middle at the Fork + 0x5A1024: [0x4CB, 0], #Aqua Blocks + 0x5A1025: [0x4CD, 0], #Elven Flute 2 + 0x5A1026: [0x4CE, 0], #Elven Flute 1 + 0x5A1027: [0x4F5, 0], #Platform Room + 0x5A1028: [0x4F6, 0], #Spring Room + 0x5A1029: [0x51E, 0], #Elven Flute 3 + 0x5A102A: [0x489, 0], #Boss + ################################################### + #Sala-Sala + 0x5A102B: [0x504, 0], #Lowest Level Left Chest + 0x5A102C: [0x505, 0], #Statue and up blocks + 0x5A102D: [0x506, 0], #Pyramid Star Chest + 0x5A102E: [0x507, 0], #Top of the Pyramid + 0x5A102F: [0x508, 0], #All Switches Chest + 0x5A1030: [0x509, 0], #Elven Flute 1 + 0x5A1031: [0x50A, 0], #Lower Right Pyramid Chest + 0x5A1032: [0x50B, 0], #Secret Elevator Chest + 0x5A1033: [0x482, 0], #Elven Flute 2 + 0x5A1034: [0x484, 0], #Boss + #################################################### + #Fuwa-Fuwa + 0x5A1035: [0x515, 0], #Block Maze + 0x5A1036: [0x516, 0], #First Plant Room + 0x5A1037: [0x517, 0], #Light Block Chest + 0x5A1038: [0x518, 0], #Dig Chest + 0x5A1039: [0x519, 0], #Final Chest + 0x5A103A: [0x483, 0], #Boss + #################################################### + #Overworld + 0x5A103B: [0x4D8, 0], #Muscle Lizard + 0x5A103C: [0x4DD, 0], #Ice Cave + 0x5A103D: [0x4E0, 0], #100 Coins + 0x5A103E: [0x4DC, 0], #Desert Island + 0x5A103F: [0x4DE, 0], #Tomb + 0x5A1040: [0x4E3, 0], #Saber Tooth + 0x5A1041: [0x4DF, 0], #North Cave + 0x5A1042: [0x4E8, 0], #300 Coins + 0x5A1043: [0x4EA, 0], #500 Coins + ################################################# + #Casino + 0x5A1045: [0x4E6, 0], #Casino 500 Coins + 0x5A1046: [0x4EB, 0], #Casino 1000 Coins + 0x5A1047: [0x4E1, 0], #Casino 2000 Coins + 0x5A1048: [0x4E2, 0], #Casino 3000 Coins + 0x5A1049: [0x4E4, 0], #Casino 5000 Coins +} + +class LocalRom(object): + + def __init__(self, file, vanillaRom=None, name=None): + self.name = name + 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): + self.buffer[address] = value + + def write_bytes(self, startaddress: int, values): + self.buffer[startaddress:startaddress + len(values)] = values + + def write_to_file(self, file): + with open(file, 'wb') as outfile: + outfile.write(self.buffer) + + def read_from_file(self, file): + with open(file, 'rb') as stream: + self.buffer = bytearray(stream.read()) + +def data_main(rom): + rom.write_bytes(0x05B3B0, bytearray([0xff, 0xff, 0x4e, 0x04, 0x4f, 0x04, 0x50, 0x04, 0x51, 0x04, 0x52, 0x04, 0x53, 0x04, 0x54, 0x04])) + rom.write_bytes(0x05B3C0, bytearray([0x55, 0x04, 0x56, 0x04, 0x57, 0x04, 0x58, 0x04, 0x59, 0x04, 0x5b, 0x04, 0x5c, 0x04, 0x5d, 0x04])) + rom.write_bytes(0x05B3D0, bytearray([0x5e, 0x04, 0x60, 0x04, 0x61, 0x04, 0x62, 0x04, 0x63, 0x04, 0x64, 0x04, 0x66, 0x04, 0x67, 0x04])) + rom.write_bytes(0x05B3E0, bytearray([0x68, 0x04, 0x69, 0x04, 0x6a, 0x04, 0x6b, 0x04, 0x6c, 0x04, 0x6d, 0x04, 0x6e, 0x04, 0x6f, 0x04])) + rom.write_bytes(0x05B3F0, bytearray([0x70, 0x04, 0x71, 0x04, 0x72, 0x04, 0x73, 0x04, 0x74, 0x04, 0x75, 0x04, 0x7d, 0x04, 0x7e, 0x04])) + rom.write_bytes(0x05B400, bytearray([0x7F, 0x04])) + + rom.write_bytes(0x082630, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x04, 0x88, 0x04])) + rom.write_bytes(0x082640, bytearray([0x8a, 0x04, 0x8d, 0x04, 0x89, 0x04, 0x82, 0x04, 0x84, 0x04, 0x83, 0x04, 0xd8, 0x04, 0xdd, 0x04])) + rom.write_bytes(0x082650, bytearray([0xdc, 0x04, 0xde, 0x04, 0xdf, 0x04, 0xe3, 0x04, 0xe8, 0x04, 0xea, 0x04, 0xe0, 0x04, 0xe4, 0x04])) + rom.write_bytes(0x082660, bytearray([0xe2, 0x04, 0xe1, 0x04, 0xeB, 0x04, 0xE6, 0x05, 0x10, 0x15, 0x6b, 0x04, 0x72, 0x04, 0x6e, 0x04])) + rom.write_bytes(0x082670, bytearray([0x6d, 0x04, 0x6f, 0x04, 0x74, 0x04, 0x69, 0x04, 0x6a, 0x04, 0x6c, 0x04, 0x66, 0x04, 0x64, 0x04])) + rom.write_bytes(0x082680, bytearray([0x67, 0x04, 0x59, 0x04, 0x68, 0x04, 0x7f, 0x04, 0x7e, 0x04, 0x7d, 0x04, 0x54, 0x04, 0x5e, 0x04])) + rom.write_bytes(0x082690, bytearray([0x63, 0x04, 0x57, 0x04, 0x3c, 0x05, 0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x0826A0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x0826B0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x0826C0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x0826D0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x0826E0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x62, 0x2c, 0x54, 0x2c, 0x5d, 0x2c, 0x63])) + rom.write_bytes(0x0826F0, bytearray([0x2c, 0x6d, 0x2c, 0x50, 0x2c, 0x61, 0x2c, 0x52, 0x2c, 0x57, 0x2c, 0x58, 0x2c, 0x5f, 0x2c, 0x54])) + rom.write_bytes(0x082700, bytearray([0x2c, 0x5b, 0x2c, 0x50, 0x2c, 0x56, 0x2c, 0x5e, 0x2c, 0x90, 0x28, 0x58, 0x2c, 0x63, 0x2c, 0x54])) + rom.write_bytes(0x082710, bytearray([0x2c, 0x5c, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x082720, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x082730, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x082740, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x082750, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0xf0, 0xef, 0x0a, 0xf0, 0x20])) + rom.write_bytes(0x082760, bytearray([0xf0, 0x34, 0xf0, 0x50, 0xf0, 0x6c, 0xf0, 0x84, 0xf0, 0x9c, 0xf0, 0xaa, 0xf0, 0xbe, 0xf0, 0xd2])) + rom.write_bytes(0x082770, bytearray([0xf0, 0xd8, 0xf0, 0xe6, 0xf0, 0xfc, 0xf0, 0x10, 0xf1, 0x26, 0xf1, 0x3e, 0xf1, 0x56, 0xf1, 0x6c])) + rom.write_bytes(0x082780, bytearray([0xf1, 0x84, 0xf1, 0x9e, 0xf1, 0xa8, 0xf1, 0xba, 0xf1, 0xcc, 0xf1, 0xe0, 0xf1, 0xf8, 0xf1, 0x0a])) + rom.write_bytes(0x082790, bytearray([0xf2, 0x22, 0xf2, 0x36, 0xf2, 0x4c, 0xf2, 0x62, 0xf2, 0x78, 0xf2, 0x90, 0xf2, 0xa6, 0xf2, 0xba])) + rom.write_bytes(0x0827A0, bytearray([0xf2, 0xd0, 0xf2, 0xe6, 0xf2, 0xf2, 0xf2, 0x00, 0xf3, 0x12, 0xf3, 0x2a, 0xf3, 0x44, 0xf3, 0x58])) + rom.write_bytes(0x0827B0, bytearray([0xf3, 0x70, 0xf3, 0x88, 0xf3, 0x50, 0xf6, 0xda, 0xf7, 0x15, 0xf7, 0x31, 0x05, 0x32, 0x05, 0x33])) + rom.write_bytes(0x0827C0, bytearray([0x05, 0x34, 0x05, 0x35, 0x05, 0x8f, 0x04, 0xa5, 0x04, 0xd5, 0x04, 0xcc, 0x04, 0xf7, 0x04, 0x20])) + rom.write_bytes(0x0827D0, bytearray([0x05, 0x28, 0x05, 0x29, 0x05, 0x2B, 0x05, 0x2A, 0x05, 0x27, 0x05])) #Contest 052A + + rom.write_bytes(0x04F580, bytearray([0x50, 0xF6])) #Special chest flag values, puts them at actual flags instead of their vanilla item + rom.write_bytes(0x01911A, bytearray([0x80, 0x04])) + rom.write_bytes(0x018C5A, bytearray([0x87, 0x04])) + rom.write_bytes(0x01025E, bytearray([0x87, 0x04])) + rom.write_bytes(0x0FC85D, bytearray([0x88, 0x04])) + rom.write_bytes(0x01A7D0, bytearray([0x8A, 0x04])) + rom.write_bytes(0x016CD2, bytearray([0x8A, 0x04])) + rom.write_bytes(0x019B04, bytearray([0x8D, 0x04])) + rom.write_bytes(0x011651, bytearray([0x8D, 0x04])) + rom.write_bytes(0x038364, bytearray([0x89, 0x04])) + rom.write_bytes(0x0179F6, bytearray([0x89, 0x04])) + rom.write_bytes(0x0FE6CD, bytearray([0x82, 0x04])) + rom.write_bytes(0x03CB8A, bytearray([0x84, 0x04])) + rom.write_bytes(0x0140CB, bytearray([0x84, 0x04])) + rom.write_bytes(0x02EDD5, bytearray([0x83, 0x04])) + rom.write_bytes(0x014BC2, bytearray([0x83, 0x04])) + rom.write_bytes(0x02F942, bytearray([0xD8, 0x04])) + rom.write_bytes(0x039312, bytearray([0xDD, 0x04])) + rom.write_bytes(0x0394A1, bytearray([0xDC, 0x04])) + rom.write_bytes(0x039142, bytearray([0xDE, 0x04])) + rom.write_bytes(0x039D83, bytearray([0xDF, 0x04])) + rom.write_bytes(0x02FA1D, bytearray([0xE3, 0x04])) + rom.write_bytes(0x0395CC, bytearray([0xE8, 0x04])) + rom.write_bytes(0x039886, bytearray([0xEA, 0x04])) + rom.write_bytes(0x039ACD, bytearray([0xE0, 0x04])) + rom.write_bytes(0x01FC1F, bytearray([0xE4, 0x04])) + rom.write_bytes(0x01FBA5, bytearray([0xE2, 0x04])) + rom.write_bytes(0x01FB2B, bytearray([0xE1, 0x04])) + rom.write_bytes(0x01FAB1, bytearray([0xEB, 0x04])) + + rom.write_byte(0x030485, 0x4D)#Map tile overrides + rom.write_byte(0x030BCE, 0x4D) + rom.write_byte(0x030CDE, 0x4D) + rom.write_byte(0x030E8C, 0x4D) + rom.write_byte(0x0311A5, 0x4D) + rom.write_byte(0x030F92, 0x4D) + rom.write_byte(0x0310B2, 0x4D) + rom.write_byte(0x030DB5, 0x4D) + rom.write_byte(0x030782, 0x4D) + rom.write_byte(0x030941, 0x4D) + rom.write_byte(0x03086D, 0x4D) + rom.write_byte(0x030A23, 0x4D) + rom.write_byte(0x032BEE, 0x4D) + rom.write_byte(0x032D75, 0x4D) + rom.write_byte(0x033032, 0x4D) + rom.write_byte(0x032F85, 0x4D) + rom.write_byte(0x0330E3, 0x4D) + rom.write_byte(0x033194, 0x4D) + rom.write_byte(0x033450, 0x4D) + rom.write_byte(0x0337C5, 0x4D) + rom.write_byte(0x033923, 0x4D) + rom.write_byte(0x033241, 0x4D) + rom.write_byte(0x0335B2, 0x4D) + rom.write_byte(0x033663, 0x4D) + rom.write_byte(0x0339D4, 0x4D) + rom.write_byte(0x0332EF, 0x4D) + rom.write_byte(0x03339F, 0x4D) + rom.write_byte(0x033501, 0x4D) + rom.write_byte(0x01FC9A, 0x4D) + rom.write_byte(0x01FCA0, 0x4D) + rom.write_byte(0x035833, 0x4D) + rom.write_byte(0x0363F3, 0x4D) + rom.write_byte(0x0362B7, 0x4D) + rom.write_byte(0x0364A4, 0x4D) + rom.write_byte(0x036555, 0x4D) + rom.write_byte(0x036602, 0x4D) + rom.write_byte(0x03E35A, 0x83) + + rom.write_bytes(0x082210, bytearray([0x00, 0x00, 0x03, 0x03, 0x04, 0x05, 0x3c, 0x05, 0x5e, 0x1a, 0x7f, 0x3b, 0x7a, 0x47, 0x44, 0x0b])) + rom.write_bytes(0x082220, bytearray([0x00, 0x00, 0x00, 0x03, 0x03, 0x07, 0x3f, 0x01, 0x7f, 0x20, 0x7e, 0x01, 0x46, 0x00, 0x2a, 0x30])) + rom.write_bytes(0x082230, bytearray([0x00, 0x00, 0xc0, 0xc0, 0x60, 0xe0, 0x78, 0xc4, 0x44, 0x1a, 0xc4, 0xba, 0x38, 0xc6, 0x54, 0x8a])) + rom.write_bytes(0x082240, bytearray([0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xb8, 0xc4, 0xe4, 0x3a, 0x44, 0xba, 0x40, 0x02, 0x2a, 0x30])) + rom.write_bytes(0x082250, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082260, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082270, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082280, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082290, bytearray([0x00, 0x00, 0x03, 0x03, 0x04, 0x05, 0x3c, 0x05, 0x5e, 0x1a, 0x7f, 0x3b, 0x7a, 0x47, 0x44, 0x0b])) + rom.write_bytes(0x0822a0, bytearray([0x00, 0x00, 0x00, 0x03, 0x03, 0x07, 0x3f, 0x01, 0x7f, 0x20, 0x7e, 0x01, 0x46, 0x00, 0x2a, 0x30])) + rom.write_bytes(0x0822b0, bytearray([0x00, 0x00, 0xc0, 0xc0, 0x60, 0xe0, 0x78, 0xc4, 0x44, 0x1a, 0xc4, 0xba, 0x38, 0xd6, 0x5c, 0x9a])) + rom.write_bytes(0x0822c0, bytearray([0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xb8, 0xc4, 0xe4, 0x3a, 0x44, 0xba, 0x50, 0x02, 0x3a, 0x20])) + rom.write_bytes(0x0822d0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0822e0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0822f0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082300, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082310, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082320, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082330, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082340, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082350, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082360, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082370, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082380, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082390, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0823a0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0823b0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0823c0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0823d0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0823e0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0823f0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082400, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082410, bytearray([0x44, 0x00, 0x41, 0x29, 0x33, 0x0b, 0x03, 0x41, 0x04, 0x3c, 0x03, 0x07, 0x00, 0x03, 0x00, 0x00])) + rom.write_bytes(0x082420, bytearray([0x03, 0x38, 0x2e, 0x12, 0x0c, 0x40, 0x06, 0x3a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082430, bytearray([0x7c, 0x42, 0xb6, 0x28, 0xbe, 0xa0, 0x7c, 0x22, 0xa0, 0x3c, 0xc0, 0xe0, 0x00, 0xc0, 0x00, 0x00])) + rom.write_bytes(0x082440, bytearray([0x82, 0x38, 0xc8, 0x92, 0x40, 0x02, 0xc0, 0x4c, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082450, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082460, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082470, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082480, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x082490, bytearray([0x44, 0x00, 0x41, 0x29, 0x33, 0x0b, 0x03, 0x41, 0x04, 0x3c, 0x03, 0x07, 0x00, 0x03, 0x00, 0x00])) + rom.write_bytes(0x0824a0, bytearray([0x03, 0x38, 0x2e, 0x12, 0x0c, 0x40, 0x06, 0x3a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + rom.write_bytes(0x0824b0, bytearray([0x3c, 0x3e, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x7e, 0xfc, 0x7c, 0xfc, 0xfc, 0x00, 0xc0, 0x00, 0x00])) + rom.write_bytes(0x0824c0, bytearray([0xfe, 0x40, 0xfe, 0x00, 0xfe, 0xc6, 0xfc, 0x44, 0xfc, 0xc4, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00])) + + rom.write_bytes(0x082C50, bytearray([0x00, 0x00, 0x6c, 0x5d, 0xe9, 0x18, 0x5e, 0x05, 0xb2, 0x04, 0x93, 0x06, 0xf3, 0x6d, 0x5d, 0x3f])) + rom.write_bytes(0x082C60, bytearray([0xee, 0x7e, 0x1a, 0x5e, 0xf4, 0x3f, 0x56, 0x08, 0xff, 0x7f, 0x56, 0x09, 0x5f, 0x29, 0x77, 0x22]))#Ap Item Palette + + rom.write_bytes(0x0cb0ae, bytearray([0x2f, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x14, 0x01, 0x0f, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cb0be, bytearray([0x02, 0x01, 0x15, 0x01, 0x19, 0x01, 0x00, 0x01, 0x0d, 0x01, 0x19, 0x01, 0x00, 0x01, 0x03, 0x01])) + rom.write_bytes(0x0cb0ce, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x81, 0x00, 0x00, 0x03, 0x81, 0x00, 0x06, 0x01])) + rom.write_bytes(0x0cb0de, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0xfe, 0x03, 0x1c, 0x01, 0x81, 0x00, 0x21, 0x00, 0x14, 0x01])) + rom.write_bytes(0x0cb0ee, bytearray([0x21, 0x01, 0x13, 0x01, 0x00, 0x01, 0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01])) + rom.write_bytes(0x0cb0fe, bytearray([0x00, 0x01, 0x06, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x0a, 0x01, 0x15, 0x01, 0x13, 0x01])) + rom.write_bytes(0x0cb10e, bytearray([0x14, 0x01, 0x00, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x00, 0x81, 0x00, 0x03, 0x01, 0x0f, 0x01])) + rom.write_bytes(0x0cb11e, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0x27, 0x01, 0xf5, 0x00, 0x80, 0x00, 0x0c, 0x01, 0x0f, 0x01])) + rom.write_bytes(0x0cb12e, bytearray([0x03, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x81, 0x00, 0x17, 0x01, 0x09, 0x01, 0x14, 0x01, 0x08, 0x01])) + rom.write_bytes(0x0cb13e, bytearray([0x00, 0x01, 0x10, 0x01, 0x15, 0x01, 0x0e, 0x01, 0x09, 0x01, 0x13, 0x01, 0x08, 0x01, 0x09, 0x01])) + rom.write_bytes(0x0cb14e, bytearray([0x0e, 0x01, 0x07, 0x01, 0x00, 0x01, 0x02, 0x01, 0x0c, 0x01, 0x0f, 0x01, 0x17, 0x01, 0x13, 0x01])) + rom.write_bytes(0x0cb15e, bytearray([0x27, 0x01, 0x81, 0x00, 0x19, 0x00, 0x0c, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x06, 0x01, 0x0f, 0x01])) + rom.write_bytes(0x0cb16e, bytearray([0x12, 0x01, 0x00, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x0c, 0x01, 0x19, 0x01, 0x00, 0x01, 0x04, 0x00])) + rom.write_bytes(0x0cb17e, bytearray([0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01, 0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01])) + rom.write_bytes(0x0cb18e, bytearray([0x27, 0x01, 0xf5, 0x00, 0x80, 0x00])) + + rom.write_bytes(0x0cb194, bytearray([0x2c, 0x00, 0x08, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x00, 0x01, 0x06, 0x01])) + rom.write_bytes(0x0cb1a4, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01, 0x00, 0x01, 0x0d, 0x01])) + rom.write_bytes(0x0cb1b4, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0x19, 0x01, 0x26, 0x01, 0x81, 0x00, 0x13, 0x01, 0x15, 0x01])) + rom.write_bytes(0x0cb1c4, bytearray([0x03, 0x01, 0x0b, 0x01, 0x05, 0x01, 0x12, 0x01, 0x1b, 0x01, 0xf4, 0x00])) + + rom.write_bytes(0x0cba3a, bytearray([0x2f, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x14, 0x01, 0x0f, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cba4a, bytearray([0x02, 0x01, 0x15, 0x01, 0x19, 0x01, 0x00, 0x01, 0x0d, 0x01, 0x19, 0x01, 0x00, 0x01, 0x03, 0x01])) + rom.write_bytes(0x0cba5a, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x81, 0x00, 0x00, 0x03, 0x81, 0x00, 0x06, 0x01])) + rom.write_bytes(0x0cba6a, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0xfe, 0x03, 0x1c, 0x01, 0x81, 0x00, 0x21, 0x00, 0x14, 0x01])) + rom.write_bytes(0x0cba7a, bytearray([0x21, 0x01, 0x13, 0x01, 0x00, 0x01, 0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01])) + rom.write_bytes(0x0cba8a, bytearray([0x00, 0x01, 0x06, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cba9a, bytearray([0x00, 0x01, 0x0c, 0x01, 0x0f, 0x01, 0x17, 0x01, 0x26, 0x01, 0x81, 0x00, 0x0c, 0x01, 0x0f, 0x01])) + rom.write_bytes(0x0cbaaa, bytearray([0x17, 0x01, 0x00, 0x01, 0x10, 0x01, 0x12, 0x01, 0x09, 0x01, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cbaba, bytearray([0x0f, 0x01, 0x06, 0x01, 0x00, 0x01, 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01])) + rom.write_bytes(0x0cbaca, bytearray([0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0x27, 0x01, 0xf5, 0x00, 0x80, 0x00])) + + rom.write_bytes(0x0cbAE0, bytearray([0x2c, 0x00, 0x08, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x00, 0x01, 0x06, 0x01])) + rom.write_bytes(0x0cbAF0, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01, 0x00, 0x01, 0x0d, 0x01])) + rom.write_bytes(0x0cbB00, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0x19, 0x01, 0x26, 0x01, 0x81, 0x00, 0x13, 0x01, 0x15, 0x01])) + rom.write_bytes(0x0cbB10, bytearray([0x03, 0x01, 0x0b, 0x01, 0x05, 0x01, 0x12, 0x01, 0x1b, 0x01, 0xf4, 0x00])) + + rom.write_bytes(0x0cac34, bytearray([0x2f, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x14, 0x01, 0x0f, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cac44, bytearray([0x02, 0x01, 0x15, 0x01, 0x19, 0x01, 0x00, 0x01, 0x0d, 0x01, 0x19, 0x01, 0x00, 0x01, 0x03, 0x01])) + rom.write_bytes(0x0cac54, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x81, 0x00, 0x00, 0x03, 0x81, 0x00, 0x06, 0x01])) + rom.write_bytes(0x0cac64, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0xfe, 0x03, 0x1c, 0x01, 0x81, 0x00, 0x21, 0x00, 0x14, 0x01])) + rom.write_bytes(0x0cac74, bytearray([0x21, 0x01, 0x13, 0x01, 0x00, 0x01, 0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01])) + rom.write_bytes(0x0cac84, bytearray([0x00, 0x01, 0x06, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cac94, bytearray([0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x13, 0x01, 0x19, 0x01, 0x00, 0x01, 0x81, 0x00, 0x10, 0x01])) + rom.write_bytes(0x0caca4, bytearray([0x01, 0x01, 0x19, 0x01, 0x0d, 0x01, 0x05, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x0f, 0x01])) + rom.write_bytes(0x0cacb4, bytearray([0x06, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01, 0x0f, 0x01])) + rom.write_bytes(0x0cacc4, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0x27, 0x01, 0xf5, 0x00, 0x80, 0x00])) + + rom.write_bytes(0x0cAD1C, bytearray([0x2c, 0x00, 0x08, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x00, 0x01, 0x06, 0x01])) + rom.write_bytes(0x0cAD2C, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01, 0x00, 0x01, 0x0d, 0x01])) + rom.write_bytes(0x0cAD3C, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0x19, 0x01, 0x26, 0x01, 0x81, 0x00, 0x13, 0x01, 0x15, 0x01])) + rom.write_bytes(0x0cAD4C, bytearray([0x03, 0x01, 0x0b, 0x01, 0x05, 0x01, 0x12, 0x01, 0x1b, 0x01, 0xf4, 0x00])) + + rom.write_bytes(0x0ceff0, bytearray([0x2b, 0x00, 0x09, 0x01, 0x0c, 0x01, 0x16, 0x01, 0x05, 0x01, 0x12, 0x01, 0x00, 0x01, 0x2b, 0x00])) + rom.write_bytes(0x0cf000, bytearray([0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03, 0x1e, 0x00, 0x09, 0x01, 0x12, 0x01])) + rom.write_bytes(0x0cf010, bytearray([0x05, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf020, bytearray([0x21, 0x00, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01])) + rom.write_bytes(0x0cf030, bytearray([0x04, 0x01, 0xff, 0x03, 0x2c, 0x00, 0x08, 0x01, 0x15, 0x01, 0x0e, 0x01, 0x04, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cf040, bytearray([0x12, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf050, bytearray([0x1b, 0x00, 0x12, 0x01, 0x19, 0x01, 0x13, 0x01, 0x14, 0x01, 0x01, 0x01, 0x0c, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cf060, bytearray([0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03, 0x28, 0x00, 0x0f, 0x01])) + rom.write_bytes(0x0cf070, bytearray([0x17, 0x01, 0x05, 0x01, 0x12, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01])) + rom.write_bytes(0x0cf080, bytearray([0x04, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01, 0x14, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cf090, bytearray([0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03, 0x1c, 0x00, 0x01, 0x01])) + rom.write_bytes(0x0cf0a0, bytearray([0x07, 0x01, 0x07, 0x01, 0x05, 0x01, 0x12, 0x01, 0xff, 0x03, 0x1e, 0x00, 0x09, 0x01, 0x12, 0x01])) + rom.write_bytes(0x0cf0b0, bytearray([0x05, 0x01, 0x02, 0x01, 0x01, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0x13, 0x01, 0xff, 0x03, 0x1a, 0x00])) + rom.write_bytes(0x0cf0c0, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0d, 0x01, 0x05, 0x01, 0x12, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x07, 0x01])) + rom.write_bytes(0x0cf0d0, bytearray([0xff, 0x03, 0x19, 0x00, 0x18, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x08, 0x01, 0x0f, 0x01, 0x16, 0x01])) + rom.write_bytes(0x0cf0e0, bytearray([0x05, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x1e, 0x00, 0x09, 0x01, 0x12, 0x01, 0x05, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cf0f0, bytearray([0x19, 0x00, 0x12, 0x01, 0x0d, 0x01, 0x0f, 0x01, 0x12, 0x01, 0xff, 0x03, 0x21, 0x00, 0x03, 0x01])) + rom.write_bytes(0x0cf100, bytearray([0x05, 0x01, 0x00, 0x01, 0x19, 0x00, 0x12, 0x01, 0x0d, 0x01, 0x0f, 0x01, 0x12, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf110, bytearray([0x19, 0x00, 0x11, 0x01, 0x15, 0x01, 0x01, 0x01, 0x00, 0x01, 0x19, 0x00, 0x12, 0x01, 0x0d, 0x01])) + rom.write_bytes(0x0cf120, bytearray([0x0f, 0x01, 0x12, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01, 0x14, 0x01])) + rom.write_bytes(0x0cf130, bytearray([0x00, 0x01, 0x19, 0x00, 0x12, 0x01, 0x0d, 0x01, 0x0f, 0x01, 0x12, 0x01, 0xff, 0x03, 0x1e, 0x00])) + rom.write_bytes(0x0cf140, bytearray([0x09, 0x01, 0x12, 0x01, 0x05, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x08, 0x01, 0x09, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cf150, bytearray([0x0c, 0x01, 0x04, 0x01, 0xff, 0x03, 0x21, 0x00, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01, 0x2b, 0x00])) + rom.write_bytes(0x0cf160, bytearray([0x08, 0x01, 0x09, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x04, 0x01, 0xff, 0x03, 0x19, 0x00, 0x11, 0x01])) + rom.write_bytes(0x0cf170, bytearray([0x15, 0x01, 0x01, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x08, 0x01, 0x09, 0x01, 0x05, 0x01, 0x0c, 0x01])) + rom.write_bytes(0x0cf180, bytearray([0x04, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01, 0x14, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cf190, bytearray([0x2b, 0x00, 0x08, 0x01, 0x09, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x04, 0x01, 0xff, 0x03, 0x2f, 0x00])) + rom.write_bytes(0x0cf1a0, bytearray([0x01, 0x01, 0x0e, 0x01, 0x04, 0x01, 0xff, 0x03, 0x21, 0x00, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cf1b0, bytearray([0x1a, 0x00, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x15, 0x01, 0x0e, 0x01])) + rom.write_bytes(0x0cf1c0, bytearray([0x00, 0x01, 0x2a, 0x00, 0x09, 0x01, 0x0e, 0x01, 0x07, 0x01, 0xff, 0x03, 0x28, 0x00, 0x0f, 0x01])) + rom.write_bytes(0x0cf1d0, bytearray([0x17, 0x01, 0x05, 0x01, 0x12, 0x01, 0x00, 0x01, 0x1e, 0x00, 0x01, 0x01, 0x0e, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf1e0, bytearray([0x1d, 0x00, 0x0c, 0x01, 0x16, 0x01, 0x05, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x1e, 0x00, 0x0c, 0x01])) + rom.write_bytes(0x0cf1f0, bytearray([0x15, 0x01, 0x14, 0x01, 0x05, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x0b, 0x01, 0x19, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cf200, bytearray([0x1a, 0x00, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01])) + rom.write_bytes(0x0cf210, bytearray([0x08, 0x01, 0x14, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cf220, bytearray([0xff, 0x03, 0x2b, 0x00, 0x15, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01])) + rom.write_bytes(0x0cf230, bytearray([0x0e, 0x01, 0x05, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x14, 0x01, 0x01, 0x01, 0x12, 0x01, 0x00, 0x01])) + rom.write_bytes(0x0cf240, bytearray([0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0xff, 0x03, 0x19, 0x00, 0x11, 0x01])) + rom.write_bytes(0x0cf250, bytearray([0x15, 0x01, 0x01, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cf260, bytearray([0xff, 0x03, 0x25, 0x00, 0x0f, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01])) + rom.write_bytes(0x0cf270, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01])) + rom.write_bytes(0x0cf280, bytearray([0x14, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf290, bytearray([0x2b, 0x00, 0x14, 0x01, 0x01, 0x01, 0x12, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cf2a0, bytearray([0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x15, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00])) + rom.write_bytes(0x0cf2b0, bytearray([0x10, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x19, 0x00, 0x11, 0x01, 0x15, 0x01])) + rom.write_bytes(0x0cf2c0, bytearray([0x01, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf2d0, bytearray([0x25, 0x00, 0x0f, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cf2e0, bytearray([0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x08, 0x01, 0x0f, 0x01, 0x16, 0x01, 0x05, 0x01])) + rom.write_bytes(0x0cf2f0, bytearray([0xff, 0x03, 0x2d, 0x00, 0x10, 0x01, 0x00, 0x01, 0x22, 0x00, 0x01, 0x01, 0x02, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf300, bytearray([0x1c, 0x00, 0x0f, 0x01, 0x17, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x22, 0x00, 0x01, 0x01, 0x02, 0x01])) + rom.write_bytes(0x0cf310, bytearray([0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x06, 0x01, 0x05, 0x01, 0x00, 0x01, 0x1a, 0x00, 0x0f, 0x01])) + rom.write_bytes(0x0cf320, bytearray([0x14, 0x01, 0x14, 0x01, 0x0c, 0x01, 0x05, 0x01, 0xff, 0x03, 0x25, 0x00, 0x01, 0x01, 0x07, 0x01])) + rom.write_bytes(0x0cf330, bytearray([0x09, 0x01, 0x03, 0x01, 0x00, 0x01, 0x1a, 0x00, 0x0f, 0x01, 0x14, 0x01, 0x14, 0x01, 0x0c, 0x01])) + rom.write_bytes(0x0cf340, bytearray([0x05, 0x01, 0xff, 0x03, 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01])) + rom.write_bytes(0x0cf350, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03, 0x02, 0x00, 0x26, 0x01, 0x01, 0x00, 0x01, 0x00])) + rom.write_bytes(0x0cf360, bytearray([0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf370, bytearray([0x03, 0x00, 0x26, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01])) + rom.write_bytes(0x0cf380, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03, 0x06, 0x00, 0x26, 0x01, 0x01, 0x00, 0x01, 0x00])) + rom.write_bytes(0x0cf390, bytearray([0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03])) + rom.write_bytes(0x0cf3a0, bytearray([0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x06, 0x01])) + rom.write_bytes(0x0cf3b0, bytearray([0xff, 0x03])) + +def code_main(rom): + rom.write_bytes(0x17ad40, bytearray([0xe0, 0x58, 0x01, 0xb0, 0x08, 0xbf, 0x80, 0x5c, 0xc0, 0x5c, 0x44, 0x5c, 0xc0, 0xa9, 0x10, 0x22])) + rom.write_bytes(0x17ad50, bytearray([0x85, 0x0e, 0xa9, 0xc8, 0x00, 0x85, 0x10, 0xa9, 0x50, 0x2c, 0x85, 0x12, 0xa9, 0xc8, 0x00, 0x85])) + rom.write_bytes(0x17ad60, bytearray([0x14, 0xa9, 0x00, 0x44, 0x85, 0x0a, 0xa9, 0x00, 0x04, 0x85, 0x0c, 0xe0, 0x68, 0x01, 0xf0, 0x0f])) + rom.write_bytes(0x17ad70, bytearray([0xe0, 0x60, 0x01, 0xf0, 0x05, 0xa9, 0x12, 0x00, 0x80, 0x08, 0xa9, 0x0e, 0x00, 0x80, 0x03, 0xa9])) + rom.write_bytes(0x17ad80, bytearray([0x10, 0x00, 0x8d, 0x52, 0x22, 0x5c, 0x6b, 0x5c, 0xc0, 0x60, 0xda, 0x5a, 0x8b, 0x38, 0xe9, 0x7d])) + rom.write_bytes(0x17ad90, bytearray([0x04, 0x0a, 0xaa, 0xbf, 0xb5, 0x27, 0xc8, 0xaa, 0xa9, 0xc5, 0x00, 0xa0, 0xf0, 0x7d, 0x54, 0x20])) + rom.write_bytes(0x17ada0, bytearray([0xc4, 0xab, 0x7a, 0xfa, 0x68, 0x60, 0xda, 0xa2, 0x00, 0x00, 0xdf, 0x6a, 0x26, 0xc8, 0xf0, 0x17])) + rom.write_bytes(0x17adb0, bytearray([0xe8, 0xe8, 0xe0, 0x2c, 0x00, 0xf0, 0x02, 0x80, 0xf1, 0xfa, 0xe6, 0x40, 0xe6, 0x40, 0x48, 0xa9])) + rom.write_bytes(0x17adc0, bytearray([0x00, 0x00, 0x68, 0x5c, 0x41, 0x42, 0xc0, 0xbf, 0x3c, 0x26, 0xc8, 0x99, 0x39, 0x0c, 0x85, 0x0a])) + rom.write_bytes(0x17add0, bytearray([0xbf, 0x10, 0x26, 0xc8, 0x99, 0x79, 0x0c, 0xc9, 0x4e, 0x04, 0x90, 0x16, 0x38, 0xe9, 0x4a, 0x04])) + rom.write_bytes(0x17ade0, bytearray([0x8d, 0x54, 0x22, 0xfa, 0x22, 0xe4, 0x5a, 0xc0, 0xe6, 0x40, 0xe6, 0x40, 0xc2, 0x20, 0x5c, 0xC3])) + rom.write_bytes(0x17adf0, bytearray([0xb2, 0x17, 0xc9, 0x04, 0x00, 0xb0, 0x02, 0x80, 0xe7, 0xe2, 0x20, 0x38, 0xe9, 0x04, 0xaa, 0xbf])) + rom.write_bytes(0x17ae00, bytearray([0x68, 0x26, 0xc8, 0xc2, 0x20, 0x80, 0xd9, 0xe2, 0x20, 0xaf, 0xe0, 0x7d, 0x20, 0xc9, 0x05, 0xb0])) + rom.write_bytes(0x17ae10, bytearray([0x07, 0x1a, 0x8f, 0xe0, 0x7d, 0x20, 0x80, 0x07, 0xad, 0x85, 0x04, 0xd0, 0x0e, 0x80, 0x00, 0xc2])) + rom.write_bytes(0x17ae20, bytearray([0x20, 0xad, 0xa0, 0x05, 0xc9, 0x00, 0x01, 0x5c, 0x95, 0x0a, 0xc2, 0xc2, 0x20, 0xb9, 0x39, 0x0c])) + rom.write_bytes(0x17ae30, bytearray([0x48, 0xa9, 0x4d, 0x04, 0x99, 0x39, 0x0c, 0xad, 0x85, 0x04, 0xc9, 0xe0, 0x00, 0x90, 0x06, 0x38])) + rom.write_bytes(0x17ae40, bytearray([0xe9, 0xe0, 0x00, 0x80, 0x06, 0x0a, 0xaa, 0xbf, 0xb0, 0xb3, 0xc5, 0x48, 0x22, 0xe9, 0x5a, 0xc0])) + rom.write_bytes(0x17ae50, bytearray([0xc2, 0x20, 0x68, 0x22, 0x18, 0x5c, 0xc0, 0xa9, 0x03, 0x00, 0x8d, 0x02, 0x0a, 0x22, 0xab, 0xb0])) + rom.write_bytes(0x17ae60, bytearray([0x17, 0x22, 0xd8, 0x5d, 0xc0, 0x68, 0x99, 0x39, 0x0c, 0x9c, 0x85, 0x04, 0x80, 0xb1])) + + rom.write_bytes(0x17b010, bytearray([0xb9, 0xda, 0x06, 0x1a, 0x1a, 0x99, 0xda, 0x06, 0x5c, 0x94, 0xc5, 0xc2, 0xb9, 0xda, 0x06, 0x3a])) + rom.write_bytes(0x17b020, bytearray([0x3a, 0x99, 0xda, 0x06, 0x5c, 0x75, 0xc5, 0xc2, 0xe2, 0x20, 0xbd, 0xbe, 0x33, 0xc9, 0x05, 0xd0])) + rom.write_bytes(0x17b030, bytearray([0x21, 0xad, 0xd3, 0x00, 0xc9, 0x21, 0xd0, 0x21, 0xaf, 0x90, 0xae, 0x17, 0xf0, 0x1b, 0xda, 0xa2])) + rom.write_bytes(0x17b040, bytearray([0x00, 0x00, 0xbd, 0x70, 0x04, 0xf0, 0x08, 0xe0, 0x05, 0x00, 0xf0, 0x0c, 0xe8, 0x80, 0xf3, 0xfa])) + rom.write_bytes(0x17b050, bytearray([0xa9, 0x01, 0xc2, 0x20, 0x5c, 0x4f, 0x6f, 0xc0, 0xfa, 0xc2, 0x20, 0xa9, 0x05, 0x00, 0x5c, 0x4f])) + rom.write_bytes(0x17b060, bytearray([0x6f, 0xc0, 0x48, 0xa9, 0x69, 0x8d, 0x34, 0x00, 0x68, 0xa2, 0x16, 0xf0, 0x86, 0x56, 0x5c, 0x69])) + rom.write_bytes(0x17b070, bytearray([0xb8, 0xc1, 0xad, 0x02, 0x0a, 0xf0, 0x11, 0xc9, 0x01, 0xf0, 0x05, 0xce, 0x02, 0x0a, 0x80, 0x0d])) + rom.write_bytes(0x17b080, bytearray([0xce, 0x02, 0x0a, 0x20, 0x96, 0xb0, 0x80, 0x05, 0xad, 0x13, 0x0a, 0xf0, 0x00, 0xc2, 0x20, 0xa9])) + rom.write_bytes(0x17b090, bytearray([0x86, 0x3e, 0x5c, 0x88, 0x40, 0xc0, 0xc2, 0x20, 0xa2, 0x10, 0x10, 0xa0, 0x53, 0x17, 0xa9, 0x0f])) + rom.write_bytes(0x17b0a0, bytearray([0x00, 0x54, 0x7e, 0xc8, 0x9c, 0x88, 0x05, 0x9c, 0x5e, 0x22, 0x60, 0xc2, 0x20, 0xa9, 0x08, 0x00])) + rom.write_bytes(0x17b0b0, bytearray([0x0c, 0x04, 0x01, 0x6b, 0xc9, 0x75, 0x04, 0x90, 0x09, 0xc9, 0x7d, 0x04, 0xb0, 0x0c, 0x5c, 0xf6])) + rom.write_bytes(0x17b0c0, bytearray([0x5a, 0xc0, 0xe2, 0x20, 0xa9, 0x01, 0x5c, 0xf3, 0x5a, 0xc0, 0x20, 0x89, 0xad, 0x80, 0xf3, 0xe0])) + rom.write_bytes(0x17b0d0, bytearray([0x58, 0x00, 0xb0, 0x08, 0xbf, 0x00, 0x00, 0xc5, 0x5c, 0xf3, 0x5d, 0xc0, 0x4C, 0x68, 0xB2, 0xe2])) + rom.write_bytes(0x17b0e0, bytearray([0x20, 0x8b, 0xa9, 0x20, 0x5c, 0xf9, 0x5d, 0xc0, 0xa7, 0x40, 0xc9, 0x76, 0x04, 0xb0, 0x08, 0xe6])) + rom.write_bytes(0x17b0f0, bytearray([0x40, 0xe6, 0x40, 0x5c, 0x4b, 0x44, 0xc0, 0x48, 0xad, 0x40, 0x00, 0x8f, 0xF9, 0x04, 0x7E, 0x8b])) + rom.write_bytes(0x17b100, bytearray([0xda, 0x5a, 0xa9, 0xc5, 0x00, 0xa2, 0x96, 0x26, 0xa0, 0xf0, 0x7d, 0x54, 0x20, 0xc8, 0x7a, 0xfa])) + rom.write_bytes(0x17b110, bytearray([0xab, 0x68, 0x80, 0xdb, 0xa7, 0xe9, 0xc9, 0x00, 0x03, 0xb0, 0x07, 0x8d, 0x0f, 0x1c, 0x5c, 0xe0])) + rom.write_bytes(0x17b120, bytearray([0xed, 0xc0, 0x29, 0xff, 0x00, 0xc9, 0xff, 0x00, 0xf0, 0x34, 0xc9, 0xfd, 0x00, 0xf0, 0x41, 0xc9])) + rom.write_bytes(0x17b130, bytearray([0xfe, 0x00, 0xf0, 0x4e, 0x48, 0xa5, 0xe9, 0x8f, 0xe5, 0x7d, 0x20, 0x68, 0xda, 0x0a, 0xaa, 0xbf])) + rom.write_bytes(0x17b140, bytearray([0x5b, 0x27, 0xc8, 0x85, 0xe9, 0xfa, 0x8b, 0x48, 0xda, 0x5a, 0xa9, 0x12, 0x00, 0xa2, 0xa0, 0xf3])) + rom.write_bytes(0x17b150, bytearray([0xa0, 0x44, 0x7e, 0x54, 0x20, 0xcc, 0x7a, 0xfa, 0x68, 0xab, 0x5c, 0xdb, 0xed, 0xc0, 0xaf, 0xe5])) + rom.write_bytes(0x17b160, bytearray([0x7d, 0x20, 0x1a, 0x1a, 0x85, 0xe9, 0xe2, 0x20, 0xa9, 0xcc, 0x85, 0xeb, 0xc2, 0x20, 0x80, 0xea])) + rom.write_bytes(0x17b170, bytearray([0xa5, 0xe9, 0x8f, 0xe5, 0x7d, 0x20, 0xa9, 0xF0, 0x00, 0x85, 0xe9, 0xa9, 0x7d, 0x20, 0x85, 0xea])) + rom.write_bytes(0x17b180, bytearray([0x80, 0xd8, 0xa5, 0xe9, 0x8f, 0xe5, 0x7d, 0x20, 0xa9, 0x44, 0x44, 0x85, 0xe9, 0xa9, 0x7e, 0x20])) + rom.write_bytes(0x17b190, bytearray([0x85, 0xea, 0x80, 0xc6, 0xad, 0x1e, 0x01, 0xc9, 0x60, 0x00, 0xb0, 0x07, 0x18, 0x69, 0x08, 0x00])) + rom.write_bytes(0x17b1a0, bytearray([0x8d, 0x1e, 0x01, 0x5c, 0x21, 0x5b, 0xc0, 0xad, 0x20, 0x01, 0x29, 0xff, 0x00, 0xc9, 0x0e, 0x00])) + rom.write_bytes(0x17b1b0, bytearray([0xb0, 0x03, 0xee, 0x20, 0x01, 0xee, 0x1c, 0x01, 0x5c, 0x3b, 0x5b, 0xc0, 0xb9, 0x00, 0x00, 0x8f])) + rom.write_bytes(0x17b1c0, bytearray([0x8e, 0x05, 0x7e, 0xa9, 0x00, 0x00, 0x8f, 0xe0, 0x7d, 0x20, 0x5c, 0x11, 0x78, 0xc0, 0xc2, 0x20])) + rom.write_bytes(0x17b1d0, bytearray([0xa5, 0x0a, 0xc9, 0xbc, 0x8b, 0xf0, 0x06, 0xe2, 0x20, 0x5c, 0x87, 0x3e, 0xc0, 0xa2, 0x00, 0x00])) + rom.write_bytes(0x17b1e0, bytearray([0xbf, 0xbb, 0x27, 0xc8, 0xa8, 0xe2, 0x20, 0xbf, 0xd0, 0x24, 0xc8, 0x99, 0x00, 0x00, 0xc2, 0x20])) + rom.write_bytes(0x17b1f0, bytearray([0xe8, 0xe8, 0xe0, 0x20, 0x00, 0xf0, 0x02, 0x80, 0xe7, 0xa2, 0x00, 0x00, 0xa0, 0x00, 0x00, 0xa9])) #Number of starting flags + rom.write_bytes(0x17b200, bytearray([0x4d, 0x04, 0x8d, 0x39, 0x0c, 0xbf, 0xF7, 0x24, 0xc8, 0xf0, 0x0c, 0xda, 0x22, 0xe9, 0x5a, 0xc0])) + rom.write_bytes(0x17b210, bytearray([0xc2, 0x20, 0xfa, 0xe8, 0xe8, 0x80, 0xee, 0xa2, 0x00, 0x00, 0xe2, 0x20, 0xbf, 0xF0, 0x24, 0xc8])) + rom.write_bytes(0x17b220, bytearray([0xc2, 0x20, 0xa8, 0xc0, 0x00, 0x00, 0xf0, 0x14, 0x8a, 0x5a, 0xda, 0xa0, 0x00, 0x00, 0x22, 0xe9])) + rom.write_bytes(0x17b230, bytearray([0x5a, 0xc0, 0xc2, 0x20, 0x29, 0xff, 0x00, 0xfa, 0x7a, 0x88, 0x80, 0xe7, 0xe0, 0x05, 0x00, 0xf0])) + rom.write_bytes(0x17b240, bytearray([0x03, 0xe8, 0x80, 0xd6, 0xa9, 0xb4, 0x8b, 0x8d, 0x0a, 0x00, 0xa9, 0x2d, 0x2d, 0x8d, 0x0d, 0x00])) + rom.write_bytes(0x17b250, bytearray([0xa9, 0x04, 0x7e, 0x8d, 0x0f, 0x00, 0x4c, 0xd7, 0xb1, 0x8a, 0x8f, 0xe7, 0x7d, 0x20, 0xe2, 0x20])) + rom.write_bytes(0x17b260, bytearray([0x9b, 0x20, 0xA0, 0xB2, 0x5c, 0xfa, 0x77, 0xc0, 0xe0, 0x66, 0x00, 0xb0, 0x06, 0xa2, 0xf0, 0x7d])) + rom.write_bytes(0x17b270, bytearray([0x4c, 0xDF, 0xb0, 0x8a, 0x38, 0xe9, 0x66, 0x00, 0xaa, 0xbf, 0xb5, 0x27, 0xc8, 0xaa, 0xe2, 0x20])) + rom.write_bytes(0x17b280, bytearray([0x8b, 0xa9, 0xc4, 0x5c, 0xf9, 0x5d, 0xc0, 0xAD, 0xFB, 0x04, 0x29, 0xFF, 0x00, 0xF0, 0x08, 0xAD])) + rom.write_bytes(0x17b290, bytearray([0xfc, 0x04, 0x9c, 0xfb, 0x04, 0x80, 0x03, 0xad, 0x54, 0x22, 0x0a, 0x0a, 0x5c, 0x3e, 0x5c, 0xc0])) + rom.write_bytes(0x17b2a0, bytearray([0xc2, 0x20, 0xa2, 0x00, 0x00, 0x48, 0xaf, 0x00, 0x7E, 0x20, 0xc9, 0x90, 0x28, 0xf0, 0x12, 0x8b])) + rom.write_bytes(0x17b2b0, bytearray([0xda, 0x5a, 0xa9, 0xc5, 0x00, 0xa2, 0x96, 0x26, 0xa0, 0xf0, 0x7d, 0x54, 0x20, 0xc8, 0x7a, 0xfa])) + rom.write_bytes(0x17b2c0, bytearray([0xab, 0x68, 0x60, 0xA9, 0x01, 0x01, 0x8D, 0x0F, 0x00, 0xA9, 0xDC, 0x04, 0x8D, 0x0A, 0x00, 0x5C])) + rom.write_bytes(0x17b2D0, bytearray([0x43, 0x42, 0xC0])) + + rom.write_bytes(0x04f650, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f660, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f670, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f680, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f690, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f6a0, bytearray([0x28, 0x90, 0x28, 0x55, 0x2c, 0x5e, 0x2c, 0x64, 0x2c, 0x5d, 0x2c, 0x53, 0x2c, 0x6d, 0x2c, 0x62])) + rom.write_bytes(0x04f6b0, bytearray([0x2c, 0x57, 0x2c, 0x5e, 0x2c, 0x65, 0x2c, 0x54, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f6c0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f6d0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x04f6e0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x04f6f0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x04f700, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x04f710, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) + rom.write_bytes(0x04f720, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) + rom.write_bytes(0x04f730, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) + rom.write_bytes(0x04f740, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) + rom.write_bytes(0x04f750, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) + rom.write_bytes(0x04f760, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x55, 0x2c, 0x5e, 0x2c, 0x64, 0x2c, 0x5d, 0x2c])) + rom.write_bytes(0x04f770, bytearray([0x53, 0x2c, 0x6d, 0x2c, 0x53, 0x2c, 0x5e, 0x2c, 0x66, 0x2c, 0x5d, 0x2c, 0x90, 0x28, 0x59, 0x2c])) + rom.write_bytes(0x04f780, bytearray([0x50, 0x2c, 0x51, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) + rom.write_bytes(0x04f790, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) + rom.write_bytes(0x04f7a0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) + rom.write_bytes(0x04f7b0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) + rom.write_bytes(0x04f7c0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) + rom.write_bytes(0x04f7d0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x20, 0x00, 0x03, 0x00, 0x00, 0x90])) + rom.write_bytes(0x04f7e0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f7f0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f800, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f810, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f820, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x55, 0x2c, 0x5e])) + rom.write_bytes(0x04f830, bytearray([0x2c, 0x64, 0x2c, 0x5d, 0x2c, 0x53, 0x2c, 0x6d, 0x2c, 0x64, 0x2c, 0x5f, 0x2c, 0x90, 0x28, 0x59])) + rom.write_bytes(0x04f840, bytearray([0x2c, 0x50, 0x2c, 0x51, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x04f850, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x97])) + rom.write_bytes(0x04f860, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x04f870, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x04f880, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x04f890, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) + + rom.write_bytes(0x00FBA4, bytearray([0xAD, 0x58, 0x00, 0x29, 0xFF, 0x00, 0xC9, 0xCE, 0x00, 0xD0, 0x07, 0xAD, 0x56, 0x00, 0x8F, 0xE7])) + rom.write_bytes(0x00FBB4, bytearray([0x7D, 0x20, 0xA7, 0x56, 0x85, 0x0A, 0x4C, 0x08, 0x25, 0x00])) + +def code_handlers(rom): + rom.write_bytes(0x020A8F, bytearray([0x5C, 0x07, 0xAe, 0x17]))#Get item from server + + rom.write_bytes(0x004083, bytearray([0x5C, 0x72, 0xB0, 0x17]))#Hide item menu sometimes + + rom.write_bytes(0x006F49, bytearray([0x5C, 0x28, 0xB0, 0x17]))#Lock Phantom behind spells + + rom.write_bytes(0x00423D, bytearray([0x5C, 0xA6, 0xAD, 0x17]))#Fix special chests + + #ORG $C05AF1 + #NOP #5 ;Don't write items from chests, use for remote items + + rom.write_bytes(0x016197, bytearray([0xEA, 0xEA]))#Unlock all maps + + rom.write_bytes(0x01B864, bytearray([0x5C, 0x62, 0xB0, 0x17]))#Send Goal + + rom.write_bytes(0x00FBA0, bytearray([0x5C, 0xCe, 0xB1, 0x17]))#Initalize starting variables + + rom.write_bytes(0x005AEF, bytearray([0x5C, 0xB4, 0xB0, 0x17]))#Prevent 'Archipelago Items' from writing inventory flags + + rom.write_bytes(0x005DEF, bytearray([0x5C, 0xCF, 0xB0, 0x17]))#Redirect AP item names to writable memory + + rom.write_bytes(0x004445, bytearray([0x5C, 0xE8, 0xB0, 0x17]))#Signal to get scout data for normal chests + + rom.write_bytes(0x00EDDB, bytearray([0x5C, 0x14, 0xB1, 0x17]))#Special text pointer for shops + + rom.write_bytes(0x005B1A, bytearray([0x5C, 0x94, 0xB1, 0x17]))#Cap health + + rom.write_bytes(0x005B35, bytearray([0x5C, 0xA7, 0xB1, 0x17]))#Cap magic + + rom.write_bytes(0x00780A, bytearray([0x5C, 0xBC, 0xB1, 0x17]))#Zero screen transition counter + + rom.write_bytes(0x0043B9, bytearray([0x4C, 0xA0, 0xFB])) + + rom.write_bytes(0x0077F4, bytearray([0x5C, 0x59, 0xB2, 0x17]))#Scout special chests + + rom.write_bytes(0x005C40, bytearray([0x5C, 0x40, 0xAD, 0x17]))#Render AP sprites + + rom.write_bytes(0x005C39, bytearray([0x5C, 0x87, 0xB2, 0x17]))#Sprite override + + rom.write_bytes(0x002504, bytearray([0x4C, 0xA4, 0xFB])) + +def casino_text_pointers(rom): + rom.write_bytes(0x050014, bytearray([0xF0, 0xFA])) #Light Sword + rom.write_bytes(0x050028, bytearray([0xC0, 0xFB])) #Light Armor + rom.write_bytes(0x050032, bytearray([0x90, 0xFC])) #Light Shield + rom.write_bytes(0x05001A, bytearray([0x80, 0xFD])) #Boomerang + + +def casino_text(rom): + rom.write_bytes(0x05FAF0, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FB00, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FB10, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FB20, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FB30, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FB40, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x5B])) + rom.write_bytes(0x05FB50, bytearray([0x2C, 0x58, 0x2C, 0x56, 0x2C, 0x57, 0x2C, 0x63, 0x2c, 0x90, 0x28, 0x62, 0x2C, 0x66, 0x2C, 0x5E])) + rom.write_bytes(0x05FB60, bytearray([0x2C, 0x61, 0x2C, 0x53, 0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FB70, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FB80, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FB90, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FBA0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FBB0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) + + rom.write_bytes(0x05FBC0, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FBD0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FBE0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FBF0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FC00, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FC10, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x5B])) + rom.write_bytes(0x05FC20, bytearray([0x2C, 0x58, 0x2C, 0x56, 0x2C, 0x57, 0x2C, 0x63, 0x2c, 0x90, 0x28, 0x50, 0x2C, 0x61, 0x2C, 0x5C])) + rom.write_bytes(0x05FC30, bytearray([0x2C, 0x5E, 0x2C, 0x61, 0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FC40, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FC50, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FC60, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FC70, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FC80, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) + + rom.write_bytes(0x05FC90, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FCA0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FCB0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FCC0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FCD0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FCE0, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x5B])) + rom.write_bytes(0x05FCF0, bytearray([0x2C, 0x58, 0x2C, 0x56, 0x2C, 0x57, 0x2C, 0x63, 0x2c, 0x90, 0x28, 0x62, 0x2C, 0x57, 0x2C, 0x58])) + rom.write_bytes(0x05FD00, bytearray([0x2C, 0x54, 0x2C, 0x5B, 0x2C, 0x53, 0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FD10, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FD20, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FD30, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FD40, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FD50, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) + + rom.write_bytes(0x05FD80, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FD90, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FDA0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FDB0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FDC0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FDD0, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x51])) + rom.write_bytes(0x05FDE0, bytearray([0x2C, 0x5E, 0x2C, 0x5E, 0x2C, 0x5C, 0x2C, 0x54, 0x2c, 0x61, 0x2C, 0x50, 0x2C, 0x5D, 0x2C, 0x56])) + rom.write_bytes(0x05FDF0, bytearray([0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) + rom.write_bytes(0x05FE00, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FE10, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FE20, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FE30, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) + rom.write_bytes(0x05FE40, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) + +def overworld_speed(rom): + rom.write_bytes(0x02C58D, bytearray([0x5C, 0xC0, 0xB3, 0x17])) + rom.write_bytes(0x02C56E, bytearray([0x5C, 0xCC, 0xB3, 0x17])) + rom.write_bytes(0x02C559, bytearray([0x5C, 0xD8, 0xB3, 0x17])) + rom.write_bytes(0x02C53A, bytearray([0x5C, 0xE4, 0xB3, 0x17])) + + + rom.write_bytes(0x17B3C0, bytearray([0xB9, 0xDA, 0x06, 0x1A, 0x1A, 0x99, 0xDA, 0x06, 0x5C, 0x94, 0xC5, 0xC2])) + rom.write_bytes(0x17B3CC, bytearray([0xB9, 0xDA, 0x06, 0x3A, 0x3A, 0x99, 0xDA, 0x06, 0x5C, 0x75, 0xC5, 0xC2])) + rom.write_bytes(0x17B3D8, bytearray([0xB9, 0x5A, 0x06, 0x1A, 0x1A, 0x99, 0x5A, 0x06, 0x5C, 0x60, 0xC5, 0xC2])) + rom.write_bytes(0x17B3E4, bytearray([0xB9, 0x5A, 0x06, 0x3A, 0x3A, 0x99, 0x5A, 0x06, 0x5C, 0x41, 0xC5, 0xC2])) + +def quick_magic(rom): + rom.write_bytes(0x021129, bytearray([0x22, 0x40, 0xB3, 0x17, 0xEA, 0xEA])) + + rom.write_bytes(0x17B340, bytearray([0xAD, 0x64, 0x04, 0xF0, 0x60, 0xAD, 0xFB, 0x05, 0x89, 0x03, 0x00, 0xF0, 0x58, 0x22, 0x4B, 0x6D])) + rom.write_bytes(0x17B350, bytearray([0xC0, 0xC2, 0x20, 0xAD, 0xFB, 0x05, 0x89, 0x02, 0x00, 0xD0, 0x07, 0x89, 0x01, 0x00, 0xD0, 0x22])) + rom.write_bytes(0x17B360, bytearray([0x80, 0x43, 0xAE, 0x08, 0x01, 0xCA, 0xE0, 0x03, 0x00, 0xF0, 0xFA, 0xE0, 0x08, 0x00, 0x90, 0x03])) + rom.write_bytes(0x17B370, bytearray([0xA2, 0x07, 0x00, 0xE0, 0x00, 0x00, 0xF0, 0x2A, 0xBD, 0x75, 0x04, 0x29, 0xFF, 0x00, 0xF0, 0xE5])) + rom.write_bytes(0x17B380, bytearray([0x80, 0x20, 0xAE, 0x08, 0x01, 0xE8, 0xE0, 0x03, 0x00, 0xF0, 0xFA, 0xE0, 0x08, 0x00, 0x90, 0x03])) + rom.write_bytes(0x17B390, bytearray([0xA2, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xF0, 0x0A, 0xBD, 0x75, 0x04, 0x29, 0xFF, 0x00, 0xF0, 0xE5])) + rom.write_bytes(0x17B3A0, bytearray([0x80, 0x00, 0x8E, 0x08, 0x01, 0xAD, 0xFB, 0x05, 0x2D, 0x14, 0x01, 0x6B])) + +def disable_encounters(rom): + rom.write_bytes(0x003022, bytearray([0x22, 0xB0, 0xB3, 0x17])) + rom.write_bytes(0x003026, bytearray([0xC9, 0x01])) + rom.write_bytes(0x003028, bytearray([0xD0, 0x03])) + rom.write_bytes(0x00302A, bytearray([0xA9, 0x00, 0xEA])) + rom.write_bytes(0x00302D, bytearray([0xEA, 0xEA])) + + rom.write_bytes(0x17B3B0, bytearray([0xEA, 0xEA, 0xEA, 0xEA])) + rom.write_bytes(0x17B3B4, bytearray([0xEA, 0xEA, 0xEA, 0xEA])) + rom.write_bytes(0x17B3B8, bytearray([0xEA])) + rom.write_bytes(0x17B3B9, bytearray([0xAF, 0x16, 0x42, 0x00])) + rom.write_bytes(0x17B3BD, bytearray([0x6B])) + +def quick_shovel(rom): + rom.write_bytes(0x001CBF, bytearray([0x22, 0xF0, 0xB2, 0xD7])) + + rom.write_bytes(0x17B2F0, bytearray([0xDA, 0xAD, 0xFB, 0x05, 0xC9, 0x00, 0x02, 0xD0, 0x36, 0xAD, 0x59, 0x04, 0x89, 0x01, 0x00, 0xF0])) + rom.write_bytes(0x17B300, bytearray([0x2E, 0xAD, 0x0C, 0x01, 0xC9, 0x0C, 0x00, 0xF0, 0x19, 0xE2, 0x20, 0x8D, 0x28, 0x04, 0xC2, 0x20])) + rom.write_bytes(0x17B310, bytearray([0x22, 0xCE, 0x65, 0xC0, 0x9C, 0x0A, 0x01, 0x9C, 0x0E, 0x01, 0xA9, 0x0C, 0x00, 0x8D, 0x0C, 0x01])) + rom.write_bytes(0x17B320, bytearray([0x80, 0x0D, 0xAD, 0x28, 0x04, 0x29, 0xFF, 0x00, 0x8D, 0x0C, 0x01, 0x22, 0x3B, 0x68, 0xC0, 0xFA])) + rom.write_bytes(0x17B330, bytearray([0xBF, 0xFB, 0x05, 0x7E, 0x6B])) + + rom.write_bytes(0x0065CE, bytearray([0x5C, 0x60, 0xAF, 0xD7])) + + rom.write_bytes(0x17AF90, bytearray([0xC2, 0x20, 0xAD, 0x0C, 0x01, 0xC9, 0x0C, 0x00, 0xF0, 0x10, 0xAD, 0x0A, 0x01, 0xE2, 0x20, 0x8D])) + rom.write_bytes(0x17AFA0, bytearray([0x27, 0x04, 0xC2, 0x20, 0xAD, 0x0E, 0x01, 0x8D, 0x29, 0x04, 0x6B])) + + rom.write_bytes(0x17AFB0, bytearray([0xAD, 0x27, 0x04, 0x29, 0xFF, 0x00, 0x8D, 0x0A, 0x01, 0xAD, 0x29, 0x04, 0x8D, 0x0E, 0x01, 0x6B])) + + rom.write_bytes(0x00683B, bytearray([0x5c, 0xB0, 0xAF, 0xD7])) + +def fix_prices(rom): + #C1FCA7 Life Bottle + #C1FCB2 Boomerang + #C1FCBB Light Shield + #C1FCBF Light Armor + #C1FCC7 Light Sword + rom.write_bytes(0x01FCAB, bytearray([0x00, 0x05, 0x00])) + rom.write_bytes(0x01FCB2, bytearray([0x00, 0x01, 0x00, 0x00])) + rom.write_bytes(0x01FCBB, bytearray([0x02, 0x00, 0x00])) + rom.write_bytes(0x01FCC2, bytearray([0x00, 0x03, 0x00, 0x00, 0x00])) + rom.write_bytes(0x01FCCA, bytearray([0x00, 0x05, 0x00, 0x00, 0x00])) + +def patch_rom(world, rom, player: int, multiworld): + data_main(rom) #Values and pointers + code_main(rom) #code execution + code_handlers(rom) #Jumps to my code + overworld_speed(rom) + casino_text(rom) + casino_text_pointers(rom) + rom.write_bytes(0x00EDCC, bytearray([0xA9, 0x01, 0x00])) #Fast text patch + #rom.write_bytes(0x006D5A, bytearray([0x08])) + #rom.write_bytes(0x02E605, bytearray([0x00])) + rom.write_bytes(0x17AE90, ([world.options.phantom_spells])) + if world.options.disable_encounters == 1: + disable_encounters(rom) + + if world.options.fast_shovel == 1: + quick_shovel(rom) + + if world.options.magic_swap == 1: + quick_magic(rom) + + if world.options.casino_checks == 1: + fix_prices(rom) + + local_start_items = [] + class_map = { + ItemClassification.progression: [0x77, 0x04], + ItemClassification.progression_skip_balancing: [0x77, 0x04], + ItemClassification.filler: [0x76, 0x04], + ItemClassification.useful: [0x76, 0x04], + ItemClassification.trap: [0x76, 0x04] + } + + unique_starting_items = [] + + shop_names = [ + 0x0CAC5E, + 0x0CB0D8, + 0x0CBA64 + ] + + shop_checks = [ + "100 Coin Shop", + "300 Coin Shop", + "500 Coin Shop" + ] + + inv_address = 0 + + for location in world.multiworld.get_locations(player): + if location.address: #dont write local data for events + if location.item.player != location.player: + ap_item = class_map[location.item.classification] + rom.write_bytes(local_locations[location.name], bytearray(ap_item)) + else: + rom.write_bytes(local_locations[location.name], bytearray(local_items[location.item.name])) + + rom.write_byte(0x0824F0, sum(item.name == "Life Bottle" for item in world.multiworld.precollected_items[player])) #The type of item doesn't matter; just count how many they have + rom.write_byte(0x0824F1, sum(item.name == "Magic Bottle" for item in world.multiworld.precollected_items[player])) + rom.write_byte(0x0824F2, sum(item.name == "500 Coins" for item in world.multiworld.precollected_items[player])) + rom.write_byte(0x0824F3, sum(item.name == "1000 Coins" for item in world.multiworld.precollected_items[player])) + rom.write_byte(0x0824F4, sum(item.name == "2000 Coins" for item in world.multiworld.precollected_items[player])) + rom.write_byte(0x0824F5, sum(item.name == "5000 Coins" for item in world.multiworld.precollected_items[player])) + + for item in world.multiworld.precollected_items[player]: + if item.name not in ["Life Bottle", "Magic Bottle", "500 Coins", "1000 Coins", "2000 Coins", "5000 Coins", "Light Gate Lowered", "Sun Gate Lowered", "Star Gate Lowered", "Sun Gate Lowered", "Aqua Gate Lowered", "Moon Gate Lowered"] and item.name not in unique_starting_items: + unique_starting_items.append(item.name) + index = unique_starting_items.index(item.name) + inv_address + rom.write_bytes(0x0824F5 + (index + 2), bytearray(local_items[item.name])) #Major items do literally nothing if the player has more than one, so ignore major items that have more than one copy precollected + inv_address += 1 + for i in range(3): + if world.multiworld.get_location(shop_checks[i], player).item.player != world.player: + rom.write_bytes(shop_names[i], bytearray([0xFD, 0x03])) + else: + rom.write_bytes(shop_names[i], bytearray(shop_items[world.multiworld.get_location(shop_checks[i], player).item.name])) + + rom.write_byte(0x0824D0, world.light_gate) + rom.write_byte(0x0824D2, world.sun_gate) + rom.write_byte(0x0824D4, world.star_gate) + rom.write_byte(0x0824D6, world.aqua_gate) + rom.write_byte(0x0824D8, world.moon_gate) + rom.write_byte(0x0824DA, world.light_switch_default) + rom.write_byte(0x0824DC, world.sun_switch_default) + rom.write_byte(0x0824DE, world.star_switch_default) + rom.write_byte(0x0824E0, world.aqua_switch_default) + rom.write_byte(0x0824E2, world.moon_switch_default) + rom.write_byte(0x0824E4, world.options.early_fuwa) + rom.write_byte(0x0824E6, world.boa_hiya_shortcut) + rom.write_byte(0x0824E8, world.sala_hiya_shortcut) + rom.write_byte(0x0824EA, world.sala_puka_shortcut) + rom.write_byte(0x0824EC, world.fuwa_puka_shortcut) + rom.write_byte(0x0824EE, world.fuwa_poka_shortcut) + + from Main import __version__ + rom.name = bytearray(f'SAI2AP{__version__.replace(".", "")[0:3]}_{player}_{world.multiworld.seed:11}\0', "utf8")[:21] + rom.name.extend([0] * (21 - len(rom.name))) + rom.write_bytes(0x00FFC0, rom.name) + +class SAI2ProcedurePatch(APProcedurePatch, APTokenMixin): + hash = [USHASH] + game = "Super Adventure Island II" + patch_file_ending = ".apsai2" + result_file_ending = ".sfc" + name: bytearray + procedure = [ + ("apply_tokens", ["token_patch.bin"]), + ("apply_bsdiff4", ["mmx3_basepatch.bsdiff4"]), + ] + + @classmethod + def get_source_data(cls) -> bytes: + return get_base_rom_bytes() + + def write_byte(self, offset, value): + self.write_token(APTokenTypes.WRITE, offset, value.to_bytes(1, "little")) + + def write_bytes(self, offset, value: typing.Iterable[int]): + self.write_token(APTokenTypes.WRITE, offset, bytes(value)) + + + +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: + options: Utils.OptionsType = Utils.get_options() + if not file_name: + file_name = options["sai2_options"]["rom_file"] + if not os.path.exists(file_name): + file_name = Utils.user_path(file_name) + return file_name diff --git a/worlds/sai2/Rules.py b/worlds/sai2/Rules.py new file mode 100644 index 000000000000..bedbed50c3ba --- /dev/null +++ b/worlds/sai2/Rules.py @@ -0,0 +1,99 @@ +from .extended_logic import logic_helpers +from worlds.generic.Rules import set_rule + + + +logic: logic_helpers +def set_location_rules(world): + logic = logic_helpers(world) + multiworld = world.multiworld + player = world.player + + set_rule(multiworld.get_location("Poka-Poka Lake Chest", player), lambda state: state.has('Silver Sword', player)) + set_rule(multiworld.get_location("Poka-Poka Digging Chest", player), lambda state: state.has('Shovel', player)) + set_rule(multiworld.get_location("Poka-Poka East Cave Chest", player), lambda state: logic.light_switch_on(state)) + + set_rule(multiworld.get_location("Poka-Poka Down Blocks Chest", player), lambda state: (state.has('Down Jab', player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Poka-Poka Moon Alcove Chest", player), lambda state: logic.moon_switch_on(state)) + set_rule(multiworld.get_location("Poka-Poka Sun Blocks Chest", player), lambda state: logic.sun_switch_off(state)) + set_rule(multiworld.get_location("Poka-Poka East Cave Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Poka-Poka Shrine Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Poka-Poka Pushable Rock Chest", player), lambda state: state.has('Shove', player)) + set_rule(multiworld.get_location("Evil Tree Chest", player), lambda state: logic.can_fight_boss(state)) + + set_rule(multiworld.get_location("Boa-Boa Sun Alcove Chest", player), lambda state: logic.sun_switch_on(state)) + set_rule(multiworld.get_location("Boa-Boa Sun Block Chest", player), lambda state: (state.has('Elven Flute', player) and logic.sun_switch_off(state))) + set_rule(multiworld.get_location("Boa-Boa Lava Lake West Chest", player), lambda state: state.has('Shovel', player)) + set_rule(multiworld.get_location("Boa-Boa Eastern Shaft Chest", player), lambda state: (state.has('Down Jab', player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Boa-Boa Western Shaft Chest", player), lambda state: (state.has('Up Jab', player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Boa-Boa Shrine Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Tortoise Chest", player), lambda state: (logic.can_fight_boss(state) and state.has("Shove", player))) + + set_rule(multiworld.get_location("Hiya-Hiya Sun Blocks Chest", player), lambda state: logic.sun_switch_off(state)) + set_rule(multiworld.get_location("Hiya-Hiya Hidden Alcove Chest", player), lambda state: (state.has('Shove', player) and logic.star_switch_on(state))) + set_rule(multiworld.get_location("Hiya-Hiya Up Block Alcove Chest", player), lambda state: (state.has_all({'Shove', "Up Jab"}, player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Hiya-Hiya Trapped Chest", player), lambda state: state.has('Shove', player) and logic.star_switch_off(state)) + set_rule(multiworld.get_location("Hiya-Hiya Ice Cubes Chest", player), lambda state: (state.has_all({'Shove', "Fire Sword"}, player))) + set_rule(multiworld.get_location("Hiya-Hiya Top Level", player), lambda state: state.has('Shove', player)) + set_rule(multiworld.get_location("Hiya-Hiya Long Fall Chest", player), lambda state: state.has('Shove', player) and logic.star_switch_off(state)) + set_rule(multiworld.get_location("Hiya-Hiya Vines Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Hiya-Hiya Shrine Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Mammoth Chest", player), lambda state: logic.can_fight_boss(state) and state.has("Shove", player) and logic.star_switch_off(state)) + + set_rule(multiworld.get_location("Puka-Puka Light Blocks Chest", player), lambda state: logic.light_switch_on(state) and state.has(("Shovel"), player)) + set_rule(multiworld.get_location("Puka-Puka Down Jab Chest", player), lambda state: (state.has('Down Jab', player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Puka-Puka Star Blocks Chest", player), lambda state: logic.star_switch_on(state)) + set_rule(multiworld.get_location("Puka-Puka Up Jab Chest", player), lambda state: (state.has('Up Jab', player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Puka-Puka Spike Maze Lower Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Puka-Puka Spike Maze Upper Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Puka-Puka Shrine Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Puka-Puka Water Control", player), lambda state: (state.has_all({'Shove', "Shovel"}, player))) + set_rule(multiworld.get_location("Puka-Puka Underwater Chest", player), lambda state: state.has('Puka-Puka Drained', player)) + set_rule(multiworld.get_location("Puka-Puka Aqua Blocks Chest", player), lambda state: (state.has_all({'Shovel', "Puka-Puka Drained"}, player)) and logic.aqua_switch_off(state)) + set_rule(multiworld.get_location("Octopus Chest", player), lambda state: (state.has_all({'Shovel', "Puka-Puka Drained"}, player)) and logic.aqua_switch_off(state) and logic.can_fight_boss) + + set_rule(multiworld.get_location("Sala-Sala Pyramid Center Chest", player), lambda state: logic.moon_switch_off(state)) + set_rule(multiworld.get_location("Sala-Sala Star Alcove Chest", player), lambda state: logic.star_switch_on(state)) + set_rule(multiworld.get_location("Sala-Sala Near Entrance Chest", player), lambda state: logic.moon_switch_on(state) and state.has("Shovel", player)) + set_rule(multiworld.get_location("Sala-Sala Top of the Pyramid Chest", player), lambda state: logic.moon_switch_on(state) and (state.has_all({"Shovel", "Down Jab"}, player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Sala-Sala Up Jab Chest", player), lambda state: logic.moon_switch_on(state) and (state.has_all({"Shovel", "Up Jab", "Shove"}, player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Sala-Sala All Blocks Chest", player), lambda state: logic.light_switch_on(state) and logic.sun_switch_on(state) and logic.star_switch_on(state) and logic.aqua_switch_on(state) and logic.moon_switch_on(state)) + set_rule(multiworld.get_location("Sala-Sala Farthest Chest", player), lambda state: (state.has_all({'Elven Flute', "Down Jab"}, player) and state.has_group("Swords", player, 1))) + set_rule(multiworld.get_location("Sala-Sala Shrine Chest", player), lambda state: state.has('Elven Flute', player)) + set_rule(multiworld.get_location("Mummy Chest", player), lambda state: logic.can_fight_boss(state) and logic.has_good_projectile(state)) + + set_rule(multiworld.get_location("Fuwa-Fuwa Block Maze Chest", player), lambda state: state.has_all({'Up Jab', 'Down Jab', 'Power Sword'}, player)) + set_rule(multiworld.get_location("Fuwa-Fuwa Moon Block Chest", player), lambda state: logic.moon_switch_on(state)) + set_rule(multiworld.get_location("Fuwa-Fuwa Light Block Chest", player), lambda state: logic.light_switch_on(state) and state.has("Power Sword", player)) + set_rule(multiworld.get_location("Fuwa-Fuwa Bridge Room Chest", player), lambda state: state.has("Shovel", player)) + set_rule(multiworld.get_location("Fuwa-Fuwa Balance Platforms Chest", player), lambda state: state.has("Shovel", player)) + set_rule(multiworld.get_location("Hawk Chest", player), lambda state: logic.can_fight_boss(state) and state.has_all({"Shovel", "Power Sword"}, player)) + set_rule(multiworld.get_location("Phantom Defeat", player), lambda state: (logic.can_fight_final_boss(state) and logic.has_good_projectile(state)) and state.has_all({"Shovel", "Power Sword"}, player)) + + #set_rule(multiworld.get_location("Muscle Lizard Chest", player), lambda state: logic.has_early_health(state)) + set_rule(multiworld.get_location("Ice Cave Chest", player), lambda state: state.has('Shove', player)) + set_rule(multiworld.get_location("Saber Tooth Chest", player), lambda state: logic.can_fight_boss(state)) + set_rule(multiworld.get_location("300 Coin Shop", player), lambda state: state.has_group("Coins", player, 1)) + set_rule(multiworld.get_location("500 Coin Shop", player), lambda state: (state.has_group("Coins", player, 2) or state.has_any({"1000 Coins", "2000 Coins", "5000 Coins"}, player))) + + set_rule(multiworld.get_location("Boa-Hiya Shortcut Room", player), lambda state: state.has_all({"Shovel", "Shove"}, player)) + set_rule(multiworld.get_location("Sala-Hiya Shortcut Room", player), lambda state: state.has('Shove', player)) + set_rule(multiworld.get_location("Sala-Puka Shortcut Room", player), lambda state: state.has_all({"Shovel", "Shove"}, player) and logic.moon_switch_on) + set_rule(multiworld.get_location("Fuwa-Poka Shortcut Room", player), lambda state: state.has_all({"Shovel", "Shove"}, player)) + set_rule(multiworld.get_location("Fuwa-Puka Shortcut Room", player), lambda state: state.has_all({"Down Jab", "Power Sword", "Shove"}, player)) + + + if world.light_gate == 0: + set_rule(multiworld.get_location("Light Gate", player), lambda state: state.has('Light Stone', player)) + + if world.sun_gate == 0: + set_rule(multiworld.get_location("Sun Gate", player), lambda state: state.has('Sun Stone', player)) + + if world.star_gate == 0: + set_rule(multiworld.get_location("Star Gate", player), lambda state: state.has('Star Stone', player)) + + if world.aqua_gate == 0: + set_rule(multiworld.get_location("Aqua Gate", player), lambda state: state.has('Aqua Stone', player)) + + if world.moon_gate == 0: + set_rule(multiworld.get_location("Moon Gate", player), lambda state: state.has('Moon Stone', player)) \ No newline at end of file diff --git a/worlds/sai2/__init__.py b/worlds/sai2/__init__.py new file mode 100644 index 000000000000..5bb03f90b2a0 --- /dev/null +++ b/worlds/sai2/__init__.py @@ -0,0 +1,293 @@ +import os +import typing +import threading + +from typing import List, Set, TextIO +from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification +from worlds.AutoWorld import World, WebWorld +import settings +from .Items import get_item_names_per_category, item_table, filler_items +from .Locations import get_locations +from .Regions import init_areas +from .Options import SAI2Options +from .setup_game import setup_gamevars +from .Client import SAI2SNIClient +from .Rules import set_location_rules +from .Rom import LocalRom, patch_rom, get_base_rom_path, SAI2ProcedurePatch, USHASH + +class SAI2Settings(settings.Group): + class RomFile(settings.SNESRomPath): + """File name of the Super Adventure Island II US ROM""" + description = "Super Adventure Island II ROM File" + copy_to = "Super Adventure Island II (USA).sfc" + md5s = [USHASH] + + rom_file: RomFile = RomFile(RomFile.copy_to) + +class SAI2Web(WebWorld): + theme = "ocean" + + setup_en = Tutorial( + "Multiworld Setup Guide", + "A guide to setting up the Super Adventure Island II randomizer" + "and connecting to an Archipelago server.", + "English", + "setup_en.md", + "setup/en", + ["Pink Switch"] + ) + + tutorials = [setup_en] + +class SAI2World(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 = "Super Adventure Island II" + option_definitions = SAI2Options + data_version = 1 + required_client_version = (0, 3, 5) + + 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 = SAI2Web() + settings: typing.ClassVar[SAI2Settings] + #topology_present = True + + options_dataclass = SAI2Options + options: SAI2Options + + locked_locations: List[str] + location_cache: List[Location] + placed_life_bottles = 0 + first_weapon_placed = False + first_projectile_placed = False + + item_classifications = {"filler": ItemClassification.filler, + "useful": ItemClassification.useful, + "progression": ItemClassification.progression} + + def __init__(self, world: MultiWorld, player: int): + self.rom_name_available_event = threading.Event() + super().__init__(world, player) + + self.locked_locations= [] + self.location_cache= [] + self.locked_items = 17 + + + #def write_spoiler_header(self, spoiler_handle: TextIO) -> None: + #spoiler_handle.write(f"Burt The Bashful's Boss Door: {self.starting_item}\n") + + def create_item(self, name: str) -> Item: + data = item_table[name] + classification = self.item_classifications[data.classification] + item = Item(name, classification, data.code, self.player) + + return item + + def create_regions(self): + init_areas(self, get_locations(self)) + + def get_filler_item_name(self) -> str: + return self.random.choice(filler_items) + + def set_rules(self): + set_location_rules(self) + self.multiworld.completion_condition[self.player] = lambda state: state.has('Tina', self.player) + self.multiworld.get_location("Poka-Poka First Cave", self.player).place_locked_item(self.create_item("Light Switch")) + self.multiworld.get_location("Hiya-Hiya Top Level", self.player).place_locked_item(self.create_item("Star Switch")) + self.multiworld.get_location("Boa-Boa Hidden Wall", self.player).place_locked_item(self.create_item("Sun Switch")) + self.multiworld.get_location("Puka-Puka Switch Room", self.player).place_locked_item(self.create_item("Aqua Switch")) + self.multiworld.get_location("Sala-Sala Switch Room", self.player).place_locked_item(self.create_item("Moon Switch")) + self.multiworld.get_location("Puka-Puka Water Control", self.player).place_locked_item(self.create_item("Puka-Puka Drained")) + self.multiworld.get_location("Phantom Defeat", self.player).place_locked_item(self.create_item("Tina")) + + self.multiworld.get_location("Boa-Hiya Shortcut Room", self.player).place_locked_item(self.create_item("Boa-Hiya Shortcut Open")) + self.multiworld.get_location("Sala-Hiya Shortcut Room", self.player).place_locked_item(self.create_item("Sala-Hiya Shortcut Open")) + self.multiworld.get_location("Sala-Puka Shortcut Room", self.player).place_locked_item(self.create_item("Sala-Puka Shortcut Open")) + self.multiworld.get_location("Fuwa-Puka Shortcut Room", self.player).place_locked_item(self.create_item("Fuwa-Puka Shortcut Open")) + self.multiworld.get_location("Fuwa-Poka Shortcut Room", self.player).place_locked_item(self.create_item("Fuwa-Poka Shortcut Open")) + + self.multiworld.get_location("Light Gate", self.player).place_locked_item(self.create_item("Light Gate Lowered")) + self.multiworld.get_location("Sun Gate", self.player).place_locked_item(self.create_item("Sun Gate Lowered")) + self.multiworld.get_location("Star Gate", self.player).place_locked_item(self.create_item("Star Gate Lowered")) + self.multiworld.get_location("Aqua Gate", self.player).place_locked_item(self.create_item("Aqua Gate Lowered")) + self.multiworld.get_location("Moon Gate", self.player).place_locked_item(self.create_item("Moon Gate Lowered")) + + if self.options.shuffle_skills != 2: + self.multiworld.get_location("100 Coin Shop", self.player).place_locked_item(self.create_item(self.locked_skills[0])) + self.multiworld.get_location("300 Coin Shop", self.player).place_locked_item(self.create_item(self.locked_skills[1])) + self.multiworld.get_location("500 Coin Shop", self.player).place_locked_item(self.create_item(self.locked_skills[2])) + + if self.options.casino_checks == 0: + self.multiworld.get_location("Casino 500 Coin Purchase", self.player).place_locked_item(self.create_item("Life Bottle")) + self.multiworld.get_location("Casino 1000 Coin Purchase", self.player).place_locked_item(self.create_item("Boomerang")) + self.multiworld.get_location("Casino 2000 Coin Purchase", self.player).place_locked_item(self.create_item("Light Shield")) + self.multiworld.get_location("Casino 3000 Coin Purchase", self.player).place_locked_item(self.create_item("Light Armor")) + self.multiworld.get_location("Casino 5000 Coin Purchase", self.player).place_locked_item(self.create_item("Light Sword")) + else: + self.multiworld.itempool.append(self.create_item('Life Bottle')) + self.multiworld.itempool.append(self.create_item('Boomerang')) + self.multiworld.itempool.append(self.create_item('Light Shield')) + self.multiworld.itempool.append(self.create_item('Light Sword')) + self.multiworld.itempool.append(self.create_item('Light Armor')) + + + def generate_early(self): + self.locals = [] + setup_gamevars(self) + if self.options.world_state != 1: + self.multiworld.push_precollected(self.create_item(self.starting_item)) + if self.options.extra_health == 1: + for _ in range(2): + self.multiworld.push_precollected(self.create_item("Life Bottle")) + + if self.light_gate == 1: + self.multiworld.push_precollected(self.create_item("Light Gate Lowered")) + + if self.sun_gate == 1: + self.multiworld.push_precollected(self.create_item("Sun Gate Lowered")) + + if self.star_gate == 1: + self.multiworld.push_precollected(self.create_item("Star Gate Lowered")) + + if self.aqua_gate == 1: + self.multiworld.push_precollected(self.create_item("Aqua Gate Lowered")) + + if self.moon_gate == 1: + self.multiworld.push_precollected(self.create_item("Moon Gate Lowered")) + + + + def get_excluded_items(self) -> Set[str]: + excluded_items: Set[str] = set() + if self.options.boss_spells == 1: + excluded_items.add('Light Spell') + excluded_items.add('Star Spell') + excluded_items.add('Sun Spell') + excluded_items.add('Aqua Spell') + excluded_items.add('Moon Spell') + + if self.options.shuffle_skills != 2: + excluded_items.add("Shove") + excluded_items.add("Down Jab") + excluded_items.add("Up Jab") + + return excluded_items + + def get_dynamic_classes(self, player: int, name: str) -> Item: + data = item_table[name] + classification = self.item_classifications[data.classification] + item = Item(name, classification, data.code, player) + weapons = ["Ice Sword", "Thunder Sword", "Crystal Sword", "Light Sword", "Dagger", "Fireballs", "Silver Sword", "Fire Sword", "Power Sword"] + projectiles = ["Ax", "Boomerang"] + + if not self.options.casino_checks: + weapons.remove("Light Sword") + + if not item.advancement: + return item + + if name in weapons: + if self.first_weapon_placed == True: + if name not in ["Silver Sword", "Power Sword", "Fire Sword"]: + item.classification = ItemClassification.useful + else: + self.first_weapon_placed = True + + if name in projectiles: + if self.first_projectile_placed == True: + item.classification = ItemClassification.useful + else: + self.first_projectile_placed = True + + if name == "Life Bottle": + item.classification = ItemClassification.useful + + if name == ("Light Sword" or "Boomerang") and self.options.casino_checks != 1: + item.classification = ItemClassification.useful + + if name == "Light Stone" and self.light_gate == 1: + item.classification = ItemClassification.filler + + if name == "Sun Stone" and self.sun_gate == 1: + item.classification = ItemClassification.filler + + if name == "Star Stone" and self.star_gate == 1: + item.classification = ItemClassification.filler + + if name == "Aqua Stone" and self.aqua_gate == 1: + item.classification = ItemClassification.filler + + if name == "Moon Stone" and self.moon_gate == 1: + item.classification = ItemClassification.filler + + return item + + def generate_filler(self, multiworld: MultiWorld, player: int, + pool: List[Item]): + + for _ in range(len(multiworld.get_unfilled_locations(player)) - len(pool) - self.locked_items): #- number of event items + item = self.get_dynamic_classes(player, self.get_filler_item_name()) + pool.append(item) + + def get_item_pool(self, player: int, 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.get_dynamic_classes(player, name) + pool.append(item) + + return pool + + + + def create_items(self): + if self.options.casino_checks == 0: + self.locked_items += 5 + + if self.options.shuffle_skills !=2: + self.locked_items += 3 + + if self.options.boss_spells == 1: + self.locked_items += 5 + excluded_items = self.get_excluded_items() + + pool = self.get_item_pool(self.player, excluded_items) + + self.generate_filler(self.multiworld, self.player, pool) + + self.multiworld.itempool += pool + + def generate_output(self, output_directory: str): + try: + world = self.multiworld + player = self.player + patch = SAI2ProcedurePatch() + patch_rom(self, patch, self.player, self.multiworld) + + self.rom_name = patch.name + + patch.write(os.path.join(output_directory, + f"{self.multiworld.get_out_file_name_base(self.player)}{patch.patch_file_ending}")) + except Exception: + raise + finally: + self.rom_name_available_event.set() # make sure threading continues and errors are collected + + def modify_multidata(self, multidata: dict): + import base64 + # 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]]): \ No newline at end of file diff --git a/worlds/sai2/extended_logic.py b/worlds/sai2/extended_logic.py new file mode 100644 index 000000000000..5acc5f1e412e --- /dev/null +++ b/worlds/sai2/extended_logic.py @@ -0,0 +1,99 @@ +from BaseClasses import CollectionState + +class logic_helpers: + player: int + + + def __init__(self, world): + self.player = world.player + self.fuwa_open = False + self.light_switch_default = world.light_switch_default + self.sun_switch_default = world.sun_switch_default + self.star_switch_default = world.star_switch_default + self.aqua_switch_default = world.aqua_switch_default + self.moon_switch_default = world.moon_switch_default + + self.light_gate = world.light_gate + self.sun_gate = world.sun_gate + self.star_gate = world.star_gate + self.aqua_gate = world.aqua_gate + self.moon_gate = world.moon_gate + + if world.options.early_fuwa.value == 1: + self.fuwa_open = True + + if world.options.phantom_spells.value == 0: + self.phantom_open = True + + def fuwa_access(self, state: CollectionState) -> bool: + return (state.has_all({"Light Spell", "Sun Spell", "Star Spell", "Aqua Spell", "Moon Spell"}, self.player) or self.fuwa_open) + + def phantom_spells(self, state: CollectionState) -> bool: + return (state.has_all({"Light Spell", "Sun Spell", "Star Spell", "Aqua Spell", "Moon Spell"}, self.player) or self.phantom_open) + + def has_early_health(self, state: CollectionState) -> bool: + return state.has("Life Bottle", self.player, 2) + + def light_switch_on(self, state: CollectionState) -> bool: + if self.light_switch_default == 0: + return state.has("Light Switch", self.player) + else: + return True + + def sun_switch_on(self, state: CollectionState) -> bool: + if self.sun_switch_default == 0: + return state.has("Sun Switch", self.player) + else: + return True + + def sun_switch_off(self, state: CollectionState) -> bool: + if self.sun_switch_default == 1: + return state.has("Sun Switch", self.player) + else: + return True + + def star_switch_on(self, state: CollectionState) -> bool: + if self.star_switch_default == 0: + return state.has("Star Switch", self.player) + else: + return True + + def star_switch_off(self, state: CollectionState) -> bool: + if self.star_switch_default == 1: + return state.has("Star Switch", self.player) + else: + return True + + def aqua_switch_on(self, state: CollectionState) -> bool: + if self.aqua_switch_default == 0: + return state.has("Aqua Switch", self.player) + else: + return True + + def aqua_switch_off(self, state: CollectionState) -> bool: + if self.aqua_switch_default == 1: + return state.has("Aqua Switch", self.player) + else: + return True + + def moon_switch_on(self, state: CollectionState) -> bool: + if self.moon_switch_default == 0: + return state.has("Moon Switch", self.player) + else: + return True + + def moon_switch_off(self, state: CollectionState) -> bool: + if self.moon_switch_default == 1: + return state.has("Moon Switch", self.player) + else: + return True + + def can_fight_boss(self, state: CollectionState) -> bool: + return (state.has_group("Swords", self.player, 1) or state.has_group("Projectiles", self.player, 1)) and self.has_early_health + + def has_good_projectile(self, state: CollectionState) -> bool: + return state.has_group("Projectiles", self.player, 1) + + def can_fight_final_boss(self, state: CollectionState) -> bool: + return state.has_group("Armor", self.player, 1) and self.has_early_health and self.phantom_spells + \ No newline at end of file diff --git a/worlds/sai2/local_data.py b/worlds/sai2/local_data.py new file mode 100644 index 000000000000..4c9daa7208e9 --- /dev/null +++ b/worlds/sai2/local_data.py @@ -0,0 +1,546 @@ + +local_items = { + "Life Bottle": [0x00, 0x00], + "Magic Bottle": [0x01, 0x00], + "500 Coins": [0x02, 0x00], + "1000 Coins": [0x03, 0x00], + "2000 Coins": [0x04, 0x00], + "5000 Coins": [0x05, 0x00], + + "Silver Sword": [0x4E, 0x04], + "Fire Sword": [0x4F, 0x04], + "Ice Sword": [0x50, 0x04], + "Thunder Sword": [0x51, 0x04], + "Crystal Sword": [0x52, 0x04], + "Power Sword": [0x53, 0x04], + "Light Sword": [0x54, 0x04], + "Dagger": [0x55, 0x04], + "Fireballs": [0x56, 0x04], + "Boomerang": [0x57, 0x04], + "Ax": [0x58, 0x04], + "Shovel": [0x59, 0x04], + + "Fire Armor": [0x5B, 0x04], + "Ice Armor": [0x5C, 0x04], + "Aqua Armor": [0x5D, 0x04], + "Light Armor": [0x5E, 0x04], + + "Fire Shield": [0x60, 0x04], + "Ice Shield": [0x61, 0x04], + "Aqua Shield": [0x62, 0x04], + "Light Shield": [0x63, 0x04], + + "Wand": [0x64, 0x04], + "Ice Bell": [0x66, 0x04], + "Sun Ring": [0x67, 0x04], + "Power Fan": [0x68, 0x04], + "Elven Flute": [0x69, 0x04], + "Sky Bell": [0x6A, 0x04], + "Light Stone": [0x6B, 0x04], + "Sun Stone": [0x6C, 0x04], + "Star Stone": [0x6D, 0x04], + "Aqua Stone": [0x6E, 0x04], + "Moon Stone": [0x6F, 0x04], + + "Light Spell": [0x70, 0x04], + "Sun Spell": [0x71, 0x04], + "Star Spell": [0x72, 0x04], + "Aqua Spell": [0x73, 0x04], + "Moon Spell": [0x74, 0x04], + + "Shove": [0x7D, 0x04], + "Up Jab": [0x7E, 0x04], + "Down Jab": [0x7F, 0x04] + +} + +local_locations = { + "Poka-Poka West Cave Chest": 0x018E7B, + "Poka-Poka Digging Chest": 0x018D90, + "Poka-Poka Lake Chest": 0x018893, + "Poka-Poka Down Blocks Chest": 0x01909D, + "Poka-Poka Moon Alcove Chest": 0x019081, + "Poka-Poka Sun Blocks Chest": 0x018E25, + "Poka-Poka East Cave Chest": 0x018E41, + "Poka-Poka Shrine Chest": 0x01911D, + "Poka-Poka Pushable Rock Chest": 0x018DD3, + "Poka-Poka Tree Chest": 0x018B4A, + "Evil Tree Chest": 0x082610, + + "Boa-Boa Lava Lake East Chest": 0x0FC817, + "Boa-Boa Lava Lake West Chest": 0x0FC7FF, + "Boa-Boa Sun Alcove Chest": 0x0FC7D1, + "Boa-Boa Clouds Chest": 0x0FC7BA, + "Boa-Boa Sun Block Chest": 0x0FC7E8, + "Boa-Boa Shrine Chest": 0x082612, + "Boa-Boa Western Shaft Chest": 0x0FC82D, + "Boa-Boa Eastern Shaft Chest": 0x0FC844, + "Tortoise Chest": 0x082614, + + "Hiya-Hiya Clouds Chest": 0x0FB565, + "Hiya-Hiya Underground Chest": 0x0FB581, + "Hiya-Hiya Sun Blocks Chest": 0x0FB59D, + "Hiya-Hiya Up Block Alcove Chest": 0x0FB5D5, + "Hiya-Hiya Ice Cubes Chest": 0x0FB60D, + "Hiya-Hiya Hidden Alcove Chest": 0x0FB629, + "Hiya-Hiya Trapped Chest": 0x0FB5F1, + "Hiya-Hiya Long Fall Chest": 0x0FB5B9, + "Hiya-Hiya Vines Chest": 0x0FB645, + "Hiya-Hiya Shrine Chest": 0x0FB65C, + "Mammoth Chest": 0x082616, + + "Puka-Puka Light Blocks Chest": 0x0FD59E, + "Puka-Puka Down Jab Chest": 0x0FD5B5, + "Puka-Puka Star Blocks Chest": 0x0FD5CC, + "Puka-Puka Up Jab Chest": 0x0FD5E3, + "Puka-Puka Moving Platforms Chest": 0x0FD656, + "Puka-Puka Springs Chest": 0x0FD66D, + "Puka-Puka Spike Maze Lower Chest": 0x0FD63F, + "Puka-Puka Spike Maze Upper Chest": 0x0FD628, + "Puka-Puka Shrine Chest": 0x0FD684, + "Puka-Puka Underwater Chest": 0x0FD5FA, + "Puka-Puka Aqua Blocks Chest": 0x0FD611, + "Octopus Chest": 0x082618, + + "Sala-Sala Pyramid Center Chest": 0x0FE69D, + "Sala-Sala Star Alcove Chest": 0x0FE641, + "Sala-Sala Near Entrance Chest": 0x0FE613, + "Sala-Sala Top of the Pyramid Chest": 0x0FE658, + "Sala-Sala Up Jab Chest": 0x0FE62A, + "Sala-Sala All Blocks Chest": 0x0FE66F, + "Sala-Sala Farthest Chest": 0x0FE686, + "Sala-Sala Elevator Chest": 0x0FE6B4, + "Sala-Sala Shrine Chest": 0x08261A, + "Mummy Chest": 0x08261C, + + "Fuwa-Fuwa Block Maze Chest": 0x0FEF93, + "Fuwa-Fuwa Moon Block Chest": 0x0FEFAA, + "Fuwa-Fuwa Light Block Chest": 0x0FEFC1, + "Fuwa-Fuwa Bridge Room Chest": 0x0FEFD8, #??? + "Fuwa-Fuwa Balance Platforms Chest": 0x0FEFEF, #Cast doubt on this + "Hawk Chest": 0x08261E, + + "Muscle Lizard Chest": 0x082620, + "Ice Cave Chest": 0x082622, + "Desert Island Chest": 0x082624, + "Overworld Tomb Chest": 0x082626, + "Northern Cave Chest": 0x082628, + "Saber Tooth Chest": 0x08262A, + "300 Coin Shop": 0x08262C, + "500 Coin Shop": 0x08262E, + "100 Coin Shop": 0x082630, + + "Casino 5000 Coin Purchase": 0x082632, + "Casino 3000 Coin Purchase": 0x082634, + "Casino 2000 Coin Purchase": 0x082636, + "Casino 1000 Coin Purchase": 0x082638, + "Casino 500 Coin Purchase": 0x08263A, + "Waku-Waku King's Gift": 0x08263A +} + +plain_encoding_table = { +'0': ([0x01, 0x00]), +'1': ([0x02, 0x00]), +'2': ([0x03, 0x00]), +"3": ([0x04, 0x00]), +"4": ([0x05, 0x00]), +"5": ([0x06, 0x00]), +"6": ([0x07, 0x00]), +"7": ([0x08, 0x00]), +"8": ([0x09, 0x00]), +"9": ([0x0A, 0x00]), +"·": ([0x13, 0x00]), +"◦": ([0x14, 0x00]), +#",": ([0x15, 0x00]), +"~": ([0x16, 0x00]), +"—": ([0x17, 0x00]), +"A": ([0x19, 0x00]), +"B": ([0x1A, 0x00]), +"C": ([0x1B, 0x00]), +"D": ([0x1C, 0x00]), +"E": ([0x1D, 0x00]), +"F": ([0x1E, 0x00]), +"G": ([0x1F, 0x00]), +"H": ([0x20, 0x00]), +"I": ([0x21, 0x00]), +"J": ([0x22, 0x00]), +"K": ([0x23, 0x00]), +"L": ([0x24, 0x00]), +"M": ([0x25, 0x00]), +"N": ([0x26, 0x00]), +"O": ([0x27, 0x00]), +"P": ([0x28, 0x00]), +"Q": ([0x29, 0x00]), +"R": ([0x2A, 0x00]), +"S": ([0x2B, 0x00]), +"T": ([0x2C, 0x00]), +"U": ([0x2D, 0x00]), +"V": ([0x2E, 0x00]), +"W": ([0x2F, 0x00]), +"X": ([0x30, 0x00]), +"Y": ([0x31, 0x00]), +"Z": ([0x32, 0x00]), +"&": ([0x33, 0x00]), +" ": ([0x00, 0x01]), +"a": ([0x01, 0x01]), +"b": ([0x02, 0x01]), +"c": ([0x03, 0x01]), +"d": ([0x04, 0x01]), +"e": ([0x05, 0x01]), +"f": ([0x06, 0x01]), +"g": ([0x07, 0x01]), +"h": ([0x08, 0x01]), +"i": ([0x09, 0x01]), +"j": ([0x0A, 0x01]), +"k": ([0x0B, 0x01]), +"l": ([0x0C, 0x01]), +"m": ([0x0D, 0x01]), +"n": ([0x0E, 0x01]), +"o": ([0x0F, 0x01]), +"p": ([0x10, 0x01]), +"q": ([0x11, 0x01]), +"r": ([0x12, 0x01]), +"s": ([0x13, 0x01]), +"t": ([0x14, 0x01]), +"u": ([0x15, 0x01]), +"v": ([0x16, 0x01]), +"w": ([0x17, 0x01]), +"x": ([0x18, 0x01]), +"y": ([0x19, 0x01]), +"z": ([0x1A, 0x01]), +"!": ([0x1B, 0x01]), +"?": ([0x1C, 0x01]), +"Γ": ([0x1D, 0x01]), +"⅃": ([0x1E, 0x01]), +"(": ([0x1F, 0x01]), +")": ([0x20, 0x01]), +"'": ([0x21, 0x01]), +":": ([0x22, 0x01]), +";": ([0x23, 0x01]), +"-": ([0x24, 0x01]), +",": ([0x26, 0x01]), +".": ([0x27, 0x01]), +"<": ([0x28, 0x01]), +">": ([0x29, 0x01]), +'"': ([0x2A, 0x01]), +"/": ([0x2B, 0x01]), +"+": ([0x2C, 0x01]) +} + +hud_encoding_table = { + "A": ([0x50, 0x2C]), + "B": ([0x51, 0x2C]), + "C": ([0x52, 0x2C]), + "D": ([0x53, 0x2C]), + "E": ([0x54, 0x2C]), + "F": ([0x55, 0x2C]), + "G": ([0x56, 0x2C]), + "H": ([0x57, 0x2C]), + "I": ([0x58, 0x2C]), + "J": ([0x59, 0x2C]), + "K": ([0x5A, 0x2C]), + "L": ([0x5B, 0x2C]), + "M": ([0x5C, 0x2C]), + "N": ([0x5D, 0x2C]), + "O": ([0x5E, 0x2C]), + "P": ([0x5F, 0x2C]), + "Q": ([0x60, 0x2C]), + "R": ([0x61, 0x2C]), + "S": ([0x62, 0x2C]), + "T": ([0x63, 0x2C]), + "U": ([0x64, 0x2C]), + "V": ([0x65, 0x2C]), + "W": ([0x66, 0x2C]), + "X": ([0x67, 0x2C]), + "Y": ([0x68, 0x2C]), + "Z": ([0x69, 0x2C]), + "'": ([0x6A, 0x2C]), + "&": ([0x6B, 0x2C]), + "/": ([0x6C, 0x2C]), + ":": ([0x6D, 0x2C]), + "-": ([0x7E, 0x2C]), + "+": ([0x7F, 0x2C]), + "~": ([0x8B, 0x2C]), + "!": ([0x8C, 0x2C]), + ".": ([0x8D, 0x2C]), + "?": ([0x8F, 0x2C]), + " ": ([0x90, 0x28]), + "0": ([0xA0, 0x2C]), + "1": ([0xA1, 0x2C]), + "2": ([0xA2, 0x2C]), + "3": ([0xA3, 0x2C]), + "4": ([0xA4, 0x2C]), + "5": ([0xA5, 0x2C]), + "6": ([0xA6, 0x2C]), + "7": ([0xA7, 0x2C]), + "8": ([0xA8, 0x2C]), + "9": ([0xA9, 0x2C]) + } + +scout_location_map = { + 0x8893: 0x5A1000, + 0x8B4A: 0x5A1001, + 0x8D90: 0x5A1002, + 0x8DD3: 0x5A1003, + 0x8E25: 0x5A1004, + 0x8E41: 0x5A1005, + 0x8E7B: 0x5A1006, + 0x9081: 0x5A1007, + 0x909D: 0x5A1008, + 0x911D: 0x5A1009, + + 0xC7BA: 0x5A100B, + 0xC7D1: 0x5A100C, + 0xC7E8: 0x5A100D, + 0xC7FF: 0x5A100E, + 0xC817: 0x5A100F, + 0xC82D: 0x5A1010, + 0xC844: 0x5A1011, + + 0xB565: 0x5A1014, + 0xB581: 0x5A1015, + 0xB59D: 0x5A1016, + 0xB62B: 0x5A1017, + 0xB5D5: 0x5A1018, + 0xB5F3: 0x5A1019, + 0xB60D: 0x5A101A, + 0xB5B9: 0x5A101B, + 0xB645: 0x5A101C, + 0xB65C: 0x5A101D, + + 0xD59E: 0x5A101F, + 0xD5B5: 0x5A1020, + 0xD5CC: 0x5A1021, + 0xD5E3: 0x5A1022, + 0xD5FA: 0x5A1023, + 0xD611: 0x5A1024, + 0xD628: 0x5A1025, + 0xD63F: 0x5A1026, + 0xD656: 0x5A1027, + 0xD66D: 0x5A1028, + 0xD684: 0x5A1029, + + 0xE613: 0x5A102B, + 0xE62A: 0x5A102C, + 0xE641: 0x5A102D, + 0xE658: 0x5A102E, + 0xE66F: 0x5A102F, + 0xE686: 0x5A1030, + 0xE69B: 0x5A1031, + 0xE6B4: 0x5A1032, + + 0xEF93: 0x5A1035, + 0xEFAA: 0x5A1036, + 0xEFC1: 0x5A1037, + 0x0FD8: 0x5A1038, + 0xEFEF: 0x5A1039 +} + +special_chests = { + 0xB4E6: 0x5A103B,#Special chests need separate mapping + 0xFEBF: 0x5A103C, + 0xB14D: 0x5A103E, + 0xB0F7: 0x5A103F, + 0xA781: 0x5A1041, + 0xC9D4: 0x5A1040, + 0xE5A1: 0x5A100A, + 0xE12A: 0x5A1012, + 0xEE4C: 0x5A1013, + 0xAC15: 0x5A102A, + 0xF441: 0x5A101E, + 0xB0A1: 0x5A1033, + 0xAA49: 0x5A1034, + 0x8284: 0x5A103A +} + +shop_scouts = { + 0xA7D7: 0x5A1042, + 0xA82D: 0x5A1043, + 0xA883: 0x5A103D +} + + +shop_items = { + "Life Bottle": [0x27, 0x03], + "Magic Bottle": [0x28, 0x03], + "500 Coins": [0x29, 0x03], + "1000 Coins": [0x2A, 0x03], + "2000 Coins": [0x2B, 0x03], + "5000 Coins": [0x2C, 0x03], + + "Silver Sword": [0x00, 0x03], + "Fire Sword": [0x01, 0x03], + "Ice Sword": [0x02, 0x03], + "Thunder Sword": [0x03, 0x03], + "Crystal Sword": [0x04, 0x03], + "Power Sword": [0x05, 0x03], + "Light Sword": [0x06, 0x03], + "Dagger": [0x07, 0x03], + "Fireballs": [0x08, 0x03], + "Boomerang": [0x09, 0x03], + "Ax": [0x0A, 0x03], + "Shovel": [0x0B, 0x03], + + "Fire Armor": [0x0C, 0x03], + "Ice Armor": [0x0D, 0x03], + "Aqua Armor": [0x0E, 0x03], + "Light Armor": [0x0F, 0x03], + + "Fire Shield": [0x10, 0x03], + "Ice Shield": [0x11, 0x03], + "Aqua Shield": [0x12, 0x03], + "Light Shield": [0x13, 0x03], + + "Wand": [0x14, 0x03], + "Ice Bell": [0x15, 0x03], + "Sun Ring": [0x16, 0x03], + "Power Fan": [0x17, 0x03], + "Elven Flute": [0x18, 0x03], + "Sky Bell": [0x19, 0x03], + "Light Stone": [0x1A, 0x03], + "Sun Stone": [0x1B, 0x03], + "Star Stone": [0x1C, 0x03], + "Aqua Stone": [0x1D, 0x03], + "Moon Stone": [0x1E, 0x03], + + "Light Spell": [0x1F, 0x03], + "Sun Spell": [0x20, 0x03], + "Star Spell": [0x21, 0x03], + "Aqua Spell": [0x22, 0x03], + "Moon Spell": [0x23, 0x03], + + "Shove": [0x24, 0x03], + "Up Jab": [0x25, 0x03], + "Down Jab": [0x26, 0x03] +} + +location_list = [ + 0x5A1000, + 0x5A1001, + 0x5A1002, + 0x5A1003, + 0x5A1004, + 0x5A1005, + 0x5A1006, + 0x5A1007, + 0x5A1008, + 0x5A1009, + 0x5A100A, + 0x5A100B, + 0x5A100C, + 0x5A100D, + 0x5A100E, + 0x5A100F, + 0x5A1010, + 0x5A1011, + 0x5A1012, + 0x5A1013, + 0x5A1014, + 0x5A1015, + 0x5A1016, + 0x5A1017, + 0x5A1018, + 0x5A1019, + 0x5A101A, + 0x5A101B, + 0x5A101C, + 0x5A101D, + 0x5A101E, + 0x5A101F, + 0x5A1020, + 0x5A1021, + 0x5A1022, + 0x5A1023, + 0x5A1024, + 0x5A1025, + 0x5A1026, + 0x5A1027, + 0x5A1028, + 0x5A1029, + 0x5A102A, + 0x5A102B, + 0x5A102C, + 0x5A102D, + 0x5A102E, + 0x5A102F, + 0x5A1030, + 0x5A1031, + 0x5A1032, + 0x5A1033, + 0x5A1034, + 0x5A1035, + 0x5A1036, + 0x5A1037, + 0x5A1038, + 0x5A1039, + 0x5A103A, + 0x5A103B, + 0x5A103C, + 0x5A103D, + 0x5A103E, + 0x5A103F, + 0x5A1040, + 0x5A1041, + 0x5A1042, + 0x5A1043, + 0x5A1045, + 0x5A1046, + 0x5A1047, + 0x5A1048, + 0x5A1049 +] + +sprite_visuals = { + "Life Bottle": [0x00], + "Magic Bottle": [0x01], + "500 Coins": [0x02], + "1000 Coins": [0x03], + "2000 Coins": [0x10], + "5000 Coins": [0x15], + + "Silver Sword": [0x04], + "Fire Sword": [0x05], + "Ice Sword": [0x06], + "Thunder Sword": [0x07], + "Crystal Sword": [0x08], + "Power Sword": [0x09], + "Light Sword": [0x0A], + "Dagger": [0x0B], + "Fireballs": [0x0C], + "Boomerang": [0x0D], + "Ax": [0x0E], + "Shovel": [0x0F], + + "Fire Armor": [0x11], + "Ice Armor": [0x12], + "Aqua Armor": [0x13], + "Light Armor": [0x14], + + "Fire Shield": [0x16], + "Ice Shield": [0x17], + "Aqua Shield": [0x18], + "Light Shield": [0x19], + + "Wand": [0x1A], + "Ice Bell": [0x1C], + "Sun Ring": [0x1D], + "Power Fan": [0x1E], + "Elven Flute": [0x1F], + "Sky Bell": [0x20], + "Light Stone": [0x21], + "Sun Stone": [0x22], + "Star Stone": [0x23], + "Aqua Stone": [0x24], + "Moon Stone": [0x25], + + "Light Spell": [0x26], + "Sun Spell": [0x27], + "Star Spell": [0x28], + "Aqua Spell": [0x29], + "Moon Spell": [0x2A], + + "Shove": [0x2B], + "Up Jab": [0x2B], + "Down Jab": [0x2B] + +} \ No newline at end of file diff --git a/worlds/sai2/setup_game.py b/worlds/sai2/setup_game.py new file mode 100644 index 000000000000..f10e26f13005 --- /dev/null +++ b/worlds/sai2/setup_game.py @@ -0,0 +1,88 @@ +import struct + + +def setup_gamevars(world): + if world.options.switch_states == 0: + world.light_switch_default = 0x00 + world.sun_switch_default = 0x01 + world.star_switch_default = 0x01 + world.aqua_switch_default = 0x01 + world.moon_switch_default = 0x00 + elif world.options.switch_states == 1: + world.light_switch_default = 0x01 + world.sun_switch_default = 0x00 + world.star_switch_default = 0x00 + world.aqua_switch_default = 0x00 + world.moon_switch_default = 0x01 + else: + world.light_switch_default = world.random.randint(0,1) + world.sun_switch_default = world.random.randint(0,1) + world.star_switch_default = world.random.randint(0,1) + world.aqua_switch_default = world.random.randint(0,1) + world.moon_switch_default = world.random.randint(0,1) + + if world.options.world_state == 2: + world.light_gate = world.random.randint(0,1) + world.sun_gate = world.random.randint(0,1) + world.star_gate = world.random.randint(0,1) + world.aqua_gate = world.random.randint(0,1) + world.moon_gate = world.random.randint(0,1) + else: + world.light_gate = world.options.world_state + world.sun_gate = world.options.world_state + world.star_gate = world.options.world_state + world.aqua_gate = world.options.world_state + world.moon_gate = world.options.world_state + + if world.options.shortcut_states == 2: + world.boa_hiya_shortcut = world.random.randint(0,1) + world.sala_hiya_shortcut = world.random.randint(0,1) + world.sala_puka_shortcut = world.random.randint(0,1) + world.fuwa_poka_shortcut = world.random.randint(0,1) + world.fuwa_puka_shortcut = world.random.randint(0,1) + else: + world.boa_hiya_shortcut = world.options.world_state + world.sala_hiya_shortcut = world.options.world_state + world.sala_puka_shortcut = world.options.world_state + world.fuwa_poka_shortcut = world.options.world_state + world.fuwa_puka_shortcut = world.options.world_state + if world.options.shortcut_states >= 3: + world.fuwa_poka_shortcut = 0 + world.fuwa_puka_shortcut = 0 + + + early_logic_items = [ + "Silver Sword", + "Shovel" + ] + + if world.light_gate == 0: + early_logic_items.append("Light Stone") + else: + early_logic_items.extend(["Life Bottle", "Sun Ring"]) + if world.sun_gate == 1: + early_logic_items.extend(["Shove", "500 Coins", "1000 Coins", "2000 Coins", "5000 Coins"]) + if world.star_gate == 0: + early_logic_items.append("Star Stone") + else: + early_logic_items.append("Sun Stone") + + if world.aqua_gate == 0: + early_logic_items.append("Aqua Stone") + else: + early_logic_items.extend(["1000 Coins", "2000 Coins", "5000 Coins"]) + if world.moon_gate == 0: + early_logic_items.append("Moon Stone") + + for item in early_logic_items: + if early_logic_items.count(item) > 1 or (item == "Life Bottle" and world.options.extra_health == 1): + early_logic_items.remove(item) + + + if world.options.world_state != 1: + #If one, append the Stones corresponding to closed gates + world.starting_item = world.random.choice(early_logic_items) + + world.locked_skills = ["Shove", "Down Jab", "Up Jab"] + if world.options.shuffle_skills == 1: + world.locked_skills.shuffle \ No newline at end of file From 7c0a35080fab285315ffd06295d6ea7633e9d9b2 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:52:56 -0500 Subject: [PATCH 10/30] Delete worlds/sai2 directory --- worlds/sai2/Client.py | 225 --------- worlds/sai2/Items.py | 99 ---- worlds/sai2/Locations.py | 118 ----- worlds/sai2/Options.py | 93 ---- worlds/sai2/Regions.py | 143 ------ worlds/sai2/Rom.py | 874 ---------------------------------- worlds/sai2/Rules.py | 99 ---- worlds/sai2/__init__.py | 293 ------------ worlds/sai2/extended_logic.py | 99 ---- worlds/sai2/local_data.py | 546 --------------------- worlds/sai2/setup_game.py | 88 ---- 11 files changed, 2677 deletions(-) delete mode 100644 worlds/sai2/Client.py delete mode 100644 worlds/sai2/Items.py delete mode 100644 worlds/sai2/Locations.py delete mode 100644 worlds/sai2/Options.py delete mode 100644 worlds/sai2/Regions.py delete mode 100644 worlds/sai2/Rom.py delete mode 100644 worlds/sai2/Rules.py delete mode 100644 worlds/sai2/__init__.py delete mode 100644 worlds/sai2/extended_logic.py delete mode 100644 worlds/sai2/local_data.py delete mode 100644 worlds/sai2/setup_game.py diff --git a/worlds/sai2/Client.py b/worlds/sai2/Client.py deleted file mode 100644 index fdd3a91df370..000000000000 --- a/worlds/sai2/Client.py +++ /dev/null @@ -1,225 +0,0 @@ -import logging -import struct -import typing -import time -from struct import pack -from .local_data import location_list, scout_location_map, plain_encoding_table, shop_scouts, special_chests, hud_encoding_table, sprite_visuals - -from NetUtils import ClientStatus, color -from worlds.AutoSNIClient import SNIClient - -if typing.TYPE_CHECKING: - from SNIClient import SNIContext -else: - SNIContext = typing.Any - -snes_logger = logging.getLogger("SNES") - -ROM_START = 0x000000 -WRAM_START = 0xF50000 -WRAM_SIZE = 0x20000 -SRAM_START = 0xE00000 - -SAI2_ROMHASH_START = 0x00FFC0 -ROMHASH_SIZE = 0x15 - -ITEMQUEUE_HIGH = WRAM_START + 0x4D6 -ITEM_RECEIVED = WRAM_START + 0x0485 -DEMO_FLAG = WRAM_START + 0x03F5 -CHEST_SCOUT_MODE = WRAM_START + 0x04F9 -SPECIAL_CHEST_SCOUT = SRAM_START + 0x7DE7 -LOCATIONS_SCOUTED_FLAG = WRAM_START + 0x04C4 -IN_GAME = WRAM_START + 0x045A -GOALFLAG = WRAM_START + 0x0034 - -SHOP_SCOUTS = [0xA7D7, 0xA82D, 0xA883] - -class SAI2SNIClient(SNIClient): - game = "Super Adventure Island II" - - async def validate_rom(self, ctx): - from SNIClient import snes_buffered_write, snes_flush_writes, snes_read - - rom_name = await snes_read(ctx, SAI2_ROMHASH_START, ROMHASH_SIZE) - if rom_name is None or rom_name[:6] != b"SAI2AP": - return False - - ctx.game = self.game - ctx.items_handling = 0b001 - ctx.rom = rom_name - return True - - async def game_watcher(self, ctx): - from SNIClient import snes_buffered_write, snes_flush_writes, snes_read - item_received = await snes_read(ctx, ITEM_RECEIVED, 0x1) - goal_flag = await snes_read(ctx, GOALFLAG, 0x1) - scout_flag = await snes_read(ctx, CHEST_SCOUT_MODE, 2) - scout_id = struct.unpack("H", scout_flag)[0] - special_scout_flag = await snes_read(ctx, SPECIAL_CHEST_SCOUT, 2) - special_scout_id = struct.unpack("H", special_scout_flag)[0] - in_game = await snes_read(ctx, IN_GAME, 0x1) - locations_scouted_flag = await snes_read(ctx, LOCATIONS_SCOUTED_FLAG, 0x1) - - if in_game is None: - return - - elif in_game[0] != 0x01: - return - - elif item_received[0] > 0x00: - return - - from .Rom import input_item_ids - rom = await snes_read(ctx, SAI2_ROMHASH_START, ROMHASH_SIZE) - if rom != ctx.rom: - ctx.rom = None - return - - if goal_flag[0] != 0x00: - await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) - ctx.finished_game = True - - if locations_scouted_flag[0] == 0x00: - for location in location_list: - await ctx.send_msgs([{"cmd": 'LocationScouts', "locations": location_list, "create_as_hint": 0}]) - snes_buffered_write(ctx, WRAM_START + 0x04C4, bytes([0x01])) - - if scout_id != 0x0000: - scout_id = hex(scout_id) - scout_id = scout_id[2:] - scout_id = int(scout_id, 16) - if scout_id in scout_location_map: - location = ctx.locations_info[scout_location_map[scout_id]] #convert the stored internal ID to the corresponding AP location id - item = ctx.item_names[location.item] - if item in sprite_visuals: - local_sprite = bytearray(0) - local_sprite.extend(sprite_visuals[item]) - snes_buffered_write(ctx, WRAM_START + 0x04FC, local_sprite)#If the item is a nonlocal SAI2 item, use its in-game sprite but act like an ap item - snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x01])) - else: - snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x00])) - item = item.upper() - sai2_item = bytearray(0) - for char in item: - if char in hud_encoding_table: - sai2_item.extend (hud_encoding_table[char]) - else: - sai2_item.extend ([0x8F, 0x2C]) - if len(item) <= 16: - for _ in range(16 - len(item)): - sai2_item.extend([0x90, 0x28]) - snes_buffered_write(ctx, SRAM_START + 0x7E4D, sai2_item)#write item name as ingame text - snes_buffered_write(ctx, CHEST_SCOUT_MODE, bytes([0x00])) - snes_buffered_write(ctx, CHEST_SCOUT_MODE + 1, bytes([0x00])) - - if special_scout_id != 0x000: - special_scout_id = hex(special_scout_id) - special_scout_id = special_scout_id[2:] - special_scout_id = int(special_scout_id, 16) - print(special_scout_id) - if special_scout_id in shop_scouts: - location = ctx.locations_info[shop_scouts[special_scout_id]] #I can probably make a function out of this and the normal one - item = ctx.item_names[location.item] - item = item[:21] - player = ctx.player_names[location.player] - player = player[:21] - sai2_item = bytearray(0) - sai2_player = bytearray(0) - for char in item: #I can probably make a function out of this - if char in plain_encoding_table: - sai2_item.extend (plain_encoding_table[char]) - else: - sai2_item.extend ([0x8F, 0x2C]) - sai2_item.extend([0xFF, 0x03]) - for char in player: #I can probably make a function out of this - if char in plain_encoding_table: - sai2_player.extend (plain_encoding_table[char]) - else: - sai2_player.extend ([0x8F, 0x2C]) - - sai2_player.extend([0xFF, 0x03]) - snes_buffered_write(ctx, SRAM_START + 0x7DF0, sai2_item)#write item name as ingame text - snes_buffered_write(ctx, SRAM_START + 0x7E44, sai2_player)#write item name as ingame text - elif special_scout_id in special_chests: - location = ctx.locations_info[special_chests[special_scout_id]] #I can probably make a function out of this and the normal one - print(location) - item = ctx.item_names[location.item] - if item in sprite_visuals: - print(item) - local_sprite = bytearray(0) - local_sprite.extend(sprite_visuals[item]) - print(local_sprite) - snes_buffered_write(ctx, WRAM_START + 0x04FC, local_sprite)#If the item is a nonlocal SAI2 item, use its in-game sprite but act like an ap item - snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x01])) - else: - snes_buffered_write(ctx, WRAM_START + 0x04FB, bytes([0x00])) - item = item.upper() - sai2_item = bytearray(0) - for char in item: - if char in hud_encoding_table: - sai2_item.extend (hud_encoding_table[char]) - else: - sai2_item.extend ([0x8F, 0x2C]) - if len(item) <= 16: - for _ in range(16 - len(item)): - sai2_item.extend([0x90, 0x28]) - snes_buffered_write(ctx, SRAM_START + 0x7E4D, sai2_item)#write item name as ingame text - snes_buffered_write(ctx, SPECIAL_CHEST_SCOUT, bytes([0x00])) - snes_buffered_write(ctx, SPECIAL_CHEST_SCOUT + 1, bytes([0x00])) - - new_checks = [] - from .Rom import location_flag_table - - location_ram_data = await snes_read(ctx, WRAM_START + 0x460, 0xF0) - for loc_id, loc_data in location_flag_table.items(): - if loc_id not in ctx.locations_checked: - data = location_ram_data[loc_data[0] - 0x460] - 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] - snes_logger.info( - f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})') - await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) - - 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 input_item_ids: - item_count = await snes_read(ctx, WRAM_START + input_item_ids[item.item][0], 0x1) - increment = input_item_ids[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 + input_item_ids[item.item][0], bytes([new_item_count])) - await snes_flush_writes(ctx) - -def get_shop_text(special_id, ctx, SRAM_START): - location = ctx.locations_info[shop_scouts[special_id]] - item = ctx.item_names[location.item] - player = ctx.player_names[location.player] - sai2_item = bytearray(0) - for char in item: - if char in hud_encoding_table: - sai2_item.extend (hud_encoding_table[char]) - else: - sai2_item.extend ([0x8F, 0x2C]) - if len(item) <= 16: - for _ in range(16 - len(item)): - sai2_item.extend([0x90, 0x28]) - snes_buffered_write(ctx, SRAM_START + 0x7E4D, sai2_item)#write item name as ingame text \ No newline at end of file diff --git a/worlds/sai2/Items.py b/worlds/sai2/Items.py deleted file mode 100644 index c65b8358822f..000000000000 --- a/worlds/sai2/Items.py +++ /dev/null @@ -1,99 +0,0 @@ -from typing import Dict, Set, Tuple, NamedTuple, Optional - -class ItemData(NamedTuple): - category: str - code: int - classification: str - amount: Optional[int] = 1 - -item_table: Dict[str, ItemData] = { - 'Silver Sword': ItemData('Swords', 0x5A1000, "progression"), - 'Fire Sword': ItemData('Swords', 0x5A1001, "progression"), - 'Ice Sword': ItemData('Swords', 0x5A1002, "progression"), - 'Thunder Sword': ItemData('Swords', 0x5A1003, "progression"), - 'Crystal Sword': ItemData('Swords', 0x5A1004, "progression"), - 'Power Sword': ItemData('Swords', 0x5A1005, "progression"), - 'Light Sword': ItemData('Swords', 0x5A1006, "progression", 0), - 'Dagger': ItemData('Projectiles', 0x5A1007, "progression"), - 'Fireballs': ItemData('Projectiles', 0x5A1008, "progression"), - 'Boomerang': ItemData('Projectiles', 0x5A1009, "progression", 0), - 'Ax': ItemData('Projectiles', 0x5A100A, "progression"), - 'Shovel': ItemData('Items', 0x5A100B, "progression"), - - 'Fire Armor': ItemData('Armor', 0x5A100C, "progression"), - 'Ice Armor': ItemData('Armor', 0x5A100D, "progression"), - 'Aqua Armor': ItemData('Armor', 0x5A100E, "progression"), - 'Light Armor': ItemData('Armor', 0x5A100F, "progression", 0), - - 'Fire Shield': ItemData('Shields', 0x5A1010, "useful"), - 'Ice Shield': ItemData('Shields', 0x5A1011, "useful"), - 'Aqua Shield': ItemData('Shields', 0x5A1012, "useful"), - 'Light Shield': ItemData('Shields', 0x5A1013, "useful", 0), - - 'Wand': ItemData('Equipment', 0x5A1014, "progression"), - 'Ice Bell': ItemData('Equipment', 0x5A1015, "progression"), - 'Sun Ring': ItemData('Equipment', 0x5A1016, "progression"), - 'Power Fan': ItemData('Equipment', 0x5A1017, "progression"), - 'Elven Flute': ItemData('Equipment', 0x5A1018, "progression"), - 'Sky Bell': ItemData('Equipment', 0x5A1019, "progression"), - 'Light Stone': ItemData('Equipment', 0x5A101A, "progression"), - 'Sun Stone': ItemData('Equipment', 0x5A101B, "progression"), - 'Star Stone': ItemData('Equipment', 0x5A101C, "progression"), - 'Aqua Stone': ItemData('Equipment', 0x5A101D, "progression"), - 'Moon Stone': ItemData('Equipment', 0x5A101E, "progression"), - - 'Light Spell': ItemData('Spells', 0x5A101F, "progression"), - 'Star Spell': ItemData('Spells', 0x5A1020, "progression"), - 'Sun Spell': ItemData('Spells', 0x5A1021, "progression"), - 'Aqua Spell': ItemData('Spells', 0x5A1022, "progression"), - 'Moon Spell': ItemData('Spells', 0x5A1023, "progression"), - - 'Shove': ItemData('Skills', 0x5A1024, "progression"), - 'Up Jab': ItemData('Skills', 0x5A1025, "progression"), - 'Down Jab': ItemData('Skills', 0x5A1026, "progression"), - - 'Life Bottle': ItemData('Upgrades', 0x5A1027, "progression", 9), - 'Magic Bottle': ItemData('Upgrades', 0x5A1028, "useful", 13), - - '500 Coins': ItemData('Coins', 0x5A1029, "progression", 2), - '1000 Coins': ItemData('Coins', 0x5A102A, "progression", 5), - '2000 Coins': ItemData('Coins', 0x5A102B, "progression", 3), - '5000 Coins': ItemData('Coins', 0x5A102C, "progression", 1), - - 'Light Switch': ItemData('Events', None, "progression", 0), - 'Sun Switch': ItemData('Events', None, "progression", 0), - 'Star Switch': ItemData('Events', None, "progression", 0), - 'Aqua Switch': ItemData('Events', None, "progression", 0), - 'Moon Switch': ItemData('Events', None, "progression", 0), - 'Puka-Puka Drained': ItemData('Events', None, "progression", 0), - 'Tina': ItemData('Events', None, "progression", 0), - 'Boa-Hiya Shortcut Open': ItemData('Events', None, "progression", 0), - 'Sala-Hiya Shortcut Open': ItemData('Events', None, "progression", 0), - 'Sala-Puka Shortcut Open': ItemData('Events', None, "progression", 0), - 'Fuwa-Poka Shortcut Open': ItemData('Events', None, "progression", 0), - 'Fuwa-Puka Shortcut Open': ItemData('Events', None, "progression", 0), - - 'Light Gate Lowered': ItemData('Events', None, "progression", 0), - 'Sun Gate Lowered': ItemData('Events', None, "progression", 0), - 'Star Gate Lowered': ItemData('Events', None, "progression", 0), - 'Aqua Gate Lowered': ItemData('Events', None, "progression", 0), - 'Moon Gate Lowered': ItemData('Events', None, "progression", 0), -} - -filler_items: Tuple[str, ...] = ( - '500 Coins', - '1000 Coins', - '2000 Coins', - '5000 Coins', - 'Life Bottle', - 'Magic Bottle' -) - -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/sai2/Locations.py b/worlds/sai2/Locations.py deleted file mode 100644 index 170a519fd495..000000000000 --- a/worlds/sai2/Locations.py +++ /dev/null @@ -1,118 +0,0 @@ -from typing import List, Tuple, Optional, Callable, NamedTuple -from BaseClasses import MultiWorld - - -class LocationData(NamedTuple): - region: str - name: str - code: Optional[int] - rule: Callable = lambda state: True - - -def get_locations(world) -> Tuple[LocationData, ...]: - - location_table: Tuple[LocationData, ...] = [ - - LocationData('Poka-Poka Island', 'Poka-Poka Lake Chest', 0x5A1000), - LocationData('Poka-Poka East', 'Poka-Poka Tree Chest', 0x5A1001), - LocationData('Poka-Poka Island', 'Poka-Poka Digging Chest', 0x5A1002), - LocationData('Poka-Poka East', 'Poka-Poka Pushable Rock Chest', 0x5A1003), - LocationData('Poka-Poka East', 'Poka-Poka Sun Blocks Chest', 0x5A1004), - LocationData('Poka-Poka East', 'Poka-Poka East Cave Chest', 0x5A1005), - LocationData('Poka-Poka Island', 'Poka-Poka West Cave Chest', 0x5A1006), - LocationData('Poka-Poka East', 'Poka-Poka Moon Alcove Chest', 0x5A1007), - LocationData('Poka-Poka East', 'Poka-Poka Down Blocks Chest', 0x5A1008), - LocationData('Poka-Poka East', 'Poka-Poka Shrine Chest', 0x5A1009), - LocationData('Poka-Poka East', 'Evil Tree Chest', 0x5A100A), - - LocationData('Boa-Boa Island', 'Boa-Boa Clouds Chest', 0x5A100B), - LocationData('Boa-Boa Island', 'Boa-Boa Sun Alcove Chest', 0x5A100C), - LocationData('Boa-Boa Island', 'Boa-Boa Sun Block Chest', 0x5A100D), - LocationData('Boa-Boa Island', 'Boa-Boa Lava Lake West Chest', 0x5A100E), - LocationData('Boa-Boa Island', 'Boa-Boa Lava Lake East Chest', 0x5A100F), - LocationData('Boa-Boa Island', 'Boa-Boa Western Shaft Chest', 0x5A1010), - LocationData('Boa-Boa Island', 'Boa-Boa Eastern Shaft Chest', 0x5A1011), - LocationData('Boa-Boa Island', 'Boa-Boa Shrine Chest', 0x5A1012), - LocationData('Boa-Boa Island', 'Tortoise Chest', 0x5A1013), - - LocationData('Hiya-Hiya Entrance', 'Hiya-Hiya Clouds Chest', 0x5A1014), - LocationData('Hiya-Hiya Underside', 'Hiya-Hiya Underground Chest', 0x5A1015), - LocationData('Hiya-Hiya Entrance', 'Hiya-Hiya Sun Blocks Chest', 0x5A1016), - LocationData('Hiya-Hiya Main', 'Hiya-Hiya Hidden Alcove Chest', 0x5A1017), - LocationData('Hiya-Hiya Main', 'Hiya-Hiya Up Block Alcove Chest', 0x5A1018), - LocationData('Hiya-Hiya Main', 'Hiya-Hiya Trapped Chest', 0x5A1019), - LocationData('Hiya-Hiya Main', 'Hiya-Hiya Ice Cubes Chest', 0x5A101A), - LocationData('Hiya-Hiya Main', 'Hiya-Hiya Long Fall Chest', 0x5A101B), - LocationData('Hiya-Hiya Back', 'Hiya-Hiya Vines Chest', 0x5A101C), - LocationData('Hiya-Hiya Back', 'Hiya-Hiya Shrine Chest', 0x5A101D), - LocationData('Hiya-Hiya Main', 'Mammoth Chest', 0x5A101E), - - LocationData('Puka-Puka Island', 'Puka-Puka Light Blocks Chest', 0x5A101F), - LocationData('Puka-Puka Island', 'Puka-Puka Down Jab Chest', 0x5A1020), - LocationData('Puka-Puka Island', 'Puka-Puka Star Blocks Chest', 0x5A1021), - LocationData('Puka-Puka Island', 'Puka-Puka Up Jab Chest', 0x5A1022), - LocationData('Puka-Puka Island', 'Puka-Puka Underwater Chest', 0x5A1023), - LocationData('Puka-Puka Island', 'Puka-Puka Aqua Blocks Chest', 0x5A1024), - LocationData('Puka-Puka Island', 'Puka-Puka Spike Maze Upper Chest', 0x5A1025), - LocationData('Puka-Puka Island', 'Puka-Puka Spike Maze Lower Chest', 0x5A1026), - LocationData('Puka-Puka Island', 'Puka-Puka Moving Platforms Chest', 0x5A1027), - LocationData('Puka-Puka Island', 'Puka-Puka Springs Chest', 0x5A1028), - LocationData('Puka-Puka Island', 'Puka-Puka Shrine Chest', 0x5A1029), - LocationData('Puka-Puka Island', 'Octopus Chest', 0x5A102A), - - LocationData('Sala-Sala Island', 'Sala-Sala Near Entrance Chest', 0x5A102B), - LocationData('Sala-Sala Island', 'Sala-Sala Up Jab Chest', 0x5A102C), - LocationData('Sala-Sala Island', 'Sala-Sala Star Alcove Chest', 0x5A102D), - LocationData('Sala-Sala Island', 'Sala-Sala Top of the Pyramid Chest', 0x5A102E), - LocationData('Sala-Sala Backside', 'Sala-Sala All Blocks Chest', 0x5A102F), - LocationData('Sala-Sala Backside', 'Sala-Sala Farthest Chest', 0x5A1030), - LocationData('Sala-Sala Island', 'Sala-Sala Pyramid Center Chest', 0x5A1031), - LocationData('Sala-Sala Backside', 'Sala-Sala Elevator Chest', 0x5A1032), - LocationData('Sala-Sala Backside', 'Sala-Sala Shrine Chest', 0x5A1033), - LocationData('Sala-Sala Backside', 'Mummy Chest', 0x5A1034), - - LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Block Maze Chest', 0x5A1035), - LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Moon Block Chest', 0x5A1036), - LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Light Block Chest', 0x5A1037), - LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Bridge Room Chest', 0x5A1038), - LocationData('Fuwa-Fuwa Island', 'Fuwa-Fuwa Balance Platforms Chest', 0x5A1039), - LocationData('Fuwa-Fuwa Island', 'Hawk Chest', 0x5A103A), - - LocationData('Western Sea', 'Muscle Lizard Chest', 0x5A103B), - LocationData('Northwestern Sea', 'Ice Cave Chest', 0x5A103C), - LocationData('Northwestern Sea', '100 Coin Shop', 0x5A103D), - LocationData('Northeastern Sea', 'Desert Island Chest', 0x5A103E), - LocationData('Northeastern Sea', 'Overworld Tomb Chest', 0x5A103F), - LocationData('Eastern Sea', 'Saber Tooth Chest', 0x5A1040), - LocationData('Eastern Sea', 'Northern Cave Chest', 0x5A1041), - LocationData('Eastern Sea', '300 Coin Shop', 0x5A1042), - LocationData('Eastern Sea', '500 Coin Shop', 0x5A1043), - #LocationData('Southern Sea', "Waku-Waku King's Gift", 0x5A1044), - LocationData("Curly's Casino", "Casino 500 Coin Purchase", 0x5A1045), - LocationData("Curly's Casino", "Casino 1000 Coin Purchase", 0x5A1046), - LocationData("Curly's Casino", "Casino 2000 Coin Purchase", 0x5A1047), - LocationData("Curly's Casino", "Casino 3000 Coin Purchase", 0x5A1048), - LocationData("Curly's Casino", "Casino 5000 Coin Purchase", 0x5A1049), - - LocationData("Poka-Poka Island", 'Poka-Poka First Cave', None), - LocationData("Boa-Boa Island", 'Boa-Boa Hidden Wall', None), - LocationData("Hiya-Hiya Main", 'Hiya-Hiya Top Level', None), - LocationData("Puka-Puka Switch Room", 'Puka-Puka Switch Room', None), - LocationData("Sala-Sala Island", 'Sala-Sala Switch Room', None), - LocationData("Puka-Puka Island", 'Puka-Puka Water Control', None), - LocationData("Fuwa-Fuwa Island", 'Phantom Defeat', None), - - LocationData("Boa-Boa Island", 'Boa-Hiya Shortcut Room', None), - LocationData("Sala-Sala Backside", 'Sala-Hiya Shortcut Room', None), - LocationData("Sala-Sala Island", 'Sala-Puka Shortcut Room', None), - LocationData("Fuwa-Fuwa Island", 'Fuwa-Puka Shortcut Room', None), - LocationData("Fuwa-Fuwa Island", 'Fuwa-Poka Shortcut Room', None), - - LocationData("Southern Sea", 'Light Gate', None), - LocationData("Western Sea", 'Sun Gate', None), - LocationData("Northwestern Sea", 'Star Gate', None), - LocationData("Southern Sea", 'Aqua Gate', None), - LocationData("Southeastern Sea", 'Moon Gate', None) - ] - - return location_table \ No newline at end of file diff --git a/worlds/sai2/Options.py b/worlds/sai2/Options.py deleted file mode 100644 index 3f59f0278bc0..000000000000 --- a/worlds/sai2/Options.py +++ /dev/null @@ -1,93 +0,0 @@ -from dataclasses import dataclass -from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, PerGameCommonOptions - -class WorldState(Choice): - """Closed: All 5 gates start closed. - Random Open: Opens 5 random gates by default. - Open: All 5 gates start open. - If not open, you will start with 1 random progression item.""" - display_name = "World State" - option_closed = 0 - option_open = 1 - option_random_open = 2 - default = 0 - -class ExtraStartingHealth(DefaultOnToggle): - """If enabled, you will start with two hearts rather than one.""" - display_name = "Extra Starting Health" - -class DisableRandomEncounters(DefaultOnToggle): - """Disables random encounters on the overworld map.""" - display_name = "No Random Encounters" - -class FastShovel(DefaultOnToggle): - """Allows easily swapping to the Shovel and back by pressing Select on the menu.""" - display_name = "Fast Shovel" - -class MagicQuickswap(DefaultOnToggle): - """Allows swapping between magic spells by pressing L and R.""" - display_name = "Magic Quickswap" - -class DefaultSwitchStates(Choice): - """Define the default state the Switches will be found in.""" - display_name = "Switch States" - option_normal = 0 - option_inverted = 1 - option_random_set = 2 - -class ShortcutStates(Choice): - """All Closed: All shortcuts start closed. - All Open: All Shortcuts start open. - Random Open: Ranom shortcuts start open. - Exclude Fuwa: Fuwa-Fuwa shortcuts will start closed regardless. - - Shortcuts that start open can be entered from their opposite side.""" - display_name = "Shortcuts" - option_all_closed = 0 - option_all_open = 1 - option_random_open = 2 - option_random_exclude_fuwa = 3 - option_all_exclude_fuwa = 4 - default = 0 - -class ForceSpells(Toggle): - """If enabled, the 5 island bosses will each lock 1 of the 5 Spells.""" - display_name = "Force Spells on Bosses" - -class CasinoChecks(Toggle): - """If enabled, will place the 5 items normally found in the Casino into the pool, - and add checks on their purchases. The prices have been severly reduced to reduce the amount of grinding, - but some may still be required.""" - display_name = "Casino Checks" - -class OpenFuwa(Toggle): - """If enabled, you will be able to access Fuwa-Fuwa Island without needing the 5 spells.""" - display_name = "Early Fuwa-Fuwa" - -class ShuffleSkills(Choice): - """Determines if the 3 techniques are in their normal location, shuffled amongst the 3 shops, or anywhere.""" - display_name = "Skills" - option_normal = 0 - option_shuffled = 1 - option_in_pool = 2 - -class SpellLockEnding(Toggle): - """If enabled, you will need to have the 5 Spells in order to use the Sky Bell and fight Phantom. Recommended to be used with 'Early Fuwa-Fuwa'.""" - display_name = "Locked Phantom" - - - -@dataclass -class SAI2Options(PerGameCommonOptions): - world_state: WorldState - switch_states: DefaultSwitchStates - shortcut_states: ShortcutStates - phantom_spells: SpellLockEnding - early_fuwa: OpenFuwa - shuffle_skills: ShuffleSkills - boss_spells: ForceSpells - casino_checks: CasinoChecks - extra_health: ExtraStartingHealth - disable_encounters: DisableRandomEncounters - fast_shovel: FastShovel - magic_swap: MagicQuickswap diff --git a/worlds/sai2/Regions.py b/worlds/sai2/Regions.py deleted file mode 100644 index c67e558456e3..000000000000 --- a/worlds/sai2/Regions.py +++ /dev/null @@ -1,143 +0,0 @@ -from typing import List, Dict, Tuple -from BaseClasses import MultiWorld, Region, Entrance, Location -from .Locations import LocationData -from .extended_logic import logic_helpers - -class SAI2Location(Location): - game: str = "Super Adventure Island II" - -def __init__(self, player: int, name: str = " ", address: int = None, parent=None): - super().__init__(player, name, address, parent) - - -def init_areas(world, locations: Tuple[LocationData, ...]): - multiworld = world.multiworld - player = world.player - location_cache = world.location_cache - logic = logic_helpers(world) - - locations_per_region = get_locations_per_region(locations) - - regions = [ - create_region(multiworld, player, locations_per_region, location_cache, 'Menu'), - create_region(multiworld, player, locations_per_region, location_cache, 'Southern Sea'), - create_region(multiworld, player, locations_per_region, location_cache, 'Western Sea'), - create_region(multiworld, player, locations_per_region, location_cache, 'Northwestern Sea'), - create_region(multiworld, player, locations_per_region, location_cache, 'Northeastern Sea'), - create_region(multiworld, player, locations_per_region, location_cache, 'Southeastern Sea'), - create_region(multiworld, player, locations_per_region, location_cache, 'Eastern Sea'), - create_region(multiworld, player, locations_per_region, location_cache, 'Poka-Poka Island'), - create_region(multiworld, player, locations_per_region, location_cache, 'Poka-Poka East'), - create_region(multiworld, player, locations_per_region, location_cache, 'Boa-Boa Island'), - create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Entrance'), - create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Underside'), - create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Main'), - create_region(multiworld, player, locations_per_region, location_cache, 'Hiya-Hiya Back'), - create_region(multiworld, player, locations_per_region, location_cache, 'Puka-Puka Island'), - create_region(multiworld, player, locations_per_region, location_cache, 'Puka-Puka Switch Room'), - create_region(multiworld, player, locations_per_region, location_cache, "Curly's Casino"), - create_region(multiworld, player, locations_per_region, location_cache, "Sala-Sala Island"), - create_region(multiworld, player, locations_per_region, location_cache, "Sala-Sala Backside"), - create_region(multiworld, player, locations_per_region, location_cache, "Fuwa-Fuwa Island") - - ] - multiworld.regions += regions - - multiworld.get_region('Menu', player).add_exits(["Southern Sea"]) - - multiworld.get_region('Southern Sea', player).add_exits(['Poka-Poka Island', 'Fuwa-Fuwa Island', 'Western Sea', 'Southeastern Sea'], - {'Fuwa-Fuwa Island': lambda state: logic.fuwa_access(state), #Fuwa island is in the south sea - 'Western Sea': lambda state: state.has("Light Gate Lowered", player), #Light gate - 'Southeastern Sea': lambda state: state.has("Aqua Gate Lowered", player)}) #Aqua gate - multiworld.get_region('Poka-Poka Island', player).add_exits(["Poka-Poka East"],{"Poka-Poka East": lambda state: state.has("Silver Sword", player)}) #Breakable rocks leading from the start to the back - multiworld.get_region('Poka-Poka East', player).add_exits(["Fuwa-Fuwa Island", "Poka-Poka Island"],{"Fuwa-Fuwa Island": lambda state: state.has_all({"Shovel", "Fuwa-Poka Shortcut Open"}, player)}) #Shortcut to Fuwa-Fuwa, poka can be reached always - multiworld.get_region('Western Sea', player).add_exits(['Boa-Boa Island', 'Northwestern Sea'], - {'Boa-Boa Island': lambda state: state.has("Sun Ring", player), #Sun ring opens island - 'Northwestern Sea': lambda state: state.has("Sun Gate Lowered", player)}) #Sun Gate - - multiworld.get_region('Boa-Boa Island', player).add_exits(['Western Sea', 'Hiya-Hiya Underside', 'Northwestern Sea', 'Hiya-Hiya Entrance'], - {'Western Sea': lambda state: state.has("Wand", player), #May not need wand. - 'Hiya-Hiya Underside': lambda state: state.has_all({"Shovel", "Fire Sword", "Boa-Hiya Shortcut Open"}, player),#Shortcut leads to this but blocked by an ice wall - 'Hiya-Hiya Entrance': lambda state: state.has_all({"Wand", "Shovel", "Shove", "Boa-Hiya Shortcut Open"}, player),#Same as above, but needs Wand to warp to the start - 'Northwestern Sea': lambda state: state.has_all({"Wand", "Shovel", "Boa-Hiya Shortcut Open"}, player)})#Same as above but doesn't need shove - multiworld.get_region('Northwestern Sea', player).add_exits(['Hiya-Hiya Entrance', 'Western Sea', 'Northeastern Sea'], - {'Hiya-Hiya Entrance': lambda state: state.has_all({"Ice Bell", "Shove"}, player), #Intended access - 'Western Sea': lambda state: state.has("Sun Gate Lowered", player),#Sun Gate - 'Northeastern Sea': lambda state: state.has("Star Gate Lowered", player)})#Star Gate - multiworld.get_region('Hiya-Hiya Entrance', player).add_exits(['Hiya-Hiya Underside', 'Hiya-Hiya Main', 'Northwestern Sea'], - {'Northwestern Sea': lambda state: state.has("Wand", player), - 'Hiya-Hiya Underside': lambda state: state.has("Shovel", player), - 'Hiya-Hiya Main': lambda state: state.has("Fire Sword", player)}) - multiworld.get_region('Hiya-Hiya Underside', player).add_exits(['Boa-Boa Island'], - {'Boa-Boa Island': lambda state: state.has_all({"Boa-Hiya Shortcut Open", "Fire Sword"}, player)}) - multiworld.get_region('Hiya-Hiya Main', player).add_exits(['Hiya-Hiya Entrance', "Sala-Sala Backside", "Sala-Sala Island", "Hiya-Hiya Back", "Northwestern Sea"],#Northwestern sea? - {'Hiya-Hiya Entrance': lambda state: (state.has("Fire Sword", player)) or (state.has_all({"Wand", "Shove"}, player)), - 'Hiya-Hiya Back': lambda state: state.has("Shove", player), - "Sala-Sala Backside": lambda state: (state.has_all({"Shove", "Sala-Hiya Shortcut Open", "Down Jab"}, player) and logic.star_switch_on(state) and state.has_group("Swords", player, 1)), - "Sala-Sala Island": lambda state: (state.has_all({"Shove", "Sala-Hiya Shortcut Open", "Wand", "Down Jab"}, player) and logic.star_switch_on(state) and state.has_group("Swords", player, 1) and logic.has_early_health(state)), - "Northwestern Sea": lambda state: state.has("Wand", player)}) - multiworld.get_region('Hiya-Hiya Back', player).add_exits(['Hiya-Hiya Main', "Hiya-Hiya Entrance"], - {'Hiya-Hiya Main': lambda state: state.has("Shove", player), - 'Hiya-Hiya Entrance': lambda state: state.has("Wand", player)}) - multiworld.get_region('Southeastern Sea', player).add_exits(['Southern Sea', 'Eastern Sea', 'Northeastern Sea', "Curly's Casino"], - {'Southern Sea': lambda state: state.has("Aqua Gate Lowered", player), - 'Northeastern Sea': lambda state: state.has("Moon Gate Lowered", player), - 'Eastern Sea': lambda state: state.has("Moon Gate Lowered", player), - "Curly's Casino": lambda state: state.has("Power Fan", player)}) - multiworld.get_region("Curly's Casino", player).add_exits(['Southeastern Sea', "Puka-Puka Island"], - {'Puka-Puka Island': lambda state: state.has("Shovel", player)}) - multiworld.get_region("Puka-Puka Island", player).add_exits(["Curly's Casino", "Puka-Puka Switch Room", "Fuwa-Fuwa Island"], - {"Curly's Casino": lambda state: state.has("Shovel", player), - "Puka-Puka Switch Room": lambda state: state.has("Puka-Puka Drained", player), - "Fuwa-Fuwa Island": lambda state: state.has_all({"Fuwa-Puka Shortcut Open", "Puka-Puka Drained"}, player) and ((state.has_group("Swords", player, 1) and state.has("Down Jab", player)) or state.has("Wand", player))}) - multiworld.get_region("Puka-Puka Switch Room", player).add_exits(["Curly's Casino", "Sala-Sala Island", "Puka-Puka Island"], - {"Curly's Casino": lambda state: state.has("Wand", player), - "Sala-Sala Island": lambda state: state.has("Sala-Puka Shortcut Open", player) and logic.has_early_health(state), - "Puka-Puka Island": lambda state: state.has("Puka-Puka Drained", player)}) - multiworld.get_region("Eastern Sea", player).add_exits(['Southeastern Sea', "Sala-Sala Island"], - {'Southeastern Sea': lambda state: state.has("Moon Gate Lowered", player), - "Sala-Sala Island": lambda state: logic.has_early_health(state)}) - multiworld.get_region("Sala-Sala Island", player).add_exits(['Eastern Sea', "Sala-Sala Backside", "Puka-Puka Switch Room"], - {'Sala-Sala Backside': lambda state: logic.moon_switch_on(state) and state.has_all({"Shovel", "Shove"}, player), - 'Pula-Puka Switch Room': lambda state: logic.moon_switch_on(state) and state.has_all({"Shovel", "Shove"}, player)}) - multiworld.get_region("Sala-Sala Backside", player).add_exits(['Sala-Sala Island', "Hiya-Hiya Back"], - {'Hiya-Hiya Back': lambda state: state.has("Sala-Hiya Shortcut Open", player)}) - multiworld.get_region('Fuwa-Fuwa Island', player).add_exits(['Southern Sea', 'Poka-Poka East', "Puka-Puka Island", "Curly's Casino"], - {'Poka-Poka East': lambda state: state.has_all({"Shovel", "Fuwa-Poka Shortcut Open"}, player), #CHECK THIS!!!! - 'Puka-Puka Island': lambda state: state.has_all({"Down Jab", "Power Sword", "Fuwa-Puka Shortcut Open", "Puka-Puka Drained"}, player), - "Curly's Casino": lambda state: state.has_all({"Down Jab", "Power Sword", "Fuwa-Puka Shortcut Open", "Wand"}, player)}) - multiworld.get_region('Northeastern Sea', player).add_exits(['Northwestern Sea', 'Southeastern Sea'], #Irrelevant except with random open gates - {'Northwestern Sea': lambda state: state.has("Star Gate Lowered", player), - 'Southeastern Sea': lambda state: state.has("Moon Gate Lowered", player)}) - -def create_location(player: int, location_data: LocationData, region: Region, location_cache: List[Location]) -> Location: - location = SAI2Location(player, location_data.name, location_data.code, region) - location.access_rule = location_data.rule - - if id is None: - location.event = True - location.locked = True - - location_cache.append(location) - - return location - -def create_region(multiworld: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], location_cache: List[Location], name: str) -> Region: - region = Region(name, player, multiworld) - region.world = multiworld - - if name in locations_per_region: - for location_data in locations_per_region[name]: - location = create_location(player, location_data, region, location_cache) - region.locations.append(location) - - return region - - -def get_locations_per_region(locations: Tuple[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/sai2/Rom.py b/worlds/sai2/Rom.py deleted file mode 100644 index fb0a3e9c5073..000000000000 --- a/worlds/sai2/Rom.py +++ /dev/null @@ -1,874 +0,0 @@ -import hashlib -import os -import typing -import Utils -from BaseClasses import ItemClassification -from worlds.Files import APProcedurePatch, APTokenMixin, APTokenTypes -from .local_data import local_locations, local_items, shop_items -USHASH = 'b4e732b3d742af1791605bcd7aa4a1c4' - -input_item_ids = { - 0x5A1000: [0x0485, 0x01], #Silver Sword - 0x5A1001: [0x0485, 0x02], #Fire Sword - 0x5A1002: [0x0485, 0x03], #Ice Sword - 0x5A1003: [0x0485, 0x04], #Thunder Sword - 0x5A1004: [0x0485, 0x05], #Crystal Sword - 0x5A1005: [0x0485, 0x06], #Power Sword - 0x5A1006: [0x0485, 0x07], #Light Sword - 0x5A1007: [0x0485, 0x08], #Dagger - 0x5A1008: [0x0485, 0x09], #Fireballs - 0x5A1009: [0x0485, 0x0A], #Boomerang - 0x5A100A: [0x0485, 0x0B], #Ax - 0x5A100B: [0x0485, 0x0C], #Shovel - 0x5A100C: [0x0485, 0x0D], #Fire Armor - 0x5A100D: [0x0485, 0x0E], #Ice Armor - 0x5A100E: [0x0485, 0x0F], #Aqua Armor - 0x5A100F: [0x0485, 0x10], #Light Armor - 0x5A1010: [0x0485, 0x11], #Fire Shield - 0x5A1011: [0x0485, 0x12], #Ice Shield - 0x5A1012: [0x0485, 0x13], #Aqua Shield - 0x5A1013: [0x0485, 0x14], #Light Shield - 0x5A1014: [0x0485, 0x15], #Magic Wand - 0x5A1015: [0x0485, 0x16], #Ice Bell - 0x5A1016: [0x0485, 0x17], #Sun Ring - 0x5A1017: [0x0485, 0x18], #Power Fan - 0x5A1018: [0x0485, 0x19], #Elven Flute - 0x5A1019: [0x0485, 0x1A], #Sky Bell - 0x5A101A: [0x0485, 0x1B], #Light Stone - 0x5A101B: [0x0485, 0x1C], #Sun Stone - 0x5A101C: [0x0485, 0x1D], #Star Stone - 0x5A101D: [0x0485, 0x1E], #Aqua Stone - 0x5A101E: [0x0485, 0x1F], #Moon Stone - 0x5A101F: [0x0485, 0x20], #Light Spell - 0x5A1020: [0x0485, 0x22], #Sun Spell - 0x5A1021: [0x0485, 0x23], #Star Spell - 0x5A1022: [0x0485, 0x23], #Aqua Spell - 0x5A1023: [0x0485, 0x24], #Moon Spell - - 0x5A1024: [0x0485, 0x26], #Shove - 0x5A1025: [0x0485, 0x27], #Up Jab - 0x5A1026: [0x0485, 0x28], #Down Jab - - 0x5A1027: [0x0485, 0xE0], #Life Bottle - 0x5A1028: [0x0485, 0xE1], #Magic Bottle - - 0x5A1029: [0x0485, 0xE2], #500 Coins - 0x5A102A: [0x0485, 0xE3], #1000 Coins - 0x5A102B: [0x0485, 0xE4], #2000 Coins - 0x5A102C: [0x0485, 0xE5], #5000 Coins - -} - -location_flag_table = { - #Poka-Poka - 0x5A1000: [0x491, 0], #Poka-Poka Lake - 0x5A1001: [0x497, 0], #Poka-Poka Tree Chest - 0x5A1002: [0x492, 0], #Poka-Poka Digging Chest - 0x5A1003: [0x493, 0], #Poka-Poka Shove - 0x5A1004: [0x496, 0], #Sun Chest - 0x5A1005: [0x53E, 0], #Poka-Poka Elven Flute 1 - 0x5A1006: [0x490, 0], #First Chest - 0x5A1007: [0x494, 0], #Moon Chest - 0x5A1008: [0x495, 0], #Poka-Poka Down Stab - 0x5A1009: [0x480, 0], #Poka-Poka Elven Flute 2 - 0x5A100A: [0x487, 0], #Poka-Poka Boss - ################################################### - #Boa-Boa - 0x5A100B: [0x53D, 0], #First room clouds - 0x5A100C: [0x4EE, 0], #First room sun bridge - 0x5A100D: [0x4EF, 0], #Elven Flute 1 - 0x5A100E: [0x4F0, 0], #Dig Chest - 0x5A100F: [0x4F1, 0], #Lava Lake - 0x5A1010: [0x4F2, 0], #West Shaft - 0x5A1011: [0x4F3, 0], #East Shaft - 0x5A1012: [0x488, 0], #Elven Flute 2 - 0x5A1013: [0x48A, 0], #Boss - ################################################## - #Hiya-Hiya - 0x5A1014: [0x4A9, 0], #Cloud Chest - 0x5A1015: [0x4AA, 0], #Dig Chest - 0x5A1016: [0x4AB, 0], #Sun Chest - 0x5A1017: [0x4AC, 0], #West Tower Fall - 0x5A1018: [0x4AD, 0], #Up Block Chest - 0x5A1019: [0x4AE, 0], #Trap Chest - 0x5A101A: [0x4AF, 0], #Ice Cube Chest - 0x5A101B: [0x4B0, 0], #East Tower Fall - 0x5A101C: [0x53F, 0], #Elven Flute 1 - 0x5A101D: [0x48D, 0], #Elven Flute 2 - 0x5A101E: [0x48B, 0], #Boss - ################################################### - #Puka-Puka - 0x5A101F: [0x4C6, 0], #Light Block Chest - 0x5A1020: [0x4C7, 0], #Down Jab Chest - 0x5A1021: [0x4C8, 0], #Star Block Chest - 0x5A1022: [0x4C9, 0], #Up Jab Chest - 0x5A1023: [0x4CA, 0], #Middle at the Fork - 0x5A1024: [0x4CB, 0], #Aqua Blocks - 0x5A1025: [0x4CD, 0], #Elven Flute 2 - 0x5A1026: [0x4CE, 0], #Elven Flute 1 - 0x5A1027: [0x4F5, 0], #Platform Room - 0x5A1028: [0x4F6, 0], #Spring Room - 0x5A1029: [0x51E, 0], #Elven Flute 3 - 0x5A102A: [0x489, 0], #Boss - ################################################### - #Sala-Sala - 0x5A102B: [0x504, 0], #Lowest Level Left Chest - 0x5A102C: [0x505, 0], #Statue and up blocks - 0x5A102D: [0x506, 0], #Pyramid Star Chest - 0x5A102E: [0x507, 0], #Top of the Pyramid - 0x5A102F: [0x508, 0], #All Switches Chest - 0x5A1030: [0x509, 0], #Elven Flute 1 - 0x5A1031: [0x50A, 0], #Lower Right Pyramid Chest - 0x5A1032: [0x50B, 0], #Secret Elevator Chest - 0x5A1033: [0x482, 0], #Elven Flute 2 - 0x5A1034: [0x484, 0], #Boss - #################################################### - #Fuwa-Fuwa - 0x5A1035: [0x515, 0], #Block Maze - 0x5A1036: [0x516, 0], #First Plant Room - 0x5A1037: [0x517, 0], #Light Block Chest - 0x5A1038: [0x518, 0], #Dig Chest - 0x5A1039: [0x519, 0], #Final Chest - 0x5A103A: [0x483, 0], #Boss - #################################################### - #Overworld - 0x5A103B: [0x4D8, 0], #Muscle Lizard - 0x5A103C: [0x4DD, 0], #Ice Cave - 0x5A103D: [0x4E0, 0], #100 Coins - 0x5A103E: [0x4DC, 0], #Desert Island - 0x5A103F: [0x4DE, 0], #Tomb - 0x5A1040: [0x4E3, 0], #Saber Tooth - 0x5A1041: [0x4DF, 0], #North Cave - 0x5A1042: [0x4E8, 0], #300 Coins - 0x5A1043: [0x4EA, 0], #500 Coins - ################################################# - #Casino - 0x5A1045: [0x4E6, 0], #Casino 500 Coins - 0x5A1046: [0x4EB, 0], #Casino 1000 Coins - 0x5A1047: [0x4E1, 0], #Casino 2000 Coins - 0x5A1048: [0x4E2, 0], #Casino 3000 Coins - 0x5A1049: [0x4E4, 0], #Casino 5000 Coins -} - -class LocalRom(object): - - def __init__(self, file, vanillaRom=None, name=None): - self.name = name - 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): - self.buffer[address] = value - - def write_bytes(self, startaddress: int, values): - self.buffer[startaddress:startaddress + len(values)] = values - - def write_to_file(self, file): - with open(file, 'wb') as outfile: - outfile.write(self.buffer) - - def read_from_file(self, file): - with open(file, 'rb') as stream: - self.buffer = bytearray(stream.read()) - -def data_main(rom): - rom.write_bytes(0x05B3B0, bytearray([0xff, 0xff, 0x4e, 0x04, 0x4f, 0x04, 0x50, 0x04, 0x51, 0x04, 0x52, 0x04, 0x53, 0x04, 0x54, 0x04])) - rom.write_bytes(0x05B3C0, bytearray([0x55, 0x04, 0x56, 0x04, 0x57, 0x04, 0x58, 0x04, 0x59, 0x04, 0x5b, 0x04, 0x5c, 0x04, 0x5d, 0x04])) - rom.write_bytes(0x05B3D0, bytearray([0x5e, 0x04, 0x60, 0x04, 0x61, 0x04, 0x62, 0x04, 0x63, 0x04, 0x64, 0x04, 0x66, 0x04, 0x67, 0x04])) - rom.write_bytes(0x05B3E0, bytearray([0x68, 0x04, 0x69, 0x04, 0x6a, 0x04, 0x6b, 0x04, 0x6c, 0x04, 0x6d, 0x04, 0x6e, 0x04, 0x6f, 0x04])) - rom.write_bytes(0x05B3F0, bytearray([0x70, 0x04, 0x71, 0x04, 0x72, 0x04, 0x73, 0x04, 0x74, 0x04, 0x75, 0x04, 0x7d, 0x04, 0x7e, 0x04])) - rom.write_bytes(0x05B400, bytearray([0x7F, 0x04])) - - rom.write_bytes(0x082630, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x04, 0x88, 0x04])) - rom.write_bytes(0x082640, bytearray([0x8a, 0x04, 0x8d, 0x04, 0x89, 0x04, 0x82, 0x04, 0x84, 0x04, 0x83, 0x04, 0xd8, 0x04, 0xdd, 0x04])) - rom.write_bytes(0x082650, bytearray([0xdc, 0x04, 0xde, 0x04, 0xdf, 0x04, 0xe3, 0x04, 0xe8, 0x04, 0xea, 0x04, 0xe0, 0x04, 0xe4, 0x04])) - rom.write_bytes(0x082660, bytearray([0xe2, 0x04, 0xe1, 0x04, 0xeB, 0x04, 0xE6, 0x05, 0x10, 0x15, 0x6b, 0x04, 0x72, 0x04, 0x6e, 0x04])) - rom.write_bytes(0x082670, bytearray([0x6d, 0x04, 0x6f, 0x04, 0x74, 0x04, 0x69, 0x04, 0x6a, 0x04, 0x6c, 0x04, 0x66, 0x04, 0x64, 0x04])) - rom.write_bytes(0x082680, bytearray([0x67, 0x04, 0x59, 0x04, 0x68, 0x04, 0x7f, 0x04, 0x7e, 0x04, 0x7d, 0x04, 0x54, 0x04, 0x5e, 0x04])) - rom.write_bytes(0x082690, bytearray([0x63, 0x04, 0x57, 0x04, 0x3c, 0x05, 0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x0826A0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x0826B0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x0826C0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x0826D0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x0826E0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x62, 0x2c, 0x54, 0x2c, 0x5d, 0x2c, 0x63])) - rom.write_bytes(0x0826F0, bytearray([0x2c, 0x6d, 0x2c, 0x50, 0x2c, 0x61, 0x2c, 0x52, 0x2c, 0x57, 0x2c, 0x58, 0x2c, 0x5f, 0x2c, 0x54])) - rom.write_bytes(0x082700, bytearray([0x2c, 0x5b, 0x2c, 0x50, 0x2c, 0x56, 0x2c, 0x5e, 0x2c, 0x90, 0x28, 0x58, 0x2c, 0x63, 0x2c, 0x54])) - rom.write_bytes(0x082710, bytearray([0x2c, 0x5c, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x082720, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x082730, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x082740, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x082750, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0xf0, 0xef, 0x0a, 0xf0, 0x20])) - rom.write_bytes(0x082760, bytearray([0xf0, 0x34, 0xf0, 0x50, 0xf0, 0x6c, 0xf0, 0x84, 0xf0, 0x9c, 0xf0, 0xaa, 0xf0, 0xbe, 0xf0, 0xd2])) - rom.write_bytes(0x082770, bytearray([0xf0, 0xd8, 0xf0, 0xe6, 0xf0, 0xfc, 0xf0, 0x10, 0xf1, 0x26, 0xf1, 0x3e, 0xf1, 0x56, 0xf1, 0x6c])) - rom.write_bytes(0x082780, bytearray([0xf1, 0x84, 0xf1, 0x9e, 0xf1, 0xa8, 0xf1, 0xba, 0xf1, 0xcc, 0xf1, 0xe0, 0xf1, 0xf8, 0xf1, 0x0a])) - rom.write_bytes(0x082790, bytearray([0xf2, 0x22, 0xf2, 0x36, 0xf2, 0x4c, 0xf2, 0x62, 0xf2, 0x78, 0xf2, 0x90, 0xf2, 0xa6, 0xf2, 0xba])) - rom.write_bytes(0x0827A0, bytearray([0xf2, 0xd0, 0xf2, 0xe6, 0xf2, 0xf2, 0xf2, 0x00, 0xf3, 0x12, 0xf3, 0x2a, 0xf3, 0x44, 0xf3, 0x58])) - rom.write_bytes(0x0827B0, bytearray([0xf3, 0x70, 0xf3, 0x88, 0xf3, 0x50, 0xf6, 0xda, 0xf7, 0x15, 0xf7, 0x31, 0x05, 0x32, 0x05, 0x33])) - rom.write_bytes(0x0827C0, bytearray([0x05, 0x34, 0x05, 0x35, 0x05, 0x8f, 0x04, 0xa5, 0x04, 0xd5, 0x04, 0xcc, 0x04, 0xf7, 0x04, 0x20])) - rom.write_bytes(0x0827D0, bytearray([0x05, 0x28, 0x05, 0x29, 0x05, 0x2B, 0x05, 0x2A, 0x05, 0x27, 0x05])) #Contest 052A - - rom.write_bytes(0x04F580, bytearray([0x50, 0xF6])) #Special chest flag values, puts them at actual flags instead of their vanilla item - rom.write_bytes(0x01911A, bytearray([0x80, 0x04])) - rom.write_bytes(0x018C5A, bytearray([0x87, 0x04])) - rom.write_bytes(0x01025E, bytearray([0x87, 0x04])) - rom.write_bytes(0x0FC85D, bytearray([0x88, 0x04])) - rom.write_bytes(0x01A7D0, bytearray([0x8A, 0x04])) - rom.write_bytes(0x016CD2, bytearray([0x8A, 0x04])) - rom.write_bytes(0x019B04, bytearray([0x8D, 0x04])) - rom.write_bytes(0x011651, bytearray([0x8D, 0x04])) - rom.write_bytes(0x038364, bytearray([0x89, 0x04])) - rom.write_bytes(0x0179F6, bytearray([0x89, 0x04])) - rom.write_bytes(0x0FE6CD, bytearray([0x82, 0x04])) - rom.write_bytes(0x03CB8A, bytearray([0x84, 0x04])) - rom.write_bytes(0x0140CB, bytearray([0x84, 0x04])) - rom.write_bytes(0x02EDD5, bytearray([0x83, 0x04])) - rom.write_bytes(0x014BC2, bytearray([0x83, 0x04])) - rom.write_bytes(0x02F942, bytearray([0xD8, 0x04])) - rom.write_bytes(0x039312, bytearray([0xDD, 0x04])) - rom.write_bytes(0x0394A1, bytearray([0xDC, 0x04])) - rom.write_bytes(0x039142, bytearray([0xDE, 0x04])) - rom.write_bytes(0x039D83, bytearray([0xDF, 0x04])) - rom.write_bytes(0x02FA1D, bytearray([0xE3, 0x04])) - rom.write_bytes(0x0395CC, bytearray([0xE8, 0x04])) - rom.write_bytes(0x039886, bytearray([0xEA, 0x04])) - rom.write_bytes(0x039ACD, bytearray([0xE0, 0x04])) - rom.write_bytes(0x01FC1F, bytearray([0xE4, 0x04])) - rom.write_bytes(0x01FBA5, bytearray([0xE2, 0x04])) - rom.write_bytes(0x01FB2B, bytearray([0xE1, 0x04])) - rom.write_bytes(0x01FAB1, bytearray([0xEB, 0x04])) - - rom.write_byte(0x030485, 0x4D)#Map tile overrides - rom.write_byte(0x030BCE, 0x4D) - rom.write_byte(0x030CDE, 0x4D) - rom.write_byte(0x030E8C, 0x4D) - rom.write_byte(0x0311A5, 0x4D) - rom.write_byte(0x030F92, 0x4D) - rom.write_byte(0x0310B2, 0x4D) - rom.write_byte(0x030DB5, 0x4D) - rom.write_byte(0x030782, 0x4D) - rom.write_byte(0x030941, 0x4D) - rom.write_byte(0x03086D, 0x4D) - rom.write_byte(0x030A23, 0x4D) - rom.write_byte(0x032BEE, 0x4D) - rom.write_byte(0x032D75, 0x4D) - rom.write_byte(0x033032, 0x4D) - rom.write_byte(0x032F85, 0x4D) - rom.write_byte(0x0330E3, 0x4D) - rom.write_byte(0x033194, 0x4D) - rom.write_byte(0x033450, 0x4D) - rom.write_byte(0x0337C5, 0x4D) - rom.write_byte(0x033923, 0x4D) - rom.write_byte(0x033241, 0x4D) - rom.write_byte(0x0335B2, 0x4D) - rom.write_byte(0x033663, 0x4D) - rom.write_byte(0x0339D4, 0x4D) - rom.write_byte(0x0332EF, 0x4D) - rom.write_byte(0x03339F, 0x4D) - rom.write_byte(0x033501, 0x4D) - rom.write_byte(0x01FC9A, 0x4D) - rom.write_byte(0x01FCA0, 0x4D) - rom.write_byte(0x035833, 0x4D) - rom.write_byte(0x0363F3, 0x4D) - rom.write_byte(0x0362B7, 0x4D) - rom.write_byte(0x0364A4, 0x4D) - rom.write_byte(0x036555, 0x4D) - rom.write_byte(0x036602, 0x4D) - rom.write_byte(0x03E35A, 0x83) - - rom.write_bytes(0x082210, bytearray([0x00, 0x00, 0x03, 0x03, 0x04, 0x05, 0x3c, 0x05, 0x5e, 0x1a, 0x7f, 0x3b, 0x7a, 0x47, 0x44, 0x0b])) - rom.write_bytes(0x082220, bytearray([0x00, 0x00, 0x00, 0x03, 0x03, 0x07, 0x3f, 0x01, 0x7f, 0x20, 0x7e, 0x01, 0x46, 0x00, 0x2a, 0x30])) - rom.write_bytes(0x082230, bytearray([0x00, 0x00, 0xc0, 0xc0, 0x60, 0xe0, 0x78, 0xc4, 0x44, 0x1a, 0xc4, 0xba, 0x38, 0xc6, 0x54, 0x8a])) - rom.write_bytes(0x082240, bytearray([0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xb8, 0xc4, 0xe4, 0x3a, 0x44, 0xba, 0x40, 0x02, 0x2a, 0x30])) - rom.write_bytes(0x082250, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082260, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082270, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082280, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082290, bytearray([0x00, 0x00, 0x03, 0x03, 0x04, 0x05, 0x3c, 0x05, 0x5e, 0x1a, 0x7f, 0x3b, 0x7a, 0x47, 0x44, 0x0b])) - rom.write_bytes(0x0822a0, bytearray([0x00, 0x00, 0x00, 0x03, 0x03, 0x07, 0x3f, 0x01, 0x7f, 0x20, 0x7e, 0x01, 0x46, 0x00, 0x2a, 0x30])) - rom.write_bytes(0x0822b0, bytearray([0x00, 0x00, 0xc0, 0xc0, 0x60, 0xe0, 0x78, 0xc4, 0x44, 0x1a, 0xc4, 0xba, 0x38, 0xd6, 0x5c, 0x9a])) - rom.write_bytes(0x0822c0, bytearray([0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xb8, 0xc4, 0xe4, 0x3a, 0x44, 0xba, 0x50, 0x02, 0x3a, 0x20])) - rom.write_bytes(0x0822d0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0822e0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0822f0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082300, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082310, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082320, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082330, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082340, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082350, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082360, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082370, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082380, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082390, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0823a0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0823b0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0823c0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0823d0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0823e0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0823f0, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082400, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082410, bytearray([0x44, 0x00, 0x41, 0x29, 0x33, 0x0b, 0x03, 0x41, 0x04, 0x3c, 0x03, 0x07, 0x00, 0x03, 0x00, 0x00])) - rom.write_bytes(0x082420, bytearray([0x03, 0x38, 0x2e, 0x12, 0x0c, 0x40, 0x06, 0x3a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082430, bytearray([0x7c, 0x42, 0xb6, 0x28, 0xbe, 0xa0, 0x7c, 0x22, 0xa0, 0x3c, 0xc0, 0xe0, 0x00, 0xc0, 0x00, 0x00])) - rom.write_bytes(0x082440, bytearray([0x82, 0x38, 0xc8, 0x92, 0x40, 0x02, 0xc0, 0x4c, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082450, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082460, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082470, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082480, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x082490, bytearray([0x44, 0x00, 0x41, 0x29, 0x33, 0x0b, 0x03, 0x41, 0x04, 0x3c, 0x03, 0x07, 0x00, 0x03, 0x00, 0x00])) - rom.write_bytes(0x0824a0, bytearray([0x03, 0x38, 0x2e, 0x12, 0x0c, 0x40, 0x06, 0x3a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - rom.write_bytes(0x0824b0, bytearray([0x3c, 0x3e, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x7e, 0xfc, 0x7c, 0xfc, 0xfc, 0x00, 0xc0, 0x00, 0x00])) - rom.write_bytes(0x0824c0, bytearray([0xfe, 0x40, 0xfe, 0x00, 0xfe, 0xc6, 0xfc, 0x44, 0xfc, 0xc4, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00])) - - rom.write_bytes(0x082C50, bytearray([0x00, 0x00, 0x6c, 0x5d, 0xe9, 0x18, 0x5e, 0x05, 0xb2, 0x04, 0x93, 0x06, 0xf3, 0x6d, 0x5d, 0x3f])) - rom.write_bytes(0x082C60, bytearray([0xee, 0x7e, 0x1a, 0x5e, 0xf4, 0x3f, 0x56, 0x08, 0xff, 0x7f, 0x56, 0x09, 0x5f, 0x29, 0x77, 0x22]))#Ap Item Palette - - rom.write_bytes(0x0cb0ae, bytearray([0x2f, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x14, 0x01, 0x0f, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cb0be, bytearray([0x02, 0x01, 0x15, 0x01, 0x19, 0x01, 0x00, 0x01, 0x0d, 0x01, 0x19, 0x01, 0x00, 0x01, 0x03, 0x01])) - rom.write_bytes(0x0cb0ce, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x81, 0x00, 0x00, 0x03, 0x81, 0x00, 0x06, 0x01])) - rom.write_bytes(0x0cb0de, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0xfe, 0x03, 0x1c, 0x01, 0x81, 0x00, 0x21, 0x00, 0x14, 0x01])) - rom.write_bytes(0x0cb0ee, bytearray([0x21, 0x01, 0x13, 0x01, 0x00, 0x01, 0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01])) - rom.write_bytes(0x0cb0fe, bytearray([0x00, 0x01, 0x06, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x0a, 0x01, 0x15, 0x01, 0x13, 0x01])) - rom.write_bytes(0x0cb10e, bytearray([0x14, 0x01, 0x00, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x00, 0x81, 0x00, 0x03, 0x01, 0x0f, 0x01])) - rom.write_bytes(0x0cb11e, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0x27, 0x01, 0xf5, 0x00, 0x80, 0x00, 0x0c, 0x01, 0x0f, 0x01])) - rom.write_bytes(0x0cb12e, bytearray([0x03, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x81, 0x00, 0x17, 0x01, 0x09, 0x01, 0x14, 0x01, 0x08, 0x01])) - rom.write_bytes(0x0cb13e, bytearray([0x00, 0x01, 0x10, 0x01, 0x15, 0x01, 0x0e, 0x01, 0x09, 0x01, 0x13, 0x01, 0x08, 0x01, 0x09, 0x01])) - rom.write_bytes(0x0cb14e, bytearray([0x0e, 0x01, 0x07, 0x01, 0x00, 0x01, 0x02, 0x01, 0x0c, 0x01, 0x0f, 0x01, 0x17, 0x01, 0x13, 0x01])) - rom.write_bytes(0x0cb15e, bytearray([0x27, 0x01, 0x81, 0x00, 0x19, 0x00, 0x0c, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x06, 0x01, 0x0f, 0x01])) - rom.write_bytes(0x0cb16e, bytearray([0x12, 0x01, 0x00, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x0c, 0x01, 0x19, 0x01, 0x00, 0x01, 0x04, 0x00])) - rom.write_bytes(0x0cb17e, bytearray([0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01, 0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01])) - rom.write_bytes(0x0cb18e, bytearray([0x27, 0x01, 0xf5, 0x00, 0x80, 0x00])) - - rom.write_bytes(0x0cb194, bytearray([0x2c, 0x00, 0x08, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x00, 0x01, 0x06, 0x01])) - rom.write_bytes(0x0cb1a4, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01, 0x00, 0x01, 0x0d, 0x01])) - rom.write_bytes(0x0cb1b4, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0x19, 0x01, 0x26, 0x01, 0x81, 0x00, 0x13, 0x01, 0x15, 0x01])) - rom.write_bytes(0x0cb1c4, bytearray([0x03, 0x01, 0x0b, 0x01, 0x05, 0x01, 0x12, 0x01, 0x1b, 0x01, 0xf4, 0x00])) - - rom.write_bytes(0x0cba3a, bytearray([0x2f, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x14, 0x01, 0x0f, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cba4a, bytearray([0x02, 0x01, 0x15, 0x01, 0x19, 0x01, 0x00, 0x01, 0x0d, 0x01, 0x19, 0x01, 0x00, 0x01, 0x03, 0x01])) - rom.write_bytes(0x0cba5a, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x81, 0x00, 0x00, 0x03, 0x81, 0x00, 0x06, 0x01])) - rom.write_bytes(0x0cba6a, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0xfe, 0x03, 0x1c, 0x01, 0x81, 0x00, 0x21, 0x00, 0x14, 0x01])) - rom.write_bytes(0x0cba7a, bytearray([0x21, 0x01, 0x13, 0x01, 0x00, 0x01, 0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01])) - rom.write_bytes(0x0cba8a, bytearray([0x00, 0x01, 0x06, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cba9a, bytearray([0x00, 0x01, 0x0c, 0x01, 0x0f, 0x01, 0x17, 0x01, 0x26, 0x01, 0x81, 0x00, 0x0c, 0x01, 0x0f, 0x01])) - rom.write_bytes(0x0cbaaa, bytearray([0x17, 0x01, 0x00, 0x01, 0x10, 0x01, 0x12, 0x01, 0x09, 0x01, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cbaba, bytearray([0x0f, 0x01, 0x06, 0x01, 0x00, 0x01, 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01])) - rom.write_bytes(0x0cbaca, bytearray([0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0x27, 0x01, 0xf5, 0x00, 0x80, 0x00])) - - rom.write_bytes(0x0cbAE0, bytearray([0x2c, 0x00, 0x08, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x00, 0x01, 0x06, 0x01])) - rom.write_bytes(0x0cbAF0, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01, 0x00, 0x01, 0x0d, 0x01])) - rom.write_bytes(0x0cbB00, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0x19, 0x01, 0x26, 0x01, 0x81, 0x00, 0x13, 0x01, 0x15, 0x01])) - rom.write_bytes(0x0cbB10, bytearray([0x03, 0x01, 0x0b, 0x01, 0x05, 0x01, 0x12, 0x01, 0x1b, 0x01, 0xf4, 0x00])) - - rom.write_bytes(0x0cac34, bytearray([0x2f, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x14, 0x01, 0x0f, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cac44, bytearray([0x02, 0x01, 0x15, 0x01, 0x19, 0x01, 0x00, 0x01, 0x0d, 0x01, 0x19, 0x01, 0x00, 0x01, 0x03, 0x01])) - rom.write_bytes(0x0cac54, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0c, 0x01, 0x00, 0x01, 0x81, 0x00, 0x00, 0x03, 0x81, 0x00, 0x06, 0x01])) - rom.write_bytes(0x0cac64, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0xfe, 0x03, 0x1c, 0x01, 0x81, 0x00, 0x21, 0x00, 0x14, 0x01])) - rom.write_bytes(0x0cac74, bytearray([0x21, 0x01, 0x13, 0x01, 0x00, 0x01, 0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01])) - rom.write_bytes(0x0cac84, bytearray([0x00, 0x01, 0x06, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cac94, bytearray([0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x13, 0x01, 0x19, 0x01, 0x00, 0x01, 0x81, 0x00, 0x10, 0x01])) - rom.write_bytes(0x0caca4, bytearray([0x01, 0x01, 0x19, 0x01, 0x0d, 0x01, 0x05, 0x01, 0x0e, 0x01, 0x14, 0x01, 0x00, 0x01, 0x0f, 0x01])) - rom.write_bytes(0x0cacb4, bytearray([0x06, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01, 0x0f, 0x01])) - rom.write_bytes(0x0cacc4, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0x27, 0x01, 0xf5, 0x00, 0x80, 0x00])) - - rom.write_bytes(0x0cAD1C, bytearray([0x2c, 0x00, 0x08, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x0b, 0x01, 0x13, 0x01, 0x00, 0x01, 0x06, 0x01])) - rom.write_bytes(0x0cAD2C, bytearray([0x0f, 0x01, 0x12, 0x01, 0x00, 0x01, 0x14, 0x01, 0x08, 0x01, 0x05, 0x01, 0x00, 0x01, 0x0d, 0x01])) - rom.write_bytes(0x0cAD3C, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0x19, 0x01, 0x26, 0x01, 0x81, 0x00, 0x13, 0x01, 0x15, 0x01])) - rom.write_bytes(0x0cAD4C, bytearray([0x03, 0x01, 0x0b, 0x01, 0x05, 0x01, 0x12, 0x01, 0x1b, 0x01, 0xf4, 0x00])) - - rom.write_bytes(0x0ceff0, bytearray([0x2b, 0x00, 0x09, 0x01, 0x0c, 0x01, 0x16, 0x01, 0x05, 0x01, 0x12, 0x01, 0x00, 0x01, 0x2b, 0x00])) - rom.write_bytes(0x0cf000, bytearray([0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03, 0x1e, 0x00, 0x09, 0x01, 0x12, 0x01])) - rom.write_bytes(0x0cf010, bytearray([0x05, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf020, bytearray([0x21, 0x00, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01])) - rom.write_bytes(0x0cf030, bytearray([0x04, 0x01, 0xff, 0x03, 0x2c, 0x00, 0x08, 0x01, 0x15, 0x01, 0x0e, 0x01, 0x04, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cf040, bytearray([0x12, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf050, bytearray([0x1b, 0x00, 0x12, 0x01, 0x19, 0x01, 0x13, 0x01, 0x14, 0x01, 0x01, 0x01, 0x0c, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cf060, bytearray([0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03, 0x28, 0x00, 0x0f, 0x01])) - rom.write_bytes(0x0cf070, bytearray([0x17, 0x01, 0x05, 0x01, 0x12, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01])) - rom.write_bytes(0x0cf080, bytearray([0x04, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01, 0x14, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cf090, bytearray([0x2b, 0x00, 0x17, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x04, 0x01, 0xff, 0x03, 0x1c, 0x00, 0x01, 0x01])) - rom.write_bytes(0x0cf0a0, bytearray([0x07, 0x01, 0x07, 0x01, 0x05, 0x01, 0x12, 0x01, 0xff, 0x03, 0x1e, 0x00, 0x09, 0x01, 0x12, 0x01])) - rom.write_bytes(0x0cf0b0, bytearray([0x05, 0x01, 0x02, 0x01, 0x01, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0x13, 0x01, 0xff, 0x03, 0x1a, 0x00])) - rom.write_bytes(0x0cf0c0, bytearray([0x0f, 0x01, 0x0f, 0x01, 0x0d, 0x01, 0x05, 0x01, 0x12, 0x01, 0x01, 0x01, 0x0e, 0x01, 0x07, 0x01])) - rom.write_bytes(0x0cf0d0, bytearray([0xff, 0x03, 0x19, 0x00, 0x18, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x08, 0x01, 0x0f, 0x01, 0x16, 0x01])) - rom.write_bytes(0x0cf0e0, bytearray([0x05, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x1e, 0x00, 0x09, 0x01, 0x12, 0x01, 0x05, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cf0f0, bytearray([0x19, 0x00, 0x12, 0x01, 0x0d, 0x01, 0x0f, 0x01, 0x12, 0x01, 0xff, 0x03, 0x21, 0x00, 0x03, 0x01])) - rom.write_bytes(0x0cf100, bytearray([0x05, 0x01, 0x00, 0x01, 0x19, 0x00, 0x12, 0x01, 0x0d, 0x01, 0x0f, 0x01, 0x12, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf110, bytearray([0x19, 0x00, 0x11, 0x01, 0x15, 0x01, 0x01, 0x01, 0x00, 0x01, 0x19, 0x00, 0x12, 0x01, 0x0d, 0x01])) - rom.write_bytes(0x0cf120, bytearray([0x0f, 0x01, 0x12, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01, 0x14, 0x01])) - rom.write_bytes(0x0cf130, bytearray([0x00, 0x01, 0x19, 0x00, 0x12, 0x01, 0x0d, 0x01, 0x0f, 0x01, 0x12, 0x01, 0xff, 0x03, 0x1e, 0x00])) - rom.write_bytes(0x0cf140, bytearray([0x09, 0x01, 0x12, 0x01, 0x05, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x08, 0x01, 0x09, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cf150, bytearray([0x0c, 0x01, 0x04, 0x01, 0xff, 0x03, 0x21, 0x00, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01, 0x2b, 0x00])) - rom.write_bytes(0x0cf160, bytearray([0x08, 0x01, 0x09, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x04, 0x01, 0xff, 0x03, 0x19, 0x00, 0x11, 0x01])) - rom.write_bytes(0x0cf170, bytearray([0x15, 0x01, 0x01, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x08, 0x01, 0x09, 0x01, 0x05, 0x01, 0x0c, 0x01])) - rom.write_bytes(0x0cf180, bytearray([0x04, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01, 0x14, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cf190, bytearray([0x2b, 0x00, 0x08, 0x01, 0x09, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x04, 0x01, 0xff, 0x03, 0x2f, 0x00])) - rom.write_bytes(0x0cf1a0, bytearray([0x01, 0x01, 0x0e, 0x01, 0x04, 0x01, 0xff, 0x03, 0x21, 0x00, 0x03, 0x01, 0x05, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cf1b0, bytearray([0x1a, 0x00, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x15, 0x01, 0x0e, 0x01])) - rom.write_bytes(0x0cf1c0, bytearray([0x00, 0x01, 0x2a, 0x00, 0x09, 0x01, 0x0e, 0x01, 0x07, 0x01, 0xff, 0x03, 0x28, 0x00, 0x0f, 0x01])) - rom.write_bytes(0x0cf1d0, bytearray([0x17, 0x01, 0x05, 0x01, 0x12, 0x01, 0x00, 0x01, 0x1e, 0x00, 0x01, 0x01, 0x0e, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf1e0, bytearray([0x1d, 0x00, 0x0c, 0x01, 0x16, 0x01, 0x05, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x1e, 0x00, 0x0c, 0x01])) - rom.write_bytes(0x0cf1f0, bytearray([0x15, 0x01, 0x14, 0x01, 0x05, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x0b, 0x01, 0x19, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cf200, bytearray([0x1a, 0x00, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01])) - rom.write_bytes(0x0cf210, bytearray([0x08, 0x01, 0x14, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cf220, bytearray([0xff, 0x03, 0x2b, 0x00, 0x15, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01])) - rom.write_bytes(0x0cf230, bytearray([0x0e, 0x01, 0x05, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x14, 0x01, 0x01, 0x01, 0x12, 0x01, 0x00, 0x01])) - rom.write_bytes(0x0cf240, bytearray([0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0xff, 0x03, 0x19, 0x00, 0x11, 0x01])) - rom.write_bytes(0x0cf250, bytearray([0x15, 0x01, 0x01, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cf260, bytearray([0xff, 0x03, 0x25, 0x00, 0x0f, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x14, 0x01])) - rom.write_bytes(0x0cf270, bytearray([0x0f, 0x01, 0x0e, 0x01, 0x05, 0x01, 0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x07, 0x01, 0x08, 0x01])) - rom.write_bytes(0x0cf280, bytearray([0x14, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf290, bytearray([0x2b, 0x00, 0x14, 0x01, 0x01, 0x01, 0x12, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cf2a0, bytearray([0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x15, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00])) - rom.write_bytes(0x0cf2b0, bytearray([0x10, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x19, 0x00, 0x11, 0x01, 0x15, 0x01])) - rom.write_bytes(0x0cf2c0, bytearray([0x01, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf2d0, bytearray([0x25, 0x00, 0x0f, 0x01, 0x0f, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x10, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cf2e0, bytearray([0x0c, 0x01, 0x0c, 0x01, 0xff, 0x03, 0x2b, 0x00, 0x08, 0x01, 0x0f, 0x01, 0x16, 0x01, 0x05, 0x01])) - rom.write_bytes(0x0cf2f0, bytearray([0xff, 0x03, 0x2d, 0x00, 0x10, 0x01, 0x00, 0x01, 0x22, 0x00, 0x01, 0x01, 0x02, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf300, bytearray([0x1c, 0x00, 0x0f, 0x01, 0x17, 0x01, 0x0e, 0x01, 0x00, 0x01, 0x22, 0x00, 0x01, 0x01, 0x02, 0x01])) - rom.write_bytes(0x0cf310, bytearray([0xff, 0x03, 0x24, 0x00, 0x09, 0x01, 0x06, 0x01, 0x05, 0x01, 0x00, 0x01, 0x1a, 0x00, 0x0f, 0x01])) - rom.write_bytes(0x0cf320, bytearray([0x14, 0x01, 0x14, 0x01, 0x0c, 0x01, 0x05, 0x01, 0xff, 0x03, 0x25, 0x00, 0x01, 0x01, 0x07, 0x01])) - rom.write_bytes(0x0cf330, bytearray([0x09, 0x01, 0x03, 0x01, 0x00, 0x01, 0x1a, 0x00, 0x0f, 0x01, 0x14, 0x01, 0x14, 0x01, 0x0c, 0x01])) - rom.write_bytes(0x0cf340, bytearray([0x05, 0x01, 0xff, 0x03, 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01])) - rom.write_bytes(0x0cf350, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03, 0x02, 0x00, 0x26, 0x01, 0x01, 0x00, 0x01, 0x00])) - rom.write_bytes(0x0cf360, bytearray([0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf370, bytearray([0x03, 0x00, 0x26, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01])) - rom.write_bytes(0x0cf380, bytearray([0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03, 0x06, 0x00, 0x26, 0x01, 0x01, 0x00, 0x01, 0x00])) - rom.write_bytes(0x0cf390, bytearray([0x01, 0x00, 0x00, 0x01, 0x1b, 0x00, 0x0f, 0x01, 0x09, 0x01, 0x0e, 0x01, 0x13, 0x01, 0xff, 0x03])) - rom.write_bytes(0x0cf3a0, bytearray([0x19, 0x01, 0x0f, 0x01, 0x15, 0x01, 0x12, 0x01, 0x13, 0x01, 0x05, 0x01, 0x0c, 0x01, 0x06, 0x01])) - rom.write_bytes(0x0cf3b0, bytearray([0xff, 0x03])) - -def code_main(rom): - rom.write_bytes(0x17ad40, bytearray([0xe0, 0x58, 0x01, 0xb0, 0x08, 0xbf, 0x80, 0x5c, 0xc0, 0x5c, 0x44, 0x5c, 0xc0, 0xa9, 0x10, 0x22])) - rom.write_bytes(0x17ad50, bytearray([0x85, 0x0e, 0xa9, 0xc8, 0x00, 0x85, 0x10, 0xa9, 0x50, 0x2c, 0x85, 0x12, 0xa9, 0xc8, 0x00, 0x85])) - rom.write_bytes(0x17ad60, bytearray([0x14, 0xa9, 0x00, 0x44, 0x85, 0x0a, 0xa9, 0x00, 0x04, 0x85, 0x0c, 0xe0, 0x68, 0x01, 0xf0, 0x0f])) - rom.write_bytes(0x17ad70, bytearray([0xe0, 0x60, 0x01, 0xf0, 0x05, 0xa9, 0x12, 0x00, 0x80, 0x08, 0xa9, 0x0e, 0x00, 0x80, 0x03, 0xa9])) - rom.write_bytes(0x17ad80, bytearray([0x10, 0x00, 0x8d, 0x52, 0x22, 0x5c, 0x6b, 0x5c, 0xc0, 0x60, 0xda, 0x5a, 0x8b, 0x38, 0xe9, 0x7d])) - rom.write_bytes(0x17ad90, bytearray([0x04, 0x0a, 0xaa, 0xbf, 0xb5, 0x27, 0xc8, 0xaa, 0xa9, 0xc5, 0x00, 0xa0, 0xf0, 0x7d, 0x54, 0x20])) - rom.write_bytes(0x17ada0, bytearray([0xc4, 0xab, 0x7a, 0xfa, 0x68, 0x60, 0xda, 0xa2, 0x00, 0x00, 0xdf, 0x6a, 0x26, 0xc8, 0xf0, 0x17])) - rom.write_bytes(0x17adb0, bytearray([0xe8, 0xe8, 0xe0, 0x2c, 0x00, 0xf0, 0x02, 0x80, 0xf1, 0xfa, 0xe6, 0x40, 0xe6, 0x40, 0x48, 0xa9])) - rom.write_bytes(0x17adc0, bytearray([0x00, 0x00, 0x68, 0x5c, 0x41, 0x42, 0xc0, 0xbf, 0x3c, 0x26, 0xc8, 0x99, 0x39, 0x0c, 0x85, 0x0a])) - rom.write_bytes(0x17add0, bytearray([0xbf, 0x10, 0x26, 0xc8, 0x99, 0x79, 0x0c, 0xc9, 0x4e, 0x04, 0x90, 0x16, 0x38, 0xe9, 0x4a, 0x04])) - rom.write_bytes(0x17ade0, bytearray([0x8d, 0x54, 0x22, 0xfa, 0x22, 0xe4, 0x5a, 0xc0, 0xe6, 0x40, 0xe6, 0x40, 0xc2, 0x20, 0x5c, 0xC3])) - rom.write_bytes(0x17adf0, bytearray([0xb2, 0x17, 0xc9, 0x04, 0x00, 0xb0, 0x02, 0x80, 0xe7, 0xe2, 0x20, 0x38, 0xe9, 0x04, 0xaa, 0xbf])) - rom.write_bytes(0x17ae00, bytearray([0x68, 0x26, 0xc8, 0xc2, 0x20, 0x80, 0xd9, 0xe2, 0x20, 0xaf, 0xe0, 0x7d, 0x20, 0xc9, 0x05, 0xb0])) - rom.write_bytes(0x17ae10, bytearray([0x07, 0x1a, 0x8f, 0xe0, 0x7d, 0x20, 0x80, 0x07, 0xad, 0x85, 0x04, 0xd0, 0x0e, 0x80, 0x00, 0xc2])) - rom.write_bytes(0x17ae20, bytearray([0x20, 0xad, 0xa0, 0x05, 0xc9, 0x00, 0x01, 0x5c, 0x95, 0x0a, 0xc2, 0xc2, 0x20, 0xb9, 0x39, 0x0c])) - rom.write_bytes(0x17ae30, bytearray([0x48, 0xa9, 0x4d, 0x04, 0x99, 0x39, 0x0c, 0xad, 0x85, 0x04, 0xc9, 0xe0, 0x00, 0x90, 0x06, 0x38])) - rom.write_bytes(0x17ae40, bytearray([0xe9, 0xe0, 0x00, 0x80, 0x06, 0x0a, 0xaa, 0xbf, 0xb0, 0xb3, 0xc5, 0x48, 0x22, 0xe9, 0x5a, 0xc0])) - rom.write_bytes(0x17ae50, bytearray([0xc2, 0x20, 0x68, 0x22, 0x18, 0x5c, 0xc0, 0xa9, 0x03, 0x00, 0x8d, 0x02, 0x0a, 0x22, 0xab, 0xb0])) - rom.write_bytes(0x17ae60, bytearray([0x17, 0x22, 0xd8, 0x5d, 0xc0, 0x68, 0x99, 0x39, 0x0c, 0x9c, 0x85, 0x04, 0x80, 0xb1])) - - rom.write_bytes(0x17b010, bytearray([0xb9, 0xda, 0x06, 0x1a, 0x1a, 0x99, 0xda, 0x06, 0x5c, 0x94, 0xc5, 0xc2, 0xb9, 0xda, 0x06, 0x3a])) - rom.write_bytes(0x17b020, bytearray([0x3a, 0x99, 0xda, 0x06, 0x5c, 0x75, 0xc5, 0xc2, 0xe2, 0x20, 0xbd, 0xbe, 0x33, 0xc9, 0x05, 0xd0])) - rom.write_bytes(0x17b030, bytearray([0x21, 0xad, 0xd3, 0x00, 0xc9, 0x21, 0xd0, 0x21, 0xaf, 0x90, 0xae, 0x17, 0xf0, 0x1b, 0xda, 0xa2])) - rom.write_bytes(0x17b040, bytearray([0x00, 0x00, 0xbd, 0x70, 0x04, 0xf0, 0x08, 0xe0, 0x05, 0x00, 0xf0, 0x0c, 0xe8, 0x80, 0xf3, 0xfa])) - rom.write_bytes(0x17b050, bytearray([0xa9, 0x01, 0xc2, 0x20, 0x5c, 0x4f, 0x6f, 0xc0, 0xfa, 0xc2, 0x20, 0xa9, 0x05, 0x00, 0x5c, 0x4f])) - rom.write_bytes(0x17b060, bytearray([0x6f, 0xc0, 0x48, 0xa9, 0x69, 0x8d, 0x34, 0x00, 0x68, 0xa2, 0x16, 0xf0, 0x86, 0x56, 0x5c, 0x69])) - rom.write_bytes(0x17b070, bytearray([0xb8, 0xc1, 0xad, 0x02, 0x0a, 0xf0, 0x11, 0xc9, 0x01, 0xf0, 0x05, 0xce, 0x02, 0x0a, 0x80, 0x0d])) - rom.write_bytes(0x17b080, bytearray([0xce, 0x02, 0x0a, 0x20, 0x96, 0xb0, 0x80, 0x05, 0xad, 0x13, 0x0a, 0xf0, 0x00, 0xc2, 0x20, 0xa9])) - rom.write_bytes(0x17b090, bytearray([0x86, 0x3e, 0x5c, 0x88, 0x40, 0xc0, 0xc2, 0x20, 0xa2, 0x10, 0x10, 0xa0, 0x53, 0x17, 0xa9, 0x0f])) - rom.write_bytes(0x17b0a0, bytearray([0x00, 0x54, 0x7e, 0xc8, 0x9c, 0x88, 0x05, 0x9c, 0x5e, 0x22, 0x60, 0xc2, 0x20, 0xa9, 0x08, 0x00])) - rom.write_bytes(0x17b0b0, bytearray([0x0c, 0x04, 0x01, 0x6b, 0xc9, 0x75, 0x04, 0x90, 0x09, 0xc9, 0x7d, 0x04, 0xb0, 0x0c, 0x5c, 0xf6])) - rom.write_bytes(0x17b0c0, bytearray([0x5a, 0xc0, 0xe2, 0x20, 0xa9, 0x01, 0x5c, 0xf3, 0x5a, 0xc0, 0x20, 0x89, 0xad, 0x80, 0xf3, 0xe0])) - rom.write_bytes(0x17b0d0, bytearray([0x58, 0x00, 0xb0, 0x08, 0xbf, 0x00, 0x00, 0xc5, 0x5c, 0xf3, 0x5d, 0xc0, 0x4C, 0x68, 0xB2, 0xe2])) - rom.write_bytes(0x17b0e0, bytearray([0x20, 0x8b, 0xa9, 0x20, 0x5c, 0xf9, 0x5d, 0xc0, 0xa7, 0x40, 0xc9, 0x76, 0x04, 0xb0, 0x08, 0xe6])) - rom.write_bytes(0x17b0f0, bytearray([0x40, 0xe6, 0x40, 0x5c, 0x4b, 0x44, 0xc0, 0x48, 0xad, 0x40, 0x00, 0x8f, 0xF9, 0x04, 0x7E, 0x8b])) - rom.write_bytes(0x17b100, bytearray([0xda, 0x5a, 0xa9, 0xc5, 0x00, 0xa2, 0x96, 0x26, 0xa0, 0xf0, 0x7d, 0x54, 0x20, 0xc8, 0x7a, 0xfa])) - rom.write_bytes(0x17b110, bytearray([0xab, 0x68, 0x80, 0xdb, 0xa7, 0xe9, 0xc9, 0x00, 0x03, 0xb0, 0x07, 0x8d, 0x0f, 0x1c, 0x5c, 0xe0])) - rom.write_bytes(0x17b120, bytearray([0xed, 0xc0, 0x29, 0xff, 0x00, 0xc9, 0xff, 0x00, 0xf0, 0x34, 0xc9, 0xfd, 0x00, 0xf0, 0x41, 0xc9])) - rom.write_bytes(0x17b130, bytearray([0xfe, 0x00, 0xf0, 0x4e, 0x48, 0xa5, 0xe9, 0x8f, 0xe5, 0x7d, 0x20, 0x68, 0xda, 0x0a, 0xaa, 0xbf])) - rom.write_bytes(0x17b140, bytearray([0x5b, 0x27, 0xc8, 0x85, 0xe9, 0xfa, 0x8b, 0x48, 0xda, 0x5a, 0xa9, 0x12, 0x00, 0xa2, 0xa0, 0xf3])) - rom.write_bytes(0x17b150, bytearray([0xa0, 0x44, 0x7e, 0x54, 0x20, 0xcc, 0x7a, 0xfa, 0x68, 0xab, 0x5c, 0xdb, 0xed, 0xc0, 0xaf, 0xe5])) - rom.write_bytes(0x17b160, bytearray([0x7d, 0x20, 0x1a, 0x1a, 0x85, 0xe9, 0xe2, 0x20, 0xa9, 0xcc, 0x85, 0xeb, 0xc2, 0x20, 0x80, 0xea])) - rom.write_bytes(0x17b170, bytearray([0xa5, 0xe9, 0x8f, 0xe5, 0x7d, 0x20, 0xa9, 0xF0, 0x00, 0x85, 0xe9, 0xa9, 0x7d, 0x20, 0x85, 0xea])) - rom.write_bytes(0x17b180, bytearray([0x80, 0xd8, 0xa5, 0xe9, 0x8f, 0xe5, 0x7d, 0x20, 0xa9, 0x44, 0x44, 0x85, 0xe9, 0xa9, 0x7e, 0x20])) - rom.write_bytes(0x17b190, bytearray([0x85, 0xea, 0x80, 0xc6, 0xad, 0x1e, 0x01, 0xc9, 0x60, 0x00, 0xb0, 0x07, 0x18, 0x69, 0x08, 0x00])) - rom.write_bytes(0x17b1a0, bytearray([0x8d, 0x1e, 0x01, 0x5c, 0x21, 0x5b, 0xc0, 0xad, 0x20, 0x01, 0x29, 0xff, 0x00, 0xc9, 0x0e, 0x00])) - rom.write_bytes(0x17b1b0, bytearray([0xb0, 0x03, 0xee, 0x20, 0x01, 0xee, 0x1c, 0x01, 0x5c, 0x3b, 0x5b, 0xc0, 0xb9, 0x00, 0x00, 0x8f])) - rom.write_bytes(0x17b1c0, bytearray([0x8e, 0x05, 0x7e, 0xa9, 0x00, 0x00, 0x8f, 0xe0, 0x7d, 0x20, 0x5c, 0x11, 0x78, 0xc0, 0xc2, 0x20])) - rom.write_bytes(0x17b1d0, bytearray([0xa5, 0x0a, 0xc9, 0xbc, 0x8b, 0xf0, 0x06, 0xe2, 0x20, 0x5c, 0x87, 0x3e, 0xc0, 0xa2, 0x00, 0x00])) - rom.write_bytes(0x17b1e0, bytearray([0xbf, 0xbb, 0x27, 0xc8, 0xa8, 0xe2, 0x20, 0xbf, 0xd0, 0x24, 0xc8, 0x99, 0x00, 0x00, 0xc2, 0x20])) - rom.write_bytes(0x17b1f0, bytearray([0xe8, 0xe8, 0xe0, 0x20, 0x00, 0xf0, 0x02, 0x80, 0xe7, 0xa2, 0x00, 0x00, 0xa0, 0x00, 0x00, 0xa9])) #Number of starting flags - rom.write_bytes(0x17b200, bytearray([0x4d, 0x04, 0x8d, 0x39, 0x0c, 0xbf, 0xF7, 0x24, 0xc8, 0xf0, 0x0c, 0xda, 0x22, 0xe9, 0x5a, 0xc0])) - rom.write_bytes(0x17b210, bytearray([0xc2, 0x20, 0xfa, 0xe8, 0xe8, 0x80, 0xee, 0xa2, 0x00, 0x00, 0xe2, 0x20, 0xbf, 0xF0, 0x24, 0xc8])) - rom.write_bytes(0x17b220, bytearray([0xc2, 0x20, 0xa8, 0xc0, 0x00, 0x00, 0xf0, 0x14, 0x8a, 0x5a, 0xda, 0xa0, 0x00, 0x00, 0x22, 0xe9])) - rom.write_bytes(0x17b230, bytearray([0x5a, 0xc0, 0xc2, 0x20, 0x29, 0xff, 0x00, 0xfa, 0x7a, 0x88, 0x80, 0xe7, 0xe0, 0x05, 0x00, 0xf0])) - rom.write_bytes(0x17b240, bytearray([0x03, 0xe8, 0x80, 0xd6, 0xa9, 0xb4, 0x8b, 0x8d, 0x0a, 0x00, 0xa9, 0x2d, 0x2d, 0x8d, 0x0d, 0x00])) - rom.write_bytes(0x17b250, bytearray([0xa9, 0x04, 0x7e, 0x8d, 0x0f, 0x00, 0x4c, 0xd7, 0xb1, 0x8a, 0x8f, 0xe7, 0x7d, 0x20, 0xe2, 0x20])) - rom.write_bytes(0x17b260, bytearray([0x9b, 0x20, 0xA0, 0xB2, 0x5c, 0xfa, 0x77, 0xc0, 0xe0, 0x66, 0x00, 0xb0, 0x06, 0xa2, 0xf0, 0x7d])) - rom.write_bytes(0x17b270, bytearray([0x4c, 0xDF, 0xb0, 0x8a, 0x38, 0xe9, 0x66, 0x00, 0xaa, 0xbf, 0xb5, 0x27, 0xc8, 0xaa, 0xe2, 0x20])) - rom.write_bytes(0x17b280, bytearray([0x8b, 0xa9, 0xc4, 0x5c, 0xf9, 0x5d, 0xc0, 0xAD, 0xFB, 0x04, 0x29, 0xFF, 0x00, 0xF0, 0x08, 0xAD])) - rom.write_bytes(0x17b290, bytearray([0xfc, 0x04, 0x9c, 0xfb, 0x04, 0x80, 0x03, 0xad, 0x54, 0x22, 0x0a, 0x0a, 0x5c, 0x3e, 0x5c, 0xc0])) - rom.write_bytes(0x17b2a0, bytearray([0xc2, 0x20, 0xa2, 0x00, 0x00, 0x48, 0xaf, 0x00, 0x7E, 0x20, 0xc9, 0x90, 0x28, 0xf0, 0x12, 0x8b])) - rom.write_bytes(0x17b2b0, bytearray([0xda, 0x5a, 0xa9, 0xc5, 0x00, 0xa2, 0x96, 0x26, 0xa0, 0xf0, 0x7d, 0x54, 0x20, 0xc8, 0x7a, 0xfa])) - rom.write_bytes(0x17b2c0, bytearray([0xab, 0x68, 0x60, 0xA9, 0x01, 0x01, 0x8D, 0x0F, 0x00, 0xA9, 0xDC, 0x04, 0x8D, 0x0A, 0x00, 0x5C])) - rom.write_bytes(0x17b2D0, bytearray([0x43, 0x42, 0xC0])) - - rom.write_bytes(0x04f650, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f660, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f670, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f680, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f690, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f6a0, bytearray([0x28, 0x90, 0x28, 0x55, 0x2c, 0x5e, 0x2c, 0x64, 0x2c, 0x5d, 0x2c, 0x53, 0x2c, 0x6d, 0x2c, 0x62])) - rom.write_bytes(0x04f6b0, bytearray([0x2c, 0x57, 0x2c, 0x5e, 0x2c, 0x65, 0x2c, 0x54, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f6c0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f6d0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x04f6e0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x04f6f0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x04f700, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x04f710, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) - rom.write_bytes(0x04f720, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) - rom.write_bytes(0x04f730, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) - rom.write_bytes(0x04f740, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) - rom.write_bytes(0x04f750, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) - rom.write_bytes(0x04f760, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x55, 0x2c, 0x5e, 0x2c, 0x64, 0x2c, 0x5d, 0x2c])) - rom.write_bytes(0x04f770, bytearray([0x53, 0x2c, 0x6d, 0x2c, 0x53, 0x2c, 0x5e, 0x2c, 0x66, 0x2c, 0x5d, 0x2c, 0x90, 0x28, 0x59, 0x2c])) - rom.write_bytes(0x04f780, bytearray([0x50, 0x2c, 0x51, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28])) - rom.write_bytes(0x04f790, bytearray([0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) - rom.write_bytes(0x04f7a0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) - rom.write_bytes(0x04f7b0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) - rom.write_bytes(0x04f7c0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) - rom.write_bytes(0x04f7d0, bytearray([0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x20, 0x00, 0x03, 0x00, 0x00, 0x90])) - rom.write_bytes(0x04f7e0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f7f0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f800, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f810, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f820, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x55, 0x2c, 0x5e])) - rom.write_bytes(0x04f830, bytearray([0x2c, 0x64, 0x2c, 0x5d, 0x2c, 0x53, 0x2c, 0x6d, 0x2c, 0x64, 0x2c, 0x5f, 0x2c, 0x90, 0x28, 0x59])) - rom.write_bytes(0x04f840, bytearray([0x2c, 0x50, 0x2c, 0x51, 0x2c, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x04f850, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x97])) - rom.write_bytes(0x04f860, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x04f870, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x04f880, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x04f890, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28])) - - rom.write_bytes(0x00FBA4, bytearray([0xAD, 0x58, 0x00, 0x29, 0xFF, 0x00, 0xC9, 0xCE, 0x00, 0xD0, 0x07, 0xAD, 0x56, 0x00, 0x8F, 0xE7])) - rom.write_bytes(0x00FBB4, bytearray([0x7D, 0x20, 0xA7, 0x56, 0x85, 0x0A, 0x4C, 0x08, 0x25, 0x00])) - -def code_handlers(rom): - rom.write_bytes(0x020A8F, bytearray([0x5C, 0x07, 0xAe, 0x17]))#Get item from server - - rom.write_bytes(0x004083, bytearray([0x5C, 0x72, 0xB0, 0x17]))#Hide item menu sometimes - - rom.write_bytes(0x006F49, bytearray([0x5C, 0x28, 0xB0, 0x17]))#Lock Phantom behind spells - - rom.write_bytes(0x00423D, bytearray([0x5C, 0xA6, 0xAD, 0x17]))#Fix special chests - - #ORG $C05AF1 - #NOP #5 ;Don't write items from chests, use for remote items - - rom.write_bytes(0x016197, bytearray([0xEA, 0xEA]))#Unlock all maps - - rom.write_bytes(0x01B864, bytearray([0x5C, 0x62, 0xB0, 0x17]))#Send Goal - - rom.write_bytes(0x00FBA0, bytearray([0x5C, 0xCe, 0xB1, 0x17]))#Initalize starting variables - - rom.write_bytes(0x005AEF, bytearray([0x5C, 0xB4, 0xB0, 0x17]))#Prevent 'Archipelago Items' from writing inventory flags - - rom.write_bytes(0x005DEF, bytearray([0x5C, 0xCF, 0xB0, 0x17]))#Redirect AP item names to writable memory - - rom.write_bytes(0x004445, bytearray([0x5C, 0xE8, 0xB0, 0x17]))#Signal to get scout data for normal chests - - rom.write_bytes(0x00EDDB, bytearray([0x5C, 0x14, 0xB1, 0x17]))#Special text pointer for shops - - rom.write_bytes(0x005B1A, bytearray([0x5C, 0x94, 0xB1, 0x17]))#Cap health - - rom.write_bytes(0x005B35, bytearray([0x5C, 0xA7, 0xB1, 0x17]))#Cap magic - - rom.write_bytes(0x00780A, bytearray([0x5C, 0xBC, 0xB1, 0x17]))#Zero screen transition counter - - rom.write_bytes(0x0043B9, bytearray([0x4C, 0xA0, 0xFB])) - - rom.write_bytes(0x0077F4, bytearray([0x5C, 0x59, 0xB2, 0x17]))#Scout special chests - - rom.write_bytes(0x005C40, bytearray([0x5C, 0x40, 0xAD, 0x17]))#Render AP sprites - - rom.write_bytes(0x005C39, bytearray([0x5C, 0x87, 0xB2, 0x17]))#Sprite override - - rom.write_bytes(0x002504, bytearray([0x4C, 0xA4, 0xFB])) - -def casino_text_pointers(rom): - rom.write_bytes(0x050014, bytearray([0xF0, 0xFA])) #Light Sword - rom.write_bytes(0x050028, bytearray([0xC0, 0xFB])) #Light Armor - rom.write_bytes(0x050032, bytearray([0x90, 0xFC])) #Light Shield - rom.write_bytes(0x05001A, bytearray([0x80, 0xFD])) #Boomerang - - -def casino_text(rom): - rom.write_bytes(0x05FAF0, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FB00, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FB10, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FB20, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FB30, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FB40, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x5B])) - rom.write_bytes(0x05FB50, bytearray([0x2C, 0x58, 0x2C, 0x56, 0x2C, 0x57, 0x2C, 0x63, 0x2c, 0x90, 0x28, 0x62, 0x2C, 0x66, 0x2C, 0x5E])) - rom.write_bytes(0x05FB60, bytearray([0x2C, 0x61, 0x2C, 0x53, 0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FB70, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FB80, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FB90, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FBA0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FBB0, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) - - rom.write_bytes(0x05FBC0, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FBD0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FBE0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FBF0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FC00, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FC10, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x5B])) - rom.write_bytes(0x05FC20, bytearray([0x2C, 0x58, 0x2C, 0x56, 0x2C, 0x57, 0x2C, 0x63, 0x2c, 0x90, 0x28, 0x50, 0x2C, 0x61, 0x2C, 0x5C])) - rom.write_bytes(0x05FC30, bytearray([0x2C, 0x5E, 0x2C, 0x61, 0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FC40, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FC50, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FC60, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FC70, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FC80, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) - - rom.write_bytes(0x05FC90, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FCA0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FCB0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FCC0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FCD0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FCE0, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x5B])) - rom.write_bytes(0x05FCF0, bytearray([0x2C, 0x58, 0x2C, 0x56, 0x2C, 0x57, 0x2C, 0x63, 0x2c, 0x90, 0x28, 0x62, 0x2C, 0x57, 0x2C, 0x58])) - rom.write_bytes(0x05FD00, bytearray([0x2C, 0x54, 0x2C, 0x5B, 0x2C, 0x53, 0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FD10, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FD20, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FD30, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FD40, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FD50, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) - - rom.write_bytes(0x05FD80, bytearray([0x20, 0x00, 0x03, 0x00, 0x00, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FD90, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FDA0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FDB0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FDC0, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FDD0, bytearray([0x28, 0x90, 0x28, 0x55, 0x2C, 0x5E, 0x2C, 0x64, 0x2C, 0x5D, 0x2C, 0x53, 0x2C, 0x6D, 0x2C, 0x51])) - rom.write_bytes(0x05FDE0, bytearray([0x2C, 0x5E, 0x2C, 0x5E, 0x2C, 0x5C, 0x2C, 0x54, 0x2c, 0x61, 0x2C, 0x50, 0x2C, 0x5D, 0x2C, 0x56])) - rom.write_bytes(0x05FDF0, bytearray([0x2C, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90, 0x28, 0x90])) - rom.write_bytes(0x05FE00, bytearray([0x28, 0x90, 0x28, 0x90, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FE10, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FE20, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FE30, bytearray([0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97, 0x28, 0x97])) - rom.write_bytes(0x05FE40, bytearray([0x28, 0x97, 0x28, 0x97, 0x28])) - -def overworld_speed(rom): - rom.write_bytes(0x02C58D, bytearray([0x5C, 0xC0, 0xB3, 0x17])) - rom.write_bytes(0x02C56E, bytearray([0x5C, 0xCC, 0xB3, 0x17])) - rom.write_bytes(0x02C559, bytearray([0x5C, 0xD8, 0xB3, 0x17])) - rom.write_bytes(0x02C53A, bytearray([0x5C, 0xE4, 0xB3, 0x17])) - - - rom.write_bytes(0x17B3C0, bytearray([0xB9, 0xDA, 0x06, 0x1A, 0x1A, 0x99, 0xDA, 0x06, 0x5C, 0x94, 0xC5, 0xC2])) - rom.write_bytes(0x17B3CC, bytearray([0xB9, 0xDA, 0x06, 0x3A, 0x3A, 0x99, 0xDA, 0x06, 0x5C, 0x75, 0xC5, 0xC2])) - rom.write_bytes(0x17B3D8, bytearray([0xB9, 0x5A, 0x06, 0x1A, 0x1A, 0x99, 0x5A, 0x06, 0x5C, 0x60, 0xC5, 0xC2])) - rom.write_bytes(0x17B3E4, bytearray([0xB9, 0x5A, 0x06, 0x3A, 0x3A, 0x99, 0x5A, 0x06, 0x5C, 0x41, 0xC5, 0xC2])) - -def quick_magic(rom): - rom.write_bytes(0x021129, bytearray([0x22, 0x40, 0xB3, 0x17, 0xEA, 0xEA])) - - rom.write_bytes(0x17B340, bytearray([0xAD, 0x64, 0x04, 0xF0, 0x60, 0xAD, 0xFB, 0x05, 0x89, 0x03, 0x00, 0xF0, 0x58, 0x22, 0x4B, 0x6D])) - rom.write_bytes(0x17B350, bytearray([0xC0, 0xC2, 0x20, 0xAD, 0xFB, 0x05, 0x89, 0x02, 0x00, 0xD0, 0x07, 0x89, 0x01, 0x00, 0xD0, 0x22])) - rom.write_bytes(0x17B360, bytearray([0x80, 0x43, 0xAE, 0x08, 0x01, 0xCA, 0xE0, 0x03, 0x00, 0xF0, 0xFA, 0xE0, 0x08, 0x00, 0x90, 0x03])) - rom.write_bytes(0x17B370, bytearray([0xA2, 0x07, 0x00, 0xE0, 0x00, 0x00, 0xF0, 0x2A, 0xBD, 0x75, 0x04, 0x29, 0xFF, 0x00, 0xF0, 0xE5])) - rom.write_bytes(0x17B380, bytearray([0x80, 0x20, 0xAE, 0x08, 0x01, 0xE8, 0xE0, 0x03, 0x00, 0xF0, 0xFA, 0xE0, 0x08, 0x00, 0x90, 0x03])) - rom.write_bytes(0x17B390, bytearray([0xA2, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xF0, 0x0A, 0xBD, 0x75, 0x04, 0x29, 0xFF, 0x00, 0xF0, 0xE5])) - rom.write_bytes(0x17B3A0, bytearray([0x80, 0x00, 0x8E, 0x08, 0x01, 0xAD, 0xFB, 0x05, 0x2D, 0x14, 0x01, 0x6B])) - -def disable_encounters(rom): - rom.write_bytes(0x003022, bytearray([0x22, 0xB0, 0xB3, 0x17])) - rom.write_bytes(0x003026, bytearray([0xC9, 0x01])) - rom.write_bytes(0x003028, bytearray([0xD0, 0x03])) - rom.write_bytes(0x00302A, bytearray([0xA9, 0x00, 0xEA])) - rom.write_bytes(0x00302D, bytearray([0xEA, 0xEA])) - - rom.write_bytes(0x17B3B0, bytearray([0xEA, 0xEA, 0xEA, 0xEA])) - rom.write_bytes(0x17B3B4, bytearray([0xEA, 0xEA, 0xEA, 0xEA])) - rom.write_bytes(0x17B3B8, bytearray([0xEA])) - rom.write_bytes(0x17B3B9, bytearray([0xAF, 0x16, 0x42, 0x00])) - rom.write_bytes(0x17B3BD, bytearray([0x6B])) - -def quick_shovel(rom): - rom.write_bytes(0x001CBF, bytearray([0x22, 0xF0, 0xB2, 0xD7])) - - rom.write_bytes(0x17B2F0, bytearray([0xDA, 0xAD, 0xFB, 0x05, 0xC9, 0x00, 0x02, 0xD0, 0x36, 0xAD, 0x59, 0x04, 0x89, 0x01, 0x00, 0xF0])) - rom.write_bytes(0x17B300, bytearray([0x2E, 0xAD, 0x0C, 0x01, 0xC9, 0x0C, 0x00, 0xF0, 0x19, 0xE2, 0x20, 0x8D, 0x28, 0x04, 0xC2, 0x20])) - rom.write_bytes(0x17B310, bytearray([0x22, 0xCE, 0x65, 0xC0, 0x9C, 0x0A, 0x01, 0x9C, 0x0E, 0x01, 0xA9, 0x0C, 0x00, 0x8D, 0x0C, 0x01])) - rom.write_bytes(0x17B320, bytearray([0x80, 0x0D, 0xAD, 0x28, 0x04, 0x29, 0xFF, 0x00, 0x8D, 0x0C, 0x01, 0x22, 0x3B, 0x68, 0xC0, 0xFA])) - rom.write_bytes(0x17B330, bytearray([0xBF, 0xFB, 0x05, 0x7E, 0x6B])) - - rom.write_bytes(0x0065CE, bytearray([0x5C, 0x60, 0xAF, 0xD7])) - - rom.write_bytes(0x17AF90, bytearray([0xC2, 0x20, 0xAD, 0x0C, 0x01, 0xC9, 0x0C, 0x00, 0xF0, 0x10, 0xAD, 0x0A, 0x01, 0xE2, 0x20, 0x8D])) - rom.write_bytes(0x17AFA0, bytearray([0x27, 0x04, 0xC2, 0x20, 0xAD, 0x0E, 0x01, 0x8D, 0x29, 0x04, 0x6B])) - - rom.write_bytes(0x17AFB0, bytearray([0xAD, 0x27, 0x04, 0x29, 0xFF, 0x00, 0x8D, 0x0A, 0x01, 0xAD, 0x29, 0x04, 0x8D, 0x0E, 0x01, 0x6B])) - - rom.write_bytes(0x00683B, bytearray([0x5c, 0xB0, 0xAF, 0xD7])) - -def fix_prices(rom): - #C1FCA7 Life Bottle - #C1FCB2 Boomerang - #C1FCBB Light Shield - #C1FCBF Light Armor - #C1FCC7 Light Sword - rom.write_bytes(0x01FCAB, bytearray([0x00, 0x05, 0x00])) - rom.write_bytes(0x01FCB2, bytearray([0x00, 0x01, 0x00, 0x00])) - rom.write_bytes(0x01FCBB, bytearray([0x02, 0x00, 0x00])) - rom.write_bytes(0x01FCC2, bytearray([0x00, 0x03, 0x00, 0x00, 0x00])) - rom.write_bytes(0x01FCCA, bytearray([0x00, 0x05, 0x00, 0x00, 0x00])) - -def patch_rom(world, rom, player: int, multiworld): - data_main(rom) #Values and pointers - code_main(rom) #code execution - code_handlers(rom) #Jumps to my code - overworld_speed(rom) - casino_text(rom) - casino_text_pointers(rom) - rom.write_bytes(0x00EDCC, bytearray([0xA9, 0x01, 0x00])) #Fast text patch - #rom.write_bytes(0x006D5A, bytearray([0x08])) - #rom.write_bytes(0x02E605, bytearray([0x00])) - rom.write_bytes(0x17AE90, ([world.options.phantom_spells])) - if world.options.disable_encounters == 1: - disable_encounters(rom) - - if world.options.fast_shovel == 1: - quick_shovel(rom) - - if world.options.magic_swap == 1: - quick_magic(rom) - - if world.options.casino_checks == 1: - fix_prices(rom) - - local_start_items = [] - class_map = { - ItemClassification.progression: [0x77, 0x04], - ItemClassification.progression_skip_balancing: [0x77, 0x04], - ItemClassification.filler: [0x76, 0x04], - ItemClassification.useful: [0x76, 0x04], - ItemClassification.trap: [0x76, 0x04] - } - - unique_starting_items = [] - - shop_names = [ - 0x0CAC5E, - 0x0CB0D8, - 0x0CBA64 - ] - - shop_checks = [ - "100 Coin Shop", - "300 Coin Shop", - "500 Coin Shop" - ] - - inv_address = 0 - - for location in world.multiworld.get_locations(player): - if location.address: #dont write local data for events - if location.item.player != location.player: - ap_item = class_map[location.item.classification] - rom.write_bytes(local_locations[location.name], bytearray(ap_item)) - else: - rom.write_bytes(local_locations[location.name], bytearray(local_items[location.item.name])) - - rom.write_byte(0x0824F0, sum(item.name == "Life Bottle" for item in world.multiworld.precollected_items[player])) #The type of item doesn't matter; just count how many they have - rom.write_byte(0x0824F1, sum(item.name == "Magic Bottle" for item in world.multiworld.precollected_items[player])) - rom.write_byte(0x0824F2, sum(item.name == "500 Coins" for item in world.multiworld.precollected_items[player])) - rom.write_byte(0x0824F3, sum(item.name == "1000 Coins" for item in world.multiworld.precollected_items[player])) - rom.write_byte(0x0824F4, sum(item.name == "2000 Coins" for item in world.multiworld.precollected_items[player])) - rom.write_byte(0x0824F5, sum(item.name == "5000 Coins" for item in world.multiworld.precollected_items[player])) - - for item in world.multiworld.precollected_items[player]: - if item.name not in ["Life Bottle", "Magic Bottle", "500 Coins", "1000 Coins", "2000 Coins", "5000 Coins", "Light Gate Lowered", "Sun Gate Lowered", "Star Gate Lowered", "Sun Gate Lowered", "Aqua Gate Lowered", "Moon Gate Lowered"] and item.name not in unique_starting_items: - unique_starting_items.append(item.name) - index = unique_starting_items.index(item.name) + inv_address - rom.write_bytes(0x0824F5 + (index + 2), bytearray(local_items[item.name])) #Major items do literally nothing if the player has more than one, so ignore major items that have more than one copy precollected - inv_address += 1 - for i in range(3): - if world.multiworld.get_location(shop_checks[i], player).item.player != world.player: - rom.write_bytes(shop_names[i], bytearray([0xFD, 0x03])) - else: - rom.write_bytes(shop_names[i], bytearray(shop_items[world.multiworld.get_location(shop_checks[i], player).item.name])) - - rom.write_byte(0x0824D0, world.light_gate) - rom.write_byte(0x0824D2, world.sun_gate) - rom.write_byte(0x0824D4, world.star_gate) - rom.write_byte(0x0824D6, world.aqua_gate) - rom.write_byte(0x0824D8, world.moon_gate) - rom.write_byte(0x0824DA, world.light_switch_default) - rom.write_byte(0x0824DC, world.sun_switch_default) - rom.write_byte(0x0824DE, world.star_switch_default) - rom.write_byte(0x0824E0, world.aqua_switch_default) - rom.write_byte(0x0824E2, world.moon_switch_default) - rom.write_byte(0x0824E4, world.options.early_fuwa) - rom.write_byte(0x0824E6, world.boa_hiya_shortcut) - rom.write_byte(0x0824E8, world.sala_hiya_shortcut) - rom.write_byte(0x0824EA, world.sala_puka_shortcut) - rom.write_byte(0x0824EC, world.fuwa_puka_shortcut) - rom.write_byte(0x0824EE, world.fuwa_poka_shortcut) - - from Main import __version__ - rom.name = bytearray(f'SAI2AP{__version__.replace(".", "")[0:3]}_{player}_{world.multiworld.seed:11}\0', "utf8")[:21] - rom.name.extend([0] * (21 - len(rom.name))) - rom.write_bytes(0x00FFC0, rom.name) - -class SAI2ProcedurePatch(APProcedurePatch, APTokenMixin): - hash = [USHASH] - game = "Super Adventure Island II" - patch_file_ending = ".apsai2" - result_file_ending = ".sfc" - name: bytearray - procedure = [ - ("apply_tokens", ["token_patch.bin"]), - ("apply_bsdiff4", ["mmx3_basepatch.bsdiff4"]), - ] - - @classmethod - def get_source_data(cls) -> bytes: - return get_base_rom_bytes() - - def write_byte(self, offset, value): - self.write_token(APTokenTypes.WRITE, offset, value.to_bytes(1, "little")) - - def write_bytes(self, offset, value: typing.Iterable[int]): - self.write_token(APTokenTypes.WRITE, offset, bytes(value)) - - - -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: - options: Utils.OptionsType = Utils.get_options() - if not file_name: - file_name = options["sai2_options"]["rom_file"] - if not os.path.exists(file_name): - file_name = Utils.user_path(file_name) - return file_name diff --git a/worlds/sai2/Rules.py b/worlds/sai2/Rules.py deleted file mode 100644 index bedbed50c3ba..000000000000 --- a/worlds/sai2/Rules.py +++ /dev/null @@ -1,99 +0,0 @@ -from .extended_logic import logic_helpers -from worlds.generic.Rules import set_rule - - - -logic: logic_helpers -def set_location_rules(world): - logic = logic_helpers(world) - multiworld = world.multiworld - player = world.player - - set_rule(multiworld.get_location("Poka-Poka Lake Chest", player), lambda state: state.has('Silver Sword', player)) - set_rule(multiworld.get_location("Poka-Poka Digging Chest", player), lambda state: state.has('Shovel', player)) - set_rule(multiworld.get_location("Poka-Poka East Cave Chest", player), lambda state: logic.light_switch_on(state)) - - set_rule(multiworld.get_location("Poka-Poka Down Blocks Chest", player), lambda state: (state.has('Down Jab', player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Poka-Poka Moon Alcove Chest", player), lambda state: logic.moon_switch_on(state)) - set_rule(multiworld.get_location("Poka-Poka Sun Blocks Chest", player), lambda state: logic.sun_switch_off(state)) - set_rule(multiworld.get_location("Poka-Poka East Cave Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Poka-Poka Shrine Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Poka-Poka Pushable Rock Chest", player), lambda state: state.has('Shove', player)) - set_rule(multiworld.get_location("Evil Tree Chest", player), lambda state: logic.can_fight_boss(state)) - - set_rule(multiworld.get_location("Boa-Boa Sun Alcove Chest", player), lambda state: logic.sun_switch_on(state)) - set_rule(multiworld.get_location("Boa-Boa Sun Block Chest", player), lambda state: (state.has('Elven Flute', player) and logic.sun_switch_off(state))) - set_rule(multiworld.get_location("Boa-Boa Lava Lake West Chest", player), lambda state: state.has('Shovel', player)) - set_rule(multiworld.get_location("Boa-Boa Eastern Shaft Chest", player), lambda state: (state.has('Down Jab', player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Boa-Boa Western Shaft Chest", player), lambda state: (state.has('Up Jab', player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Boa-Boa Shrine Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Tortoise Chest", player), lambda state: (logic.can_fight_boss(state) and state.has("Shove", player))) - - set_rule(multiworld.get_location("Hiya-Hiya Sun Blocks Chest", player), lambda state: logic.sun_switch_off(state)) - set_rule(multiworld.get_location("Hiya-Hiya Hidden Alcove Chest", player), lambda state: (state.has('Shove', player) and logic.star_switch_on(state))) - set_rule(multiworld.get_location("Hiya-Hiya Up Block Alcove Chest", player), lambda state: (state.has_all({'Shove', "Up Jab"}, player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Hiya-Hiya Trapped Chest", player), lambda state: state.has('Shove', player) and logic.star_switch_off(state)) - set_rule(multiworld.get_location("Hiya-Hiya Ice Cubes Chest", player), lambda state: (state.has_all({'Shove', "Fire Sword"}, player))) - set_rule(multiworld.get_location("Hiya-Hiya Top Level", player), lambda state: state.has('Shove', player)) - set_rule(multiworld.get_location("Hiya-Hiya Long Fall Chest", player), lambda state: state.has('Shove', player) and logic.star_switch_off(state)) - set_rule(multiworld.get_location("Hiya-Hiya Vines Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Hiya-Hiya Shrine Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Mammoth Chest", player), lambda state: logic.can_fight_boss(state) and state.has("Shove", player) and logic.star_switch_off(state)) - - set_rule(multiworld.get_location("Puka-Puka Light Blocks Chest", player), lambda state: logic.light_switch_on(state) and state.has(("Shovel"), player)) - set_rule(multiworld.get_location("Puka-Puka Down Jab Chest", player), lambda state: (state.has('Down Jab', player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Puka-Puka Star Blocks Chest", player), lambda state: logic.star_switch_on(state)) - set_rule(multiworld.get_location("Puka-Puka Up Jab Chest", player), lambda state: (state.has('Up Jab', player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Puka-Puka Spike Maze Lower Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Puka-Puka Spike Maze Upper Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Puka-Puka Shrine Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Puka-Puka Water Control", player), lambda state: (state.has_all({'Shove', "Shovel"}, player))) - set_rule(multiworld.get_location("Puka-Puka Underwater Chest", player), lambda state: state.has('Puka-Puka Drained', player)) - set_rule(multiworld.get_location("Puka-Puka Aqua Blocks Chest", player), lambda state: (state.has_all({'Shovel', "Puka-Puka Drained"}, player)) and logic.aqua_switch_off(state)) - set_rule(multiworld.get_location("Octopus Chest", player), lambda state: (state.has_all({'Shovel', "Puka-Puka Drained"}, player)) and logic.aqua_switch_off(state) and logic.can_fight_boss) - - set_rule(multiworld.get_location("Sala-Sala Pyramid Center Chest", player), lambda state: logic.moon_switch_off(state)) - set_rule(multiworld.get_location("Sala-Sala Star Alcove Chest", player), lambda state: logic.star_switch_on(state)) - set_rule(multiworld.get_location("Sala-Sala Near Entrance Chest", player), lambda state: logic.moon_switch_on(state) and state.has("Shovel", player)) - set_rule(multiworld.get_location("Sala-Sala Top of the Pyramid Chest", player), lambda state: logic.moon_switch_on(state) and (state.has_all({"Shovel", "Down Jab"}, player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Sala-Sala Up Jab Chest", player), lambda state: logic.moon_switch_on(state) and (state.has_all({"Shovel", "Up Jab", "Shove"}, player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Sala-Sala All Blocks Chest", player), lambda state: logic.light_switch_on(state) and logic.sun_switch_on(state) and logic.star_switch_on(state) and logic.aqua_switch_on(state) and logic.moon_switch_on(state)) - set_rule(multiworld.get_location("Sala-Sala Farthest Chest", player), lambda state: (state.has_all({'Elven Flute', "Down Jab"}, player) and state.has_group("Swords", player, 1))) - set_rule(multiworld.get_location("Sala-Sala Shrine Chest", player), lambda state: state.has('Elven Flute', player)) - set_rule(multiworld.get_location("Mummy Chest", player), lambda state: logic.can_fight_boss(state) and logic.has_good_projectile(state)) - - set_rule(multiworld.get_location("Fuwa-Fuwa Block Maze Chest", player), lambda state: state.has_all({'Up Jab', 'Down Jab', 'Power Sword'}, player)) - set_rule(multiworld.get_location("Fuwa-Fuwa Moon Block Chest", player), lambda state: logic.moon_switch_on(state)) - set_rule(multiworld.get_location("Fuwa-Fuwa Light Block Chest", player), lambda state: logic.light_switch_on(state) and state.has("Power Sword", player)) - set_rule(multiworld.get_location("Fuwa-Fuwa Bridge Room Chest", player), lambda state: state.has("Shovel", player)) - set_rule(multiworld.get_location("Fuwa-Fuwa Balance Platforms Chest", player), lambda state: state.has("Shovel", player)) - set_rule(multiworld.get_location("Hawk Chest", player), lambda state: logic.can_fight_boss(state) and state.has_all({"Shovel", "Power Sword"}, player)) - set_rule(multiworld.get_location("Phantom Defeat", player), lambda state: (logic.can_fight_final_boss(state) and logic.has_good_projectile(state)) and state.has_all({"Shovel", "Power Sword"}, player)) - - #set_rule(multiworld.get_location("Muscle Lizard Chest", player), lambda state: logic.has_early_health(state)) - set_rule(multiworld.get_location("Ice Cave Chest", player), lambda state: state.has('Shove', player)) - set_rule(multiworld.get_location("Saber Tooth Chest", player), lambda state: logic.can_fight_boss(state)) - set_rule(multiworld.get_location("300 Coin Shop", player), lambda state: state.has_group("Coins", player, 1)) - set_rule(multiworld.get_location("500 Coin Shop", player), lambda state: (state.has_group("Coins", player, 2) or state.has_any({"1000 Coins", "2000 Coins", "5000 Coins"}, player))) - - set_rule(multiworld.get_location("Boa-Hiya Shortcut Room", player), lambda state: state.has_all({"Shovel", "Shove"}, player)) - set_rule(multiworld.get_location("Sala-Hiya Shortcut Room", player), lambda state: state.has('Shove', player)) - set_rule(multiworld.get_location("Sala-Puka Shortcut Room", player), lambda state: state.has_all({"Shovel", "Shove"}, player) and logic.moon_switch_on) - set_rule(multiworld.get_location("Fuwa-Poka Shortcut Room", player), lambda state: state.has_all({"Shovel", "Shove"}, player)) - set_rule(multiworld.get_location("Fuwa-Puka Shortcut Room", player), lambda state: state.has_all({"Down Jab", "Power Sword", "Shove"}, player)) - - - if world.light_gate == 0: - set_rule(multiworld.get_location("Light Gate", player), lambda state: state.has('Light Stone', player)) - - if world.sun_gate == 0: - set_rule(multiworld.get_location("Sun Gate", player), lambda state: state.has('Sun Stone', player)) - - if world.star_gate == 0: - set_rule(multiworld.get_location("Star Gate", player), lambda state: state.has('Star Stone', player)) - - if world.aqua_gate == 0: - set_rule(multiworld.get_location("Aqua Gate", player), lambda state: state.has('Aqua Stone', player)) - - if world.moon_gate == 0: - set_rule(multiworld.get_location("Moon Gate", player), lambda state: state.has('Moon Stone', player)) \ No newline at end of file diff --git a/worlds/sai2/__init__.py b/worlds/sai2/__init__.py deleted file mode 100644 index 5bb03f90b2a0..000000000000 --- a/worlds/sai2/__init__.py +++ /dev/null @@ -1,293 +0,0 @@ -import os -import typing -import threading - -from typing import List, Set, TextIO -from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification -from worlds.AutoWorld import World, WebWorld -import settings -from .Items import get_item_names_per_category, item_table, filler_items -from .Locations import get_locations -from .Regions import init_areas -from .Options import SAI2Options -from .setup_game import setup_gamevars -from .Client import SAI2SNIClient -from .Rules import set_location_rules -from .Rom import LocalRom, patch_rom, get_base_rom_path, SAI2ProcedurePatch, USHASH - -class SAI2Settings(settings.Group): - class RomFile(settings.SNESRomPath): - """File name of the Super Adventure Island II US ROM""" - description = "Super Adventure Island II ROM File" - copy_to = "Super Adventure Island II (USA).sfc" - md5s = [USHASH] - - rom_file: RomFile = RomFile(RomFile.copy_to) - -class SAI2Web(WebWorld): - theme = "ocean" - - setup_en = Tutorial( - "Multiworld Setup Guide", - "A guide to setting up the Super Adventure Island II randomizer" - "and connecting to an Archipelago server.", - "English", - "setup_en.md", - "setup/en", - ["Pink Switch"] - ) - - tutorials = [setup_en] - -class SAI2World(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 = "Super Adventure Island II" - option_definitions = SAI2Options - data_version = 1 - required_client_version = (0, 3, 5) - - 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 = SAI2Web() - settings: typing.ClassVar[SAI2Settings] - #topology_present = True - - options_dataclass = SAI2Options - options: SAI2Options - - locked_locations: List[str] - location_cache: List[Location] - placed_life_bottles = 0 - first_weapon_placed = False - first_projectile_placed = False - - item_classifications = {"filler": ItemClassification.filler, - "useful": ItemClassification.useful, - "progression": ItemClassification.progression} - - def __init__(self, world: MultiWorld, player: int): - self.rom_name_available_event = threading.Event() - super().__init__(world, player) - - self.locked_locations= [] - self.location_cache= [] - self.locked_items = 17 - - - #def write_spoiler_header(self, spoiler_handle: TextIO) -> None: - #spoiler_handle.write(f"Burt The Bashful's Boss Door: {self.starting_item}\n") - - def create_item(self, name: str) -> Item: - data = item_table[name] - classification = self.item_classifications[data.classification] - item = Item(name, classification, data.code, self.player) - - return item - - def create_regions(self): - init_areas(self, get_locations(self)) - - def get_filler_item_name(self) -> str: - return self.random.choice(filler_items) - - def set_rules(self): - set_location_rules(self) - self.multiworld.completion_condition[self.player] = lambda state: state.has('Tina', self.player) - self.multiworld.get_location("Poka-Poka First Cave", self.player).place_locked_item(self.create_item("Light Switch")) - self.multiworld.get_location("Hiya-Hiya Top Level", self.player).place_locked_item(self.create_item("Star Switch")) - self.multiworld.get_location("Boa-Boa Hidden Wall", self.player).place_locked_item(self.create_item("Sun Switch")) - self.multiworld.get_location("Puka-Puka Switch Room", self.player).place_locked_item(self.create_item("Aqua Switch")) - self.multiworld.get_location("Sala-Sala Switch Room", self.player).place_locked_item(self.create_item("Moon Switch")) - self.multiworld.get_location("Puka-Puka Water Control", self.player).place_locked_item(self.create_item("Puka-Puka Drained")) - self.multiworld.get_location("Phantom Defeat", self.player).place_locked_item(self.create_item("Tina")) - - self.multiworld.get_location("Boa-Hiya Shortcut Room", self.player).place_locked_item(self.create_item("Boa-Hiya Shortcut Open")) - self.multiworld.get_location("Sala-Hiya Shortcut Room", self.player).place_locked_item(self.create_item("Sala-Hiya Shortcut Open")) - self.multiworld.get_location("Sala-Puka Shortcut Room", self.player).place_locked_item(self.create_item("Sala-Puka Shortcut Open")) - self.multiworld.get_location("Fuwa-Puka Shortcut Room", self.player).place_locked_item(self.create_item("Fuwa-Puka Shortcut Open")) - self.multiworld.get_location("Fuwa-Poka Shortcut Room", self.player).place_locked_item(self.create_item("Fuwa-Poka Shortcut Open")) - - self.multiworld.get_location("Light Gate", self.player).place_locked_item(self.create_item("Light Gate Lowered")) - self.multiworld.get_location("Sun Gate", self.player).place_locked_item(self.create_item("Sun Gate Lowered")) - self.multiworld.get_location("Star Gate", self.player).place_locked_item(self.create_item("Star Gate Lowered")) - self.multiworld.get_location("Aqua Gate", self.player).place_locked_item(self.create_item("Aqua Gate Lowered")) - self.multiworld.get_location("Moon Gate", self.player).place_locked_item(self.create_item("Moon Gate Lowered")) - - if self.options.shuffle_skills != 2: - self.multiworld.get_location("100 Coin Shop", self.player).place_locked_item(self.create_item(self.locked_skills[0])) - self.multiworld.get_location("300 Coin Shop", self.player).place_locked_item(self.create_item(self.locked_skills[1])) - self.multiworld.get_location("500 Coin Shop", self.player).place_locked_item(self.create_item(self.locked_skills[2])) - - if self.options.casino_checks == 0: - self.multiworld.get_location("Casino 500 Coin Purchase", self.player).place_locked_item(self.create_item("Life Bottle")) - self.multiworld.get_location("Casino 1000 Coin Purchase", self.player).place_locked_item(self.create_item("Boomerang")) - self.multiworld.get_location("Casino 2000 Coin Purchase", self.player).place_locked_item(self.create_item("Light Shield")) - self.multiworld.get_location("Casino 3000 Coin Purchase", self.player).place_locked_item(self.create_item("Light Armor")) - self.multiworld.get_location("Casino 5000 Coin Purchase", self.player).place_locked_item(self.create_item("Light Sword")) - else: - self.multiworld.itempool.append(self.create_item('Life Bottle')) - self.multiworld.itempool.append(self.create_item('Boomerang')) - self.multiworld.itempool.append(self.create_item('Light Shield')) - self.multiworld.itempool.append(self.create_item('Light Sword')) - self.multiworld.itempool.append(self.create_item('Light Armor')) - - - def generate_early(self): - self.locals = [] - setup_gamevars(self) - if self.options.world_state != 1: - self.multiworld.push_precollected(self.create_item(self.starting_item)) - if self.options.extra_health == 1: - for _ in range(2): - self.multiworld.push_precollected(self.create_item("Life Bottle")) - - if self.light_gate == 1: - self.multiworld.push_precollected(self.create_item("Light Gate Lowered")) - - if self.sun_gate == 1: - self.multiworld.push_precollected(self.create_item("Sun Gate Lowered")) - - if self.star_gate == 1: - self.multiworld.push_precollected(self.create_item("Star Gate Lowered")) - - if self.aqua_gate == 1: - self.multiworld.push_precollected(self.create_item("Aqua Gate Lowered")) - - if self.moon_gate == 1: - self.multiworld.push_precollected(self.create_item("Moon Gate Lowered")) - - - - def get_excluded_items(self) -> Set[str]: - excluded_items: Set[str] = set() - if self.options.boss_spells == 1: - excluded_items.add('Light Spell') - excluded_items.add('Star Spell') - excluded_items.add('Sun Spell') - excluded_items.add('Aqua Spell') - excluded_items.add('Moon Spell') - - if self.options.shuffle_skills != 2: - excluded_items.add("Shove") - excluded_items.add("Down Jab") - excluded_items.add("Up Jab") - - return excluded_items - - def get_dynamic_classes(self, player: int, name: str) -> Item: - data = item_table[name] - classification = self.item_classifications[data.classification] - item = Item(name, classification, data.code, player) - weapons = ["Ice Sword", "Thunder Sword", "Crystal Sword", "Light Sword", "Dagger", "Fireballs", "Silver Sword", "Fire Sword", "Power Sword"] - projectiles = ["Ax", "Boomerang"] - - if not self.options.casino_checks: - weapons.remove("Light Sword") - - if not item.advancement: - return item - - if name in weapons: - if self.first_weapon_placed == True: - if name not in ["Silver Sword", "Power Sword", "Fire Sword"]: - item.classification = ItemClassification.useful - else: - self.first_weapon_placed = True - - if name in projectiles: - if self.first_projectile_placed == True: - item.classification = ItemClassification.useful - else: - self.first_projectile_placed = True - - if name == "Life Bottle": - item.classification = ItemClassification.useful - - if name == ("Light Sword" or "Boomerang") and self.options.casino_checks != 1: - item.classification = ItemClassification.useful - - if name == "Light Stone" and self.light_gate == 1: - item.classification = ItemClassification.filler - - if name == "Sun Stone" and self.sun_gate == 1: - item.classification = ItemClassification.filler - - if name == "Star Stone" and self.star_gate == 1: - item.classification = ItemClassification.filler - - if name == "Aqua Stone" and self.aqua_gate == 1: - item.classification = ItemClassification.filler - - if name == "Moon Stone" and self.moon_gate == 1: - item.classification = ItemClassification.filler - - return item - - def generate_filler(self, multiworld: MultiWorld, player: int, - pool: List[Item]): - - for _ in range(len(multiworld.get_unfilled_locations(player)) - len(pool) - self.locked_items): #- number of event items - item = self.get_dynamic_classes(player, self.get_filler_item_name()) - pool.append(item) - - def get_item_pool(self, player: int, 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.get_dynamic_classes(player, name) - pool.append(item) - - return pool - - - - def create_items(self): - if self.options.casino_checks == 0: - self.locked_items += 5 - - if self.options.shuffle_skills !=2: - self.locked_items += 3 - - if self.options.boss_spells == 1: - self.locked_items += 5 - excluded_items = self.get_excluded_items() - - pool = self.get_item_pool(self.player, excluded_items) - - self.generate_filler(self.multiworld, self.player, pool) - - self.multiworld.itempool += pool - - def generate_output(self, output_directory: str): - try: - world = self.multiworld - player = self.player - patch = SAI2ProcedurePatch() - patch_rom(self, patch, self.player, self.multiworld) - - self.rom_name = patch.name - - patch.write(os.path.join(output_directory, - f"{self.multiworld.get_out_file_name_base(self.player)}{patch.patch_file_ending}")) - except Exception: - raise - finally: - self.rom_name_available_event.set() # make sure threading continues and errors are collected - - def modify_multidata(self, multidata: dict): - import base64 - # 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]]): \ No newline at end of file diff --git a/worlds/sai2/extended_logic.py b/worlds/sai2/extended_logic.py deleted file mode 100644 index 5acc5f1e412e..000000000000 --- a/worlds/sai2/extended_logic.py +++ /dev/null @@ -1,99 +0,0 @@ -from BaseClasses import CollectionState - -class logic_helpers: - player: int - - - def __init__(self, world): - self.player = world.player - self.fuwa_open = False - self.light_switch_default = world.light_switch_default - self.sun_switch_default = world.sun_switch_default - self.star_switch_default = world.star_switch_default - self.aqua_switch_default = world.aqua_switch_default - self.moon_switch_default = world.moon_switch_default - - self.light_gate = world.light_gate - self.sun_gate = world.sun_gate - self.star_gate = world.star_gate - self.aqua_gate = world.aqua_gate - self.moon_gate = world.moon_gate - - if world.options.early_fuwa.value == 1: - self.fuwa_open = True - - if world.options.phantom_spells.value == 0: - self.phantom_open = True - - def fuwa_access(self, state: CollectionState) -> bool: - return (state.has_all({"Light Spell", "Sun Spell", "Star Spell", "Aqua Spell", "Moon Spell"}, self.player) or self.fuwa_open) - - def phantom_spells(self, state: CollectionState) -> bool: - return (state.has_all({"Light Spell", "Sun Spell", "Star Spell", "Aqua Spell", "Moon Spell"}, self.player) or self.phantom_open) - - def has_early_health(self, state: CollectionState) -> bool: - return state.has("Life Bottle", self.player, 2) - - def light_switch_on(self, state: CollectionState) -> bool: - if self.light_switch_default == 0: - return state.has("Light Switch", self.player) - else: - return True - - def sun_switch_on(self, state: CollectionState) -> bool: - if self.sun_switch_default == 0: - return state.has("Sun Switch", self.player) - else: - return True - - def sun_switch_off(self, state: CollectionState) -> bool: - if self.sun_switch_default == 1: - return state.has("Sun Switch", self.player) - else: - return True - - def star_switch_on(self, state: CollectionState) -> bool: - if self.star_switch_default == 0: - return state.has("Star Switch", self.player) - else: - return True - - def star_switch_off(self, state: CollectionState) -> bool: - if self.star_switch_default == 1: - return state.has("Star Switch", self.player) - else: - return True - - def aqua_switch_on(self, state: CollectionState) -> bool: - if self.aqua_switch_default == 0: - return state.has("Aqua Switch", self.player) - else: - return True - - def aqua_switch_off(self, state: CollectionState) -> bool: - if self.aqua_switch_default == 1: - return state.has("Aqua Switch", self.player) - else: - return True - - def moon_switch_on(self, state: CollectionState) -> bool: - if self.moon_switch_default == 0: - return state.has("Moon Switch", self.player) - else: - return True - - def moon_switch_off(self, state: CollectionState) -> bool: - if self.moon_switch_default == 1: - return state.has("Moon Switch", self.player) - else: - return True - - def can_fight_boss(self, state: CollectionState) -> bool: - return (state.has_group("Swords", self.player, 1) or state.has_group("Projectiles", self.player, 1)) and self.has_early_health - - def has_good_projectile(self, state: CollectionState) -> bool: - return state.has_group("Projectiles", self.player, 1) - - def can_fight_final_boss(self, state: CollectionState) -> bool: - return state.has_group("Armor", self.player, 1) and self.has_early_health and self.phantom_spells - \ No newline at end of file diff --git a/worlds/sai2/local_data.py b/worlds/sai2/local_data.py deleted file mode 100644 index 4c9daa7208e9..000000000000 --- a/worlds/sai2/local_data.py +++ /dev/null @@ -1,546 +0,0 @@ - -local_items = { - "Life Bottle": [0x00, 0x00], - "Magic Bottle": [0x01, 0x00], - "500 Coins": [0x02, 0x00], - "1000 Coins": [0x03, 0x00], - "2000 Coins": [0x04, 0x00], - "5000 Coins": [0x05, 0x00], - - "Silver Sword": [0x4E, 0x04], - "Fire Sword": [0x4F, 0x04], - "Ice Sword": [0x50, 0x04], - "Thunder Sword": [0x51, 0x04], - "Crystal Sword": [0x52, 0x04], - "Power Sword": [0x53, 0x04], - "Light Sword": [0x54, 0x04], - "Dagger": [0x55, 0x04], - "Fireballs": [0x56, 0x04], - "Boomerang": [0x57, 0x04], - "Ax": [0x58, 0x04], - "Shovel": [0x59, 0x04], - - "Fire Armor": [0x5B, 0x04], - "Ice Armor": [0x5C, 0x04], - "Aqua Armor": [0x5D, 0x04], - "Light Armor": [0x5E, 0x04], - - "Fire Shield": [0x60, 0x04], - "Ice Shield": [0x61, 0x04], - "Aqua Shield": [0x62, 0x04], - "Light Shield": [0x63, 0x04], - - "Wand": [0x64, 0x04], - "Ice Bell": [0x66, 0x04], - "Sun Ring": [0x67, 0x04], - "Power Fan": [0x68, 0x04], - "Elven Flute": [0x69, 0x04], - "Sky Bell": [0x6A, 0x04], - "Light Stone": [0x6B, 0x04], - "Sun Stone": [0x6C, 0x04], - "Star Stone": [0x6D, 0x04], - "Aqua Stone": [0x6E, 0x04], - "Moon Stone": [0x6F, 0x04], - - "Light Spell": [0x70, 0x04], - "Sun Spell": [0x71, 0x04], - "Star Spell": [0x72, 0x04], - "Aqua Spell": [0x73, 0x04], - "Moon Spell": [0x74, 0x04], - - "Shove": [0x7D, 0x04], - "Up Jab": [0x7E, 0x04], - "Down Jab": [0x7F, 0x04] - -} - -local_locations = { - "Poka-Poka West Cave Chest": 0x018E7B, - "Poka-Poka Digging Chest": 0x018D90, - "Poka-Poka Lake Chest": 0x018893, - "Poka-Poka Down Blocks Chest": 0x01909D, - "Poka-Poka Moon Alcove Chest": 0x019081, - "Poka-Poka Sun Blocks Chest": 0x018E25, - "Poka-Poka East Cave Chest": 0x018E41, - "Poka-Poka Shrine Chest": 0x01911D, - "Poka-Poka Pushable Rock Chest": 0x018DD3, - "Poka-Poka Tree Chest": 0x018B4A, - "Evil Tree Chest": 0x082610, - - "Boa-Boa Lava Lake East Chest": 0x0FC817, - "Boa-Boa Lava Lake West Chest": 0x0FC7FF, - "Boa-Boa Sun Alcove Chest": 0x0FC7D1, - "Boa-Boa Clouds Chest": 0x0FC7BA, - "Boa-Boa Sun Block Chest": 0x0FC7E8, - "Boa-Boa Shrine Chest": 0x082612, - "Boa-Boa Western Shaft Chest": 0x0FC82D, - "Boa-Boa Eastern Shaft Chest": 0x0FC844, - "Tortoise Chest": 0x082614, - - "Hiya-Hiya Clouds Chest": 0x0FB565, - "Hiya-Hiya Underground Chest": 0x0FB581, - "Hiya-Hiya Sun Blocks Chest": 0x0FB59D, - "Hiya-Hiya Up Block Alcove Chest": 0x0FB5D5, - "Hiya-Hiya Ice Cubes Chest": 0x0FB60D, - "Hiya-Hiya Hidden Alcove Chest": 0x0FB629, - "Hiya-Hiya Trapped Chest": 0x0FB5F1, - "Hiya-Hiya Long Fall Chest": 0x0FB5B9, - "Hiya-Hiya Vines Chest": 0x0FB645, - "Hiya-Hiya Shrine Chest": 0x0FB65C, - "Mammoth Chest": 0x082616, - - "Puka-Puka Light Blocks Chest": 0x0FD59E, - "Puka-Puka Down Jab Chest": 0x0FD5B5, - "Puka-Puka Star Blocks Chest": 0x0FD5CC, - "Puka-Puka Up Jab Chest": 0x0FD5E3, - "Puka-Puka Moving Platforms Chest": 0x0FD656, - "Puka-Puka Springs Chest": 0x0FD66D, - "Puka-Puka Spike Maze Lower Chest": 0x0FD63F, - "Puka-Puka Spike Maze Upper Chest": 0x0FD628, - "Puka-Puka Shrine Chest": 0x0FD684, - "Puka-Puka Underwater Chest": 0x0FD5FA, - "Puka-Puka Aqua Blocks Chest": 0x0FD611, - "Octopus Chest": 0x082618, - - "Sala-Sala Pyramid Center Chest": 0x0FE69D, - "Sala-Sala Star Alcove Chest": 0x0FE641, - "Sala-Sala Near Entrance Chest": 0x0FE613, - "Sala-Sala Top of the Pyramid Chest": 0x0FE658, - "Sala-Sala Up Jab Chest": 0x0FE62A, - "Sala-Sala All Blocks Chest": 0x0FE66F, - "Sala-Sala Farthest Chest": 0x0FE686, - "Sala-Sala Elevator Chest": 0x0FE6B4, - "Sala-Sala Shrine Chest": 0x08261A, - "Mummy Chest": 0x08261C, - - "Fuwa-Fuwa Block Maze Chest": 0x0FEF93, - "Fuwa-Fuwa Moon Block Chest": 0x0FEFAA, - "Fuwa-Fuwa Light Block Chest": 0x0FEFC1, - "Fuwa-Fuwa Bridge Room Chest": 0x0FEFD8, #??? - "Fuwa-Fuwa Balance Platforms Chest": 0x0FEFEF, #Cast doubt on this - "Hawk Chest": 0x08261E, - - "Muscle Lizard Chest": 0x082620, - "Ice Cave Chest": 0x082622, - "Desert Island Chest": 0x082624, - "Overworld Tomb Chest": 0x082626, - "Northern Cave Chest": 0x082628, - "Saber Tooth Chest": 0x08262A, - "300 Coin Shop": 0x08262C, - "500 Coin Shop": 0x08262E, - "100 Coin Shop": 0x082630, - - "Casino 5000 Coin Purchase": 0x082632, - "Casino 3000 Coin Purchase": 0x082634, - "Casino 2000 Coin Purchase": 0x082636, - "Casino 1000 Coin Purchase": 0x082638, - "Casino 500 Coin Purchase": 0x08263A, - "Waku-Waku King's Gift": 0x08263A -} - -plain_encoding_table = { -'0': ([0x01, 0x00]), -'1': ([0x02, 0x00]), -'2': ([0x03, 0x00]), -"3": ([0x04, 0x00]), -"4": ([0x05, 0x00]), -"5": ([0x06, 0x00]), -"6": ([0x07, 0x00]), -"7": ([0x08, 0x00]), -"8": ([0x09, 0x00]), -"9": ([0x0A, 0x00]), -"·": ([0x13, 0x00]), -"◦": ([0x14, 0x00]), -#",": ([0x15, 0x00]), -"~": ([0x16, 0x00]), -"—": ([0x17, 0x00]), -"A": ([0x19, 0x00]), -"B": ([0x1A, 0x00]), -"C": ([0x1B, 0x00]), -"D": ([0x1C, 0x00]), -"E": ([0x1D, 0x00]), -"F": ([0x1E, 0x00]), -"G": ([0x1F, 0x00]), -"H": ([0x20, 0x00]), -"I": ([0x21, 0x00]), -"J": ([0x22, 0x00]), -"K": ([0x23, 0x00]), -"L": ([0x24, 0x00]), -"M": ([0x25, 0x00]), -"N": ([0x26, 0x00]), -"O": ([0x27, 0x00]), -"P": ([0x28, 0x00]), -"Q": ([0x29, 0x00]), -"R": ([0x2A, 0x00]), -"S": ([0x2B, 0x00]), -"T": ([0x2C, 0x00]), -"U": ([0x2D, 0x00]), -"V": ([0x2E, 0x00]), -"W": ([0x2F, 0x00]), -"X": ([0x30, 0x00]), -"Y": ([0x31, 0x00]), -"Z": ([0x32, 0x00]), -"&": ([0x33, 0x00]), -" ": ([0x00, 0x01]), -"a": ([0x01, 0x01]), -"b": ([0x02, 0x01]), -"c": ([0x03, 0x01]), -"d": ([0x04, 0x01]), -"e": ([0x05, 0x01]), -"f": ([0x06, 0x01]), -"g": ([0x07, 0x01]), -"h": ([0x08, 0x01]), -"i": ([0x09, 0x01]), -"j": ([0x0A, 0x01]), -"k": ([0x0B, 0x01]), -"l": ([0x0C, 0x01]), -"m": ([0x0D, 0x01]), -"n": ([0x0E, 0x01]), -"o": ([0x0F, 0x01]), -"p": ([0x10, 0x01]), -"q": ([0x11, 0x01]), -"r": ([0x12, 0x01]), -"s": ([0x13, 0x01]), -"t": ([0x14, 0x01]), -"u": ([0x15, 0x01]), -"v": ([0x16, 0x01]), -"w": ([0x17, 0x01]), -"x": ([0x18, 0x01]), -"y": ([0x19, 0x01]), -"z": ([0x1A, 0x01]), -"!": ([0x1B, 0x01]), -"?": ([0x1C, 0x01]), -"Γ": ([0x1D, 0x01]), -"⅃": ([0x1E, 0x01]), -"(": ([0x1F, 0x01]), -")": ([0x20, 0x01]), -"'": ([0x21, 0x01]), -":": ([0x22, 0x01]), -";": ([0x23, 0x01]), -"-": ([0x24, 0x01]), -",": ([0x26, 0x01]), -".": ([0x27, 0x01]), -"<": ([0x28, 0x01]), -">": ([0x29, 0x01]), -'"': ([0x2A, 0x01]), -"/": ([0x2B, 0x01]), -"+": ([0x2C, 0x01]) -} - -hud_encoding_table = { - "A": ([0x50, 0x2C]), - "B": ([0x51, 0x2C]), - "C": ([0x52, 0x2C]), - "D": ([0x53, 0x2C]), - "E": ([0x54, 0x2C]), - "F": ([0x55, 0x2C]), - "G": ([0x56, 0x2C]), - "H": ([0x57, 0x2C]), - "I": ([0x58, 0x2C]), - "J": ([0x59, 0x2C]), - "K": ([0x5A, 0x2C]), - "L": ([0x5B, 0x2C]), - "M": ([0x5C, 0x2C]), - "N": ([0x5D, 0x2C]), - "O": ([0x5E, 0x2C]), - "P": ([0x5F, 0x2C]), - "Q": ([0x60, 0x2C]), - "R": ([0x61, 0x2C]), - "S": ([0x62, 0x2C]), - "T": ([0x63, 0x2C]), - "U": ([0x64, 0x2C]), - "V": ([0x65, 0x2C]), - "W": ([0x66, 0x2C]), - "X": ([0x67, 0x2C]), - "Y": ([0x68, 0x2C]), - "Z": ([0x69, 0x2C]), - "'": ([0x6A, 0x2C]), - "&": ([0x6B, 0x2C]), - "/": ([0x6C, 0x2C]), - ":": ([0x6D, 0x2C]), - "-": ([0x7E, 0x2C]), - "+": ([0x7F, 0x2C]), - "~": ([0x8B, 0x2C]), - "!": ([0x8C, 0x2C]), - ".": ([0x8D, 0x2C]), - "?": ([0x8F, 0x2C]), - " ": ([0x90, 0x28]), - "0": ([0xA0, 0x2C]), - "1": ([0xA1, 0x2C]), - "2": ([0xA2, 0x2C]), - "3": ([0xA3, 0x2C]), - "4": ([0xA4, 0x2C]), - "5": ([0xA5, 0x2C]), - "6": ([0xA6, 0x2C]), - "7": ([0xA7, 0x2C]), - "8": ([0xA8, 0x2C]), - "9": ([0xA9, 0x2C]) - } - -scout_location_map = { - 0x8893: 0x5A1000, - 0x8B4A: 0x5A1001, - 0x8D90: 0x5A1002, - 0x8DD3: 0x5A1003, - 0x8E25: 0x5A1004, - 0x8E41: 0x5A1005, - 0x8E7B: 0x5A1006, - 0x9081: 0x5A1007, - 0x909D: 0x5A1008, - 0x911D: 0x5A1009, - - 0xC7BA: 0x5A100B, - 0xC7D1: 0x5A100C, - 0xC7E8: 0x5A100D, - 0xC7FF: 0x5A100E, - 0xC817: 0x5A100F, - 0xC82D: 0x5A1010, - 0xC844: 0x5A1011, - - 0xB565: 0x5A1014, - 0xB581: 0x5A1015, - 0xB59D: 0x5A1016, - 0xB62B: 0x5A1017, - 0xB5D5: 0x5A1018, - 0xB5F3: 0x5A1019, - 0xB60D: 0x5A101A, - 0xB5B9: 0x5A101B, - 0xB645: 0x5A101C, - 0xB65C: 0x5A101D, - - 0xD59E: 0x5A101F, - 0xD5B5: 0x5A1020, - 0xD5CC: 0x5A1021, - 0xD5E3: 0x5A1022, - 0xD5FA: 0x5A1023, - 0xD611: 0x5A1024, - 0xD628: 0x5A1025, - 0xD63F: 0x5A1026, - 0xD656: 0x5A1027, - 0xD66D: 0x5A1028, - 0xD684: 0x5A1029, - - 0xE613: 0x5A102B, - 0xE62A: 0x5A102C, - 0xE641: 0x5A102D, - 0xE658: 0x5A102E, - 0xE66F: 0x5A102F, - 0xE686: 0x5A1030, - 0xE69B: 0x5A1031, - 0xE6B4: 0x5A1032, - - 0xEF93: 0x5A1035, - 0xEFAA: 0x5A1036, - 0xEFC1: 0x5A1037, - 0x0FD8: 0x5A1038, - 0xEFEF: 0x5A1039 -} - -special_chests = { - 0xB4E6: 0x5A103B,#Special chests need separate mapping - 0xFEBF: 0x5A103C, - 0xB14D: 0x5A103E, - 0xB0F7: 0x5A103F, - 0xA781: 0x5A1041, - 0xC9D4: 0x5A1040, - 0xE5A1: 0x5A100A, - 0xE12A: 0x5A1012, - 0xEE4C: 0x5A1013, - 0xAC15: 0x5A102A, - 0xF441: 0x5A101E, - 0xB0A1: 0x5A1033, - 0xAA49: 0x5A1034, - 0x8284: 0x5A103A -} - -shop_scouts = { - 0xA7D7: 0x5A1042, - 0xA82D: 0x5A1043, - 0xA883: 0x5A103D -} - - -shop_items = { - "Life Bottle": [0x27, 0x03], - "Magic Bottle": [0x28, 0x03], - "500 Coins": [0x29, 0x03], - "1000 Coins": [0x2A, 0x03], - "2000 Coins": [0x2B, 0x03], - "5000 Coins": [0x2C, 0x03], - - "Silver Sword": [0x00, 0x03], - "Fire Sword": [0x01, 0x03], - "Ice Sword": [0x02, 0x03], - "Thunder Sword": [0x03, 0x03], - "Crystal Sword": [0x04, 0x03], - "Power Sword": [0x05, 0x03], - "Light Sword": [0x06, 0x03], - "Dagger": [0x07, 0x03], - "Fireballs": [0x08, 0x03], - "Boomerang": [0x09, 0x03], - "Ax": [0x0A, 0x03], - "Shovel": [0x0B, 0x03], - - "Fire Armor": [0x0C, 0x03], - "Ice Armor": [0x0D, 0x03], - "Aqua Armor": [0x0E, 0x03], - "Light Armor": [0x0F, 0x03], - - "Fire Shield": [0x10, 0x03], - "Ice Shield": [0x11, 0x03], - "Aqua Shield": [0x12, 0x03], - "Light Shield": [0x13, 0x03], - - "Wand": [0x14, 0x03], - "Ice Bell": [0x15, 0x03], - "Sun Ring": [0x16, 0x03], - "Power Fan": [0x17, 0x03], - "Elven Flute": [0x18, 0x03], - "Sky Bell": [0x19, 0x03], - "Light Stone": [0x1A, 0x03], - "Sun Stone": [0x1B, 0x03], - "Star Stone": [0x1C, 0x03], - "Aqua Stone": [0x1D, 0x03], - "Moon Stone": [0x1E, 0x03], - - "Light Spell": [0x1F, 0x03], - "Sun Spell": [0x20, 0x03], - "Star Spell": [0x21, 0x03], - "Aqua Spell": [0x22, 0x03], - "Moon Spell": [0x23, 0x03], - - "Shove": [0x24, 0x03], - "Up Jab": [0x25, 0x03], - "Down Jab": [0x26, 0x03] -} - -location_list = [ - 0x5A1000, - 0x5A1001, - 0x5A1002, - 0x5A1003, - 0x5A1004, - 0x5A1005, - 0x5A1006, - 0x5A1007, - 0x5A1008, - 0x5A1009, - 0x5A100A, - 0x5A100B, - 0x5A100C, - 0x5A100D, - 0x5A100E, - 0x5A100F, - 0x5A1010, - 0x5A1011, - 0x5A1012, - 0x5A1013, - 0x5A1014, - 0x5A1015, - 0x5A1016, - 0x5A1017, - 0x5A1018, - 0x5A1019, - 0x5A101A, - 0x5A101B, - 0x5A101C, - 0x5A101D, - 0x5A101E, - 0x5A101F, - 0x5A1020, - 0x5A1021, - 0x5A1022, - 0x5A1023, - 0x5A1024, - 0x5A1025, - 0x5A1026, - 0x5A1027, - 0x5A1028, - 0x5A1029, - 0x5A102A, - 0x5A102B, - 0x5A102C, - 0x5A102D, - 0x5A102E, - 0x5A102F, - 0x5A1030, - 0x5A1031, - 0x5A1032, - 0x5A1033, - 0x5A1034, - 0x5A1035, - 0x5A1036, - 0x5A1037, - 0x5A1038, - 0x5A1039, - 0x5A103A, - 0x5A103B, - 0x5A103C, - 0x5A103D, - 0x5A103E, - 0x5A103F, - 0x5A1040, - 0x5A1041, - 0x5A1042, - 0x5A1043, - 0x5A1045, - 0x5A1046, - 0x5A1047, - 0x5A1048, - 0x5A1049 -] - -sprite_visuals = { - "Life Bottle": [0x00], - "Magic Bottle": [0x01], - "500 Coins": [0x02], - "1000 Coins": [0x03], - "2000 Coins": [0x10], - "5000 Coins": [0x15], - - "Silver Sword": [0x04], - "Fire Sword": [0x05], - "Ice Sword": [0x06], - "Thunder Sword": [0x07], - "Crystal Sword": [0x08], - "Power Sword": [0x09], - "Light Sword": [0x0A], - "Dagger": [0x0B], - "Fireballs": [0x0C], - "Boomerang": [0x0D], - "Ax": [0x0E], - "Shovel": [0x0F], - - "Fire Armor": [0x11], - "Ice Armor": [0x12], - "Aqua Armor": [0x13], - "Light Armor": [0x14], - - "Fire Shield": [0x16], - "Ice Shield": [0x17], - "Aqua Shield": [0x18], - "Light Shield": [0x19], - - "Wand": [0x1A], - "Ice Bell": [0x1C], - "Sun Ring": [0x1D], - "Power Fan": [0x1E], - "Elven Flute": [0x1F], - "Sky Bell": [0x20], - "Light Stone": [0x21], - "Sun Stone": [0x22], - "Star Stone": [0x23], - "Aqua Stone": [0x24], - "Moon Stone": [0x25], - - "Light Spell": [0x26], - "Sun Spell": [0x27], - "Star Spell": [0x28], - "Aqua Spell": [0x29], - "Moon Spell": [0x2A], - - "Shove": [0x2B], - "Up Jab": [0x2B], - "Down Jab": [0x2B] - -} \ No newline at end of file diff --git a/worlds/sai2/setup_game.py b/worlds/sai2/setup_game.py deleted file mode 100644 index f10e26f13005..000000000000 --- a/worlds/sai2/setup_game.py +++ /dev/null @@ -1,88 +0,0 @@ -import struct - - -def setup_gamevars(world): - if world.options.switch_states == 0: - world.light_switch_default = 0x00 - world.sun_switch_default = 0x01 - world.star_switch_default = 0x01 - world.aqua_switch_default = 0x01 - world.moon_switch_default = 0x00 - elif world.options.switch_states == 1: - world.light_switch_default = 0x01 - world.sun_switch_default = 0x00 - world.star_switch_default = 0x00 - world.aqua_switch_default = 0x00 - world.moon_switch_default = 0x01 - else: - world.light_switch_default = world.random.randint(0,1) - world.sun_switch_default = world.random.randint(0,1) - world.star_switch_default = world.random.randint(0,1) - world.aqua_switch_default = world.random.randint(0,1) - world.moon_switch_default = world.random.randint(0,1) - - if world.options.world_state == 2: - world.light_gate = world.random.randint(0,1) - world.sun_gate = world.random.randint(0,1) - world.star_gate = world.random.randint(0,1) - world.aqua_gate = world.random.randint(0,1) - world.moon_gate = world.random.randint(0,1) - else: - world.light_gate = world.options.world_state - world.sun_gate = world.options.world_state - world.star_gate = world.options.world_state - world.aqua_gate = world.options.world_state - world.moon_gate = world.options.world_state - - if world.options.shortcut_states == 2: - world.boa_hiya_shortcut = world.random.randint(0,1) - world.sala_hiya_shortcut = world.random.randint(0,1) - world.sala_puka_shortcut = world.random.randint(0,1) - world.fuwa_poka_shortcut = world.random.randint(0,1) - world.fuwa_puka_shortcut = world.random.randint(0,1) - else: - world.boa_hiya_shortcut = world.options.world_state - world.sala_hiya_shortcut = world.options.world_state - world.sala_puka_shortcut = world.options.world_state - world.fuwa_poka_shortcut = world.options.world_state - world.fuwa_puka_shortcut = world.options.world_state - if world.options.shortcut_states >= 3: - world.fuwa_poka_shortcut = 0 - world.fuwa_puka_shortcut = 0 - - - early_logic_items = [ - "Silver Sword", - "Shovel" - ] - - if world.light_gate == 0: - early_logic_items.append("Light Stone") - else: - early_logic_items.extend(["Life Bottle", "Sun Ring"]) - if world.sun_gate == 1: - early_logic_items.extend(["Shove", "500 Coins", "1000 Coins", "2000 Coins", "5000 Coins"]) - if world.star_gate == 0: - early_logic_items.append("Star Stone") - else: - early_logic_items.append("Sun Stone") - - if world.aqua_gate == 0: - early_logic_items.append("Aqua Stone") - else: - early_logic_items.extend(["1000 Coins", "2000 Coins", "5000 Coins"]) - if world.moon_gate == 0: - early_logic_items.append("Moon Stone") - - for item in early_logic_items: - if early_logic_items.count(item) > 1 or (item == "Life Bottle" and world.options.extra_health == 1): - early_logic_items.remove(item) - - - if world.options.world_state != 1: - #If one, append the Stones corresponding to closed gates - world.starting_item = world.random.choice(early_logic_items) - - world.locked_skills = ["Shove", "Down Jab", "Up Jab"] - if world.options.shuffle_skills == 1: - world.locked_skills.shuffle \ No newline at end of file From 6bbfeb22ffdf3d5c200fcf811cae0b577145f195 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:13:18 -0500 Subject: [PATCH 11/30] Create spelunker --- worlds/spelunker | 1 + 1 file changed, 1 insertion(+) create mode 100644 worlds/spelunker diff --git a/worlds/spelunker b/worlds/spelunker new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/worlds/spelunker @@ -0,0 +1 @@ + From 95d70d6218de3900a55b1ac249dda61896e46a4c Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:13:42 -0500 Subject: [PATCH 12/30] Delete worlds/spelunker --- worlds/spelunker | 1 - 1 file changed, 1 deletion(-) delete mode 100644 worlds/spelunker diff --git a/worlds/spelunker b/worlds/spelunker deleted file mode 100644 index 8b137891791f..000000000000 --- a/worlds/spelunker +++ /dev/null @@ -1 +0,0 @@ - From cf3816c942706e87041f6dc2628651aacabd66d3 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:14:17 -0500 Subject: [PATCH 13/30] Create t --- worlds/spelunker/t | 1 + 1 file changed, 1 insertion(+) create mode 100644 worlds/spelunker/t diff --git a/worlds/spelunker/t b/worlds/spelunker/t new file mode 100644 index 000000000000..4bcfe98e640c --- /dev/null +++ b/worlds/spelunker/t @@ -0,0 +1 @@ +d From b606513746d9e1b2e265fd96410e0da26fc9ecea Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:14:25 -0500 Subject: [PATCH 14/30] Delete worlds/spelunker/t --- worlds/spelunker/t | 1 - 1 file changed, 1 deletion(-) delete mode 100644 worlds/spelunker/t diff --git a/worlds/spelunker/t b/worlds/spelunker/t deleted file mode 100644 index 4bcfe98e640c..000000000000 --- a/worlds/spelunker/t +++ /dev/null @@ -1 +0,0 @@ -d From ac0bd678860fea2987ce5fc7636192b8635a2d0d Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:14:44 -0500 Subject: [PATCH 15/30] Create t --- worlds/spelunker/t | 1 + 1 file changed, 1 insertion(+) create mode 100644 worlds/spelunker/t diff --git a/worlds/spelunker/t b/worlds/spelunker/t new file mode 100644 index 000000000000..718f4d2ff533 --- /dev/null +++ b/worlds/spelunker/t @@ -0,0 +1 @@ +t From 73a4b64ed7a953b9bbca8f14149033c8ff3ec200 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:15:07 -0500 Subject: [PATCH 16/30] Add New Game: Spelunker --- worlds/spelunker/Client.py | 207 +++++++++++++++ worlds/spelunker/Items.py | 49 ++++ worlds/spelunker/Locations.py | 212 +++++++++++++++ worlds/spelunker/Options.py | 22 ++ worlds/spelunker/Regions.py | 59 +++++ worlds/spelunker/Rom.py | 356 ++++++++++++++++++++++++++ worlds/spelunker/Rules.py | 121 +++++++++ worlds/spelunker/__init__.py | 155 +++++++++++ worlds/spelunker/docs/en_Spelunker.md | 29 +++ worlds/spelunker/docs/setup_en.md | 122 +++++++++ worlds/spelunker/local_data.py | 189 ++++++++++++++ 11 files changed, 1521 insertions(+) create mode 100644 worlds/spelunker/Client.py create mode 100644 worlds/spelunker/Items.py create mode 100644 worlds/spelunker/Locations.py create mode 100644 worlds/spelunker/Options.py create mode 100644 worlds/spelunker/Regions.py create mode 100644 worlds/spelunker/Rom.py create mode 100644 worlds/spelunker/Rules.py create mode 100644 worlds/spelunker/__init__.py create mode 100644 worlds/spelunker/docs/en_Spelunker.md create mode 100644 worlds/spelunker/docs/setup_en.md create mode 100644 worlds/spelunker/local_data.py diff --git a/worlds/spelunker/Client.py b/worlds/spelunker/Client.py new file mode 100644 index 000000000000..b75b3a211939 --- /dev/null +++ b/worlds/spelunker/Client.py @@ -0,0 +1,207 @@ +import logging +import struct +import time +from struct import pack +from .Rom import location_table, hidden_table +from typing import TYPE_CHECKING, Dict, Set + +# TODO: Remove this when Archipelago 0.4.4 gets released +import sys + +if "worlds._bizhawk" not in sys.modules: + import importlib + import os + import zipimport + + bh_apworld_path = os.path.join( + os.path.dirname(sys.modules["worlds"].__file__), "_bizhawk.apworld" + ) + if os.path.isfile(bh_apworld_path): + importer = zipimport.zipimporter(bh_apworld_path) + spec = importer.find_spec(os.path.basename(bh_apworld_path).rsplit(".", 1)[0]) + mod = importlib.util.module_from_spec(spec) + mod.__package__ = f"worlds.{mod.__package__}" + mod.__name__ = f"worlds.{mod.__name__}" + sys.modules[mod.__name__] = mod + importer.exec_module(mod) + elif not os.path.isdir(os.path.splitext(bh_apworld_path)[0]): + raise AssertionError("Could not import worlds._bizhawk") + +from NetUtils import ClientStatus +import worlds._bizhawk as bizhawk +from worlds._bizhawk.client import BizHawkClient +import time + +if TYPE_CHECKING: + from worlds._bizhawk.context import BizHawkClientContext +else: + BizHawkClientContext = object + +# Add .apwl suffix to bizhawk client +from worlds.LauncherComponents import SuffixIdentifier, components + +for component in components: + if component.script_name == "BizHawkClient": + component.file_identifier = SuffixIdentifier( + *(*component.file_identifier.suffixes, ".apsplunker") + ) + break + +EXPECTED_ROM_NAME = "SPELUNKERAP" + + +class SpelunkerClient(BizHawkClient): + game = "Spelunker" + system = ("NES") + location_map = location_table + received_deathlinks = 0 + deathlink_all_clear = False + + def __init__(self) -> None: + super().__init__() + + async def validate_rom(self, ctx: BizHawkClientContext) -> bool: + from CommonClient import logger + + try: + # Check ROM name/patch version + rom_name_bytes = ( + await bizhawk.read(ctx.bizhawk_ctx, [(0x7030, 11, "PRG ROM")]) + )[0] + rom_name = bytes([byte for byte in rom_name_bytes if byte != 0]).decode( + "ascii" + ) + if not rom_name.startswith(EXPECTED_ROM_NAME): + logger.info( + "ERROR: Rom is not valid!" + ) + return False + except UnicodeDecodeError: + return False + except bizhawk.RequestFailedError: + return False # Should verify on the next pass + + ctx.game = self.game + ctx.items_handling = 0b111 + + death_link = await bizhawk.read(ctx.bizhawk_ctx, [(0x7052, 1, "PRG ROM")]) + if death_link: + await ctx.update_death_link(bool(death_link[0])) + return True + + async def set_auth(self, ctx: BizHawkClientContext) -> None: + from CommonClient import logger + + slot_name_length = await bizhawk.read(ctx.bizhawk_ctx, [(0x7040, 1, "PRG ROM")]) + slot_name_bytes = await bizhawk.read( + ctx.bizhawk_ctx, [(0x7041, slot_name_length[0][0], "PRG ROM")] + ) + ctx.auth = bytes([byte for byte in slot_name_bytes[0] if byte != 0]).decode( + "utf-8" + ) + + def on_package(self, ctx: "BizHawkClientContext", cmd: str, args: dict) -> None: + if cmd != "Bounced": + return + if "tags" not in args: + return + if "DeathLink" in args["tags"] and args["data"]["source"] != ctx.slot_info[ctx.slot].name: + self.received_deathlinks += 1 + + async def game_watcher(self, ctx: BizHawkClientContext) -> None: + from CommonClient import logger + + if ctx.server_version.build > 0: + ctx.connected = True + else: + ctx.connected = False + ctx.refresh_connect = True + + if ctx.slot_data != None: + ctx.data_present = True + else: + ctx.data_present = False + + if ctx.server is None or ctx.server.socket.closed or ctx.slot_data is None: + return + + from .Rom import item_ids + + #if goal_flag[0] != 0x00: + #await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) + #ctx.finished_game = True + + read_state = await bizhawk.read(ctx.bizhawk_ctx, [(0x229, 1, "RAM"), + (0x0500, 0xFF, "RAM"), + (0x0780, 1, "RAM"), + (0x7051, 1, "PRG ROM"), + (0x022C, 1, "RAM"), + (0x022D, 1, "RAM"), + (0x0783, 1, "RAM")]) + + demo_mode = int.from_bytes(read_state[0], "little") + loc_array = bytearray(read_state[1]) + item_pause = int.from_bytes(read_state[2], "little") + hidden_checks = int.from_bytes(read_state[3], "little") + is_dead = int.from_bytes(read_state[4], "little") + is_paused = int.from_bytes(read_state[5], "little") + goal_trigger = int.from_bytes(read_state[6], "little") + + if hidden_checks == 0x01: + self.location_map.update(hidden_table) + + if demo_mode != 0x00: + return + + if item_pause != 0x00: + return + + if is_dead == 0x00: + self.deathlink_all_clear = True + + if "DeathLink" in ctx.tags and ctx.last_death_link + 1 < time.time(): + if is_dead in range(0x01,0x80) and self.received_deathlinks == 0x00 and is_paused != 0xFF and self.deathlink_all_clear == True: + self.deathlink_all_clear = False + await ctx.send_death(f"{ctx.player_names[ctx.slot]} died!") + + #The death animation is long enough to send 2 deathlinks per death + if self.received_deathlinks != 0: + await bizhawk.write(ctx.bizhawk_ctx, [(0x780, bytes([0x0D]), "RAM")]) + self.received_deathlinks -= 1 + + new_checks = [] + + for loc_id, loc_pointer in self.location_map.items(): + if loc_id not in ctx.locations_checked: + location = loc_array[loc_pointer] + if location == 0: + new_checks.append(loc_id) + + if loc_id in ctx.checked_locations: + await bizhawk.write(ctx.bizhawk_ctx, [(0x0500 + loc_pointer, bytes([0x00]), "RAM")]) + + + for new_check_id in new_checks: + ctx.locations_checked.add(new_check_id) + location = ctx.location_names[new_check_id] + await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) + + recv_count = await bizhawk.read(ctx.bizhawk_ctx, [(0x0781, 1, "RAM")]) + recv_index = recv_count[0] + recv_index = int.from_bytes(recv_index, byteorder='big') + if recv_index < len(ctx.items_received): + item = ctx.items_received[recv_index] + recv_index += 1 + + if item.item in item_ids: + ram_item = item_ids[item.item] + await bizhawk.write(ctx.bizhawk_ctx, [(0x780, bytes([ram_item]), "RAM")]) + await bizhawk.write(ctx.bizhawk_ctx, [(0x781, bytes([recv_index]), "RAM")]) + + if not ctx.finished_game and goal_trigger == 0x01: + await ctx.send_msgs([{ + "cmd": "StatusUpdate", + "status": ClientStatus.CLIENT_GOAL + }]) + + diff --git a/worlds/spelunker/Items.py b/worlds/spelunker/Items.py new file mode 100644 index 000000000000..af214369798e --- /dev/null +++ b/worlds/spelunker/Items.py @@ -0,0 +1,49 @@ +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] = { + "Money Bag": ItemData("Treasure", 0x696969, ItemClassification.filler, 0), + "Coin": ItemData("Treasure", 0x69696A, ItemClassification.filler, 0), + "Miracle": ItemData("Treasure", 0x69696B, ItemClassification.filler, 0), + "Diamond": ItemData("Treasure", 0x69696C, ItemClassification.filler, 0), + "Dynamite": ItemData("Equipment", 0x69696D, ItemClassification.progression, 18), + "Flare": ItemData("Equipment", 0x69696E, ItemClassification.progression, 9), + "Blue Key": ItemData("Equipment", 0x69696F, ItemClassification.progression, 9), + "Red Key": ItemData("Equipment", 0x696970, ItemClassification.progression, 6), + + "1-Up": ItemData("Powerups", 0x696971, ItemClassification.useful, 0), + "Multiplier": ItemData("Powerups", 0x696972, ItemClassification.useful, 0), + "Potion": ItemData("Powerups", 0x696973, ItemClassification.useful, 0), + "Invincibility": ItemData("Powerups", 0x696974, ItemClassification.useful, 0), + + "Golden Pyramid": ItemData("Events", None, ItemClassification.progression, 0) +} + +filler_items: Tuple[str, ...] = ( + "Money Bag", + "Coin", + "Diamond", + "Miracle" +) + +useful_items: Tuple[str, ...] = ( + "1-Up", + "Multiplier", + "Potion", + "Invincibility" +) + +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/spelunker/Locations.py b/worlds/spelunker/Locations.py new file mode 100644 index 000000000000..cf86d5d8ead7 --- /dev/null +++ b/worlds/spelunker/Locations.py @@ -0,0 +1,212 @@ +from typing import List, Optional, NamedTuple, TYPE_CHECKING + +from .Options import HiddenLocs +from worlds.generic.Rules import CollectionRule + +if TYPE_CHECKING: + from . import SpelunkerWorld + + +class LocationData(NamedTuple): + region: str + name: str + code: Optional[int] + rule: CollectionRule = lambda state: True + + +def get_locations(world: Optional["SpelunkerWorld"]) -> List[LocationData]: + + location_table: List[LocationData] = [ + LocationData("Area 1", "1F - First Item", 0x696969), + LocationData("Area 1", "1F - Pit Item", 0x69696A), + LocationData("Area 1", "1F - Right Item 1", 0x69696B), + LocationData("Area 1", "1F - Between Mounds", 0x69696C), + LocationData("Area 1", "1F - Far Wall 1", 0x69696D), + LocationData("Area 1", "1F - Far Wall 2", 0x69696E), + + LocationData("Area 1", "B1F - Elevator Item", 0x69696F), + LocationData("Area 1", "B1F - Undulating Rocks", 0x696970), + LocationData("Area 1", "B1F - Past Boulder", 0x696971), + LocationData("Area 1", "B1F - Side Shaft Ledge", 0x696972), + LocationData("Area 1", "B1F - Side Shaft Mound", 0x696973), + LocationData("Area 1", "B1F - Side Shaft Bottom Left", 0x696974), + LocationData("Area 1", "B1F - Side Shaft Bottom Right", 0x696975), + LocationData("Area 1", "B1F - Side Shaft Ladder Right", 0x6969F8), + + LocationData("Area 1", "B2F - First Item", 0x696976), + LocationData("Area 1", "B2F - Second Item", 0x696977), + + LocationData("Area 1", "B3F - Mound Item", 0x696978), + LocationData("Area 1", "B3F - Ramp Item", 0x696979), + LocationData("Area 1", "B3F - Ledge Item", 0x69697A), + LocationData("Area 1", "B3F - Upper Nook 1", 0x69697B), + LocationData("Area 1", "B3F - Upper Nook 2", 0x69697C), + LocationData("Area 1", "B3F - Upper Nook 3", 0x69697D), + LocationData("Area 1", "B3F - Middle Ledge", 0x69697E), + LocationData("Area 1", "B3F - Bottom", 0x69697F), + LocationData("Area 1", "B3F - Bat Item", 0x696980), + LocationData("Area 1", "B3F - Ladder Left", 0x696981), + LocationData("Area 1", "B3F - Bombable Wall", 0x696982), + + LocationData("Area 1", "B4F - Top Item", 0x696983), + LocationData("Area 1", "B4F - Minecart 1", 0x696984), + LocationData("Area 1", "B4F - Minecart 2", 0x696985), + + LocationData("Area 1", "B5F - Near Ramp", 0x696986), + LocationData("Area 1", "B5F - Ladder Left", 0x696987), + LocationData("Area 1", "B5F - Ladder Right", 0x696988), + + LocationData("Area 1", "B6F - Item", 0x696989), + + LocationData("Area 2", "B7F - Left of Elevators", 0x69698A), + + LocationData("Area 2", "B8F - Right Side 1", 0x69698B), + LocationData("Area 2", "B8F - Right Side 2", 0x69698C), + LocationData("Area 2", "B8F - Rope 1", 0x69698D), + LocationData("Area 2", "B8F - Rope 2", 0x69698E), + LocationData("Area 2", "B8F - Boulder Pit 1", 0x69698F), + LocationData("Area 2", "B8F - Boulder Pit 2", 0x696990), + + LocationData("Area 2", "B9F - Right Item", 0x696991), + LocationData("Area 2", "B9F - Left Top of Ramp", 0x696992), + LocationData("Area 2", "B9F - Left Mounds", 0x696993), + LocationData("Area 2", "B9F - Left Near Edge", 0x696994), + + LocationData("Area 2", "B10F - Far Ropes Ledge", 0x696995), + LocationData("Area 2", "B10F - First Bridge", 0x6969F9), + LocationData("Area 2", "B10F - Between Bridges", 0x696996), + LocationData("Area 2", "B10F - After Bridges", 0x696997), + LocationData("Area 2", "B10F - Ladder Item", 0x696998), + LocationData("Area 2", "B10F - Rope Item", 0x696999), + LocationData("Area 2", "B10F - Solo Rope", 0x69699A), + LocationData("Area 2", "B10F - Platform Item", 0x69699B), + LocationData("Area 2", "B10F - Left Shaft", 0x69699C), + + LocationData("Area 2", "B11F - Boulder Pit", 0x69699D), + LocationData("Area 2", "B11F - Bombable Wall", 0x69699E), + LocationData("Area 2", "B11F - Left Shaft", 0x69699F), + + LocationData("Area 2", "B12F - Pit Item 1", 0x6969A0), + LocationData("Area 2", "B12F - Pit Item 2", 0x6969A1), + LocationData("Area 2", "B12F - Pit Item 3", 0x6969A2), + LocationData("Area 2", "B12F - Locked Item", 0x6969A3), + + LocationData("Area 2", "B13F - Item", 0x6969A4), + + LocationData("Area 3", "B14F - Near Ladder", 0x6969FA), + LocationData("Area 3", "B14F - Disconnected Platform", 0x6969A5), + LocationData("Area 3", "B14F - Rope Item", 0x6969A6), + LocationData("Area 3", "B14F - Boulder Item", 0x6969A7), + LocationData("Area 3", "B14F - Far Ledge", 0x6969A8), + + LocationData("Area 3", "B15F - Left Wall", 0x6969A9), + LocationData("Area 3", "B15F - Past Boulder", 0x6969AA), + LocationData("Area 3", "B15F - Upper Ledge", 0x6969AB), + LocationData("Area 3", "B15F - Three in a Row 1", 0x6969AC), + LocationData("Area 3", "B15F - Three in a Row 2", 0x6969AD), + LocationData("Area 3", "B15F - Three in a Row 3", 0x6969AE), + LocationData("Area 3", "B15F - Right Wall", 0x6969AF), + + LocationData("Area 3", "B16F - Undulating Rocks", 0x6969B0), + LocationData("Area 3", "B16F - Top of Waterfall", 0x6969B1), + LocationData("Area 3", "B16F - Below Waterfall", 0x6969B2), + LocationData("Area 3", "B16F - Bat 1", 0x6969B3), + LocationData("Area 3", "B16F - Bat 2", 0x6969B4), + + LocationData("Area 3", "B17F - Item", 0x6969b5), + + LocationData("Area 3", "B18F - Before Pit", 0x6969B6), + LocationData("Area 3", "B18F - Trap Item", 0x6969B7), + + LocationData("Area 3", "B19F - Long Rope Bottom", 0x6969B8), + LocationData("Area 3", "B19F - Near Ladder", 0x6969B9), + LocationData("Area 3", "B19F - Past Boulder", 0x6969BA), + + LocationData("Area 3", "B20F - Near Ladder", 0x6969BB), + LocationData("Area 3", "B20F - Boulder 1", 0x6969BC), + LocationData("Area 3", "B20F - Boulder 2", 0x6969BD), + LocationData("Area 3", "B20F - Boulder 3", 0x6969BF), + LocationData("Area 3", "B20F - Right Side Bombable Wall", 0x6969C0), + LocationData("Area 3", "B20F - Water Spout Upper 1", 0x6969C1), + LocationData("Area 3", "B20F - Water Spout Upper Trap", 0x6969C2), + LocationData("Area 3", "B20F - Water Spout Lonely Ledge", 0x6969C3), + LocationData("Area 3", "B20F - Water Spout Middle Left Ledge", 0x6969C4), + LocationData("Area 3", "B20F - Water Spout Middle Left Rope", 0x6969C5), + LocationData("Area 3", "B20F - Water Spout Middle Right Ledge", 0x6969C6), + LocationData("Area 3", "B20F - Near Right Rope", 0x6969C7), + + LocationData("Area 3", "B21F - Bat Pit 1", 0x6969C8), + LocationData("Area 3", "B21F - Bat Pit 2", 0x6969C9), + LocationData("Area 3", "B21F - Bat Pit 3", 0x6969CA), + LocationData("Area 3", "B21F - Ladder Right", 0x6969CB), + LocationData("Area 3", "B21F - Ladder Left", 0x6969CC), + + LocationData("Area 4", "B22F - Lonely Platform", 0x6969CD), + + LocationData("Area 4", "B23F - Pyramid Platforming", 0x6969D0), + LocationData("Area 4", "B23F - Long Way Around", 0x6969D1), + LocationData("Area 4", "B23F - Left Wall Near Pyramid", 0x6969FC), + LocationData("Area 4", "B23F - Middle Pyramid Jump", 0x6969D2), + LocationData("Area 4", "B23F - Pyramid Bombable Wall", 0x6969D3), + LocationData("Area 4", "B23F - Offcenter T", 0x6969D4), + LocationData("Area 4", "B23F - Lonely Platform Before Door", 0x6969FB), + LocationData("Area 4", "B23F - Just After Door", 0x6969D5), + LocationData("Area 4", "B23F - Ropes Right Wall", 0x6969D6), + + LocationData("Area 4", "B24F - Left Side Item", 0x6969D7), + LocationData("Area 4", "B24F - Right Side Item", 0x6969D8), + LocationData("Area 4", "B24F - Pit Trap", 0x6969D9), + + LocationData("Area 4", "B25F - Left 1", 0x6969DA), + LocationData("Area 4", "B25F - Left 2", 0x6969DB), + LocationData("Area 4", "B25F - Right 1", 0x6969DC), + LocationData("Area 4", "B25F - Right 2", 0x6969DD), + LocationData("Area 4", "B25F - Ropes Item", 0x6969DE), + + LocationData("Area 4", "B26F - Rope Right 1", 0x6969DF), + LocationData("Area 4", "B26F - Rope Right 2", 0x6969E0), + LocationData("Area 4", "B26F - So Close You Can Smell It Item", 0x6969E1), + + LocationData("Area 4", "B27F - Right of Pit 1", 0x6969E2), + LocationData("Area 4", "B27F - Right of Pit 2", 0x6969E3), + LocationData("Area 4", "B27F - Entry Item", 0x6969E4), + + LocationData("Area 4", "B28F - Boulder Item", 0x6969E5), + LocationData("Area 4", "B28F - Bat Ledge", 0x6969E6), + LocationData("Area 4", "B28F - Locked Item 1", 0x6969E7), + LocationData("Area 4", "B28F - Locked Item 2", 0x6969E8), + + LocationData("Area 4", "B28F - Final Boulder", 0x6969E9), + LocationData("Area 4", "B28F - Final Rope Left", 0x6969EA), + LocationData("Area 4", "B28F - Final Rope Right", 0x6969EB), + + LocationData("Area 4", "B29F - Ladder Ledge", 0x6969EC), + LocationData("Area 4", "B29F - Pit Trap", 0x6969ED), + LocationData("Area 4", "B29F - Before Pit Trap", 0x6969EE), + LocationData("Area 4", "B29F - Rope Alcove", 0x6969EF), + LocationData("Area 4", "B29F - Left Wall Rope Ledge", 0x6969F0), + LocationData("Area 4", "B29F - Left Pit Item", 0x6969F1), + LocationData("Area 4", "B29F - Bombable Wall", 0x6969F2), + LocationData("Area 4", "B29F - Left Wall Item", 0x6969F3), + + LocationData("Area 4", "B30F - Far Bottom Right", 0x6969F4), + LocationData("Area 4", "B30F - Undulating Rocks", 0x6969F5), + LocationData("Area 4", "B30F - Mound Item", 0x6969F6), + LocationData("Area 4", "B30F - Far Bottom Left", 0x6969F7), + + LocationData("Area 4", "Golden Pyramid", None) + ] + + if not world or world.options.hidden_items: + location_table += [ + LocationData("Area 1", "B1F - Hidden Item before Boulder", 0x6969FD), + LocationData("Area 1", "B1F - Side Shaft Hidden Item", 0x6969FE), + LocationData("Area 2", "B8F - Boulder Pit Hidden Item", 0x6969FF), + LocationData("Area 2", "B10F - Bridge Hidden Item", 0x696A00), + LocationData("Area 3", "B16F - Blue Door Hidden Item", 0x696A01), + LocationData("Area 3", "B20F - Water Spout Upper Ledge Hidden Item", 0x696A02), + LocationData("Area 4", "B23F - Pyramid Hidden Item", 0x696A03), + LocationData("Area 4", "B24F - Pit Trap Hidden Item", 0x696A04), + ] + + return location_table diff --git a/worlds/spelunker/Options.py b/worlds/spelunker/Options.py new file mode 100644 index 000000000000..64a9f38b4534 --- /dev/null +++ b/worlds/spelunker/Options.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, PerGameCommonOptions + + +class HiddenLocs(Toggle): + """Places items on the secret invisible items. Does not count for Keys on cave difficulty 4.""" + display_name = "Hidden Item Checks" + +class CaveLevel(Choice): + """This will determine the difficulty level of the cave you venture through.""" + display_name = "Cave Difficulty" + option_cave_1 = 0 + option_cave_2 = 1 + option_cave_3 = 2 + option_cave_4 = 3 + default = 0 + +@dataclass +class SpelunkerOptions(PerGameCommonOptions): + hidden_items: HiddenLocs + cave_difficulty: CaveLevel + death_link: DeathLink diff --git a/worlds/spelunker/Regions.py b/worlds/spelunker/Regions.py new file mode 100644 index 000000000000..91f3df312e02 --- /dev/null +++ b/worlds/spelunker/Regions.py @@ -0,0 +1,59 @@ +from typing import List, Dict, TYPE_CHECKING +from BaseClasses import Region, Location +from .Locations import LocationData +if TYPE_CHECKING: + from . import YoshisIslandWorld + + +class SpelunkerLocation(Location): + game: str = "Spelunker" + + def __init__(self, player: int, name: str = " ", address: int = None, parent=None): + super().__init__(player, name, address, parent) + + +def init_areas(world: "SpelunkerWorld", locations: List[LocationData]) -> None: + multiworld = world.multiworld + player = world.player + + locations_per_region = get_locations_per_region(locations) + + regions = [ + create_region(world, player, locations_per_region, "Menu"), + create_region(world, player, locations_per_region, "Area 1"), + create_region(world, player, locations_per_region, "Area 2"), + create_region(world, player, locations_per_region, "Area 3"), + create_region(world, player, locations_per_region, "Area 4"), + ] + multiworld.regions += regions + + multiworld.get_region("Menu", player).add_exits(["Area 1"]) + + multiworld.get_region("Area 1", player).add_exits(["Area 2"],{"Area 2": lambda state: state.has("Dynamite", player, 1) and state.has("Blue Key", player, 2) and state.has("Red Key", player, 1)}) + multiworld.get_region("Area 2", player).add_exits(["Area 3"],{"Area 3": lambda state: state.has("Dynamite", player, 3) and state.has("Blue Key", player, 3) and state.has("Red Key", player, 2)}) + multiworld.get_region("Area 3", player).add_exits(["Area 4"],{"Area 4": lambda state: state.has("Dynamite", player, 3) and state.has("Blue Key", player, 4) and state.has("Red Key", player, 3)}) + +def create_location(player: int, location_data: LocationData, region: Region) -> Location: + location = SpelunkerLocation(player, location_data.name, location_data.code, region) + location.access_rule = location_data.rule + + return location + + +def create_region(world: "SpelunkerWorld", 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 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/spelunker/Rom.py b/worlds/spelunker/Rom.py new file mode 100644 index 000000000000..4d78bb362df3 --- /dev/null +++ b/worlds/spelunker/Rom.py @@ -0,0 +1,356 @@ +import hashlib +import os +import Utils +import typing +from worlds.Files import APProcedurePatch, APTokenMixin, APTokenTypes +from BaseClasses import ItemClassification +from settings import get_settings +from typing import TYPE_CHECKING +from .local_data import local_locations, hidden_locations + +if TYPE_CHECKING: + from . import SpelunkerWorld +USHASH = "4359c225ebcbb1ac66ec889f300f8376" + +item_ids = { + 0x696969: 0x01, #Money bag + 0x69696A: 0x02, #Coin + 0x69696B: 0x03, #Miracle + 0x69696C: 0x04, #Diamond + 0x69696D: 0x05, #Dynamite + 0x69696E: 0x06, #Flare + 0x69696F: 0x07, #Blue Key + 0x696970: 0x08, #Red Key + 0x696971: 0x09, + 0x696972: 0x0A, + 0x696973: 0x0B, + 0x696974: 0x0C + +} + +location_table = { + 0x696969: 0x09, + 0x69696a: 0x0a, + 0x69696B: 0x06, + 0x69696C: 0x0B, + 0x69696D: 0x07, + 0x69696E: 0x08, + + 0x69696F: 0x0F, + 0x696970: 0x10, + 0x696971: 0x11, + 0x696972: 0x19, + 0x696973: 0x29, + 0x6969F8: 0x31, + 0x696974: 0x38, + 0x696975: 0x37, + + 0x696976: 0x13, + 0x696977: 0x14, + + 0x696978: 0x1E, + 0x696979: 0x23, + 0x69697A: 0x28, + + 0x69697B: 0x16, + 0x69697C: 0x1A, + 0x69697D: 0x18, + 0x69697E: 0x2E, + 0x69697F: 0x36, + 0x696980: 0x32, + 0x696981: 0x26, + 0x696981: 0x27, + + 0x696983: 0x35, + 0x696984: 0x41, + 0x696985: 0x40, + + 0x696986: 0x46, + 0x696987: 0x42, + 0x696988: 0x43, + + 0x696989: 0x44, + + 0x69698A: 0x4E, + 0x69698B: 0x58, + 0x69698C: 0x57, + 0x69698D: 0x4D, + 0x69698E: 0x4C, + 0x69698F: 0x59, + 0x696990: 0x56, + 0x696991: 0x5D, + 0x696992: 0x5E, + + 0x696993: 0x63, + 0x696994: 0x62, + 0x696995: 0x65, + 0x6969F9: 0x68, + 0x696996: 0x69, + 0x696997: 0x6A, + 0x696998: 0x6F, + 0x696999: 0x70, + 0x69699A: 0x6E, + 0x69699B: 0x6D, + 0x69699C: 0x71, + + 0x69699D: 0x74, + 0x69699E: 0x75, + 0x69699F: 0x76, + + 0x6969A0: 0x7A, + 0x6969A1: 0x79, + 0x6969A2: 0x77, + 0x6969A3: 0x78, + 0x6969A4: 0x7D, + 0x6969FA: 0x80, + 0x6969A5: 0x82, + 0x6969A6: 0x7F, + 0x6969A7: 0x7E, + 0x6969A8: 0x83, + 0x6969A9: 0x8C, + 0x6969AA: 0x8E, + 0x6969AB: 0x84, + 0x6969AC: 0x85, + 0x6969AD: 0x86, + 0x6969AE: 0x87, + 0x6969AF: 0x88, + 0x6969B0: 0x90, + 0x6969B1: 0x92, + 0x6969B2: 0x98, + 0x6969B3: 0x96, + 0x6969B4: 0x95, + 0x6969B5: 0x94, + 0x6969B6: 0x99, + 0x6969B7: 0x9B, + 0x6969B8: 0x9E, + 0x6969B9: 0x9F, + 0x6969BA: 0xA0, + 0x6969BB: 0xA1, + 0x6969BC: 0xB0, + 0x6969BD: 0xB1, + 0x6969BF: 0xB2, + 0x6969C0: 0xAA, + 0x6969C1: 0xA5, + 0x6969C2: 0xA4, + 0x6969C3: 0xA9, + 0x6969C4: 0xAC, + 0x6969C5: 0xAB, + 0x6969C6: 0xAD, + 0x6969C7: 0xAE, + 0x6969C8: 0xBB, + 0x6969C9: 0xB9, + 0x6969CA: 0xB8, + 0x6969CB: 0xB4, + 0x6969CC: 0xB3, + 0x6969CD: 0xBA, + 0x6969D0: 0xBF, + 0x6969D1: 0xBC, + 0x6969D2: 0xC4, + 0x6969D3: 0xC5, + 0x6969D4: 0xC2, + 0x6969D5: 0xC1, + 0x6969D6: 0xC8, + 0x6969D7: 0xCB, + 0x6969D8: 0xCC, + 0x6969D9: 0xCD, + + 0x6969DA: 0xD0, + 0x6969DB: 0xD1, + 0x6969DC: 0xD4, + 0x6969DD: 0xD2, + 0x6969DE: 0xCF, + 0x6969DF: 0xDB, + 0x6969E0: 0xDA, + 0x6969E1: 0xD9, + 0x6969FB: 0xBD, + 0x6969E2: 0xDE, + 0x6969E3: 0xDC, + 0x6969E4: 0xDD, + 0x6969FC: 0xC3, + 0x6969E5: 0xE6, + 0x6969E6: 0xE7, + 0x6969E7: 0xE4, + 0x6969E8: 0xE5, + 0x6969E9: 0xE2, + 0x6969EA: 0xE1, + 0x6969EB: 0xE0, + 0x6969EC: 0xEC, + 0x6969ED: 0xF2, + 0x6969EE: 0xF3, + 0x6969EF: 0xEB, + + 0x6969F0: 0xF0, + 0x6969F1: 0xEE, + 0x6969F2: 0xED, + 0x6969F2: 0xEA, + 0x6969F4: 0xF7, + 0x6969F5: 0xF6, + 0x6969F6: 0xF9, + 0x6969F7: 0xFA +} + +hidden_table = { + 0x6969FD: 0x0D, + 0x6969FE: 0x1D, + 0x6969FF: 0x55, + 0x696A00: 0x66, + 0x696A01: 0x8F, + 0x696A02: 0xA2, + 0x696A03: 0xC6, + 0x696A04: 0xCA +} + +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 code_main(rom: LocalRom) -> None: + rom.write_bytes(0x1B72, bytearray([0x45, 0x9C]))#Disable Blue Key + rom.write_bytes(0x1B74, bytearray([0x45, 0x9C]))#Disable Red Key + rom.write_bytes(0x1B76, bytearray([0x88, 0x9C]))#Disable Money Bag + rom.write_bytes(0x1B78, bytearray([0x45, 0x9C]))#Disable Coin + rom.write_bytes(0x1B7A, bytearray([0x45, 0x9C]))#Disable Dynamite + rom.write_bytes(0x1B7C, bytearray([0x74, 0x9C]))#Disable Flare + #rom.write_bytes(0x1B7E, bytearray([0x09, 0x9C]))Air refill, ignore + rom.write_bytes(0x1B80, bytearray([0x45, 0x9C]))#Disable Miracle + rom.write_bytes(0x1B90, bytearray([0x24, 0x9D]))#Disable Diamond + + rom.write_bytes(0x1C66, bytearray([0xF0, 0x13]))#Disable Speedup + rom.write_bytes(0x1C6A, bytearray([0xF0, 0x0F]))#Disable Invincibility + rom.write_bytes(0x1C64, bytearray([0x90, 0xE9]))#Disable 1-Up + rom.write_bytes(0x1C6F, bytearray([0x6B, 0x9C]))#Disable Points + + rom.write_bytes(0x65D2, bytearray([0x8A, 0x48, 0xAD, 0x80, 0x07, 0xF0, 0x11, 0x0A, 0xAA, 0xBD, 0x40, 0xE8, 0x8D, 0x90, 0x07, 0xBD])) + rom.write_bytes(0x65E2, bytearray([0x41, 0xE8, 0x8D, 0x91, 0x07, 0x20, 0xE9, 0xE5, 0x68, 0xAA, 0xA9, 0x00, 0x8D, 0x80, 0x07, 0xA4])) + rom.write_bytes(0x65F2, bytearray([0x17, 0xB9, 0x00, 0x05, 0x4C, 0xF3, 0x96, 0xA2, 0xFF, 0x6C, 0x90, 0x07, 0xA0, 0x00, 0xA2, 0x00])) + rom.write_bytes(0x6602, bytearray([0xCA, 0xD0, 0x11, 0x88, 0xD0, 0x0C, 0x60])) + + rom.write_bytes(0x6610, bytearray([0xAD, 0x50, 0xF0, 0x8D, 0x3D, 0x02, 0x4C, 0xA5, 0x81])) + + rom.write_bytes(0x6632, bytearray([0xA9, 0x00, 0x85, 0xFE, 0x8D, 0x80, 0x07, 0x8D, 0x81, 0x07, 0x4C, 0xD9, 0x81])) + + rom.write_bytes(0x6642, bytearray([0xAD, 0x80, 0x07, 0xD0, 0x07, 0xA5, 0x4D, 0x85, 0x92, 0x4C, 0x4C, 0x9B, 0x60])) + + rom.write_bytes(0x6650, bytearray([0xA9, 0x01, 0x8D, 0x83, 0x07, 0x4C, 0x40 ,0xA0])) + + rom.write_bytes(0x1B9E, bytearray([0x05])) + + +def data_main(rom: LocalRom) -> None: + rom.write_bytes(0x6852, bytearray([0x88, 0x9C, 0x74, 0x9C, 0x27, 0x9C, 0x16, 0x9D, 0xE1, 0x9B, 0xF8, 0x9B, 0xBA, 0x9B, 0xCA, 0x9B])) + rom.write_bytes(0x6862, bytearray([0x3F, 0x9C, 0x5C, 0x9C, 0x61, 0x9C, 0x66, 0x9C, 0x36, 0x95])) + + rom.write_bytes(0x8D50, bytearray([0x00, 0x42, 0xE7, 0xE7, 0x06, 0x1F, 0x3E, 0x1E, 0x18, 0x3C, 0x18, 0x00, 0xE7, 0xEF, 0x46, 0x06])) + rom.write_bytes(0x8E30, bytearray([0x00, 0x42, 0xE7, 0xE7, 0x00, 0x18, 0x3C, 0x18, 0x18, 0x3C, 0x18, 0x00, 0xE7, 0xE7, 0x42, 0x00])) + + +def code_handlers(rom: LocalRom) -> None: + rom.write_bytes(0x16FE, bytearray([0x4C, 0xC2, 0xE5])) #Get Item + rom.write_bytes(0x01E5, bytearray([0x4C, 0x22, 0xE6])) #Init memory + rom.write_bytes(0x01AF, bytearray([0x4C, 0x00, 0xE6])) #Set starting difficulty + rom.write_bytes(0x1B58, bytearray([0x4C, 0x32, 0xE6])) #Dont set checkpoint when receiving an item + rom.write_bytes(0x2A8D, bytearray([0x20, 0x40, 0xE6])) #Write goal + + +def patch_rom(world, rom, player: int, multiworld): + code_main(rom) + data_main(rom) + code_handlers(rom) + + for location in world.multiworld.get_locations(player): + if location.address and location.name not in hidden_locations: #dont write local data for events + if location.item.classification in [ItemClassification.progression, ItemClassification.progression_skip_balancing]: + rom.write_bytes(local_locations[location.name], bytearray([0x05])) + else: + rom.write_bytes(local_locations[location.name], bytearray([0x02])) + + rom.write_bytes(0x7060, bytearray([world.options.cave_difficulty.value + 1])) + rom.write_bytes(0x7061, bytearray([world.options.hidden_items.value])) + rom.write_bytes(0x7062, bytearray([world.options.death_link.value])) + + from Main import __version__ + rom.name = bytearray(f'SPELUNKERAP{__version__.replace(".", "")[0:3]}_{player}_{world.multiworld.seed:11}\0', "utf8")[:21] + rom.name.extend([0] * (21 - len(rom.name))) + rom.write_bytes(0x007040, rom.name) + + player_name_length = 0 + for i, byte in enumerate(world.multiworld.player_name[player].encode("utf-8")): + rom.write_byte(0x7051 + i, byte) + player_name_length += 1 + rom.write_byte(0x7050, player_name_length) + + rom.write_file("token_patch.bin", rom.get_token_binary()) + + +class SpelunkerProcPatch(APProcedurePatch, APTokenMixin): + hash = [USHASH] + game = "Spelunker" + patch_file_ending = ".apsplunker" + result_file_ending = ".nes" + name: bytearray + procedure = [ + ("apply_tokens", ["token_patch.bin"]), + ] + + @classmethod + def get_source_data(cls) -> bytes: + return get_base_rom_bytes() + + def write_byte(self, offset, value): + self.write_token(APTokenTypes.WRITE, offset, value.to_bytes(1, "little")) + + def write_bytes(self, offset, value: typing.Iterable[int]): + self.write_token(APTokenTypes.WRITE, offset, bytes(value)) + + +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: + options: Utils.OptionsType = Utils.get_options() + if not file_name: + file_name = options["spelunker_options"]["rom_file"] + if not os.path.exists(file_name): + file_name = Utils.user_path(file_name) + return file_name diff --git a/worlds/spelunker/Rules.py b/worlds/spelunker/Rules.py new file mode 100644 index 000000000000..f0067468c2de --- /dev/null +++ b/worlds/spelunker/Rules.py @@ -0,0 +1,121 @@ +from worlds.generic.Rules import set_rule +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from . import SpelunkerWorld + + +def set_rules(world: "SpelunkerWorld") -> None: + player = world.player + + set_rule(world.multiworld.get_location("B1F - Past Boulder", player), lambda state: state.has("Dynamite", player, 1)) + set_rule(world.multiworld.get_location("B1F - Side Shaft Ledge", player), lambda state: state.has("Dynamite", player, 1)) + set_rule(world.multiworld.get_location("B1F - Side Shaft Mound", player), lambda state: state.has("Dynamite", player, 1)) + set_rule(world.multiworld.get_location("B1F - Side Shaft Bottom Left", player), lambda state: state.has("Dynamite", player, 1)) + set_rule(world.multiworld.get_location("B1F - Side Shaft Bottom Right", player), lambda state: state.has("Dynamite", player, 1)) + set_rule(world.multiworld.get_location("B1F - Side Shaft Ladder Right", player), lambda state: state.has("Dynamite", player, 1)) + + set_rule(world.multiworld.get_location("B3F - Bat Item", player), lambda state: state.has("Flare", player, 1)) + set_rule(world.multiworld.get_location("B3F - Ladder Left", player), lambda state: state.has("Flare", player, 1)) + set_rule(world.multiworld.get_location("B3F - Bombable Wall", player), lambda state: state.has("Dynamite", player, 1) and state.has("Flare", player, 1)) + + set_rule(world.multiworld.get_location("B5F - Near Ramp", player), lambda state: state.has("Dynamite", player, 1) and state.has("Blue Key", player, 1)) + set_rule(world.multiworld.get_location("B5F - Ladder Left", player), lambda state: state.has("Dynamite", player, 1) and state.has("Blue Key", player, 1)) + set_rule(world.multiworld.get_location("B5F - Ladder Right", player), lambda state: state.has("Dynamite", player, 1) and state.has("Blue Key", player, 1)) + + set_rule(world.multiworld.get_location("B8F - Rope 1", player), lambda state: state.has("Dynamite", player, 2)) + set_rule(world.multiworld.get_location("B8F - Rope 2", player), lambda state: state.has("Dynamite", player, 2)) + set_rule(world.multiworld.get_location("B8F - Boulder Pit 1", player), lambda state: state.has("Dynamite", player, 2)) + set_rule(world.multiworld.get_location("B8F - Boulder Pit 2", player), lambda state: state.has("Dynamite", player, 2)) + + set_rule(world.multiworld.get_location("B11F - Boulder Pit", player), lambda state: state.has("Dynamite", player, 2)) + + set_rule(world.multiworld.get_location("B10F - Solo Rope", player), lambda state: state.has("Flare", player, 1)) + set_rule(world.multiworld.get_location("B10F - Platform Item", player), lambda state: state.has("Flare", player, 1)) + set_rule(world.multiworld.get_location("B11F - Bombable Wall", player), lambda state: state.has("Dynamite", player, 2) and state.has("Flare", player, 1)) + + set_rule(world.multiworld.get_location("B12F - Pit Item 1", player), lambda state: state.has("Blue Key", player, 3)) + set_rule(world.multiworld.get_location("B12F - Pit Item 2", player), lambda state: state.has("Blue Key", player, 3)) + set_rule(world.multiworld.get_location("B12F - Pit Item 3", player), lambda state: state.has("Blue Key", player, 3)) + set_rule(world.multiworld.get_location("B12F - Locked Item", player), lambda state: state.has("Blue Key", player, 4)) + + set_rule(world.multiworld.get_location("B14F - Boulder Item", player), lambda state: state.has("Dynamite", player, 4)) + + set_rule(world.multiworld.get_location("B15F - Past Boulder", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B15F - Upper Ledge", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B15F - Three in a Row 1", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B15F - Three in a Row 2", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B15F - Three in a Row 3", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B15F - Right Wall", player), lambda state: state.has("Dynamite", player, 4)) + + set_rule(world.multiworld.get_location("B16F - Undulating Rocks", player), lambda state: state.has("Blue Key", player, 4)) + set_rule(world.multiworld.get_location("B16F - Top of Waterfall", player), lambda state: state.has("Blue Key", player, 4)) + set_rule(world.multiworld.get_location("B16F - Below Waterfall", player), lambda state: state.has("Blue Key", player, 4)) + set_rule(world.multiworld.get_location("B16F - Bat 2", player), lambda state: state.has("Blue Key", player, 4) and state.has("Flare", player, 1)) + set_rule(world.multiworld.get_location("B16F - Bat 2", player), lambda state: state.has("Blue Key", player, 4) and state.has("Flare", player, 1)) + + set_rule(world.multiworld.get_location("B20F - Boulder 1", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B20F - Boulder 2", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B20F - Boulder 3", player), lambda state: state.has("Dynamite", player, 4)) + + set_rule(world.multiworld.get_location("B19F - Past Boulder", player), lambda state: state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B20F - Right Side Bombable Wall", player), lambda state: state.has("Dynamite", player, 5)) + + set_rule(world.multiworld.get_location("B21F - Bat Pit 1", player), lambda state: state.has("Flare", player, 1)) + set_rule(world.multiworld.get_location("B21F - Bat Pit 2", player), lambda state: state.has("Flare", player, 1)) + set_rule(world.multiworld.get_location("B21F - Bat Pit 3", player), lambda state: state.has("Flare", player, 1)) + + set_rule(world.multiworld.get_location("B23F - Pyramid Bombable Wall", player), lambda state: state.has("Dynamite", player, 4)) + + set_rule(world.multiworld.get_location("B23F - Just After Door", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B23F - Ropes Right Wall", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B25F - Ropes Item", player), lambda state: state.has("Red Key", player, 4)) + + set_rule(world.multiworld.get_location("B23F - Just After Door", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B26F - Rope Right 1", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B26F - Rope Right 2", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B26F - So Close You Can Smell It Item", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B27F - Right of Pit 1", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B27F - Right of Pit 2", player), lambda state: state.has("Red Key", player, 4)) + set_rule(world.multiworld.get_location("B27F - Entry Item", player), lambda state: state.has("Red Key", player, 4)) + + set_rule(world.multiworld.get_location("B28F - Boulder Item", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B28F - Bat Ledge", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4) and state.has("Flare", player, 1)) + + set_rule(world.multiworld.get_location("B29F - Ladder Ledge", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B29F - Pit Trap", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B29F - Before Pit Trap", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B29F - Rope Alcove", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4)) + + set_rule(world.multiworld.get_location("B30F - Far Bottom Right", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4)) + set_rule(world.multiworld.get_location("B30F - Undulating Rocks", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4)) + + set_rule(world.multiworld.get_location("B30F - Mound Item", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 4) and state.has("Blue Key", player, 5)) + + set_rule(world.multiworld.get_location("B30F - Far Bottom Left", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + set_rule(world.multiworld.get_location("B29F - Left Wall Rope Ledge", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + set_rule(world.multiworld.get_location("B29F - Left Pit Item", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + + set_rule(world.multiworld.get_location("B29F - Bombable Wall", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 6) and state.has("Blue Key", player, 5)) + + set_rule(world.multiworld.get_location("B29F - Left Wall Item", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + + set_rule(world.multiworld.get_location("B28F - Locked Item 1", player), lambda state: state.has("Red Key", player, 5) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + set_rule(world.multiworld.get_location("B28F - Locked Item 2", player), lambda state: state.has("Red Key", player, 5) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + + set_rule(world.multiworld.get_location("B28F - Final Rope Left", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + set_rule(world.multiworld.get_location("B28F - Final Rope Right", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 5) and state.has("Blue Key", player, 5)) + + set_rule(world.multiworld.get_location("B28F - Final Boulder", player), lambda state: state.has("Red Key", player, 4) and state.has("Dynamite", player, 6) and state.has("Blue Key", player, 5)) + + set_rule(world.multiworld.get_location("Golden Pyramid", player), lambda state: state.has("Red Key", player, 5) and state.has("Dynamite", player, 6) and state.has("Blue Key", player, 6)) + + hidden_rules(world) + + +def hidden_rules(world: "YoshisIslandWorld") -> None: + player = world.player + if not world.options.hidden_items: + return + set_rule(world.multiworld.get_location("B1F - Side Shaft Hidden Item", player), lambda state: state.has("Dynamite", player, 1)) + set_rule(world.multiworld.get_location("B8F - Boulder Pit Hidden Item", player), lambda state: state.has("Dynamite", player, 2)) + set_rule(world.multiworld.get_location("B16F - Blue Door Hidden Item", player), lambda state: state.has("Blue Key", player, 4)) \ No newline at end of file diff --git a/worlds/spelunker/__init__.py b/worlds/spelunker/__init__.py new file mode 100644 index 000000000000..c712c739112c --- /dev/null +++ b/worlds/spelunker/__init__.py @@ -0,0 +1,155 @@ +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, useful_items +from .Locations import get_locations +from .Regions import init_areas +from .Options import SpelunkerOptions +from .Client import SpelunkerClient +from .Rules import set_rules +from .Rom import LocalRom, patch_rom, get_base_rom_path, SpelunkerProcPatch, USHASH + + +class SpelunkerSettings(settings.Group): + class RomFile(settings.UserFilePath): + """File name of the Spelunker NES ROM""" + description = "Spelunker ROM File" + copy_to = "Spelunker.nes" + md5s = [USHASH] + + rom_file: RomFile = RomFile(RomFile.copy_to) + + +class SpelunkerWeb(WebWorld): + theme = "dirt" + + setup_en = Tutorial( + "Multiworld Setup Guide", + "A guide to setting up the Spelunker randomizer and connecting to an Archipelago server.", + "English", + "setup_en.md", + "setup/en", + ["Pink Switch"] + ) + + tutorials = [setup_en] + + +class SpelunkerWorld(World): + """ + Spelunker is a 2D platformer for the NES. + Explore the cavernous depths, collecting treasure along the way and seeking the mythical Pyramid of Gold. + Also, you'll probably die a lot. + """ + game = "Spelunker" + option_definitions = SpelunkerOptions + required_client_version = (0, 4, 6) + + 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 = SpelunkerWeb() + settings: typing.ClassVar[SpelunkerSettings] + # topology_present = True + + options_dataclass = SpelunkerOptions + options: SpelunkerOptions + + locked_locations: List[str] + 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 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: + if self.random.randint(0, 100) <= 10: + return self.random.choice(useful_items) + else: + return self.random.choice(filler_items) + + def set_rules(self) -> None: + set_rules(self) + self.multiworld.completion_condition[self.player] = lambda state: state.has("Golden Pyramid", self.player) + self.get_location("Golden Pyramid").place_locked_item(self.create_item("Golden Pyramid")) + + def get_excluded_items(self) -> Set[str]: + excluded_items: Set[str] = set() + 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 + + return item + + def generate_filler(self, pool: List[Item]) -> None: + for _ in range(len(self.multiworld.get_unfilled_locations(self.player)) - len(pool) - 1): + 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: + pool = self.get_item_pool(self.get_excluded_items()) + + self.generate_filler(pool) + + self.multiworld.itempool += pool + + def generate_output(self, output_directory: str): + try: + world = self.multiworld + player = self.player + patch = SpelunkerProcPatch() + patch_rom(self, patch, self.player, self.multiworld) + + self.rom_name = patch.name + + patch.write(os.path.join(output_directory, + f"{self.multiworld.get_out_file_name_base(self.player)}{patch.patch_file_ending}")) + except Exception: + raise + finally: + self.rom_name_available_event.set() # make sure threading continues and errors are collected + + 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]] diff --git a/worlds/spelunker/docs/en_Spelunker.md b/worlds/spelunker/docs/en_Spelunker.md new file mode 100644 index 000000000000..f3050c22b94f --- /dev/null +++ b/worlds/spelunker/docs/en_Spelunker.md @@ -0,0 +1,29 @@ +# Spelunker + +## Where is the options 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? + +All of the collectable items scattered throughout the cave are randomized into the Multiworld pool, with the exception of Energy refills. + +## What is the goal of Spelunker when randomized? + +The goal is to reach the bottom of the cave and discover the Pyramid of Gold. + +## What items and locations get shuffled? + +Locations consist of any collectable items aside from Energy refills. Optionally, the player may also randomize the hidden items. + +## 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 Spelunker + +All items, whether they are for another world or not, appear as Archipelago symbols, with Progression items being colored blue and white, and all others being green and red. + +## When the player receives an item, what happens? + +When the player receives an item, a fanfare or tune is played and the player receives the corresponding equipment or powerup. diff --git a/worlds/spelunker/docs/setup_en.md b/worlds/spelunker/docs/setup_en.md new file mode 100644 index 000000000000..4e4133483cc9 --- /dev/null +++ b/worlds/spelunker/docs/setup_en.md @@ -0,0 +1,122 @@ +# 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 options 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/Connector.lua`. +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/spelunker/local_data.py b/worlds/spelunker/local_data.py new file mode 100644 index 000000000000..2e19fa5362f5 --- /dev/null +++ b/worlds/spelunker/local_data.py @@ -0,0 +1,189 @@ +local_locations = { + "1F - First Item": 0x2EAD, + "1F - Pit Item": 0x2EB5, + "1F - Right Item 1": 0x2E95, + "1F - Between Mounds": 0x2EBD, + "1F - Far Wall 1": 0x2E9D, + "1F - Far Wall 2": 0x2EA5, + + "B1F - Elevator Item": 0x2EDD, + "B1F - Undulating Rocks": 0x2EE5, + "B1F - Past Boulder": 0x2EED, + "B1F - Side Shaft Ledge": 0x2F2D, + "B1F - Side Shaft Mound": 0x2FAD, + "B1F - Side Shaft Bottom Left": 0x2FED, + "B1F - Side Shaft Bottom Right": 0x3025, + "B1F - Side Shaft Ladder Right": 0x301D, + + "B2F - First Item": 0x2EFD, + "B2F - Second Item": 0x2F05, + + "B3F - Mound Item": 0x2F55, + "B3F - Ramp Item": 0x2F7D, + "B3F - Ledge Item": 0x2FA5, + "B3F - Upper Nook 1": 0x2F15, + "B3F - Upper Nook 2": 0x2F35, + "B3F - Upper Nook 3": 0x2F25, + "B3F - Middle Ledge": 0x2FD5, + "B3F - Bottom": 0x3015, + "B3F - Bat Item": 0x2FF5, + "B3F - Ladder Left": 0x2F95, + "B3F - Bombable Wall": 0x2F9D, + + "B4F - Top Item": 0x300D, + "B4F - Minecart 1": 0x306D, + "B4F - Minecart 2": 0x3065, + + "B5F - Near Ramp": 0x3095, + "B5F - Ladder Left": 0x3075, + "B5F - Ladder Right": 0x307D, + + "B6F - Item": 0x3085, + + "B7F - Left of Elevators": 0x30D5, + + "B8F - Right Side 1": 0x3125, + "B8F - Right Side 2": 0x311D, + "B8F - Rope 1": 0x30CD, + "B8F - Rope 2": 0x30C5, + "B8F - Boulder Pit 1": 0x312D, + "B8F - Boulder Pit 2": 0x3115, + + "B9F - Right Item": 0x314D, + "B9F - Left Top of Ramp": 0x3155, + "B9F - Left Mounds": 0x317D, + "B9F - Left Near Edge": 0x3175, + + "B10F - Far Ropes Ledge": 0x318D, + "B10F - First Bridge": 0x31A5, + "B10F - Between Bridges": 0x31AD, + "B10F - After Bridges": 0x31B5, + "B10F - Ladder Item": 0x31DD, + "B10F - Rope Item": 0x31E5, + "B10F - Solo Rope": 0x31D5, + "B10F - Platform Item": 0x31CD, + "B10F - Left Shaft": 0x31ED, + + "B11F - Boulder Pit": 0x3205, + "B11F - Bombable Wall": 0x320D, + "B11F - Left Shaft": 0x3215, + + "B12F - Pit Item 1": 0x3235, + "B12F - Pit Item 2": 0x322D, + "B12F - Pit Item 3": 0x321D, + "B12F - Locked Item": 0x3225, + + "B13F - Item": 0x324D, + + "B14F - Near Ladder": 0x3265, + "B14F - Disconnected Platform": 0x3275, + "B14F - Rope Item": 0x325D, + "B14F - Boulder Item": 0x3255, + "B14F - Far Ledge": 0x327D, + + "B15F - Left Wall": 0x32A5, + "B15F - Past Boulder": 0x32D5, + "B15F - Upper Ledge": 0x3285, + "B15F - Three in a Row 1": 0x328D, + "B15F - Three in a Row 2": 0x3295, + "B15F - Three in a Row 3": 0x329D, + "B15F - Right Wall": 0x32A5, + + "B16F - Undulating Rocks": 0x32E5, + "B16F - Top of Waterfall": 0x32F5, + "B16F - Below Waterfall": 0x3325, + "B16F - Bat 1": 0x3315, + "B16F - Bat 2": 0x330D, + + "B17F - Item": 0x3305, + + "B18F - Before Pit": 0x332D, + "B18F - Trap Item": 0x333D, + + "B19F - Long Rope Bottom": 0x3355, + "B19F - Near Ladder": 0x335D, + "B19F - Past Boulder": 0x3365, + + "B20F - Near Ladder": 0x336D, + "B20F - Boulder 1": 0x33E5, + "B20F - Boulder 2": 0x33ED, + "B20F - Boulder 3": 0x33F5, + "B20F - Right Side Bombable Wall": 0x33B5, + "B20F - Water Spout Upper 1": 0x338D, + "B20F - Water Spout Upper Trap": 0x3385, + "B20F - Water Spout Lonely Ledge": 0x33AD, + "B20F - Water Spout Middle Left Ledge": 0x33C5, + "B20F - Water Spout Middle Left Rope": 0x33BD, + "B20F - Water Spout Middle Right Ledge": 0x33CD, + "B20F - Near Right Rope": 0x33D5, + + "B21F - Bat Pit 1": 0x343D, + "B21F - Bat Pit 2": 0x342D, + "B21F - Bat Pit 3": 0x3425, + "B21F - Ladder Right": 0x3405, + "B21F - Ladder Left": 0x33FD, + + "B22F - Lonely Platform": 0x3435, + + "B23F - Pyramid Platforming": 0x345D, + "B23F - Long Way Around": 0x3445, + "B23F - Left Wall Near Pyramid": 0x347D, + "B23F - Middle Pyramid Jump": 0x3485, + "B23F - Pyramid Bombable Wall": 0x348D, + "B23F - Offcenter T": 0x3475, + "B23F - Lonely Platform Before Door": 0x344D, + "B23F - Just After Door": 0x346D, + "B23F - Ropes Right Wall": 0x34A5, + + "B24F - Left Side Item": 0x34BD, + "B24F - Right Side Item": 0x34C5, + "B24F - Pit Trap": 0x34CD, + + "B25F - Left 1": 0x34E5, + "B25F - Left 2": 0x34ED, + "B25F - Right 1": 0x3505, + "B25F - Right 2": 0x34F5, + "B25F - Ropes Item": 0x34DD, + + "B26F - Rope Right 1": 0x353D, + "B26F - Rope Right 2": 0x3535, + "B26F - So Close You Can Smell It Item": 0x352D, + + "B27F - Right of Pit 1": 0x3555, + "B27F - Right of Pit 2": 0x3545, + "B27F - Entry Item": 0x354D, + + "B28F - Boulder Item": 0x3595, + "B28F - Bat Ledge": 0x359D, + "B28F - Locked Item 1": 0x3585, + "B28F - Locked Item 2": 0x358D, + + "B28F - Final Boulder": 0x3575, + "B28F - Final Rope Left": 0x356D, + "B28F - Final Rope Right": 0x3565, + + "B29F - Ladder Ledge": 0x35C5, + "B29F - Pit Trap": 0x35F5, + "B29F - Before Pit Trap": 0x35FD, + "B29F - Rope Alcove": 0x35BD, + "B29F - Left Wall Rope Ledge": 0x35E5, + "B29F - Left Pit Item": 0x35D5, + "B29F - Bombable Wall": 0x35CD, + "B29F - Left Wall Item": 0x35B5, + + "B30F - Far Bottom Right": 0x361D, + "B30F - Undulating Rocks": 0x3615, + "B30F - Mound Item": 0x362D, + "B30F - Far Bottom Left": 0x3635 +} + +hidden_locations = [ + "B1F - Hidden Item before Boulder", + "B1F - Side Shaft Hidden Item", + "B8F - Boulder Pit Hidden Item", + "B10F - Bridge Hidden Item", + "B16F - Blue Door Hidden Item", + "B20F - Water Spout Upper Ledge Hidden Item", + "B23F - Pyramid Hidden Item", + "B24F - Pit Trap Hidden Item" +] \ No newline at end of file From ceb36cfe00f917ee1c163b74c4285a7a8b09ffe8 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:39:09 -0500 Subject: [PATCH 17/30] Delete worlds/spelunker/t --- worlds/spelunker/t | 1 - 1 file changed, 1 deletion(-) delete mode 100644 worlds/spelunker/t diff --git a/worlds/spelunker/t b/worlds/spelunker/t deleted file mode 100644 index 718f4d2ff533..000000000000 --- a/worlds/spelunker/t +++ /dev/null @@ -1 +0,0 @@ -t From ac3bcb57eaf63b2e2beb78e3a4b551397f5f9dfb Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Wed, 8 May 2024 23:39:34 -0500 Subject: [PATCH 18/30] Fix stray instances of YoshisIslandWorld --- worlds/spelunker/Regions.py | 2 +- worlds/spelunker/Rules.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/spelunker/Regions.py b/worlds/spelunker/Regions.py index 91f3df312e02..fcbd16b03fd8 100644 --- a/worlds/spelunker/Regions.py +++ b/worlds/spelunker/Regions.py @@ -2,7 +2,7 @@ from BaseClasses import Region, Location from .Locations import LocationData if TYPE_CHECKING: - from . import YoshisIslandWorld + from . import SpelunkerWorld class SpelunkerLocation(Location): diff --git a/worlds/spelunker/Rules.py b/worlds/spelunker/Rules.py index f0067468c2de..59e0b7af94e5 100644 --- a/worlds/spelunker/Rules.py +++ b/worlds/spelunker/Rules.py @@ -112,7 +112,7 @@ def set_rules(world: "SpelunkerWorld") -> None: hidden_rules(world) -def hidden_rules(world: "YoshisIslandWorld") -> None: +def hidden_rules(world: "SpelunkerWorld") -> None: player = world.player if not world.options.hidden_items: return From c73df3d33659c6050e0775b6b26a9e02bb97af8b Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 00:20:25 -0500 Subject: [PATCH 19/30] Clean stray commas and fix incorrect check values --- worlds/spelunker/Client.py | 20 ++++++++++---------- worlds/spelunker/Locations.py | 2 +- worlds/spelunker/Options.py | 8 ++++---- worlds/spelunker/Rom.py | 6 +++--- worlds/spelunker/local_data.py | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/worlds/spelunker/Client.py b/worlds/spelunker/Client.py index b75b3a211939..5511be53b3c7 100644 --- a/worlds/spelunker/Client.py +++ b/worlds/spelunker/Client.py @@ -137,7 +137,8 @@ async def game_watcher(self, ctx: BizHawkClientContext) -> None: (0x7051, 1, "PRG ROM"), (0x022C, 1, "RAM"), (0x022D, 1, "RAM"), - (0x0783, 1, "RAM")]) + (0x0783, 1, "RAM"), + (0x0781, 1, "RAM")]) demo_mode = int.from_bytes(read_state[0], "little") loc_array = bytearray(read_state[1]) @@ -146,6 +147,7 @@ async def game_watcher(self, ctx: BizHawkClientContext) -> None: is_dead = int.from_bytes(read_state[4], "little") is_paused = int.from_bytes(read_state[5], "little") goal_trigger = int.from_bytes(read_state[6], "little") + recv_count = int.from_bytes(read_state[7], "big") if hidden_checks == 0x01: self.location_map.update(hidden_table) @@ -178,25 +180,23 @@ async def game_watcher(self, ctx: BizHawkClientContext) -> None: new_checks.append(loc_id) if loc_id in ctx.checked_locations: - await bizhawk.write(ctx.bizhawk_ctx, [(0x0500 + loc_pointer, bytes([0x00]), "RAM")]) - + loc_array[loc_pointer] = 0 + await bizhawk.write(ctx.bizhawk_ctx, [(0x0500, loc_array, "RAM")]) + for new_check_id in new_checks: ctx.locations_checked.add(new_check_id) location = ctx.location_names[new_check_id] await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) - recv_count = await bizhawk.read(ctx.bizhawk_ctx, [(0x0781, 1, "RAM")]) - recv_index = recv_count[0] - recv_index = int.from_bytes(recv_index, byteorder='big') - if recv_index < len(ctx.items_received): - item = ctx.items_received[recv_index] - recv_index += 1 + if recv_count < len(ctx.items_received): + item = ctx.items_received[recv_count] + recv_count += 1 if item.item in item_ids: ram_item = item_ids[item.item] await bizhawk.write(ctx.bizhawk_ctx, [(0x780, bytes([ram_item]), "RAM")]) - await bizhawk.write(ctx.bizhawk_ctx, [(0x781, bytes([recv_index]), "RAM")]) + await bizhawk.write(ctx.bizhawk_ctx, [(0x781, bytes([recv_count]), "RAM")]) if not ctx.finished_game and goal_trigger == 0x01: await ctx.send_msgs([{ diff --git a/worlds/spelunker/Locations.py b/worlds/spelunker/Locations.py index cf86d5d8ead7..300c36926e28 100644 --- a/worlds/spelunker/Locations.py +++ b/worlds/spelunker/Locations.py @@ -206,7 +206,7 @@ def get_locations(world: Optional["SpelunkerWorld"]) -> List[LocationData]: LocationData("Area 3", "B16F - Blue Door Hidden Item", 0x696A01), LocationData("Area 3", "B20F - Water Spout Upper Ledge Hidden Item", 0x696A02), LocationData("Area 4", "B23F - Pyramid Hidden Item", 0x696A03), - LocationData("Area 4", "B24F - Pit Trap Hidden Item", 0x696A04), + LocationData("Area 4", "B24F - Pit Trap Hidden Item", 0x696A04) ] return location_table diff --git a/worlds/spelunker/Options.py b/worlds/spelunker/Options.py index 64a9f38b4534..93f89c80e9a6 100644 --- a/worlds/spelunker/Options.py +++ b/worlds/spelunker/Options.py @@ -3,12 +3,12 @@ class HiddenLocs(Toggle): - """Places items on the secret invisible items. Does not count for Keys on cave difficulty 4.""" + """Places items on the secret invisible item locations.""" display_name = "Hidden Item Checks" class CaveLevel(Choice): - """This will determine the difficulty level of the cave you venture through.""" - display_name = "Cave Difficulty" + """This will determine the color palette of the cave you venture though.""" + display_name = "Cave Palette" option_cave_1 = 0 option_cave_2 = 1 option_cave_3 = 2 @@ -18,5 +18,5 @@ class CaveLevel(Choice): @dataclass class SpelunkerOptions(PerGameCommonOptions): hidden_items: HiddenLocs - cave_difficulty: CaveLevel + cave_color: CaveLevel death_link: DeathLink diff --git a/worlds/spelunker/Rom.py b/worlds/spelunker/Rom.py index 4d78bb362df3..c3870ef1ee30 100644 --- a/worlds/spelunker/Rom.py +++ b/worlds/spelunker/Rom.py @@ -59,7 +59,7 @@ 0x69697F: 0x36, 0x696980: 0x32, 0x696981: 0x26, - 0x696981: 0x27, + 0x696982: 0x27, 0x696983: 0x35, 0x696984: 0x41, @@ -182,7 +182,7 @@ 0x6969F0: 0xF0, 0x6969F1: 0xEE, 0x6969F2: 0xED, - 0x6969F2: 0xEA, + 0x6969F3: 0xEA, 0x6969F4: 0xF7, 0x6969F5: 0xF6, 0x6969F6: 0xF9, @@ -294,7 +294,7 @@ def patch_rom(world, rom, player: int, multiworld): else: rom.write_bytes(local_locations[location.name], bytearray([0x02])) - rom.write_bytes(0x7060, bytearray([world.options.cave_difficulty.value + 1])) + rom.write_bytes(0x7060, bytearray([world.options.cave_color.value + 1])) rom.write_bytes(0x7061, bytearray([world.options.hidden_items.value])) rom.write_bytes(0x7062, bytearray([world.options.death_link.value])) diff --git a/worlds/spelunker/local_data.py b/worlds/spelunker/local_data.py index 2e19fa5362f5..7aabd3d3aa02 100644 --- a/worlds/spelunker/local_data.py +++ b/worlds/spelunker/local_data.py @@ -81,7 +81,7 @@ "B14F - Boulder Item": 0x3255, "B14F - Far Ledge": 0x327D, - "B15F - Left Wall": 0x32A5, + "B15F - Left Wall": 0x32C5, "B15F - Past Boulder": 0x32D5, "B15F - Upper Ledge": 0x3285, "B15F - Three in a Row 1": 0x328D, From 005ebbfe53ef5551c57caf3bebb7fa2ebaaf62f3 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 00:49:40 -0500 Subject: [PATCH 20/30] Fix rom still being asked for even though it was on procedure patch --- worlds/spelunker/__init__.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/worlds/spelunker/__init__.py b/worlds/spelunker/__init__.py index c712c739112c..d327d67a3a88 100644 --- a/worlds/spelunker/__init__.py +++ b/worlds/spelunker/__init__.py @@ -70,12 +70,6 @@ def __init__(self, multiworld: MultiWorld, player: int): 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 create_item(self, name: str) -> Item: data = item_table[name] return Item(name, data.classification, data.code, self.player) From 281181394f4ad60ed3f0ee2c3d95b73dd86c69a6 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 08:17:17 -0500 Subject: [PATCH 21/30] Update worlds/spelunker/Client.py Co-authored-by: Bryce Wilson --- worlds/spelunker/Client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/spelunker/Client.py b/worlds/spelunker/Client.py index 5511be53b3c7..fcd87cd40ef0 100644 --- a/worlds/spelunker/Client.py +++ b/worlds/spelunker/Client.py @@ -60,7 +60,7 @@ class SpelunkerClient(BizHawkClient): def __init__(self) -> None: super().__init__() - async def validate_rom(self, ctx: BizHawkClientContext) -> bool: + async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: from CommonClient import logger try: From 176791da606b3b7266d2c101b0096e893128a2b6 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 08:30:52 -0500 Subject: [PATCH 22/30] Clean up code and remove unnecessary code --- worlds/spelunker/Client.py | 44 +++++--------------------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/worlds/spelunker/Client.py b/worlds/spelunker/Client.py index fcd87cd40ef0..374b42b70ceb 100644 --- a/worlds/spelunker/Client.py +++ b/worlds/spelunker/Client.py @@ -5,28 +5,6 @@ from .Rom import location_table, hidden_table from typing import TYPE_CHECKING, Dict, Set -# TODO: Remove this when Archipelago 0.4.4 gets released -import sys - -if "worlds._bizhawk" not in sys.modules: - import importlib - import os - import zipimport - - bh_apworld_path = os.path.join( - os.path.dirname(sys.modules["worlds"].__file__), "_bizhawk.apworld" - ) - if os.path.isfile(bh_apworld_path): - importer = zipimport.zipimporter(bh_apworld_path) - spec = importer.find_spec(os.path.basename(bh_apworld_path).rsplit(".", 1)[0]) - mod = importlib.util.module_from_spec(spec) - mod.__package__ = f"worlds.{mod.__package__}" - mod.__name__ = f"worlds.{mod.__name__}" - sys.modules[mod.__name__] = mod - importer.exec_module(mod) - elif not os.path.isdir(os.path.splitext(bh_apworld_path)[0]): - raise AssertionError("Could not import worlds._bizhawk") - from NetUtils import ClientStatus import worlds._bizhawk as bizhawk from worlds._bizhawk.client import BizHawkClient @@ -34,19 +12,7 @@ if TYPE_CHECKING: from worlds._bizhawk.context import BizHawkClientContext -else: - BizHawkClientContext = object - -# Add .apwl suffix to bizhawk client -from worlds.LauncherComponents import SuffixIdentifier, components - -for component in components: - if component.script_name == "BizHawkClient": - component.file_identifier = SuffixIdentifier( - *(*component.file_identifier.suffixes, ".apsplunker") - ) - break - + EXPECTED_ROM_NAME = "SPELUNKERAP" @@ -60,7 +26,7 @@ class SpelunkerClient(BizHawkClient): def __init__(self) -> None: super().__init__() - async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: + async def validate_rom(self, ctx: BizHawkClientContext) -> bool: from CommonClient import logger try: @@ -89,7 +55,7 @@ async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: await ctx.update_death_link(bool(death_link[0])) return True - async def set_auth(self, ctx: BizHawkClientContext) -> None: + async def set_auth(self, ctx: "BizHawkClientContext") -> None: from CommonClient import logger slot_name_length = await bizhawk.read(ctx.bizhawk_ctx, [(0x7040, 1, "PRG ROM")]) @@ -108,7 +74,7 @@ def on_package(self, ctx: "BizHawkClientContext", cmd: str, args: dict) -> None: if "DeathLink" in args["tags"] and args["data"]["source"] != ctx.slot_info[ctx.slot].name: self.received_deathlinks += 1 - async def game_watcher(self, ctx: BizHawkClientContext) -> None: + async def game_watcher(self, ctx: "BizHawkClientContext") -> None: from CommonClient import logger if ctx.server_version.build > 0: @@ -187,7 +153,7 @@ async def game_watcher(self, ctx: BizHawkClientContext) -> None: for new_check_id in new_checks: ctx.locations_checked.add(new_check_id) location = ctx.location_names[new_check_id] - await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}]) + await ctx.send_msgs([{"cmd": "LocationChecks", "locations": [new_check_id]}]) if recv_count < len(ctx.items_received): item = ctx.items_received[recv_count] From c72217212bdd3e64acb8e804e8d0ad02064309fc Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 19:15:27 -0500 Subject: [PATCH 23/30] Remove unnecessary item return From fd4dd72d78218da2a29a88f39ee5fe9f4015c70b Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 19:16:40 -0500 Subject: [PATCH 24/30] Convert item lists to lists --- worlds/spelunker/Items.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/worlds/spelunker/Items.py b/worlds/spelunker/Items.py index af214369798e..53c9f440c0ef 100644 --- a/worlds/spelunker/Items.py +++ b/worlds/spelunker/Items.py @@ -1,4 +1,4 @@ -from typing import Dict, Set, Tuple, NamedTuple, Optional +from typing import Dict, Set, List, NamedTuple, Optional from BaseClasses import ItemClassification class ItemData(NamedTuple): @@ -25,19 +25,18 @@ class ItemData(NamedTuple): "Golden Pyramid": ItemData("Events", None, ItemClassification.progression, 0) } -filler_items: Tuple[str, ...] = ( +filler_items: List[str] = [ "Money Bag", "Coin", "Diamond", "Miracle" -) - -useful_items: Tuple[str, ...] = ( +] +useful_items: List[str] = [ "1-Up", "Multiplier", "Potion", "Invincibility" -) +] def get_item_names_per_category() -> Dict[str, Set[str]]: categories: Dict[str, Set[str]] = {} From 9a12623df5e4b3c281779700325fedbdbdb08a10 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 19:47:17 -0500 Subject: [PATCH 25/30] fix the rest of the stuff --- worlds/spelunker/Client.py | 4 +- worlds/spelunker/Locations.py | 2 +- worlds/spelunker/Options.py | 14 +++ worlds/spelunker/Rules.py | 15 +-- worlds/spelunker/__init__.py | 4 - worlds/spelunker/docs/en_Spelunker.md | 2 +- worlds/spelunker/docs/setup_en.md | 169 ++++++++------------------ worlds/spelunker/local_data.py | 6 +- 8 files changed, 77 insertions(+), 139 deletions(-) diff --git a/worlds/spelunker/Client.py b/worlds/spelunker/Client.py index 374b42b70ceb..a8ed79ac2373 100644 --- a/worlds/spelunker/Client.py +++ b/worlds/spelunker/Client.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: from worlds._bizhawk.context import BizHawkClientContext - + EXPECTED_ROM_NAME = "SPELUNKERAP" @@ -26,7 +26,7 @@ class SpelunkerClient(BizHawkClient): def __init__(self) -> None: super().__init__() - async def validate_rom(self, ctx: BizHawkClientContext) -> bool: + async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: from CommonClient import logger try: diff --git a/worlds/spelunker/Locations.py b/worlds/spelunker/Locations.py index 300c36926e28..d90448e3c061 100644 --- a/worlds/spelunker/Locations.py +++ b/worlds/spelunker/Locations.py @@ -14,7 +14,7 @@ class LocationData(NamedTuple): rule: CollectionRule = lambda state: True -def get_locations(world: Optional["SpelunkerWorld"]) -> List[LocationData]: +def get_locations(world: ["SpelunkerWorld"]) -> List[LocationData]: location_table: List[LocationData] = [ LocationData("Area 1", "1F - First Item", 0x696969), diff --git a/worlds/spelunker/Options.py b/worlds/spelunker/Options.py index 93f89c80e9a6..a2a930da1f71 100644 --- a/worlds/spelunker/Options.py +++ b/worlds/spelunker/Options.py @@ -15,8 +15,22 @@ class CaveLevel(Choice): option_cave_4 = 3 default = 0 +class EnergyLink(Toggle): + """Enables Energy Link. If enabled, you can hold the Select button to refill your energy from the pool. + A specified percent of energy received from refills will be put into the pool.""" + display_name = "Energy Link" + +class EnergyLinkPercent(Range): + """Specifies how much energy from """ + display_name = "Energy Link Percent" + range_start = 1 + range_end = 100 + default = 50 + @dataclass class SpelunkerOptions(PerGameCommonOptions): hidden_items: HiddenLocs cave_color: CaveLevel + energy_link: EnergyLink + energy_link_percent: EnergyLinkPercent death_link: DeathLink diff --git a/worlds/spelunker/Rules.py b/worlds/spelunker/Rules.py index 59e0b7af94e5..e6f82e220466 100644 --- a/worlds/spelunker/Rules.py +++ b/worlds/spelunker/Rules.py @@ -109,13 +109,8 @@ def set_rules(world: "SpelunkerWorld") -> None: set_rule(world.multiworld.get_location("Golden Pyramid", player), lambda state: state.has("Red Key", player, 5) and state.has("Dynamite", player, 6) and state.has("Blue Key", player, 6)) - hidden_rules(world) - - -def hidden_rules(world: "SpelunkerWorld") -> None: - player = world.player - if not world.options.hidden_items: - return - set_rule(world.multiworld.get_location("B1F - Side Shaft Hidden Item", player), lambda state: state.has("Dynamite", player, 1)) - set_rule(world.multiworld.get_location("B8F - Boulder Pit Hidden Item", player), lambda state: state.has("Dynamite", player, 2)) - set_rule(world.multiworld.get_location("B16F - Blue Door Hidden Item", player), lambda state: state.has("Blue Key", player, 4)) \ No newline at end of file + if world.options.hidden_items: + set_rule(world.multiworld.get_location("B1F - Side Shaft Hidden Item", player), lambda state: state.has("Dynamite", player, 1)) + set_rule(world.multiworld.get_location("B8F - Boulder Pit Hidden Item", player), lambda state: state.has("Dynamite", player, 2)) + set_rule(world.multiworld.get_location("B16F - Blue Door Hidden Item", player), lambda state: state.has("Blue Key", player, 4)) + \ No newline at end of file diff --git a/worlds/spelunker/__init__.py b/worlds/spelunker/__init__.py index d327d67a3a88..445402109e51 100644 --- a/worlds/spelunker/__init__.py +++ b/worlds/spelunker/__init__.py @@ -95,10 +95,6 @@ def get_excluded_items(self) -> Set[str]: 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 - return item def generate_filler(self, pool: List[Item]) -> None: diff --git a/worlds/spelunker/docs/en_Spelunker.md b/worlds/spelunker/docs/en_Spelunker.md index f3050c22b94f..29d92c9b4719 100644 --- a/worlds/spelunker/docs/en_Spelunker.md +++ b/worlds/spelunker/docs/en_Spelunker.md @@ -14,7 +14,7 @@ The goal is to reach the bottom of the cave and discover the Pyramid of Gold. ## What items and locations get shuffled? -Locations consist of any collectable items aside from Energy refills. Optionally, the player may also randomize the hidden items. +The shuffled items and locations are the game's collectible items aside from Energy refills. Optionally, the player may also randomize the hidden items. ## Which items can be in another player's world? diff --git a/worlds/spelunker/docs/setup_en.md b/worlds/spelunker/docs/setup_en.md index 4e4133483cc9..f1e6b1346c1c 100644 --- a/worlds/spelunker/docs/setup_en.md +++ b/worlds/spelunker/docs/setup_en.md @@ -1,122 +1,53 @@ -# Yoshi's Island Archipelago Randomizer Setup Guide +# Spelunker 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 options 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/Connector.lua`. -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. +- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases) +- An English Spelunker ROM. +- [BizHawk](https://tasvideos.org/BizHawk/ReleaseHistory) 2.7 or later + +### Configuring Bizhawk + +Once you have installed BizHawk, open `EmuHawk.exe` and change the following settings: + +- If you're using BizHawk 2.7 or 2.8, go to `Config > Customize`. On the Advanced tab, switch the Lua Core from +`NLua+KopiLua` to `Lua+LuaInterface`, then restart EmuHawk. (If you're using BizHawk 2.9, you can skip this step.) +- Under `Config > Customize`, check the "Run in background" option to prevent disconnecting from the client while you're +tabbed out of EmuHawk. +- Open a `.nes` file in EmuHawk and go to `Config > Controllers…` to configure your inputs. If you can't click +`Controllers…`, load any `.nes` ROM first. +- Consider clearing keybinds in `Config > Hotkeys…` if you don't intend to use them. Select the keybind and press Esc to +clear it. + +## Generating and Patching a Game + +1. Create your options file (YAML). You can make one on the +[Spelunker options page](../../../games/Spelunker/player-options). +2. Follow the general Archipelago instructions for [generating a game](../../Archipelago/setup/en#generating-a-game). +This will generate an output file for you. Your patch file will have the `.apsplunker` file extension. +3. Open `ArchipelagoLauncher.exe` +4. Select "Open Patch" on the left side and select your patch file. +5. If this is your first time patching, you will be prompted to locate your vanilla ROM +6. A patched `.nes` file will be created in the same place as the patch file. +7. On your first time opening a patch with BizHawk Client, you will also be asked to locate `EmuHawk.exe` in your +BizHawk install. + +## Connecting to a Server + +By default, opening a patch file will do steps 1-5 below for you automatically. Even so, keep them in your memory just +in case you have to close and reopen a window mid-game for some reason. + +1. Spelunker uses Archipelago's BizHawk Client. If the client isn't still open from when you patched your game, +you can re-open it from the launcher. +2. Ensure EmuHawk is running the patched ROM. +3. In EmuHawk, go to `Tools > Lua Console`. This window must stay open while playing. +4. In the Lua Console window, go to `Script > Open Script…`. +5. Navigate to your Archipelago install folder and open `data/lua/connector_bizhawk_generic.lua`. +6. The emulator and client will eventually connect to each other. The BizHawk Client window should indicate that it +connected and recognized Spelunker. +7. To connect the client to the server, enter your room's address and port (e.g. `archipelago.gg:38281`) into the +top text field of the client and click Connect. + +You should now be able to receive and send items. You'll need to do these steps every time you want to reconnect. It is +perfectly safe to make progress offline; everything will re-sync when you reconnect. However, if the game is reset +or the player receives a game-over after collecting locations offline, they will need to be recollected upon reconnecting. diff --git a/worlds/spelunker/local_data.py b/worlds/spelunker/local_data.py index 7aabd3d3aa02..b12f203240f8 100644 --- a/worlds/spelunker/local_data.py +++ b/worlds/spelunker/local_data.py @@ -1,4 +1,6 @@ -local_locations = { +from typing import Dict, List + +local_locations: Dict[str, int] = { "1F - First Item": 0x2EAD, "1F - Pit Item": 0x2EB5, "1F - Right Item 1": 0x2E95, @@ -186,4 +188,4 @@ "B20F - Water Spout Upper Ledge Hidden Item", "B23F - Pyramid Hidden Item", "B24F - Pit Trap Hidden Item" -] \ No newline at end of file +] From 0827165150c6f0ef2b2ef869a29bee049a99c99f Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 21:43:36 -0500 Subject: [PATCH 26/30] remove energylink from options --- worlds/spelunker/Options.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/worlds/spelunker/Options.py b/worlds/spelunker/Options.py index a2a930da1f71..73a092709948 100644 --- a/worlds/spelunker/Options.py +++ b/worlds/spelunker/Options.py @@ -14,18 +14,18 @@ class CaveLevel(Choice): option_cave_3 = 2 option_cave_4 = 3 default = 0 +#NOT IMPLEMENTED +#class EnergyLink(Toggle): + # """Enables Energy Link. If enabled, you can hold the Select button to refill your energy from the pool. + # A specified percent of energy received from refills will be put into the pool.""" + #display_name = "Energy Link" -class EnergyLink(Toggle): - """Enables Energy Link. If enabled, you can hold the Select button to refill your energy from the pool. - A specified percent of energy received from refills will be put into the pool.""" - display_name = "Energy Link" - -class EnergyLinkPercent(Range): - """Specifies how much energy from """ - display_name = "Energy Link Percent" - range_start = 1 - range_end = 100 - default = 50 +#class EnergyLinkPercent(Range): + # """Specifies how much energy from """ + # display_name = "Energy Link Percent" + # range_start = 1 + #range_end = 100 + #default = 50 @dataclass class SpelunkerOptions(PerGameCommonOptions): From 6ddc9920dbd31bf8d4054a1635db41555fe4801a Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 9 May 2024 22:27:32 -0500 Subject: [PATCH 27/30] Update Options.py --- worlds/spelunker/Options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/spelunker/Options.py b/worlds/spelunker/Options.py index 73a092709948..55e81d03cfc1 100644 --- a/worlds/spelunker/Options.py +++ b/worlds/spelunker/Options.py @@ -31,6 +31,6 @@ class CaveLevel(Choice): class SpelunkerOptions(PerGameCommonOptions): hidden_items: HiddenLocs cave_color: CaveLevel - energy_link: EnergyLink - energy_link_percent: EnergyLinkPercent + #energy_link: EnergyLink + #energy_link_percent: EnergyLinkPercent death_link: DeathLink From 29c8f8daefd0378f0ffa189f1f26fa4ba724d145 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Mon, 13 May 2024 10:53:42 -0500 Subject: [PATCH 28/30] Fix deathlink being always enabled --- worlds/spelunker/Client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/spelunker/Client.py b/worlds/spelunker/Client.py index a8ed79ac2373..597619ea7818 100644 --- a/worlds/spelunker/Client.py +++ b/worlds/spelunker/Client.py @@ -51,7 +51,7 @@ async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: ctx.items_handling = 0b111 death_link = await bizhawk.read(ctx.bizhawk_ctx, [(0x7052, 1, "PRG ROM")]) - if death_link: + if death_link == 0x01: await ctx.update_death_link(bool(death_link[0])) return True From 179e4cd53d86ccffc9c8d65a8f0d31204f0d7807 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 23 May 2024 14:48:27 -0500 Subject: [PATCH 29/30] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4633c99c664d..97c9667b4b21 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Currently, the following games are supported: * Aquaria * Yu-Gi-Oh! Ultimate Masters: World Championship Tournament 2006 * A Hat in Time +* Spelunker 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 From 988193c2ae3060fc75ae0b581943885268198a01 Mon Sep 17 00:00:00 2001 From: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com> Date: Thu, 23 May 2024 14:50:08 -0500 Subject: [PATCH 30/30] Update CODEOWNERS --- docs/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index c34046d5dc30..a03d855a35e3 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -173,6 +173,9 @@ # Slay the Spire /worlds/spire/ @KonoTyran +# Spelunker +/worlds/spelunker/ @PinkSwitch + # Stardew Valley /worlds/stardew_valley/ @agilbert1412