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
This commit is contained in:
parent
6d3a7487e0
commit
45268b18f3
|
@ -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
|
||||
|
||||
|
|
71
Main.py
71
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
|
||||
|
||||
|
||||
|
|
436
Rom.py
436
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',
|
||||
|
|
Loading…
Reference in New Issue