diff --git a/CLI.py b/CLI.py index 62163b28..6d5a0292 100644 --- a/CLI.py +++ b/CLI.py @@ -179,7 +179,7 @@ def parse_cli(argv, no_defaults=False): 'decoupledoors', 'door_type_mode', 'bonk_drops', 'trap_door_mode', 'key_logic_algorithm', 'door_self_loops', 'any_enemy_logic', 'aga_randomness', - 'money_balance']: + 'money_balance', 'patches']: value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) if player == 1: setattr(ret, name, {1: value}) diff --git a/Main.py b/Main.py index b1aaa1c4..e0f0f73d 100644 --- a/Main.py +++ b/Main.py @@ -67,6 +67,7 @@ from Rom import ( JsonRom, LocalRom, apply_rom_settings, + apply_rom_patches, get_hash_string, patch_race_rom, patch_rom, @@ -364,6 +365,7 @@ def main(args, seed=None, fish=None): rom_names.append((player, team, list(rom.name))) world.spoiler.hashes[(player, team)] = get_hash_string(rom.hash) + apply_rom_patches(rom, map(lambda arg: arg.strip(), args.patches[player].split(","))) apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player], args.fastmenu[player], args.disablemusic[player], args.sprite[player], args.triforce_gfx[player], args.ow_palettes[player], args.uw_palettes[player], args.reduce_flashing[player], diff --git a/Rom.py b/Rom.py index 67a14a46..8b3873b2 100644 --- a/Rom.py +++ b/Rom.py @@ -2088,6 +2088,49 @@ def hud_format_text(text): output += b'\x7f\x00' return output[:32] +def read_bytes(f, count): + values = f.read(count) + if len(values) < count: + raise EOFError + return values + +def apply_rom_patches(rom, patches): + for patch in patches: + if not os.path.exists(f"patches/{patch}.ips"): + logging.getLogger('').warning("Patch %s not found -- skipping", patch) + continue + + with open(f"patches/{patch}.ips", "rb") as f: + byte_changes = [] + try: + header = read_bytes(f, 5) + if header != b"PATCH": + logging.getLogger('').warning("Patch %s invalid -- skipping", patch) + continue + + while True: + address = read_bytes(f, 3) + if address == b"EOF": + break + + address = int.from_bytes(address, byteorder="big") + length = int.from_bytes(read_bytes(f, 2), byteorder="big") + + if length > 0: + byte_changes.append((address, list(f.read(length)))) + else: + length = int.from_bytes(read_bytes(f, 2), byteorder="big") + value = read_bytes(f, 1) + byte_changes.append((address, length * list(value))) + + for address, values in byte_changes: + rom.write_bytes(address, values) + + logging.getLogger("").info("Patch %s applied successfully", patch) + + except EOFError: + logging.getLogger('').warning("Patch %s invalid -- skipping", patch) + continue def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, triforce_gfx, ow_palettes, uw_palettes, reduce_flashing, shuffle_sfx, diff --git a/patches/no_dungeon_item_popups.ips b/patches/no_dungeon_item_popups.ips new file mode 100644 index 00000000..b9865236 Binary files /dev/null and b/patches/no_dungeon_item_popups.ips differ diff --git a/patches/pod_key_swap.ips b/patches/pod_key_swap.ips new file mode 100644 index 00000000..ee72cd70 Binary files /dev/null and b/patches/pod_key_swap.ips differ diff --git a/patches/pod_key_swap.ips.bak b/patches/pod_key_swap.ips.bak new file mode 100644 index 00000000..abe2e3ad Binary files /dev/null and b/patches/pod_key_swap.ips.bak differ diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index d62965e6..a728cb10 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -754,6 +754,10 @@ "type": "bool" }, "money_balance": {}, + "patches": { + "type": "str", + "help": "suppress" + }, "settingsonload": { "choices": [ "default",