From 45268b18f35d6fe354b95591a5e97c5287c568e4 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Fri, 21 Aug 2020 18:35:48 +0200 Subject: [PATCH] another round of optimizations and cleanup including some I/O multithreading also alias sprite names with their file names as that's an often done mistake --- BaseClasses.py | 3 +- Main.py | 71 ++++---- Rom.py | 436 +++++++++++++++++++++++++------------------------ 3 files changed, 263 insertions(+), 247 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index e1284ec8..83f0204a 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -983,7 +983,8 @@ class Location(object): return self.always_allow(state, item) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state))) def can_reach(self, state: CollectionState) -> bool: - if self.parent_region.can_reach(state) and self.access_rule(state): + # self.access_rule computes faster on average, so placing it first for faster abort + if self.access_rule(state) and self.parent_region.can_reach(state): return True return False diff --git a/Main.py b/Main.py index be370979..8fcd6b4d 100644 --- a/Main.py +++ b/Main.py @@ -7,6 +7,7 @@ import os import random import time import zlib +import concurrent.futures from BaseClasses import World, CollectionState, Item, Region, Location, Shop from Items import ItemFactory @@ -244,16 +245,15 @@ def main(args, seed=None): Patch.create_patch_file(rompath) return player, team, bytes(rom.name).decode() + pool = concurrent.futures.ThreadPoolExecutor() + if not args.suppress_rom: - import concurrent.futures - futures = [] - with concurrent.futures.ThreadPoolExecutor() as pool: - for team in range(world.teams): - for player in range(1, world.players + 1): - futures.append(pool.submit(_gen_rom, team, player)) - for future in futures: - rom_name = future.result() - rom_names.append(rom_name) + + rom_futures = [] + + for team in range(world.teams): + for player in range(1, world.players + 1): + rom_futures.append(pool.submit(_gen_rom, team, player)) def get_entrance_to_region(region: Region): for entrance in region.entrances: @@ -276,37 +276,42 @@ def main(args, seed=None): precollected_items = [[] for player in range(world.players)] for item in world.precollected_items: precollected_items[item.player - 1].append(item.code) - multidata = zlib.compress(json.dumps({"names": parsed_names, - # backwards compat for < 2.4.1 - "roms": [(slot, team, list(name.encode())) - for (slot, team, name) in rom_names], - "rom_strings": rom_names, - "remote_items": [player for player in range(1, world.players + 1) if - world.remote_items[player]], - "locations": [((location.address, location.player), - (location.item.code, location.item.player)) - for location in world.get_filled_locations() if - type(location.address) is int], - "server_options": get_options()["server_options"], - "er_hint_data": er_hint_data, - "precollected_items": precollected_items, - "version": _version_tuple, - "tags": ["ER"] - }).encode("utf-8"), 9) - with open(output_path('%s.multidata' % outfilebase), 'wb') as f: - f.write(multidata) + def write_multidata(roms): + for future in roms: + rom_name = future.result() + rom_names.append(rom_name) + multidata = zlib.compress(json.dumps({"names": parsed_names, + # backwards compat for < 2.4.1 + "roms": [(slot, team, list(name.encode())) + for (slot, team, name) in rom_names], + "rom_strings": rom_names, + "remote_items": [player for player in range(1, world.players + 1) if + world.remote_items[player]], + "locations": [((location.address, location.player), + (location.item.code, location.item.player)) + for location in world.get_filled_locations() if + type(location.address) is int], + "server_options": get_options()["server_options"], + "er_hint_data": er_hint_data, + "precollected_items": precollected_items, + "version": _version_tuple, + "tags": ["ER"] + }).encode("utf-8"), 9) + + with open(output_path('%s.multidata' % outfilebase), 'wb') as f: + f.write(multidata) + + pool.submit(write_multidata, rom_futures) if not args.skip_playthrough: logger.info('Calculating playthrough.') create_playthrough(world) - - if args.create_spoiler: + pool.shutdown() # wait for all queued tasks to complete + if args.create_spoiler: # needs spoiler.hashes to be filled, that depend on rom_futures being done world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase)) - logger.info('Done. Enjoy.') - logger.debug('Total Time: %s', time.perf_counter() - start) - + logger.info('Done. Enjoy. Total Time: %s', time.perf_counter() - start) return world diff --git a/Rom.py b/Rom.py index d712f0a1..5cd69484 100644 --- a/Rom.py +++ b/Rom.py @@ -11,6 +11,7 @@ import struct import sys import subprocess import threading +import concurrent.futures from BaseClasses import CollectionState, ShopType, Region, Location from Dungeons import dungeon_music_addresses @@ -38,7 +39,7 @@ class LocalRom(object): self.patch_base_rom() self.orig_buffer = self.buffer.copy() - def write_byte(self, address: int, value): + def write_byte(self, address: int, value: int): self.buffer[address] = value def write_bytes(self, startaddress: int, values): @@ -62,22 +63,12 @@ class LocalRom(object): self.buffer = bytearray(stream.read()) @staticmethod - def fromJsonRom(rom, file, rom_size=0x200000): - ret = LocalRom(file, True, rom.name, rom.hash) - ret.buffer.extend(bytearray([0x00]) * (rom_size - len(ret.buffer))) - for address, values in rom.patches.items(): - ret.write_bytes(int(address), values) - return ret - - @staticmethod - def verify(buffer, expected=RANDOMIZERBASEHASH): + def verify(buffer, expected: str = RANDOMIZERBASEHASH) -> bool: buffermd5 = hashlib.md5() buffermd5.update(buffer) return expected == buffermd5.hexdigest() def patch_base_rom(self): - - if os.path.isfile(local_path('basepatch.sfc')): with open(local_path('basepatch.sfc'), 'rb') as stream: buffer = bytearray(stream.read()) @@ -128,24 +119,24 @@ class LocalRom(object): inv = crc ^ 0xFFFF self.write_bytes(0x7FDC, [inv & 0xFF, (inv >> 8) & 0xFF, crc & 0xFF, (crc >> 8) & 0xFF]) - def get_hash(self): + def get_hash(self) -> str: h = hashlib.md5() h.update(self.buffer) return h.hexdigest() -def write_int16(rom, address, value): - rom.write_bytes(address, int16_as_bytes(value)) + def write_int16(self, address: int, value: int): + self.write_bytes(address, int16_as_bytes(value)) -def write_int32(rom, address, value): - rom.write_bytes(address, int32_as_bytes(value)) + def write_int32(self, address: int, value: int): + self.write_bytes(address, int32_as_bytes(value)) -def write_int16s(rom, startaddress, values): - for i, value in enumerate(values): - write_int16(rom, startaddress + (i * 2), value) + def write_int16s(self, startaddress: int, values): + for i, value in enumerate(values): + self.write_int16(startaddress + (i * 2), value) -def write_int32s(rom, startaddress, values): - for i, value in enumerate(values): - write_int32(rom, startaddress + (i * 4), value) + def write_int32s(self, startaddress: int, values): + for i, value in enumerate(values): + self.write_int32(startaddress + (i * 4), value) def read_rom(stream) -> bytearray: @@ -160,13 +151,17 @@ check_lock = threading.Lock() def check_enemizer(enemizercli): - with check_lock: - if getattr(check_enemizer, "done", None): - return - if not os.path.exists(enemizercli) and not os.path.exists(enemizercli + ".exe"): - raise Exception(f"Enemizer not found at {enemizercli}, please install it." - f"Such as https://github.com/Ijwu/Enemizer/releases") - if sys.platform == "win32": + if getattr(check_enemizer, "done", None): + return + if not os.path.exists(enemizercli) and not os.path.exists(enemizercli + ".exe"): + raise Exception(f"Enemizer not found at {enemizercli}, please install it." + f"Such as https://github.com/Ijwu/Enemizer/releases") + if sys.platform == "win32": + # the win32api calls appear to not be threadsafe, which is the reason for the lock + with check_lock: + # some time may have passed since the lock was acquired, as such a quick re-check doesn't hurt + if getattr(check_enemizer, "done", None): + return try: import pythoncom from win32com.client import Dispatch @@ -185,10 +180,11 @@ def check_enemizer(enemizercli): raise Exception( f"Enemizer found at {enemizercli} is outdated ({info}), please update your Enemizer. " f"Such as https://github.com/Ijwu/Enemizer/releases") + check_enemizer.done = True -def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite_on_hit): +def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite_on_hit: bool): check_enemizer(enemizercli) randopatch_path = os.path.abspath(output_path(f'enemizer_randopatch_{player}.sfc')) options_path = os.path.abspath(output_path(f'enemizer_options_{player}.json')) @@ -323,14 +319,13 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite if random_sprite_on_hit: _populate_sprite_table() - sprites = list(_sprite_table.values()) + sprites = list(set(_sprite_table.values())) # convert to list and remove dupes if sprites: while len(sprites) < 32: sprites.extend(sprites) world.rom_seeds[player].shuffle(sprites) - for i, path in enumerate(sprites[:32]): - sprite = Sprite(path) + for i, sprite in enumerate(sprites[:32]): rom.write_bytes(0x300000 + (i * 0x8000), sprite.sprite) rom.write_bytes(0x307000 + (i * 0x8000), sprite.palette) rom.write_bytes(0x307078 + (i * 0x8000), sprite.glove_palette) @@ -345,21 +340,24 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, random_sprite _sprite_table = {} def _populate_sprite_table(): if not _sprite_table: - for dir in [local_path('data/sprites/alttpr'), local_path('data/sprites/custom')]: - for file in os.listdir(dir): - filepath = os.path.join(dir, file) - if not os.path.isfile(filepath): - continue - sprite = Sprite(filepath) - if sprite.valid: - _sprite_table[sprite.name.lower()] = filepath + def load_sprite_from_file(file): + filepath = os.path.join(dir, file) + sprite = Sprite(filepath) + if sprite.valid: + _sprite_table[sprite.name.lower()] = sprite + _sprite_table[os.path.basename(filepath).split(".")[0]] = sprite # alias for filename base + + with concurrent.futures.ThreadPoolExecutor() as pool: + for dir in [local_path('data/sprites/alttpr'), local_path('data/sprites/custom')]: + for file in os.listdir(dir): + pool.submit(load_sprite_from_file, file) def get_sprite_from_name(name, local_random=random): _populate_sprite_table() name = name.lower() if name in ['random', 'randomonhit']: - return Sprite(local_random.choice(list(_sprite_table.values()))) - return Sprite(_sprite_table[name]) if name in _sprite_table else None + return local_random.choice(list(_sprite_table.values())) + return _sprite_table.get(name, None) class Sprite(object): default_palette = [255, 127, 126, 35, 183, 17, 158, 54, 165, 20, 255, 1, 120, 16, 157, @@ -508,8 +506,10 @@ class Sprite(object): return list(zip(*[iter(arr)] * size)) def make_int16(pair): return pair[1]<<8 | pair[0] + def expand_color(i): - return ((i & 0x1F) * 8, (i>>5 & 0x1F) * 8, (i>>10 & 0x1F) * 8) + return ((i & 0x1F) * 8, (i >> 5 & 0x1F) * 8, (i >> 10 & 0x1F) * 8) + raw_palette = self.palette if raw_palette is None: raw_palette = Sprite.default_palette @@ -519,6 +519,9 @@ class Sprite(object): # split into palettes of 15 colors return array_chunk(palette_as_colors, 15) + def __hash__(self): + return hash(self.name) + def patch_rom(world, rom, player, team, enemized): local_random = world.rom_seeds[player] @@ -586,42 +589,43 @@ def patch_rom(world, rom, player, team, enemized): if isinstance(exit.addresses, tuple): offset = exit.target room_id, ow_area, vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x, unknown_1, unknown_2, door_1, door_2 = exit.addresses - #room id is deliberately not written - + # room id is deliberately not written rom.write_byte(0x15B8C + offset, ow_area) - write_int16(rom, 0x15BDB + 2 * offset, vram_loc) - write_int16(rom, 0x15C79 + 2 * offset, scroll_y) - write_int16(rom, 0x15D17 + 2 * offset, scroll_x) + rom.write_int16(0x15BDB + 2 * offset, vram_loc) + rom.write_int16(0x15C79 + 2 * offset, scroll_y) + rom.write_int16(0x15D17 + 2 * offset, scroll_x) # for positioning fixups we abuse the roomid as a way of identifying which exit data we are appling # Thanks to Zarby89 for originally finding these values # todo fix screen scrolling if world.shuffle[player] not in ['insanity', 'insanity_legacy', 'madness_legacy'] and \ - exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Ice Palace Exit', 'Misery Mire Exit', - 'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)', + exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', + 'Skull Woods Final Section Exit', 'Ice Palace Exit', 'Misery Mire Exit', + 'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', + 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)']: # For exits that connot be reached from another, no need to apply offset fixes. - write_int16(rom, 0x15DB5 + 2 * offset, link_y) # same as final else + rom.write_int16(0x15DB5 + 2 * offset, link_y) # same as final else elif room_id == 0x0059 and world.fix_skullwoods_exit[player]: - write_int16(rom, 0x15DB5 + 2 * offset, 0x00F8) + rom.write_int16(0x15DB5 + 2 * offset, 0x00F8) elif room_id == 0x004a and world.fix_palaceofdarkness_exit[player]: - write_int16(rom, 0x15DB5 + 2 * offset, 0x0640) + rom.write_int16(0x15DB5 + 2 * offset, 0x0640) elif room_id == 0x00d6 and world.fix_trock_exit[player]: - write_int16(rom, 0x15DB5 + 2 * offset, 0x0134) - elif room_id == 0x000c and world.fix_gtower_exit: # fix ganons tower exit point - write_int16(rom, 0x15DB5 + 2 * offset, 0x00A4) + rom.write_int16(0x15DB5 + 2 * offset, 0x0134) + elif room_id == 0x000c and world.fix_gtower_exit: # fix ganons tower exit point + rom.write_int16(0x15DB5 + 2 * offset, 0x00A4) else: - write_int16(rom, 0x15DB5 + 2 * offset, link_y) + rom.write_int16(0x15DB5 + 2 * offset, link_y) - write_int16(rom, 0x15E53 + 2 * offset, link_x) - write_int16(rom, 0x15EF1 + 2 * offset, camera_y) - write_int16(rom, 0x15F8F + 2 * offset, camera_x) + rom.write_int16(0x15E53 + 2 * offset, link_x) + rom.write_int16(0x15EF1 + 2 * offset, camera_y) + rom.write_int16(0x15F8F + 2 * offset, camera_x) rom.write_byte(0x1602D + offset, unknown_1) rom.write_byte(0x1607C + offset, unknown_2) - write_int16(rom, 0x160CB + 2 * offset, door_1) - write_int16(rom, 0x16169 + 2 * offset, door_2) + rom.write_int16(0x160CB + 2 * offset, door_1) + rom.write_int16(0x16169 + 2 * offset, door_2) elif isinstance(exit.addresses, list): # is hole for address in exit.addresses: @@ -706,7 +710,7 @@ def patch_rom(world, rom, player, team, enemized): rom.write_byte(0x34FD6, 0x80) overflow_replacement = GREEN_TWENTY_RUPEES # Rupoor negative value - write_int16(rom, 0x180036, world.rupoor_cost) + rom.write_int16(0x180036, world.rupoor_cost) # Set stun items rom.write_byte(0x180180, 0x02) # Hookshot only elif world.difficulty_adjustments[player] == 'expert': @@ -726,7 +730,7 @@ def patch_rom(world, rom, player, team, enemized): rom.write_byte(0x34FD6, 0x80) overflow_replacement = GREEN_TWENTY_RUPEES # Rupoor negative value - write_int16(rom, 0x180036, world.rupoor_cost) + rom.write_int16(0x180036, world.rupoor_cost) # Set stun items rom.write_byte(0x180180, 0x00) # Nothing else: @@ -745,7 +749,7 @@ def patch_rom(world, rom, player, team, enemized): #Enable catching fairies rom.write_byte(0x34FD6, 0xF0) # Rupoor negative value - write_int16(rom, 0x180036, world.rupoor_cost) + rom.write_int16(0x180036, world.rupoor_cost) # Set stun items rom.write_byte(0x180180, 0x03) # All standard items #Set overflow items for progressive equipment @@ -906,37 +910,37 @@ def patch_rom(world, rom, player, team, enemized): ERtimeincrease = ERtimeincrease + 15 if world.clock_mode[player] == False: rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode - write_int32(rom, 0x180200, 0) # red clock adjustment time (in frames, sint32) - write_int32(rom, 0x180204, 0) # blue clock adjustment time (in frames, sint32) - write_int32(rom, 0x180208, 0) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, 0) # starting time (in frames, sint32) + rom.write_int32(0x180200, 0) # red clock adjustment time (in frames, sint32) + rom.write_int32(0x180204, 0) # blue clock adjustment time (in frames, sint32) + rom.write_int32(0x180208, 0) # green clock adjustment time (in frames, sint32) + rom.write_int32(0x18020C, 0) # starting time (in frames, sint32) elif world.clock_mode[player] == 'ohko': rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality - write_int32(rom, 0x180200, 0) # red clock adjustment time (in frames, sint32) - write_int32(rom, 0x180204, 0) # blue clock adjustment time (in frames, sint32) - write_int32(rom, 0x180208, 0) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, 0) # starting time (in frames, sint32) + rom.write_int32(0x180200, 0) # red clock adjustment time (in frames, sint32) + rom.write_int32(0x180204, 0) # blue clock adjustment time (in frames, sint32) + rom.write_int32(0x180208, 0) # green clock adjustment time (in frames, sint32) + rom.write_int32(0x18020C, 0) # starting time (in frames, sint32) elif world.clock_mode[player] == 'countdown-ohko': rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality - write_int32(rom, 0x180200, -100 * 60 * 60 * 60) # red clock adjustment time (in frames, sint32) - write_int32(rom, 0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) - write_int32(rom, 0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) + rom.write_int32(0x180200, -100 * 60 * 60 * 60) # red clock adjustment time (in frames, sint32) + rom.write_int32(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) + rom.write_int32(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) if world.difficulty_adjustments[player] == 'normal': - write_int32(rom, 0x18020C, (10 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) + rom.write_int32(0x18020C, (10 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) else: - write_int32(rom, 0x18020C, int((5 + ERtimeincrease / 2) * 60 * 60)) # starting time (in frames, sint32) + rom.write_int32(0x18020C, int((5 + ERtimeincrease / 2) * 60 * 60)) # starting time (in frames, sint32) if world.clock_mode[player] == 'stopwatch': rom.write_bytes(0x180190, [0x02, 0x01, 0x00]) # set stopwatch mode - write_int32(rom, 0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) - write_int32(rom, 0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) - write_int32(rom, 0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, 0) # starting time (in frames, sint32) + rom.write_int32(0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) + rom.write_int32(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) + rom.write_int32(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) + rom.write_int32(0x18020C, 0) # starting time (in frames, sint32) if world.clock_mode[player] == 'countdown': rom.write_bytes(0x180190, [0x01, 0x01, 0x00]) # set countdown, with no reset available - write_int32(rom, 0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) - write_int32(rom, 0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) - write_int32(rom, 0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, (40 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) + rom.write_int32(0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) + rom.write_int32(0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) + rom.write_int32(0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) + rom.write_int32(0x18020C, (40 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) # set up goals for treasure hunt rom.write_bytes(0x180165, [0x0E, 0x28] if world.treasure_hunt_icon[player] == 'Triforce Piece' else [0x0D, 0x28]) @@ -1234,18 +1238,23 @@ def patch_rom(world, rom, player, team, enemized): return reveal_bytes.get(location.parent_region.dungeon.name, 0x0000) return 0x0000 - write_int16(rom, 0x18017A, get_reveal_bytes('Green Pendant') if world.mapshuffle[player] else 0x0000) # Sahasrahla reveal - write_int16(rom, 0x18017C, get_reveal_bytes('Crystal 5')|get_reveal_bytes('Crystal 6') if world.mapshuffle[player] else 0x0000) # Bomb Shop Reveal + rom.write_int16(0x18017A, + get_reveal_bytes('Green Pendant') if world.mapshuffle[player] else 0x0000) # Sahasrahla reveal + rom.write_int16(0x18017C, get_reveal_bytes('Crystal 5') | get_reveal_bytes('Crystal 6') if world.mapshuffle[ + player] else 0x0000) # Bomb Shop Reveal rom.write_byte(0x180172, 0x01 if world.keyshuffle[player] == "universal" else 0x00) # universal keys rom.write_byte(0x180175, 0x01 if world.retro[player] else 0x00) # rupee bow rom.write_byte(0x180176, 0x0A if world.retro[player] else 0x00) # wood arrow cost rom.write_byte(0x180178, 0x32 if world.retro[player] else 0x00) # silver arrow cost rom.write_byte(0x301FC, 0xDA if world.retro[player] else 0xE1) # rupees replace arrows under pots - rom.write_byte(0x30052, 0xDB if world.retro[player] else 0xE2) # replace arrows in fish prize from bottle merchant - rom.write_bytes(0xECB4E, [0xA9, 0x00, 0xEA, 0xEA] if world.retro[player] else [0xAF, 0x77, 0xF3, 0x7E]) # Thief steals rupees instead of arrows - rom.write_bytes(0xF0D96, [0xA9, 0x00, 0xEA, 0xEA] if world.retro[player] else [0xAF, 0x77, 0xF3, 0x7E]) # Pikit steals rupees instead of arrows - rom.write_bytes(0xEDA5, [0x35, 0x41] if world.retro[player] else [0x43, 0x44]) # Chest game gives rupees instead of arrows + rom.write_byte(0x30052, 0xDB if world.retro[player] else 0xE2) # replace arrows in fish prize from bottle merchant + rom.write_bytes(0xECB4E, [0xA9, 0x00, 0xEA, 0xEA] if world.retro[player] else [0xAF, 0x77, 0xF3, + 0x7E]) # Thief steals rupees instead of arrows + rom.write_bytes(0xF0D96, [0xA9, 0x00, 0xEA, 0xEA] if world.retro[player] else [0xAF, 0x77, 0xF3, + 0x7E]) # Pikit steals rupees instead of arrows + rom.write_bytes(0xEDA5, + [0x35, 0x41] if world.retro[player] else [0x43, 0x44]) # Chest game gives rupees instead of arrows digging_game_rng = local_random.randint(1, 30) # set rng for digging game rom.write_byte(0x180020, digging_game_rng) rom.write_byte(0xEFD95, digging_game_rng) @@ -1262,16 +1271,16 @@ def patch_rom(world, rom, player, team, enemized): rom.write_bytes(0x6D2FB, [0x00, 0x00, 0xf7, 0xff, 0x02, 0x0E]) rom.write_bytes(0x6D313, [0x00, 0x00, 0xe4, 0xff, 0x08, 0x0E]) - rom.write_byte(0x18004E, 0) # Escape Fill (nothing) - write_int16(rom, 0x180183, 300) # Escape fill rupee bow - rom.write_bytes(0x180185, [0,0,0]) # Uncle respawn refills (magic, bombs, arrows) + rom.write_byte(0x18004E, 0) # Escape Fill (nothing) + rom.write_int16(0x180183, 300) # Escape fill rupee bow + rom.write_bytes(0x180185, [0, 0, 0]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0,0,0]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0,0,0]) # Mantle respawn refills (magic, bombs, arrows) if world.mode[player] == 'standard': if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']: - rom.write_byte(0x18004E, 1) # Escape Fill (arrows) - write_int16(rom, 0x180183, 300) # Escape fill rupee bow - rom.write_bytes(0x180185, [0,0,70]) # Uncle respawn refills (magic, bombs, arrows) + rom.write_byte(0x18004E, 1) # Escape Fill (arrows) + rom.write_int16(0x180183, 300) # Escape fill rupee bow + rom.write_bytes(0x180185, [0, 0, 70]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0,0,10]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0,0,10]) # Mantle respawn refills (magic, bombs, arrows) elif uncle_location.item is not None and uncle_location.item.name in ['Bombs (10)']: @@ -1945,117 +1954,118 @@ def set_inverted_mode(world, player, rom): rom.write_byte(snes_to_pc(0x05AF79), 0xF0) rom.write_byte(snes_to_pc(0x0DB3C5), 0xC6) rom.write_byte(snes_to_pc(0x07A3F4), 0xF0) # duck - write_int16s(rom, snes_to_pc(0x02E849), [0x0043, 0x0056, 0x0058, 0x006C, 0x006F, 0x0070, 0x007B, 0x007F, 0x001B]) # dw flute - write_int16(rom, snes_to_pc(0x02E8D5), 0x07C8) - write_int16(rom, snes_to_pc(0x02E8F7), 0x01F8) + rom.write_int16s(snes_to_pc(0x02E849), + [0x0043, 0x0056, 0x0058, 0x006C, 0x006F, 0x0070, 0x007B, 0x007F, 0x001B]) # dw flute + rom.write_int16(snes_to_pc(0x02E8D5), 0x07C8) + rom.write_int16(snes_to_pc(0x02E8F7), 0x01F8) rom.write_byte(snes_to_pc(0x08D40C), 0xD0) # morph proof # the following bytes should only be written in vanilla # or they'll overwrite the randomizer's shuffles if world.shuffle[player] == 'vanilla': rom.write_byte(0xDBB73 + 0x23, 0x37) # switch AT and GT rom.write_byte(0xDBB73 + 0x36, 0x24) - write_int16(rom, 0x15AEE + 2*0x38, 0x00E0) - write_int16(rom, 0x15AEE + 2*0x25, 0x000C) + rom.write_int16(0x15AEE + 2 * 0x38, 0x00E0) + rom.write_int16(0x15AEE + 2 * 0x25, 0x000C) if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: rom.write_byte(0x15B8C, 0x6C) rom.write_byte(0xDBB73 + 0x00, 0x53) # switch bomb shop and links house rom.write_byte(0xDBB73 + 0x52, 0x01) rom.write_byte(0xDBB73 + 0x15, 0x06) # bumper and old man cave - write_int16(rom, 0x15AEE + 2*0x17, 0x00F0) + rom.write_int16(0x15AEE + 2 * 0x17, 0x00F0) rom.write_byte(0xDBB73 + 0x05, 0x16) - write_int16(rom, 0x15AEE + 2*0x07, 0x00FB) + rom.write_int16(0x15AEE + 2 * 0x07, 0x00FB) rom.write_byte(0xDBB73 + 0x2D, 0x17) - write_int16(rom, 0x15AEE + 2*0x2F, 0x00EB) + rom.write_int16(0x15AEE + 2 * 0x2F, 0x00EB) rom.write_byte(0xDBB73 + 0x06, 0x2E) - write_int16(rom, 0x15AEE + 2*0x08, 0x00E6) + rom.write_int16(0x15AEE + 2 * 0x08, 0x00E6) rom.write_byte(0xDBB73 + 0x16, 0x5E) rom.write_byte(0xDBB73 + 0x6F, 0x07) # DDM fairy to old man cave - write_int16(rom, 0x15AEE + 2*0x18, 0x00F1) + rom.write_int16(0x15AEE + 2 * 0x18, 0x00F1) rom.write_byte(0x15B8C + 0x18, 0x43) - write_int16(rom, 0x15BDB + 2 * 0x18, 0x1400) - write_int16(rom, 0x15C79 + 2 * 0x18, 0x0294) - write_int16(rom, 0x15D17 + 2 * 0x18, 0x0600) - write_int16(rom, 0x15DB5 + 2 * 0x18, 0x02E8) - write_int16(rom, 0x15E53 + 2 * 0x18, 0x0678) - write_int16(rom, 0x15EF1 + 2 * 0x18, 0x0303) - write_int16(rom, 0x15F8F + 2 * 0x18, 0x0685) + rom.write_int16(0x15BDB + 2 * 0x18, 0x1400) + rom.write_int16(0x15C79 + 2 * 0x18, 0x0294) + rom.write_int16(0x15D17 + 2 * 0x18, 0x0600) + rom.write_int16(0x15DB5 + 2 * 0x18, 0x02E8) + rom.write_int16(0x15E53 + 2 * 0x18, 0x0678) + rom.write_int16(0x15EF1 + 2 * 0x18, 0x0303) + rom.write_int16(0x15F8F + 2 * 0x18, 0x0685) rom.write_byte(0x1602D + 0x18, 0x0A) rom.write_byte(0x1607C + 0x18, 0xF6) - write_int16(rom, 0x160CB + 2 * 0x18, 0x0000) - write_int16(rom, 0x16169 + 2 * 0x18, 0x0000) - write_int16(rom, 0x15AEE + 2 * 0x3D, 0x0003) # pyramid exit and houlihan + rom.write_int16(0x160CB + 2 * 0x18, 0x0000) + rom.write_int16(0x16169 + 2 * 0x18, 0x0000) + rom.write_int16(0x15AEE + 2 * 0x3D, 0x0003) # pyramid exit and houlihan rom.write_byte(0x15B8C + 0x3D, 0x5B) - write_int16(rom, 0x15BDB + 2 * 0x3D, 0x0B0E) - write_int16(rom, 0x15C79 + 2 * 0x3D, 0x075A) - write_int16(rom, 0x15D17 + 2 * 0x3D, 0x0674) - write_int16(rom, 0x15DB5 + 2 * 0x3D, 0x07A8) - write_int16(rom, 0x15E53 + 2 * 0x3D, 0x06E8) - write_int16(rom, 0x15EF1 + 2 * 0x3D, 0x07C7) - write_int16(rom, 0x15F8F + 2 * 0x3D, 0x06F3) + rom.write_int16(0x15BDB + 2 * 0x3D, 0x0B0E) + rom.write_int16(0x15C79 + 2 * 0x3D, 0x075A) + rom.write_int16(0x15D17 + 2 * 0x3D, 0x0674) + rom.write_int16(0x15DB5 + 2 * 0x3D, 0x07A8) + rom.write_int16(0x15E53 + 2 * 0x3D, 0x06E8) + rom.write_int16(0x15EF1 + 2 * 0x3D, 0x07C7) + rom.write_int16(0x15F8F + 2 * 0x3D, 0x06F3) rom.write_byte(0x1602D + 0x3D, 0x06) rom.write_byte(0x1607C + 0x3D, 0xFA) - write_int16(rom, 0x160CB + 2 * 0x3D, 0x0000) - write_int16(rom, 0x16169 + 2 * 0x3D, 0x0000) - write_int16(rom, snes_to_pc(0x02D8D4), 0x112) # change sactuary spawn point to dark sanc + rom.write_int16(0x160CB + 2 * 0x3D, 0x0000) + rom.write_int16(0x16169 + 2 * 0x3D, 0x0000) + rom.write_int16(snes_to_pc(0x02D8D4), 0x112) # change sactuary spawn point to dark sanc rom.write_bytes(snes_to_pc(0x02D8E8), [0x22, 0x22, 0x22, 0x23, 0x04, 0x04, 0x04, 0x05]) - write_int16(rom, snes_to_pc(0x02D91A), 0x0400) - write_int16(rom, snes_to_pc(0x02D928), 0x222E) - write_int16(rom, snes_to_pc(0x02D936), 0x229A) - write_int16(rom, snes_to_pc(0x02D944), 0x0480) - write_int16(rom, snes_to_pc(0x02D952), 0x00A5) - write_int16(rom, snes_to_pc(0x02D960), 0x007F) + rom.write_int16(snes_to_pc(0x02D91A), 0x0400) + rom.write_int16(snes_to_pc(0x02D928), 0x222E) + rom.write_int16(snes_to_pc(0x02D936), 0x229A) + rom.write_int16(snes_to_pc(0x02D944), 0x0480) + rom.write_int16(snes_to_pc(0x02D952), 0x00A5) + rom.write_int16(snes_to_pc(0x02D960), 0x007F) rom.write_byte(snes_to_pc(0x02D96D), 0x14) rom.write_byte(snes_to_pc(0x02D974), 0x00) rom.write_byte(snes_to_pc(0x02D97B), 0xFF) rom.write_byte(snes_to_pc(0x02D982), 0x00) rom.write_byte(snes_to_pc(0x02D989), 0x02) rom.write_byte(snes_to_pc(0x02D990), 0x00) - write_int16(rom, snes_to_pc(0x02D998), 0x0000) - write_int16(rom, snes_to_pc(0x02D9A6), 0x005A) + rom.write_int16(snes_to_pc(0x02D998), 0x0000) + rom.write_int16(snes_to_pc(0x02D9A6), 0x005A) rom.write_byte(snes_to_pc(0x02D9B3), 0x12) # keep the old man spawn point at old man house unless shuffle is vanilla if world.shuffle[player] in ['vanilla', 'dungeonsfull', 'dungeonssimple']: rom.write_bytes(snes_to_pc(0x308350), [0x00, 0x00, 0x01]) - write_int16(rom, snes_to_pc(0x02D8DE), 0x00F1) + rom.write_int16(snes_to_pc(0x02D8DE), 0x00F1) rom.write_bytes(snes_to_pc(0x02D910), [0x1F, 0x1E, 0x1F, 0x1F, 0x03, 0x02, 0x03, 0x03]) - write_int16(rom, snes_to_pc(0x02D924), 0x0300) - write_int16(rom, snes_to_pc(0x02D932), 0x1F10) - write_int16(rom, snes_to_pc(0x02D940), 0x1FC0) - write_int16(rom, snes_to_pc(0x02D94E), 0x0378) - write_int16(rom, snes_to_pc(0x02D95C), 0x0187) - write_int16(rom, snes_to_pc(0x02D96A), 0x017F) + rom.write_int16(snes_to_pc(0x02D924), 0x0300) + rom.write_int16(snes_to_pc(0x02D932), 0x1F10) + rom.write_int16(snes_to_pc(0x02D940), 0x1FC0) + rom.write_int16(snes_to_pc(0x02D94E), 0x0378) + rom.write_int16(snes_to_pc(0x02D95C), 0x0187) + rom.write_int16(snes_to_pc(0x02D96A), 0x017F) rom.write_byte(snes_to_pc(0x02D972), 0x06) rom.write_byte(snes_to_pc(0x02D979), 0x00) rom.write_byte(snes_to_pc(0x02D980), 0xFF) rom.write_byte(snes_to_pc(0x02D987), 0x00) rom.write_byte(snes_to_pc(0x02D98E), 0x22) rom.write_byte(snes_to_pc(0x02D995), 0x12) - write_int16(rom, snes_to_pc(0x02D9A2), 0x0000) - write_int16(rom, snes_to_pc(0x02D9B0), 0x0007) + rom.write_int16(snes_to_pc(0x02D9A2), 0x0000) + rom.write_int16(snes_to_pc(0x02D9B0), 0x0007) rom.write_byte(snes_to_pc(0x02D9B8), 0x12) rom.write_bytes(0x180247, [0x00, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00]) - write_int16(rom, 0x15AEE + 2 * 0x06, 0x0020) # post aga hyrule castle spawn + rom.write_int16(0x15AEE + 2 * 0x06, 0x0020) # post aga hyrule castle spawn rom.write_byte(0x15B8C + 0x06, 0x1B) - write_int16(rom, 0x15BDB + 2 * 0x06, 0x00AE) - write_int16(rom, 0x15C79 + 2 * 0x06, 0x0610) - write_int16(rom, 0x15D17 + 2 * 0x06, 0x077E) - write_int16(rom, 0x15DB5 + 2 * 0x06, 0x0672) - write_int16(rom, 0x15E53 + 2 * 0x06, 0x07F8) - write_int16(rom, 0x15EF1 + 2 * 0x06, 0x067D) - write_int16(rom, 0x15F8F + 2 * 0x06, 0x0803) + rom.write_int16(0x15BDB + 2 * 0x06, 0x00AE) + rom.write_int16(0x15C79 + 2 * 0x06, 0x0610) + rom.write_int16(0x15D17 + 2 * 0x06, 0x077E) + rom.write_int16(0x15DB5 + 2 * 0x06, 0x0672) + rom.write_int16(0x15E53 + 2 * 0x06, 0x07F8) + rom.write_int16(0x15EF1 + 2 * 0x06, 0x067D) + rom.write_int16(0x15F8F + 2 * 0x06, 0x0803) rom.write_byte(0x1602D + 0x06, 0x00) rom.write_byte(0x1607C + 0x06, 0xF2) - write_int16(rom, 0x160CB + 2 * 0x06, 0x0000) - write_int16(rom, 0x16169 + 2 * 0x06, 0x0000) - write_int16(rom, snes_to_pc(0x02E87B), 0x00AE) # move flute splot 9 - write_int16(rom, snes_to_pc(0x02E89D), 0x0610) - write_int16(rom, snes_to_pc(0x02E8BF), 0x077E) - write_int16(rom, snes_to_pc(0x02E8E1), 0x0672) - write_int16(rom, snes_to_pc(0x02E903), 0x07F8) - write_int16(rom, snes_to_pc(0x02E925), 0x067D) - write_int16(rom, snes_to_pc(0x02E947), 0x0803) - write_int16(rom, snes_to_pc(0x02E969), 0x0000) - write_int16(rom, snes_to_pc(0x02E98B), 0xFFF2) + rom.write_int16(0x160CB + 2 * 0x06, 0x0000) + rom.write_int16(0x16169 + 2 * 0x06, 0x0000) + rom.write_int16(snes_to_pc(0x02E87B), 0x00AE) # move flute splot 9 + rom.write_int16(snes_to_pc(0x02E89D), 0x0610) + rom.write_int16(snes_to_pc(0x02E8BF), 0x077E) + rom.write_int16(snes_to_pc(0x02E8E1), 0x0672) + rom.write_int16(snes_to_pc(0x02E903), 0x07F8) + rom.write_int16(snes_to_pc(0x02E925), 0x067D) + rom.write_int16(snes_to_pc(0x02E947), 0x0803) + rom.write_int16(snes_to_pc(0x02E969), 0x0000) + rom.write_int16(snes_to_pc(0x02E98B), 0xFFF2) rom.write_byte(snes_to_pc(0x1AF696), 0xF0) # bat sprite retreat rom.write_byte(snes_to_pc(0x1AF6B2), 0x33) rom.write_bytes(snes_to_pc(0x1AF730), [0x6A, 0x9E, 0x0C, 0x00, 0x7A, 0x9E, 0x0C, @@ -2063,46 +2073,46 @@ def set_inverted_mode(world, player, rom): 0x0C, 0x00, 0x7A, 0xAE, 0x0C, 0x00, 0x8A, 0xAE, 0x0C, 0x00, 0x67, 0x97, 0x0C, 0x00, 0x8D, 0x97, 0x0C, 0x00]) - write_int16s(rom, snes_to_pc(0x0FF1C8), [0x190F, 0x190F, 0x190F, 0x194C, 0x190F, - 0x194B, 0x190F, 0x195C, 0x594B, 0x194C, - 0x19EE, 0x19EE, 0x194B, 0x19EE, 0x19EE, - 0x19EE, 0x594B, 0x190F, 0x595C, 0x190F, - 0x190F, 0x195B, 0x190F, 0x190F, 0x19EE, - 0x19EE, 0x195C, 0x19EE, 0x19EE, 0x19EE, - 0x19EE, 0x595C, 0x595B, 0x190F, 0x190F, - 0x190F]) - write_int16s(rom, snes_to_pc(0x0FA480), [0x190F, 0x196B, 0x9D04, 0x9D04, 0x196B, - 0x190F, 0x9D04, 0x9D04]) - write_int16s(rom, snes_to_pc(0x1bb810), [0x00BE, 0x00C0, 0x013E]) - write_int16s(rom, snes_to_pc(0x1bb836), [0x001B, 0x001B, 0x001B]) - write_int16(rom, snes_to_pc(0x308300), 0x0140) # new pyramid hole entrance - write_int16(rom, snes_to_pc(0x308320), 0x001B) + rom.write_int16s(snes_to_pc(0x0FF1C8), [0x190F, 0x190F, 0x190F, 0x194C, 0x190F, + 0x194B, 0x190F, 0x195C, 0x594B, 0x194C, + 0x19EE, 0x19EE, 0x194B, 0x19EE, 0x19EE, + 0x19EE, 0x594B, 0x190F, 0x595C, 0x190F, + 0x190F, 0x195B, 0x190F, 0x190F, 0x19EE, + 0x19EE, 0x195C, 0x19EE, 0x19EE, 0x19EE, + 0x19EE, 0x595C, 0x595B, 0x190F, 0x190F, + 0x190F]) + rom.write_int16s(snes_to_pc(0x0FA480), [0x190F, 0x196B, 0x9D04, 0x9D04, 0x196B, + 0x190F, 0x9D04, 0x9D04]) + rom.write_int16s(snes_to_pc(0x1bb810), [0x00BE, 0x00C0, 0x013E]) + rom.write_int16s(snes_to_pc(0x1bb836), [0x001B, 0x001B, 0x001B]) + rom.write_int16(snes_to_pc(0x308300), 0x0140) # new pyramid hole entrance + rom.write_int16(snes_to_pc(0x308320), 0x001B) if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: rom.write_byte(snes_to_pc(0x308340), 0x7B) - write_int16(rom, snes_to_pc(0x1af504), 0x148B) - write_int16(rom, snes_to_pc(0x1af50c), 0x149B) - write_int16(rom, snes_to_pc(0x1af514), 0x14A4) - write_int16(rom, snes_to_pc(0x1af51c), 0x1489) - write_int16(rom, snes_to_pc(0x1af524), 0x14AC) - write_int16(rom, snes_to_pc(0x1af52c), 0x54AC) - write_int16(rom, snes_to_pc(0x1af534), 0x148C) - write_int16(rom, snes_to_pc(0x1af53c), 0x548C) - write_int16(rom, snes_to_pc(0x1af544), 0x1484) - write_int16(rom, snes_to_pc(0x1af54c), 0x5484) - write_int16(rom, snes_to_pc(0x1af554), 0x14A2) - write_int16(rom, snes_to_pc(0x1af55c), 0x54A2) - write_int16(rom, snes_to_pc(0x1af564), 0x14A0) - write_int16(rom, snes_to_pc(0x1af56c), 0x54A0) - write_int16(rom, snes_to_pc(0x1af574), 0x148E) - write_int16(rom, snes_to_pc(0x1af57c), 0x548E) - write_int16(rom, snes_to_pc(0x1af584), 0x14AE) - write_int16(rom, snes_to_pc(0x1af58c), 0x54AE) + rom.write_int16(snes_to_pc(0x1af504), 0x148B) + rom.write_int16(snes_to_pc(0x1af50c), 0x149B) + rom.write_int16(snes_to_pc(0x1af514), 0x14A4) + rom.write_int16(snes_to_pc(0x1af51c), 0x1489) + rom.write_int16(snes_to_pc(0x1af524), 0x14AC) + rom.write_int16(snes_to_pc(0x1af52c), 0x54AC) + rom.write_int16(snes_to_pc(0x1af534), 0x148C) + rom.write_int16(snes_to_pc(0x1af53c), 0x548C) + rom.write_int16(snes_to_pc(0x1af544), 0x1484) + rom.write_int16(snes_to_pc(0x1af54c), 0x5484) + rom.write_int16(snes_to_pc(0x1af554), 0x14A2) + rom.write_int16(snes_to_pc(0x1af55c), 0x54A2) + rom.write_int16(snes_to_pc(0x1af564), 0x14A0) + rom.write_int16(snes_to_pc(0x1af56c), 0x54A0) + rom.write_int16(snes_to_pc(0x1af574), 0x148E) + rom.write_int16(snes_to_pc(0x1af57c), 0x548E) + rom.write_int16(snes_to_pc(0x1af584), 0x14AE) + rom.write_int16(snes_to_pc(0x1af58c), 0x54AE) rom.write_byte(snes_to_pc(0x00DB9D), 0x1A) # castle hole graphics rom.write_byte(snes_to_pc(0x00DC09), 0x1A) rom.write_byte(snes_to_pc(0x00D009), 0x31) rom.write_byte(snes_to_pc(0x00D0e8), 0xE0) rom.write_byte(snes_to_pc(0x00D1c7), 0x00) - write_int16(rom, snes_to_pc(0x1BE8DA), 0x39AD) + rom.write_int16(snes_to_pc(0x1BE8DA), 0x39AD) rom.write_byte(0xF6E58, 0x80) # no whirlpool under castle gate rom.write_bytes(0x0086E, [0x5C, 0x00, 0xA0, 0xA1]) # TR tail rom.write_bytes(snes_to_pc(0x1BC67A), [0x2E, 0x0B, 0x82]) # add warps under rocks @@ -2112,25 +2122,25 @@ def set_inverted_mode(world, player, rom): rom.write_bytes(snes_to_pc(0x1BC3DF), [0xD8, 0xD1]) rom.write_bytes(snes_to_pc(0x1BD1D8), [0xA8, 0x02, 0x82, 0xFF, 0xFF]) rom.write_bytes(snes_to_pc(0x1BC85A), [0x50, 0x0F, 0x82]) - write_int16(rom, 0xDB96F + 2 * 0x35, 0x001B) # move pyramid exit door - write_int16(rom, 0xDBA71 + 2 * 0x35, 0x06A4) + rom.write_int16(0xDB96F + 2 * 0x35, 0x001B) # move pyramid exit door + rom.write_int16(0xDBA71 + 2 * 0x35, 0x06A4) if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: rom.write_byte(0xDBB73 + 0x35, 0x36) rom.write_byte(snes_to_pc(0x09D436), 0xF3) # remove castle gate warp if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: - write_int16(rom, 0x15AEE + 2 * 0x37, 0x0010) # pyramid exit to new hc area + rom.write_int16(0x15AEE + 2 * 0x37, 0x0010) # pyramid exit to new hc area rom.write_byte(0x15B8C + 0x37, 0x1B) - write_int16(rom, 0x15BDB + 2 * 0x37, 0x0418) - write_int16(rom, 0x15C79 + 2 * 0x37, 0x0679) - write_int16(rom, 0x15D17 + 2 * 0x37, 0x06B4) - write_int16(rom, 0x15DB5 + 2 * 0x37, 0x06C6) - write_int16(rom, 0x15E53 + 2 * 0x37, 0x0738) - write_int16(rom, 0x15EF1 + 2 * 0x37, 0x06E6) - write_int16(rom, 0x15F8F + 2 * 0x37, 0x0733) + rom.write_int16(0x15BDB + 2 * 0x37, 0x0418) + rom.write_int16(0x15C79 + 2 * 0x37, 0x0679) + rom.write_int16(0x15D17 + 2 * 0x37, 0x06B4) + rom.write_int16(0x15DB5 + 2 * 0x37, 0x06C6) + rom.write_int16(0x15E53 + 2 * 0x37, 0x0738) + rom.write_int16(0x15EF1 + 2 * 0x37, 0x06E6) + rom.write_int16(0x15F8F + 2 * 0x37, 0x0733) rom.write_byte(0x1602D + 0x37, 0x07) rom.write_byte(0x1607C + 0x37, 0xF9) - write_int16(rom, 0x160CB + 2 * 0x37, 0x0000) - write_int16(rom, 0x16169 + 2 * 0x37, 0x0000) + rom.write_int16(0x160CB + 2 * 0x37, 0x0000) + rom.write_int16(0x16169 + 2 * 0x37, 0x0000) rom.write_bytes(snes_to_pc(0x1BC387), [0xDD, 0xD1]) rom.write_bytes(snes_to_pc(0x1BD1DD), [0xA4, 0x06, 0x82, 0x9E, 0x06, 0x82, 0xFF, 0xFF]) rom.write_byte(0x180089, 0x01) # open TR after exit @@ -2146,9 +2156,9 @@ def patch_shuffled_dark_sanc(world, rom, player): rom.write_byte(0x180241, 0x01) rom.write_byte(0x180248, door_index + 1) - write_int16(rom, 0x180250, room_id) + rom.write_int16(0x180250, room_id) rom.write_byte(0x180252, ow_area) - write_int16s(rom, 0x180253, [vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x]) + rom.write_int16s(0x180253, [vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x]) rom.write_bytes(0x180262, [unknown_1, unknown_2, 0x00]) InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main',