From e4d1d7b7eee93644840e67ce5962ab12fdce6bbe Mon Sep 17 00:00:00 2001 From: biosp4rk <37962487+biosp4rk@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:19:39 -0700 Subject: [PATCH 1/2] Add reserved constants for ZM --- src/mars_patcher/constants/game_data.py | 130 +++--------------- .../mf/constants/reserved_space.py | 2 +- src/mars_patcher/mf/item_patcher.py | 18 +-- src/mars_patcher/mf/misc_patches.py | 6 +- src/mars_patcher/mf/navigation_text.py | 4 +- src/mars_patcher/mf/room_names.py | 4 +- src/mars_patcher/mf/starting.py | 4 +- src/mars_patcher/rom.py | 16 ++- src/mars_patcher/titlescreen_text.py | 6 +- src/mars_patcher/zm/constants/game_data.py | 82 +++++++++++ .../zm/constants/reserved_space.py | 83 +++++++++++ 11 files changed, 217 insertions(+), 138 deletions(-) create mode 100644 src/mars_patcher/zm/constants/game_data.py create mode 100644 src/mars_patcher/zm/constants/reserved_space.py diff --git a/src/mars_patcher/constants/game_data.py b/src/mars_patcher/constants/game_data.py index ce2ceb6..7926889 100644 --- a/src/mars_patcher/constants/game_data.py +++ b/src/mars_patcher/constants/game_data.py @@ -1,4 +1,5 @@ from mars_patcher.rom import Game, Region, Rom +from mars_patcher.zm.constants.reserved_space import ReservedConstantsZM def area_room_entry_ptrs(rom: Rom) -> int: @@ -13,14 +14,7 @@ def area_room_entry_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77D5C0 elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x75FAC4 - elif rom.region == Region.E: - return 0x773964 - elif rom.region == Region.J: - return 0x75FBD4 - elif rom.region == Region.C: - return 0x79ECBC + return rom.read_ptr(ReservedConstantsZM.ROOM_AREA_ENTRIES_PTR) raise ValueError("Rom has unknown game loaded.") @@ -37,14 +31,7 @@ def tileset_entries(rom: Rom) -> int: elif rom.region == Region.C: return 0x3C1E94 elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x33DFDC - elif rom.region == Region.E: - return 0x33EC68 - elif rom.region == Region.J: - return 0x33E038 - elif rom.region == Region.C: - return 0x3577C8 + return rom.read_ptr(ReservedConstantsZM.TILESET_ENTRIES_PTR) raise ValueError("Rom has unknown game loaded.") @@ -70,14 +57,7 @@ def area_doors_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77D598 elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x75FAA8 - elif rom.region == Region.E: - return 0x773948 - elif rom.region == Region.J: - return 0x75FBB8 - elif rom.region == Region.C: - return 0x79ECA0 + return rom.read_ptr(ReservedConstantsZM.AREA_DOORS_PTR) raise ValueError("Rom has unknown game loaded.") @@ -94,14 +74,7 @@ def area_connections(rom: Rom) -> int: elif rom.region == Region.C: return 0x3CB19C elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x360274 - elif rom.region == Region.E: - return 0x360F00 - elif rom.region == Region.J: - return 0x3602D0 - elif rom.region == Region.C: - return 0x379A60 + return rom.read_ptr(ReservedConstantsZM.AREA_CONNECTIONS_PTR) raise ValueError("Rom has unknown game loaded.") @@ -128,14 +101,7 @@ def anim_palette_entries(rom: Rom) -> int: elif rom.region == Region.C: return 0x3E5D7C elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x35FBFC - elif rom.region == Region.E: - return 0x360888 - elif rom.region == Region.J: - return 0x35FC58 - elif rom.region == Region.C: - return 0x3793E8 + return rom.read_ptr(ReservedConstantsZM.ANIM_PALETTE_ENTRIES_PTR) raise ValueError("Rom has unknown game loaded.") @@ -164,14 +130,7 @@ def sprite_graphics_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77C2DC elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x75EBF8 - elif rom.region == Region.E: - return 0x772A98 - elif rom.region == Region.J: - return 0x75ED08 - elif rom.region == Region.C: - return 0x79DDF0 + return rom.read_ptr(ReservedConstantsZM.SPRITE_GRAPHICS_PTR) raise ValueError(rom.game, rom.region) @@ -187,14 +146,7 @@ def sprite_palette_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77C5D8 elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x75EEF0 - elif rom.region == Region.E: - return 0x772D90 - elif rom.region == Region.J: - return 0x75F000 - elif rom.region == Region.C: - return 0x79E0E8 + return rom.read_ptr(ReservedConstantsZM.SPRITE_PALETTES_PTR) raise ValueError(rom.game, rom.region) @@ -219,14 +171,7 @@ def spriteset_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77CADC elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x75F31C - elif rom.region == Region.E: - return 0x7731BC - elif rom.region == Region.J: - return 0x75F42C - elif rom.region == Region.C: - return 0x79E514 + return rom.read_ptr(ReservedConstantsZM.SPRITESET_PTR) raise ValueError(rom.game, rom.region) @@ -251,14 +196,8 @@ def samus_palettes(rom: Rom) -> list[tuple[int, int]]: elif rom.region == Region.C: return [(0x2900C8, 0x5E), (0x290E48, 0x70), (0x56CC68, 3)] elif rom.game == Game.ZM: - if rom.region == Region.U: - return [(0x2376A8, 0xA3)] - elif rom.region == Region.E: - return [(0x238334, 0xA3)] - elif rom.region == Region.J: - return [(0x237704, 0xA3)] - elif rom.region == Region.C: - return [(0x250E94, 0xA3)] + addr = rom.read_ptr(ReservedConstantsZM.AREA_DOORS_PTR) + return [(addr, 0xA3)] raise ValueError(rom.game, rom.region) @@ -277,14 +216,8 @@ def helmet_cursor_palettes(rom: Rom) -> list[tuple[int, int]]: elif rom.region == Region.C: return [(0x6CE360, 1), (0x6CE400, 2), (0x6CA8F8, 1), (0x6CA938, 2)] elif rom.game == Game.ZM: - if rom.region == Region.U: - return [(0x454938, 1), (0x4549B8, 1)] - elif rom.region == Region.E: - return [(0x4603F8, 1), (0x460478, 1)] - elif rom.region == Region.J: - return [(0x454994, 1), (0x454A14, 1)] - elif rom.region == Region.C: - return [(0x4768FC, 1), (0x47697C, 1)] + addr = rom.read_ptr(ReservedConstantsZM.HELMET_CURSOR_PALETTES_PTR) + return [(addr, 1), (addr + 0x80, 1)] raise ValueError(rom.game, rom.region) @@ -300,14 +233,8 @@ def beam_palettes(rom: Rom) -> list[tuple[int, int]]: elif rom.region == Region.C: return [(0x592578, 6)] elif rom.game == Game.ZM: - if rom.region == Region.U: - return [(0x3270E8, 6)] - elif rom.region == Region.E: - return [(0x327D74, 6)] - elif rom.region == Region.J: - return [(0x327144, 6)] - elif rom.region == Region.C: - return [(0x3408D4, 6)] + addr = rom.read_ptr(ReservedConstantsZM.BEAM_PALETTES_PTR) + return [(addr, 6)] raise ValueError(rom.game, rom.region) @@ -323,14 +250,7 @@ def character_widths(rom: Rom) -> int: elif rom.region == Region.C: return 0x57D21C elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x40D7B0 - elif rom.region == Region.E: - return 0x40E5E4 - elif rom.region == Region.J: - return 0x40D80C - elif rom.region == Region.C: - return 0x42F34C + return rom.read_ptr(ReservedConstantsZM.CHARACTER_WIDTHS_PTR) raise ValueError(rom.game, rom.region) @@ -346,14 +266,7 @@ def sound_data_entries(rom: Rom) -> int: elif rom.region == Region.C: return 0xAB0E4 elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x8F2C0 - elif rom.region == Region.E: - return 0x8FF4C - elif rom.region == Region.J: - return 0x8F31C - elif rom.region == Region.C: - return 0xA8AAC + return rom.read_ptr(ReservedConstantsZM.SOUND_DATA_PTR) raise ValueError(rom.game, rom.region) @@ -378,14 +291,7 @@ def minimap_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77DB60 elif rom.game == Game.ZM: - if rom.region == Region.U: - return 0x7601EC - elif rom.region == Region.E: - return 0x77408C - elif rom.region == Region.J: - return 0x7602FC - elif rom.region == Region.C: - return 0x79F3EC + return rom.read_ptr(ReservedConstantsZM.MINIMAPS_PTR) raise ValueError(rom.game, rom.region) diff --git a/src/mars_patcher/mf/constants/reserved_space.py b/src/mars_patcher/mf/constants/reserved_space.py index c255e68..d1f7aa9 100644 --- a/src/mars_patcher/mf/constants/reserved_space.py +++ b/src/mars_patcher/mf/constants/reserved_space.py @@ -1,4 +1,4 @@ -class ReservedConstants: +class ReservedConstantsMF: """ These are constants that are in the patches 'Reserved Space'; things that are intended to be modified by this patcher. diff --git a/src/mars_patcher/mf/item_patcher.py b/src/mars_patcher/mf/item_patcher.py index 79d354a..ea6cf0e 100644 --- a/src/mars_patcher/mf/item_patcher.py +++ b/src/mars_patcher/mf/item_patcher.py @@ -1,5 +1,5 @@ from mars_patcher.mf.auto_generated_types import MarsschemamfTankincrements -from mars_patcher.mf.constants.reserved_space import ReservedConstants +from mars_patcher.mf.constants.reserved_space import ReservedConstantsMF from mars_patcher.mf.locations import ( ItemMessages, ItemMessagesKind, @@ -12,16 +12,16 @@ from mars_patcher.text import Language, MessageType, encode_text from mars_patcher.tileset import Tileset -MINOR_LOCS_TABLE_ADDR = ReservedConstants.MINOR_LOCS_TABLE_ADDR -MINOR_LOCS_ARRAY_ADDR = ReservedConstants.MINOR_LOCS_ARRAY_ADDR +MINOR_LOCS_TABLE_ADDR = ReservedConstantsMF.MINOR_LOCS_TABLE_ADDR +MINOR_LOCS_ARRAY_ADDR = ReservedConstantsMF.MINOR_LOCS_ARRAY_ADDR MINOR_LOC_SIZE = 0x10 -MAJOR_LOCS_POINTER_ADDR = ReservedConstants.MAJOR_LOCS_POINTER_ADDR +MAJOR_LOCS_POINTER_ADDR = ReservedConstantsMF.MAJOR_LOCS_POINTER_ADDR MAJOR_LOC_SIZE = 0x4 -TANK_INC_ADDR = ReservedConstants.TANK_INC_ADDR -REQUIRED_METROID_COUNT_ADDR = ReservedConstants.REQUIRED_METROID_COUNT_ADDR -TOTAL_METROID_COUNT_ADDR = ReservedConstants.TOTAL_METROID_COUNT_ADDR -MESSAGE_TABLE_LOOKUP_ADDR = ReservedConstants.MESSAGE_TABLE_LOOKUP_ADDR -FIRST_CUSTOM_MESSAGE_ID = ReservedConstants.FIRST_CUSTOM_MESSAGE_ID +TANK_INC_ADDR = ReservedConstantsMF.TANK_INC_ADDR +REQUIRED_METROID_COUNT_ADDR = ReservedConstantsMF.REQUIRED_METROID_COUNT_ADDR +TOTAL_METROID_COUNT_ADDR = ReservedConstantsMF.TOTAL_METROID_COUNT_ADDR +MESSAGE_TABLE_LOOKUP_ADDR = ReservedConstantsMF.MESSAGE_TABLE_LOOKUP_ADDR +FIRST_CUSTOM_MESSAGE_ID = ReservedConstantsMF.FIRST_CUSTOM_MESSAGE_ID AUTO_MESSAGE_ID = 0xFF TANK_CLIP = (0x62, 0x63, 0x68) diff --git a/src/mars_patcher/mf/misc_patches.py b/src/mars_patcher/mf/misc_patches.py index 2400d82..d50aa6f 100644 --- a/src/mars_patcher/mf/misc_patches.py +++ b/src/mars_patcher/mf/misc_patches.py @@ -1,5 +1,5 @@ import mars_patcher.constants.game_data as gd -from mars_patcher.mf.constants.reserved_space import ReservedConstants +from mars_patcher.mf.constants.reserved_space import ReservedConstantsMF from mars_patcher.mf.data import get_data_path from mars_patcher.patching import BpsDecoder, IpsDecoder from mars_patcher.rom import Rom @@ -70,7 +70,7 @@ def disable_sound_effects(rom: Rom) -> None: def change_missile_limit(rom: Rom, limit: int) -> None: - rom.write_8(rom.read_ptr(ReservedConstants.MISSILE_LIMIT_ADDR), limit) + rom.write_8(rom.read_ptr(ReservedConstantsMF.MISSILE_LIMIT_ADDR), limit) def apply_unexplored_map(rom: Rom) -> None: @@ -82,7 +82,7 @@ def apply_pbs_without_bombs(rom: Rom) -> None: def apply_reveal_hidden_tiles(rom: Rom) -> None: - rom.write_8(rom.read_ptr(ReservedConstants.REVEAL_HIDDEN_TILES_ADDR), 1) + rom.write_8(rom.read_ptr(ReservedConstantsMF.REVEAL_HIDDEN_TILES_ADDR), 1) def apply_reveal_unexplored_doors(rom: Rom) -> None: diff --git a/src/mars_patcher/mf/navigation_text.py b/src/mars_patcher/mf/navigation_text.py index e313fe3..fbad6f1 100644 --- a/src/mars_patcher/mf/navigation_text.py +++ b/src/mars_patcher/mf/navigation_text.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING from mars_patcher.mf.constants.game_data import navigation_text_ptrs -from mars_patcher.mf.constants.reserved_space import ReservedConstants +from mars_patcher.mf.constants.reserved_space import ReservedConstantsMF from mars_patcher.rom import Rom from mars_patcher.text import Language, MessageType, encode_text @@ -132,6 +132,6 @@ def apply_hint_security( default_lock_name = "OPEN" for location, offset in NavigationText.NAV_ROOM_ENUMS.items(): rom.write_8( - rom.read_ptr(ReservedConstants.HINT_SECURITY_LEVELS_ADDR) + offset.value, + rom.read_ptr(ReservedConstantsMF.HINT_SECURITY_LEVELS_ADDR) + offset.value, NavStationLockType[locks.get(location, default_lock_name)].value, ) diff --git a/src/mars_patcher/mf/room_names.py b/src/mars_patcher/mf/room_names.py index 441d75d..1d92cf9 100644 --- a/src/mars_patcher/mf/room_names.py +++ b/src/mars_patcher/mf/room_names.py @@ -1,9 +1,9 @@ from mars_patcher.mf.auto_generated_types import Areaid, MarsschemamfRoomnamesItem, Typeu8 -from mars_patcher.mf.constants.reserved_space import ReservedConstants +from mars_patcher.mf.constants.reserved_space import ReservedConstantsMF from mars_patcher.rom import Rom from mars_patcher.text import MessageType, encode_text -ROOM_NAMES_TABLE_ADDR = ReservedConstants.ROOM_NAMES_TABLE_ADDR +ROOM_NAMES_TABLE_ADDR = ReservedConstantsMF.ROOM_NAMES_TABLE_ADDR # Write Room Names to ROM diff --git a/src/mars_patcher/mf/starting.py b/src/mars_patcher/mf/starting.py index f0da771..17d025b 100644 --- a/src/mars_patcher/mf/starting.py +++ b/src/mars_patcher/mf/starting.py @@ -5,12 +5,12 @@ ) from mars_patcher.mf.constants.game_data import starting_equipment from mars_patcher.mf.constants.items import BEAM_FLAGS, MISSILE_BOMB_FLAGS, SUIT_MISC_FLAGS -from mars_patcher.mf.constants.reserved_space import ReservedConstants +from mars_patcher.mf.constants.reserved_space import ReservedConstantsMF from mars_patcher.rom import Rom from mars_patcher.room_entry import RoomEntry # Keep in sync with base patch -STARTING_LOC_ADDR = ReservedConstants.STARTING_LOCATION_ADDR +STARTING_LOC_ADDR = ReservedConstantsMF.STARTING_LOCATION_ADDR def set_starting_location(rom: Rom, data: MarsschemamfStartinglocation) -> None: diff --git a/src/mars_patcher/rom.py b/src/mars_patcher/rom.py index 220bc53..4de3a6f 100644 --- a/src/mars_patcher/rom.py +++ b/src/mars_patcher/rom.py @@ -1,7 +1,8 @@ from enum import Enum from os import PathLike -from mars_patcher.mf.constants.reserved_space import ReservedConstants +from mars_patcher.mf.constants.reserved_space import ReservedConstantsMF +from mars_patcher.zm.constants.reserved_space import ReservedConstantsZM BytesLike = bytes | bytearray @@ -107,9 +108,9 @@ def __init__(self, path: str | PathLike[str]): raise ValueError("Only compatible with the North American (U) version") # Set free space address if self.is_mf(): - self.free_space_addr = ReservedConstants.PATCHER_FREE_SPACE_ADDR + self.free_space_addr = ReservedConstantsMF.PATCHER_FREE_SPACE_ADDR elif self.is_zm(): - raise NotImplementedError() + self.free_space_addr = ReservedConstantsZM.PATCHER_FREE_SPACE_ADDR def is_mf(self) -> bool: """Returns true when the currently loaded game is Metroid Fusion.""" @@ -233,7 +234,14 @@ def reserve_free_space(self, size: int) -> int: self.free_space_addr += 4 - remain addr = self.free_space_addr self.free_space_addr += size - if self.free_space_addr > ReservedConstants.PATCHER_FREE_SPACE_END: + # Check if past end of reserved space + if self.is_mf(): + free_space_end = ReservedConstantsMF.PATCHER_FREE_SPACE_END + elif self.is_zm(): + free_space_end = ReservedConstantsZM.PATCHER_FREE_SPACE_END + else: + raise ValueError(self.game) + if self.free_space_addr > free_space_end: raise RuntimeError("Ran out of reserved free space") return addr diff --git a/src/mars_patcher/titlescreen_text.py b/src/mars_patcher/titlescreen_text.py index 41676e9..dfbfdc7 100644 --- a/src/mars_patcher/titlescreen_text.py +++ b/src/mars_patcher/titlescreen_text.py @@ -1,8 +1,8 @@ from mars_patcher.mf.auto_generated_types import MarsschemamfTitletextItem -from mars_patcher.mf.constants.reserved_space import ReservedConstants +from mars_patcher.mf.constants.reserved_space import ReservedConstantsMF from mars_patcher.rom import Rom -TITLE_TEXT_POINTER_ADDR = ReservedConstants.TITLESCREEN_TEXT_POINTERS_POINTER_ADDR +TITLE_TEXT_POINTER_ADDR = ReservedConstantsMF.TITLESCREEN_TEXT_POINTERS_POINTER_ADDR MAX_LENGTH = 30 MAX_LINES = 14 @@ -30,6 +30,6 @@ def write_title_text(rom: Rom, lines: list[MarsschemamfTitletextItem]) -> None: def write_title_text_line(rom: Rom, line: MarsschemamfTitletextItem) -> None: if len(line["Text"]) > 30: raise ValueError(f'String for title-screen text exceeds 30 characters.\n"{line["Text"]}"') - text_pointers = rom.read_ptr(ReservedConstants.TITLESCREEN_TEXT_POINTERS_POINTER_ADDR) + text_pointers = rom.read_ptr(ReservedConstantsMF.TITLESCREEN_TEXT_POINTERS_POINTER_ADDR) addr = rom.read_ptr(text_pointers + (line["LineNum"] * 4)) rom.write_bytes(addr, line["Text"].encode("ascii")) diff --git a/src/mars_patcher/zm/constants/game_data.py b/src/mars_patcher/zm/constants/game_data.py new file mode 100644 index 0000000..e540623 --- /dev/null +++ b/src/mars_patcher/zm/constants/game_data.py @@ -0,0 +1,82 @@ +from mars_patcher.rom import Rom +from mars_patcher.zm.constants.reserved_space import ReservedConstantsZM + + +def tileset_tilemap_sizes_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.TILESET_TILEMAP_SIZES_PTR) + + +def chozo_statue_targets_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.CHOZO_STATUE_TARGETS_PTR) + + +def intro_cutscene_data_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.INTRO_CUTSCENE_DATA_PTR) + + +def starting_info_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.STARTING_INFO_PTR) + + +def major_locations_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.MAJOR_LOCATIONS_PTR) + + +def minor_locations_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.MINOR_LOCATIONS_PTR) + + +def difficulty_options_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.DIFFICULTY_OPTIONS_PTR) + + +def metroid_sprite_stats_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.METROID_SPRITE_STATS_PTR) + + +def black_pirates_require_plasma_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.BLACK_PIRATES_REQUIRE_PLASMA_PTR) + + +def skip_door_transitions_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.SKIP_DOOR_TRANSITIONS_PTR) + + +def ball_launcher_without_bombs_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.BALL_LAUNCHER_WITHOUT_BOMBS_PTR) + + +def disable_midair_bomb_jump_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.DISABLE_MIDAIR_BOMB_JUMP_PTR) + + +def disable_walljump_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.DISABLE_WALLJUMP_PTR) + + +def remove_cutscenes_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.REMOVE_CUTSCENES_PTR) + + +def skip_suitless_sequence_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.SKIP_SUITLESS_SEQUENCE_PTR) + + +def energy_tank_increase_amount_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.ENERGY_TANK_INCREASE_AMOUNT_PTR) + + +def missile_tank_increase_amount_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.MISSILE_TANK_INCREASE_AMOUNT_PTR) + + +def super_missile_tank_increase_amount_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.SUPER_MISSILE_TANK_INCREASE_AMOUNT_PTR) + + +def power_bomb_tank_increase_amount_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.POWER_BOMB_TANK_INCREASE_AMOUNT_PTR) + + +def title_text_lines_addr(rom: Rom) -> int: + return rom.read_ptr(ReservedConstantsZM.TITLE_TEXT_LINES_PTR) diff --git a/src/mars_patcher/zm/constants/reserved_space.py b/src/mars_patcher/zm/constants/reserved_space.py new file mode 100644 index 0000000..90f917b --- /dev/null +++ b/src/mars_patcher/zm/constants/reserved_space.py @@ -0,0 +1,83 @@ +class ReservedConstantsZM: + """ + These are constants that are in the ROM's 'Reserved Space'; things that are intended to be + modified by this patcher. Most of these are pointers at a hard-coded address that point to + various pieces of data. + """ + + # Important addresses: + # 0x760D38 - End of data (U region) + # 0x7C0000 - Patcher data free space + # 0x7D0000 - Randomizer data pointers + # 0x7D8000 - NES Metroid data + + # These need to be kept in sync with the data pointers in the decomp, which can be found in + # src/data/randomizer_pointers.c + RANDO_POINTERS_ADDR = 0x7D0000 + + # Existing data + ROOM_AREA_ENTRIES_PTR = RANDO_POINTERS_ADDR + 0x00 + """Pointer to the list of pointers to the room entries for each area.""" + TILESET_ENTRIES_PTR = RANDO_POINTERS_ADDR + 0x04 + """Pointer to the list of tileset entries.""" + TILESET_TILEMAP_SIZES_PTR = RANDO_POINTERS_ADDR + 0x08 + """Pointer to an array containing the size of each tileset's tilemap.""" + MINIMAPS_PTR = RANDO_POINTERS_ADDR + 0x0C + """Pointer to a list of pointers to the minimap data for each area.""" + AREA_DOORS_PTR = RANDO_POINTERS_ADDR + 0x10 + """Pointer to the list of pointers to the door entries for each area.""" + AREA_CONNECTIONS_PTR = RANDO_POINTERS_ADDR + 0x14 + """Pointer to the list of area connections.""" + ANIM_PALETTE_ENTRIES_PTR = RANDO_POINTERS_ADDR + 0x18 + """Pointer to the list of animated palette entries.""" + SPRITE_GRAPHICS_PTR = RANDO_POINTERS_ADDR + 0x1C + """Pointer to the list of pointers to the graphics for each sprite.""" + SPRITE_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x20 + """Pointer to the list of pointers to the palette for each sprite.""" + SPRITESET_PTR = RANDO_POINTERS_ADDR + 0x24 + """Pointer to the list of pointers to spriteset entries.""" + SAMUS_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x28 + """Pointer to the start of all of Samus's palettes.""" + HELMET_CURSOR_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x2C + """Pointer to the palette used for the helmet cursor in menus.""" + BEAM_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x30 + """Pointer to the start of the beam palettes.""" + CHARACTER_WIDTHS_PTR = RANDO_POINTERS_ADDR + 0x34 + """Pointer to the character widths table.""" + SOUND_DATA_PTR = RANDO_POINTERS_ADDR + 0x38 + """Pointer to the list of sound data entries.""" + CHOZO_STATUE_TARGETS_PTR = RANDO_POINTERS_ADDR + 0x3C + """Pointer to the list of Chozo statue targets.""" + + # Rando data + INTRO_CUTSCENE_DATA_PTR = RANDO_POINTERS_ADDR + 0x40 + """Pointer to the in-game cutscene data for the intro cutscene; + needed for writing the starting area.""" + STARTING_INFO_PTR = RANDO_POINTERS_ADDR + 0x44 + """Pointer to a struct containing the starting location and items.""" + MAJOR_LOCATIONS_PTR = RANDO_POINTERS_ADDR + 0x48 + """Pointer to a list of major locations and the items they have.""" + MINOR_LOCATIONS_PTR = RANDO_POINTERS_ADDR + 0x4C + """Pointer to a list of minor locations and the items they have.""" + + # Rando options + DIFFICULTY_OPTIONS_PTR = RANDO_POINTERS_ADDR + 0x50 + METROID_SPRITE_STATS_PTR = RANDO_POINTERS_ADDR + 0x54 + BLACK_PIRATES_REQUIRE_PLASMA_PTR = RANDO_POINTERS_ADDR + 0x58 + SKIP_DOOR_TRANSITIONS_PTR = RANDO_POINTERS_ADDR + 0x5C + BALL_LAUNCHER_WITHOUT_BOMBS_PTR = RANDO_POINTERS_ADDR + 0x60 + DISABLE_MIDAIR_BOMB_JUMP_PTR = RANDO_POINTERS_ADDR + 0x64 + DISABLE_WALLJUMP_PTR = RANDO_POINTERS_ADDR + 0x68 + REMOVE_CUTSCENES_PTR = RANDO_POINTERS_ADDR + 0x6C + SKIP_SUITLESS_SEQUENCE_PTR = RANDO_POINTERS_ADDR + 0x70 + + ENERGY_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x74 + MISSILE_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x78 + SUPER_MISSILE_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x7C + POWER_BOMB_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x80 + + TITLE_TEXT_LINES_PTR = RANDO_POINTERS_ADDR + 0x84 + + # Address for any additional data that the patcher may need to write + PATCHER_FREE_SPACE_ADDR = 0x7C0000 + PATCHER_FREE_SPACE_END = RANDO_POINTERS_ADDR - PATCHER_FREE_SPACE_ADDR From ba7f87f84463aae6ad43763a6bd46edcd7e6692b Mon Sep 17 00:00:00 2001 From: biosp4rk <37962487+biosp4rk@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:11:02 -0700 Subject: [PATCH 2/2] Use IntEnum for ZM pointers --- src/mars_patcher/constants/game_data.py | 30 +++---- src/mars_patcher/zm/constants/game_data.py | 42 ++++----- .../zm/constants/reserved_space.py | 90 +++++++++++-------- 3 files changed, 88 insertions(+), 74 deletions(-) diff --git a/src/mars_patcher/constants/game_data.py b/src/mars_patcher/constants/game_data.py index 7926889..5359485 100644 --- a/src/mars_patcher/constants/game_data.py +++ b/src/mars_patcher/constants/game_data.py @@ -1,5 +1,5 @@ from mars_patcher.rom import Game, Region, Rom -from mars_patcher.zm.constants.reserved_space import ReservedConstantsZM +from mars_patcher.zm.constants.reserved_space import ReservedPointersZM def area_room_entry_ptrs(rom: Rom) -> int: @@ -14,7 +14,7 @@ def area_room_entry_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77D5C0 elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.ROOM_AREA_ENTRIES_PTR) + return rom.read_ptr(ReservedPointersZM.ROOM_AREA_ENTRIES_PTR) raise ValueError("Rom has unknown game loaded.") @@ -31,7 +31,7 @@ def tileset_entries(rom: Rom) -> int: elif rom.region == Region.C: return 0x3C1E94 elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.TILESET_ENTRIES_PTR) + return rom.read_ptr(ReservedPointersZM.TILESET_ENTRIES_PTR) raise ValueError("Rom has unknown game loaded.") @@ -57,7 +57,7 @@ def area_doors_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77D598 elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.AREA_DOORS_PTR) + return rom.read_ptr(ReservedPointersZM.AREA_DOORS_PTR) raise ValueError("Rom has unknown game loaded.") @@ -74,7 +74,7 @@ def area_connections(rom: Rom) -> int: elif rom.region == Region.C: return 0x3CB19C elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.AREA_CONNECTIONS_PTR) + return rom.read_ptr(ReservedPointersZM.AREA_CONNECTIONS_PTR) raise ValueError("Rom has unknown game loaded.") @@ -101,7 +101,7 @@ def anim_palette_entries(rom: Rom) -> int: elif rom.region == Region.C: return 0x3E5D7C elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.ANIM_PALETTE_ENTRIES_PTR) + return rom.read_ptr(ReservedPointersZM.ANIM_PALETTE_ENTRIES_PTR) raise ValueError("Rom has unknown game loaded.") @@ -130,7 +130,7 @@ def sprite_graphics_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77C2DC elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.SPRITE_GRAPHICS_PTR) + return rom.read_ptr(ReservedPointersZM.SPRITE_GRAPHICS_PTR) raise ValueError(rom.game, rom.region) @@ -146,7 +146,7 @@ def sprite_palette_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77C5D8 elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.SPRITE_PALETTES_PTR) + return rom.read_ptr(ReservedPointersZM.SPRITE_PALETTES_PTR) raise ValueError(rom.game, rom.region) @@ -171,7 +171,7 @@ def spriteset_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77CADC elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.SPRITESET_PTR) + return rom.read_ptr(ReservedPointersZM.SPRITESET_PTR) raise ValueError(rom.game, rom.region) @@ -196,7 +196,7 @@ def samus_palettes(rom: Rom) -> list[tuple[int, int]]: elif rom.region == Region.C: return [(0x2900C8, 0x5E), (0x290E48, 0x70), (0x56CC68, 3)] elif rom.game == Game.ZM: - addr = rom.read_ptr(ReservedConstantsZM.AREA_DOORS_PTR) + addr = rom.read_ptr(ReservedPointersZM.AREA_DOORS_PTR) return [(addr, 0xA3)] raise ValueError(rom.game, rom.region) @@ -216,7 +216,7 @@ def helmet_cursor_palettes(rom: Rom) -> list[tuple[int, int]]: elif rom.region == Region.C: return [(0x6CE360, 1), (0x6CE400, 2), (0x6CA8F8, 1), (0x6CA938, 2)] elif rom.game == Game.ZM: - addr = rom.read_ptr(ReservedConstantsZM.HELMET_CURSOR_PALETTES_PTR) + addr = rom.read_ptr(ReservedPointersZM.HELMET_CURSOR_PALETTES_PTR) return [(addr, 1), (addr + 0x80, 1)] raise ValueError(rom.game, rom.region) @@ -233,7 +233,7 @@ def beam_palettes(rom: Rom) -> list[tuple[int, int]]: elif rom.region == Region.C: return [(0x592578, 6)] elif rom.game == Game.ZM: - addr = rom.read_ptr(ReservedConstantsZM.BEAM_PALETTES_PTR) + addr = rom.read_ptr(ReservedPointersZM.BEAM_PALETTES_PTR) return [(addr, 6)] raise ValueError(rom.game, rom.region) @@ -250,7 +250,7 @@ def character_widths(rom: Rom) -> int: elif rom.region == Region.C: return 0x57D21C elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.CHARACTER_WIDTHS_PTR) + return rom.read_ptr(ReservedPointersZM.CHARACTER_WIDTHS_PTR) raise ValueError(rom.game, rom.region) @@ -266,7 +266,7 @@ def sound_data_entries(rom: Rom) -> int: elif rom.region == Region.C: return 0xAB0E4 elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.SOUND_DATA_PTR) + return rom.read_ptr(ReservedPointersZM.SOUND_DATA_PTR) raise ValueError(rom.game, rom.region) @@ -291,7 +291,7 @@ def minimap_ptrs(rom: Rom) -> int: elif rom.region == Region.C: return 0x77DB60 elif rom.game == Game.ZM: - return rom.read_ptr(ReservedConstantsZM.MINIMAPS_PTR) + return rom.read_ptr(ReservedPointersZM.MINIMAPS_PTR) raise ValueError(rom.game, rom.region) diff --git a/src/mars_patcher/zm/constants/game_data.py b/src/mars_patcher/zm/constants/game_data.py index e540623..a94378f 100644 --- a/src/mars_patcher/zm/constants/game_data.py +++ b/src/mars_patcher/zm/constants/game_data.py @@ -1,82 +1,82 @@ from mars_patcher.rom import Rom -from mars_patcher.zm.constants.reserved_space import ReservedConstantsZM +from mars_patcher.zm.constants.reserved_space import ReservedPointersZM def tileset_tilemap_sizes_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.TILESET_TILEMAP_SIZES_PTR) + return rom.read_ptr(ReservedPointersZM.TILESET_TILEMAP_SIZES_PTR) def chozo_statue_targets_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.CHOZO_STATUE_TARGETS_PTR) + return rom.read_ptr(ReservedPointersZM.CHOZO_STATUE_TARGETS_PTR) def intro_cutscene_data_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.INTRO_CUTSCENE_DATA_PTR) + return rom.read_ptr(ReservedPointersZM.INTRO_CUTSCENE_DATA_PTR) def starting_info_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.STARTING_INFO_PTR) + return rom.read_ptr(ReservedPointersZM.STARTING_INFO_PTR) def major_locations_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.MAJOR_LOCATIONS_PTR) + return rom.read_ptr(ReservedPointersZM.MAJOR_LOCATIONS_PTR) def minor_locations_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.MINOR_LOCATIONS_PTR) + return rom.read_ptr(ReservedPointersZM.MINOR_LOCATIONS_PTR) def difficulty_options_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.DIFFICULTY_OPTIONS_PTR) + return rom.read_ptr(ReservedPointersZM.DIFFICULTY_OPTIONS_PTR) def metroid_sprite_stats_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.METROID_SPRITE_STATS_PTR) + return rom.read_ptr(ReservedPointersZM.METROID_SPRITE_STATS_PTR) def black_pirates_require_plasma_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.BLACK_PIRATES_REQUIRE_PLASMA_PTR) + return rom.read_ptr(ReservedPointersZM.BLACK_PIRATES_REQUIRE_PLASMA_PTR) def skip_door_transitions_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.SKIP_DOOR_TRANSITIONS_PTR) + return rom.read_ptr(ReservedPointersZM.SKIP_DOOR_TRANSITIONS_PTR) def ball_launcher_without_bombs_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.BALL_LAUNCHER_WITHOUT_BOMBS_PTR) + return rom.read_ptr(ReservedPointersZM.BALL_LAUNCHER_WITHOUT_BOMBS_PTR) def disable_midair_bomb_jump_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.DISABLE_MIDAIR_BOMB_JUMP_PTR) + return rom.read_ptr(ReservedPointersZM.DISABLE_MIDAIR_BOMB_JUMP_PTR) def disable_walljump_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.DISABLE_WALLJUMP_PTR) + return rom.read_ptr(ReservedPointersZM.DISABLE_WALLJUMP_PTR) def remove_cutscenes_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.REMOVE_CUTSCENES_PTR) + return rom.read_ptr(ReservedPointersZM.REMOVE_CUTSCENES_PTR) def skip_suitless_sequence_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.SKIP_SUITLESS_SEQUENCE_PTR) + return rom.read_ptr(ReservedPointersZM.SKIP_SUITLESS_SEQUENCE_PTR) def energy_tank_increase_amount_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.ENERGY_TANK_INCREASE_AMOUNT_PTR) + return rom.read_ptr(ReservedPointersZM.ENERGY_TANK_INCREASE_AMOUNT_PTR) def missile_tank_increase_amount_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.MISSILE_TANK_INCREASE_AMOUNT_PTR) + return rom.read_ptr(ReservedPointersZM.MISSILE_TANK_INCREASE_AMOUNT_PTR) def super_missile_tank_increase_amount_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.SUPER_MISSILE_TANK_INCREASE_AMOUNT_PTR) + return rom.read_ptr(ReservedPointersZM.SUPER_MISSILE_TANK_INCREASE_AMOUNT_PTR) def power_bomb_tank_increase_amount_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.POWER_BOMB_TANK_INCREASE_AMOUNT_PTR) + return rom.read_ptr(ReservedPointersZM.POWER_BOMB_TANK_INCREASE_AMOUNT_PTR) def title_text_lines_addr(rom: Rom) -> int: - return rom.read_ptr(ReservedConstantsZM.TITLE_TEXT_LINES_PTR) + return rom.read_ptr(ReservedPointersZM.TITLE_TEXT_LINES_PTR) diff --git a/src/mars_patcher/zm/constants/reserved_space.py b/src/mars_patcher/zm/constants/reserved_space.py index 90f917b..d660d76 100644 --- a/src/mars_patcher/zm/constants/reserved_space.py +++ b/src/mars_patcher/zm/constants/reserved_space.py @@ -1,3 +1,8 @@ +from enum import IntEnum, auto + +from typing_extensions import Self + + class ReservedConstantsZM: """ These are constants that are in the ROM's 'Reserved Space'; things that are intended to be @@ -11,73 +16,82 @@ class ReservedConstantsZM: # 0x7D0000 - Randomizer data pointers # 0x7D8000 - NES Metroid data + # Hardcoded address for the pointers listed below; see linker.ld (around line 12) + RANDO_POINTERS_ADDR = 0x7D0000 + + # Address for any additional data that the patcher may need to write + PATCHER_FREE_SPACE_ADDR = 0x7C0000 + PATCHER_FREE_SPACE_END = RANDO_POINTERS_ADDR - PATCHER_FREE_SPACE_ADDR + + +class ReservedPointersZM(IntEnum): # These need to be kept in sync with the data pointers in the decomp, which can be found in # src/data/randomizer_pointers.c - RANDO_POINTERS_ADDR = 0x7D0000 # Existing data - ROOM_AREA_ENTRIES_PTR = RANDO_POINTERS_ADDR + 0x00 + ROOM_AREA_ENTRIES_PTR = 0 """Pointer to the list of pointers to the room entries for each area.""" - TILESET_ENTRIES_PTR = RANDO_POINTERS_ADDR + 0x04 + TILESET_ENTRIES_PTR = auto() """Pointer to the list of tileset entries.""" - TILESET_TILEMAP_SIZES_PTR = RANDO_POINTERS_ADDR + 0x08 + TILESET_TILEMAP_SIZES_PTR = auto() """Pointer to an array containing the size of each tileset's tilemap.""" - MINIMAPS_PTR = RANDO_POINTERS_ADDR + 0x0C + MINIMAPS_PTR = auto() """Pointer to a list of pointers to the minimap data for each area.""" - AREA_DOORS_PTR = RANDO_POINTERS_ADDR + 0x10 + AREA_DOORS_PTR = auto() """Pointer to the list of pointers to the door entries for each area.""" - AREA_CONNECTIONS_PTR = RANDO_POINTERS_ADDR + 0x14 + AREA_CONNECTIONS_PTR = auto() """Pointer to the list of area connections.""" - ANIM_PALETTE_ENTRIES_PTR = RANDO_POINTERS_ADDR + 0x18 + ANIM_PALETTE_ENTRIES_PTR = auto() """Pointer to the list of animated palette entries.""" - SPRITE_GRAPHICS_PTR = RANDO_POINTERS_ADDR + 0x1C + SPRITE_GRAPHICS_PTR = auto() """Pointer to the list of pointers to the graphics for each sprite.""" - SPRITE_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x20 + SPRITE_PALETTES_PTR = auto() """Pointer to the list of pointers to the palette for each sprite.""" - SPRITESET_PTR = RANDO_POINTERS_ADDR + 0x24 + SPRITESET_PTR = auto() """Pointer to the list of pointers to spriteset entries.""" - SAMUS_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x28 + SAMUS_PALETTES_PTR = auto() """Pointer to the start of all of Samus's palettes.""" - HELMET_CURSOR_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x2C + HELMET_CURSOR_PALETTES_PTR = auto() """Pointer to the palette used for the helmet cursor in menus.""" - BEAM_PALETTES_PTR = RANDO_POINTERS_ADDR + 0x30 + BEAM_PALETTES_PTR = auto() """Pointer to the start of the beam palettes.""" - CHARACTER_WIDTHS_PTR = RANDO_POINTERS_ADDR + 0x34 + CHARACTER_WIDTHS_PTR = auto() """Pointer to the character widths table.""" - SOUND_DATA_PTR = RANDO_POINTERS_ADDR + 0x38 + SOUND_DATA_PTR = auto() """Pointer to the list of sound data entries.""" - CHOZO_STATUE_TARGETS_PTR = RANDO_POINTERS_ADDR + 0x3C + CHOZO_STATUE_TARGETS_PTR = auto() """Pointer to the list of Chozo statue targets.""" # Rando data - INTRO_CUTSCENE_DATA_PTR = RANDO_POINTERS_ADDR + 0x40 + INTRO_CUTSCENE_DATA_PTR = auto() """Pointer to the in-game cutscene data for the intro cutscene; needed for writing the starting area.""" - STARTING_INFO_PTR = RANDO_POINTERS_ADDR + 0x44 + STARTING_INFO_PTR = auto() """Pointer to a struct containing the starting location and items.""" - MAJOR_LOCATIONS_PTR = RANDO_POINTERS_ADDR + 0x48 + MAJOR_LOCATIONS_PTR = auto() """Pointer to a list of major locations and the items they have.""" - MINOR_LOCATIONS_PTR = RANDO_POINTERS_ADDR + 0x4C + MINOR_LOCATIONS_PTR = auto() """Pointer to a list of minor locations and the items they have.""" # Rando options - DIFFICULTY_OPTIONS_PTR = RANDO_POINTERS_ADDR + 0x50 - METROID_SPRITE_STATS_PTR = RANDO_POINTERS_ADDR + 0x54 - BLACK_PIRATES_REQUIRE_PLASMA_PTR = RANDO_POINTERS_ADDR + 0x58 - SKIP_DOOR_TRANSITIONS_PTR = RANDO_POINTERS_ADDR + 0x5C - BALL_LAUNCHER_WITHOUT_BOMBS_PTR = RANDO_POINTERS_ADDR + 0x60 - DISABLE_MIDAIR_BOMB_JUMP_PTR = RANDO_POINTERS_ADDR + 0x64 - DISABLE_WALLJUMP_PTR = RANDO_POINTERS_ADDR + 0x68 - REMOVE_CUTSCENES_PTR = RANDO_POINTERS_ADDR + 0x6C - SKIP_SUITLESS_SEQUENCE_PTR = RANDO_POINTERS_ADDR + 0x70 + DIFFICULTY_OPTIONS_PTR = auto() + METROID_SPRITE_STATS_PTR = auto() + BLACK_PIRATES_REQUIRE_PLASMA_PTR = auto() + SKIP_DOOR_TRANSITIONS_PTR = auto() + BALL_LAUNCHER_WITHOUT_BOMBS_PTR = auto() + DISABLE_MIDAIR_BOMB_JUMP_PTR = auto() + DISABLE_WALLJUMP_PTR = auto() + REMOVE_CUTSCENES_PTR = auto() + SKIP_SUITLESS_SEQUENCE_PTR = auto() - ENERGY_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x74 - MISSILE_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x78 - SUPER_MISSILE_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x7C - POWER_BOMB_TANK_INCREASE_AMOUNT_PTR = RANDO_POINTERS_ADDR + 0x80 + ENERGY_TANK_INCREASE_AMOUNT_PTR = auto() + MISSILE_TANK_INCREASE_AMOUNT_PTR = auto() + SUPER_MISSILE_TANK_INCREASE_AMOUNT_PTR = auto() + POWER_BOMB_TANK_INCREASE_AMOUNT_PTR = auto() - TITLE_TEXT_LINES_PTR = RANDO_POINTERS_ADDR + 0x84 + TITLE_TEXT_LINES_PTR = auto() - # Address for any additional data that the patcher may need to write - PATCHER_FREE_SPACE_ADDR = 0x7C0000 - PATCHER_FREE_SPACE_END = RANDO_POINTERS_ADDR - PATCHER_FREE_SPACE_ADDR + def __new__(cls, offset: int) -> Self: + obj = object.__new__(cls) + obj._value_ = ReservedConstantsZM.RANDO_POINTERS_ADDR + (offset * 4) + return obj