Files
dockipelago/worlds/tloz_ooa/patching/ProcedurePatch.py
Jonathan Tinney 7971961166
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

107 lines
4.1 KiB
Python

import hashlib
import os
import pkgutil
import yaml
import Utils
from worlds.Files import APProcedurePatch, APTokenMixin, APPatchExtension
from .Functions import *
from .Constants import *
from .RomData import RomData
from .z80asm.Assembler import Z80Assembler, Z80Block
from tkinter.filedialog import askopenfilename
ROM_HASH = "c4639cc61c049e5a085526bb6cac03bb"
class OoAPatchExtensions(APPatchExtension):
game = "The Legend of Zelda - Oracle of Ages"
@staticmethod
def apply_patches(caller: APProcedurePatch, rom: bytes, patch_file: str) -> bytes:
rom_data = RomData(rom)
patch_data = yaml.safe_load(caller.get_file(patch_file).decode("utf-8"))
if not (patch_data["version"] in RETRO_COMPAT_VERSION):
raise Exception(f"Invalid version: this seed was generated on v{patch_data['version']}, "
f"and is not compatible with current : v{VERSION}")
#if patch_data["options"]["enforce_potion_in_shop"]:
# patch_data["locations"]["Horon Village: Shop #3"] = "Potion"
assembler = Z80Assembler()
# Define static values & data blocks
for i, offset in enumerate(EOB_ADDR):
assembler.end_of_banks[i] = offset
for key, value in DEFINES.items():
assembler.define(key, value)
for symbolic_name, price in patch_data["shop_prices"].items():
assembler.define_byte(f"shopPrices.{symbolic_name}", RUPEE_VALUES[price])
define_location_constants(assembler, patch_data)
define_option_constants(assembler, patch_data)
define_text_constants(assembler, patch_data)
define_dungeon_items_text_constants(assembler, patch_data)
# Define dynamic data blocks
define_compass_rooms_table(assembler, patch_data)
define_collect_properties_table(assembler, patch_data)
set_file_select_text(assembler, caller.player_name)
# Parse assembler files, compile them and write the result in the ROM
print(f"Compiling ASM files...")
for file_path in get_asm_files(patch_data):
data_loaded = yaml.safe_load(pkgutil.get_data(__name__, file_path))
for metalabel, contents in data_loaded.items():
assembler.add_block(Z80Block(metalabel, contents))
assembler.compile_all()
for block in assembler.blocks:
rom_data.write_bytes(block.addr.full_address(), block.byte_array)
alter_treasures(rom_data)
write_chest_contents(rom_data, patch_data)
write_seed_tree_content(rom_data, patch_data)
set_dungeon_warps(rom_data, patch_data)
#apply_miscellaneous_options(rom_data, patch_data)
set_heart_beep_interval_from_settings(rom_data)
set_character_sprite_from_settings(rom_data)
apply_misc_option(rom_data, patch_data)
inject_slot_name(rom_data, caller.player_name)
rom_data.update_checksum(0x14e)
return rom_data.output()
class OoAProcedurePatch(APProcedurePatch, APTokenMixin):
hash = [ROM_HASH]
patch_file_ending: str = ".apooa"
result_file_ending: str = ".gbc"
game = "The Legend of Zelda - Oracle of Ages"
procedure = [
("apply_patches", ["patch.dat"])
]
@classmethod
def get_source_data(cls) -> bytes:
base_rom_bytes = getattr(cls, "base_rom_bytes", None)
if not base_rom_bytes:
file_name = get_settings().tloz_ooa_options["rom_file"]
if not os.path.exists(file_name):
file_name = Utils.user_path(file_name)
if not os.path.exists(file_name):
file_name = askopenfilename()
base_rom_bytes = bytes(open(file_name, "rb").read())
basemd5 = hashlib.md5()
basemd5.update(base_rom_bytes)
if ROM_HASH != basemd5.hexdigest():
raise Exception("Supplied ROM does not match known MD5 for Oracle of Seasons US version."
"Get the correct game and version, then dump it.")
setattr(cls, "base_rom_bytes", base_rom_bytes)
return base_rom_bytes