From b28282d1d9056c3f57154fd8260c8d4f212696e4 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Sat, 24 Jan 2026 17:51:43 +0000 Subject: [PATCH 01/13] commit --- .vscode/launch.json | 17 +++ src/mars_patcher/mf/auto_generated_types.py | 9 ++ src/mars_patcher/mf/constants/game_data.py | 16 +++ src/mars_patcher/mf/data/schema.json | 12 ++ src/mars_patcher/mf/music.py | 118 ++++++++++++++++++++ src/mars_patcher/mf/patcher.py | 6 + 6 files changed, 178 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 src/mars_patcher/mf/music.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..ed73856 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "name": "run test", + "type": "debugpy", + "request": "launch", + "program": "C:\\Coding\\mars-patcher-py\\src\\mars_patcher\\__main__.py", + "console": "integratedTerminal", + "args": ["ignore\\Metroid Fusion (USA).gba", "ignore\\Output.gba", "ignore\\Fusion - Zone Sciser Kago_mars.json"] + } + ] +} \ No newline at end of file diff --git a/src/mars_patcher/mf/auto_generated_types.py b/src/mars_patcher/mf/auto_generated_types.py index 523ebd3..4306589 100644 --- a/src/mars_patcher/mf/auto_generated_types.py +++ b/src/mars_patcher/mf/auto_generated_types.py @@ -230,6 +230,12 @@ class BlocklayerItem(typ.TypedDict, total=False): # Schema entries +class MarsschemamfMusicmapping(typ.TypedDict, total=False): + """Shuffles the in-game music.""" + + Original: str + New: str + class MarsschemamfLocationsMajorlocationsItem(typ.TypedDict): Source: Validsources """Valid major locations.""" @@ -572,6 +578,9 @@ class Marsschemamf(typ.TypedDict, total=False): SeedHash: typ.Required[typ.Annotated[str, '/^[0-9A-Z]{8}$/']] """A seed hash that will be displayed on the file select screen.""" + MusicMapping: MarsschemamfMusicmapping + """Shuffles the in-game music.""" + Locations: typ.Required[MarsschemamfLocations] """Specifies how the item locations in the game should be changed.""" diff --git a/src/mars_patcher/mf/constants/game_data.py b/src/mars_patcher/mf/constants/game_data.py index d6698fc..423408a 100644 --- a/src/mars_patcher/mf/constants/game_data.py +++ b/src/mars_patcher/mf/constants/game_data.py @@ -41,6 +41,22 @@ def starting_equipment(rom: Rom) -> int: raise ValueError(rom.region) +def sounds(rom: Rom) -> int: + """Returns the address of music and sound data.""" + if rom.game != Game.MF: + raise ValueError(rom.game) + if rom.region == Region.U: + return 0xA8D3C + elif rom.region == Region.E: + return 0xA9398 + elif rom.region == Region.J: + return 0xAB0A0 + elif rom.region == Region.C: + return 0xAB0E4 + else: + raise ValueError(rom.region) + + def sprite_vram_sizes(rom: Rom) -> int: """Returns the address of the sprite VRAM sizes.""" if rom.game != Game.MF: diff --git a/src/mars_patcher/mf/data/schema.json b/src/mars_patcher/mf/data/schema.json index 82d7582..53db05f 100644 --- a/src/mars_patcher/mf/data/schema.json +++ b/src/mars_patcher/mf/data/schema.json @@ -9,6 +9,18 @@ "type": "string", "pattern": "^[0-9A-Z]{8}$" }, + "MusicMapping": { + "description": "Shuffles the in-game music.", + "type": "object", + "properties": { + "Original": { + "type": "string" + }, + "New": { + "type": "string" + } + } + }, "Locations": { "type": "object", "description": "Specifies how the item locations in the game should be changed.", diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/music.py new file mode 100644 index 0000000..bbf7464 --- /dev/null +++ b/src/mars_patcher/mf/music.py @@ -0,0 +1,118 @@ +from mars_patcher.mf.auto_generated_types import MarsschemamfMusicmapping +from mars_patcher.mf.constants.game_data import sounds +from mars_patcher.rom import Rom + +MUSIC_LIBRARY = { + "MUSIC_NONE": 0x0, + "MUSIC_1": 0x1, + "MUSIC_2": 0x2, + "MUSIC_3": 0x3, + "MUSIC_SECTOR_1": 0x4, + "MUSIC_5": 0x5, + "MUSIC_SECTOR_2": 0x6, + "MUSIC_SECTOR_3": 0x7, + "MUSIC_SECTOR_5": 0x8, + "MUSIC_SECTOR_4": 0x9, + "MUSIC_SECTOR_6": 0xA, + "MUSIC_NAVIGATION_ROOM": 0xB, + "MUSIC_C": 0xC, + "MUSIC_D": 0xD, + "MUSIC_E": 0xE, + "MUSIC_F": 0xF, + "MUSIC_ITEM_FANFARE": 0x10, + "MUSIC_11": 0x11, + "MUSIC_12": 0x12, + "MUSIC_13": 0x13, + "SOUND_MESSAGE_POPUP": 0x14, + "MUSIC_15": 0x15, + "MUSIC_16": 0x16, + "MUSIC_SA_X_CHASE": 0x17, + "MUSIC_BOSS_TENSION": 0x18, + "MUSIC_ARACHNUS_BATTLE": 0x19, + "MUSIC_ZAZABI_BATTLE": 0x1A, + "MUSIC_BOX_BATTLE": 0x1B, + "MUSIC_1C": 0x1C, + "MUSIC_1D": 0x1D, + "MUSIC_1E": 0x1E, + "MUSIC_1F": 0x1F, + "MUSIC_20": 0x20, + "MUSIC_21": 0x21, + "MUSIC_22": 0x22, + "MUSIC_23": 0x23, + "MUSIC_24": 0x24, + "MUSIC_25": 0x25, + "MUSIC_26": 0x26, + "MUSIC_27": 0x27, + "MUSIC_28": 0x28, + "MUSIC_29": 0x29, + "MUSIC_2A": 0x2A, + "MUSIC_2B": 0x2B, + "MUSIC_2C": 0x2C, + "MUSIC_2D": 0x2D, + "MUSIC_2E": 0x2E, + "MUSIC_2F": 0x2F, + "MUSIC_30": 0x30, + "MUSIC_31": 0x31, + "MUSIC_32": 0x32, + "MUSIC_OPERATIONS_DECK_ELEVATOR_OFFLINE": 0x33, + "MUSIC_OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE": 0x34, + "MUSIC_MAIN_BOILER_COOLDOWN_MISSION": 0x35, + "MUSIC_36": 0x36, + "MUSIC_37": 0x37, + "MUSIC_ORBIT_CHANGE": 0x38, + "MUSIC_39": 0x39, + "MUSIC_3A": 0x3A, + "MUSIC_OBJECTIVE_COMPLETE": 0x3B, + "MUSIC_3C": 0x3C, + "MUSIC_3D": 0x3D, + "MUSIC_3E": 0x3E, + "MUSIC_SERRIS_YAKUZA_BATTLE": 0x3F, + "MUSIC_VARIA_CORE_X_BATTLE": 0x40, + "MUSIC_NIGHTMARE_BATTLE": 0x41, + "MUSIC_NEO_RIDLEY_BATTLE": 0x42, + "MUSIC_CHOZO_STATUE_CORE_X_BATTLE": 0x43, + "MUSIC_NETTORI_BATTLE": 0x44, + "MUSIC_45": 0x45, + "MUSIC_46": 0x46, + "MUSIC_47": 0x47, + "MUSIC_48": 0x48, + "MUSIC_49": 0x49, + "MUSIC_TITLE": 0x4A, + "MUSIC_4B": 0x4B, + "MUSIC_4C": 0x4C, + "MUSIC_4D": 0x4D, + "MUSIC_4E": 0x4E, + "MUSIC_4F": 0x4F, + "MUSIC_50": 0x50, + "MUSIC_SA_X_BATTLE": 0x51, + "MUSIC_52": 0x52, + "MUSIC_53": 0x53, + "MUSIC_54": 0x54, + "MUSIC_55": 0x55, + "MUSIC_56": 0x56, + "MUSIC_57": 0x57, + "MUSIC_58": 0x58, + "MUSIC_59": 0x59, + "MUSIC_5A": 0x5A, + "MUSIC_5B": 0x5B, + "MUSIC_5C": 0x5C, + "MUSIC_5D": 0x5D, + "MUSIC_5E": 0x5E, + "MUSIC_5F": 0x5F, + "MUSIC_60": 0x60, + "MUSIC_61": 0x61, + "MUSIC_62": 0x62, + "MUSIC_63": 0x63, +} + + +def set_sounds(rom: Rom, patch_data: MarsschemamfMusicmapping) -> None: + # Write to rom + read_location = sounds(rom) + 8 * MUSIC_LIBRARY[patch_data["New"]] + read_SoundheaderPtr = rom.read_32(read_location) + read_TrackGroupNum1 = rom.read_16(read_location + 4) + read_TrackGroupNum2 = rom.read_16(read_location + 6) + write_location = sounds(rom) + 8 * MUSIC_LIBRARY[patch_data["Original"]] + rom.write_32(write_location, read_SoundheaderPtr) + rom.write_16(write_location + 4, read_TrackGroupNum1) + rom.write_16(write_location + 6, read_TrackGroupNum2) diff --git a/src/mars_patcher/mf/patcher.py b/src/mars_patcher/mf/patcher.py index 1a4b99e..8fe17ea 100644 --- a/src/mars_patcher/mf/patcher.py +++ b/src/mars_patcher/mf/patcher.py @@ -30,6 +30,7 @@ skip_door_transitions, stereo_default, ) +from mars_patcher.mf.music import set_sounds from mars_patcher.mf.navigation_text import NavigationText from mars_patcher.mf.room_names import write_room_names from mars_patcher.mf.starting import set_starting_items, set_starting_location @@ -80,6 +81,11 @@ def patch_mf( # Required metroid count set_required_metroid_count(rom, patch_data["RequiredMetroidCount"]) + # Music + if "MusicMapping" in patch_data: + status_update("Writing music...", -1) + set_sounds(rom, patch_data["MusicMapping"]) + # Starting location if "StartingLocation" in patch_data: status_update("Writing starting location...", -1) From 1ed40d1300e9f12c629bf878f5111a97bd6d4a85 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Sat, 24 Jan 2026 19:17:18 +0000 Subject: [PATCH 02/13] Added MusicMapping to patcher --- src/mars_patcher/mf/auto_generated_types.py | 4 ++-- src/mars_patcher/mf/data/schema.json | 24 ++++++++++++------- src/mars_patcher/mf/music.py | 26 ++++++++++++++------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/mars_patcher/mf/auto_generated_types.py b/src/mars_patcher/mf/auto_generated_types.py index 4306589..75bbfaa 100644 --- a/src/mars_patcher/mf/auto_generated_types.py +++ b/src/mars_patcher/mf/auto_generated_types.py @@ -233,8 +233,8 @@ class BlocklayerItem(typ.TypedDict, total=False): class MarsschemamfMusicmapping(typ.TypedDict, total=False): """Shuffles the in-game music.""" - Original: str - New: str + Original: list[str] + New: list[str] class MarsschemamfLocationsMajorlocationsItem(typ.TypedDict): Source: Validsources diff --git a/src/mars_patcher/mf/data/schema.json b/src/mars_patcher/mf/data/schema.json index 53db05f..9476363 100644 --- a/src/mars_patcher/mf/data/schema.json +++ b/src/mars_patcher/mf/data/schema.json @@ -11,15 +11,21 @@ }, "MusicMapping": { "description": "Shuffles the in-game music.", - "type": "object", - "properties": { - "Original": { - "type": "string" - }, - "New": { - "type": "string" - } - } + "type": "object", + "properties": { + "Original": { + "type": "array", + "items": { + "type": "string" + } + }, + "New": { + "type": "array", + "items": { + "type": "string" + } + } + } }, "Locations": { "type": "object", diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/music.py index bbf7464..dc50443 100644 --- a/src/mars_patcher/mf/music.py +++ b/src/mars_patcher/mf/music.py @@ -107,12 +107,22 @@ def set_sounds(rom: Rom, patch_data: MarsschemamfMusicmapping) -> None: + read_SoundheaderPtr = [] + read_TrackGroupNum1 = [] + read_TrackGroupNum2 = [] + + # Read new data + for New in patch_data["New"]: + read_location = sounds(rom) + 8 * MUSIC_LIBRARY[New] + read_SoundheaderPtr.append(rom.read_32(read_location)) + read_TrackGroupNum1.append(rom.read_16(read_location + 4)) + read_TrackGroupNum2.append(rom.read_16(read_location + 6)) + # Write to rom - read_location = sounds(rom) + 8 * MUSIC_LIBRARY[patch_data["New"]] - read_SoundheaderPtr = rom.read_32(read_location) - read_TrackGroupNum1 = rom.read_16(read_location + 4) - read_TrackGroupNum2 = rom.read_16(read_location + 6) - write_location = sounds(rom) + 8 * MUSIC_LIBRARY[patch_data["Original"]] - rom.write_32(write_location, read_SoundheaderPtr) - rom.write_16(write_location + 4, read_TrackGroupNum1) - rom.write_16(write_location + 6, read_TrackGroupNum2) + for Original, SoundHdrPtr, TrackGrpNum1, TrackGrpNum2 in zip( + patch_data["Original"], read_SoundheaderPtr, read_TrackGroupNum1, read_TrackGroupNum2 + ): + write_location = sounds(rom) + 8 * MUSIC_LIBRARY[Original] + rom.write_32(write_location, SoundHdrPtr) + rom.write_16(write_location + 4, TrackGrpNum1) + rom.write_16(write_location + 6, TrackGrpNum2) From 15a4a4b710f776376f20f9550c168aa86e07a6cb Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Sat, 24 Jan 2026 19:23:52 +0000 Subject: [PATCH 03/13] removed launch.json --- .vscode/launch.json | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index ed73856..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - - { - "name": "run test", - "type": "debugpy", - "request": "launch", - "program": "C:\\Coding\\mars-patcher-py\\src\\mars_patcher\\__main__.py", - "console": "integratedTerminal", - "args": ["ignore\\Metroid Fusion (USA).gba", "ignore\\Output.gba", "ignore\\Fusion - Zone Sciser Kago_mars.json"] - } - ] -} \ No newline at end of file From c228aab03f016a1e9a0655570872ea2f9cb23d7f Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Fri, 6 Feb 2026 19:14:46 +0000 Subject: [PATCH 04/13] changed sound to sound_entries --- src/mars_patcher/mf/constants/game_data.py | 2 +- src/mars_patcher/mf/music.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mars_patcher/mf/constants/game_data.py b/src/mars_patcher/mf/constants/game_data.py index 423408a..f2a14c3 100644 --- a/src/mars_patcher/mf/constants/game_data.py +++ b/src/mars_patcher/mf/constants/game_data.py @@ -41,7 +41,7 @@ def starting_equipment(rom: Rom) -> int: raise ValueError(rom.region) -def sounds(rom: Rom) -> int: +def sound_entries(rom: Rom) -> int: """Returns the address of music and sound data.""" if rom.game != Game.MF: raise ValueError(rom.game) diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/music.py index dc50443..1129c0f 100644 --- a/src/mars_patcher/mf/music.py +++ b/src/mars_patcher/mf/music.py @@ -1,5 +1,5 @@ from mars_patcher.mf.auto_generated_types import MarsschemamfMusicmapping -from mars_patcher.mf.constants.game_data import sounds +from mars_patcher.mf.constants.game_data import sound_entries from mars_patcher.rom import Rom MUSIC_LIBRARY = { @@ -113,7 +113,7 @@ def set_sounds(rom: Rom, patch_data: MarsschemamfMusicmapping) -> None: # Read new data for New in patch_data["New"]: - read_location = sounds(rom) + 8 * MUSIC_LIBRARY[New] + read_location = sound_entries(rom) + 8 * MUSIC_LIBRARY[New] read_SoundheaderPtr.append(rom.read_32(read_location)) read_TrackGroupNum1.append(rom.read_16(read_location + 4)) read_TrackGroupNum2.append(rom.read_16(read_location + 6)) @@ -122,7 +122,7 @@ def set_sounds(rom: Rom, patch_data: MarsschemamfMusicmapping) -> None: for Original, SoundHdrPtr, TrackGrpNum1, TrackGrpNum2 in zip( patch_data["Original"], read_SoundheaderPtr, read_TrackGroupNum1, read_TrackGroupNum2 ): - write_location = sounds(rom) + 8 * MUSIC_LIBRARY[Original] + write_location = sound_entries(rom) + 8 * MUSIC_LIBRARY[Original] rom.write_32(write_location, SoundHdrPtr) rom.write_16(write_location + 4, TrackGrpNum1) rom.write_16(write_location + 6, TrackGrpNum2) From 04971e18330e22e652a74dfcff7f529456cfaa75 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Fri, 6 Feb 2026 19:24:17 +0000 Subject: [PATCH 05/13] renamed patch_data to data --- src/mars_patcher/mf/music.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/music.py index 1129c0f..b713455 100644 --- a/src/mars_patcher/mf/music.py +++ b/src/mars_patcher/mf/music.py @@ -106,13 +106,13 @@ } -def set_sounds(rom: Rom, patch_data: MarsschemamfMusicmapping) -> None: +def set_sounds(rom: Rom, data: MarsschemamfMusicmapping) -> None: read_SoundheaderPtr = [] read_TrackGroupNum1 = [] read_TrackGroupNum2 = [] # Read new data - for New in patch_data["New"]: + for New in data["New"]: read_location = sound_entries(rom) + 8 * MUSIC_LIBRARY[New] read_SoundheaderPtr.append(rom.read_32(read_location)) read_TrackGroupNum1.append(rom.read_16(read_location + 4)) @@ -120,7 +120,7 @@ def set_sounds(rom: Rom, patch_data: MarsschemamfMusicmapping) -> None: # Write to rom for Original, SoundHdrPtr, TrackGrpNum1, TrackGrpNum2 in zip( - patch_data["Original"], read_SoundheaderPtr, read_TrackGroupNum1, read_TrackGroupNum2 + data["Original"], read_SoundheaderPtr, read_TrackGroupNum1, read_TrackGroupNum2 ): write_location = sound_entries(rom) + 8 * MUSIC_LIBRARY[Original] rom.write_32(write_location, SoundHdrPtr) From f50ea1db4ef03917cc51120160f80435167a7b65 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Fri, 6 Feb 2026 21:45:24 +0000 Subject: [PATCH 06/13] changed music library from dictionary to intenum, removed null tracks. now read sound entries as chunk of bytes. renamed musicmapping to musicreplacement --- src/mars_patcher/mf/auto_generated_types.py | 112 ++++++++++++- src/mars_patcher/mf/data/schema.json | 165 ++++++++++++++++--- src/mars_patcher/mf/music.py | 172 ++++++-------------- src/mars_patcher/mf/patcher.py | 4 +- 4 files changed, 302 insertions(+), 151 deletions(-) diff --git a/src/mars_patcher/mf/auto_generated_types.py b/src/mars_patcher/mf/auto_generated_types.py index 75bbfaa..310ab2e 100644 --- a/src/mars_patcher/mf/auto_generated_types.py +++ b/src/mars_patcher/mf/auto_generated_types.py @@ -189,6 +189,34 @@ 'Italian', 'Spanish' ] +Validmusictracks = typ.Literal[ + 'SECTOR_1', + 'SECTOR_2', + 'SECTOR_3', + 'SECTOR_5', + 'SECTOR_4', + 'SECTOR_6', + 'NAVIGATION_ROOM', + 'ITEM_FANFARE', + 'SA_X_CHASE', + 'BOSS_TENSION', + 'ARACHNUS_BATTLE', + 'ZAZABI_BATTLE', + 'BOX_BATTLE', + 'OPERATIONS_DECK_ELEVATOR_OFFLINE', + 'OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE', + 'MAIN_BOILER_COOLDOWN_MISSION', + 'ORBIT_CHANGE', + 'OBJECTIVE_COMPLETE', + 'SERRIS_YAKUZA_BATTLE', + 'VARIA_CORE_X_BATTLE', + 'NIGHTMARE_BATTLE', + 'NEO_RIDLEY_BATTLE', + 'CHOZO_STATUE_CORE_X_BATTLE', + 'NETTORI_BATTLE', + 'TITLE', + 'SA_X_BATTLE' +] Messagelanguages: typ.TypeAlias = dict[Validlanguages, str] class Itemmessages(typ.TypedDict, total=False): @@ -230,11 +258,87 @@ class BlocklayerItem(typ.TypedDict, total=False): # Schema entries -class MarsschemamfMusicmapping(typ.TypedDict, total=False): +class MarsschemamfMusicreplacement(typ.TypedDict, total=False): """Shuffles the in-game music.""" - Original: list[str] - New: list[str] + SECTOR_1: Validmusictracks + """Valid music tracks supported by the game.""" + + SECTOR_2: Validmusictracks + """Valid music tracks supported by the game.""" + + SECTOR_3: Validmusictracks + """Valid music tracks supported by the game.""" + + SECTOR_5: Validmusictracks + """Valid music tracks supported by the game.""" + + SECTOR_4: Validmusictracks + """Valid music tracks supported by the game.""" + + SECTOR_6: Validmusictracks + """Valid music tracks supported by the game.""" + + NAVIGATION_ROOM: Validmusictracks + """Valid music tracks supported by the game.""" + + ITEM_FANFARE: Validmusictracks + """Valid music tracks supported by the game.""" + + SA_X_CHASE: Validmusictracks + """Valid music tracks supported by the game.""" + + BOSS_TENSION: Validmusictracks + """Valid music tracks supported by the game.""" + + ARACHNUS_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + ZAZABI_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + BOX_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + OPERATIONS_DECK_ELEVATOR_OFFLINE: Validmusictracks + """Valid music tracks supported by the game.""" + + OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE: Validmusictracks + """Valid music tracks supported by the game.""" + + MAIN_BOILER_COOLDOWN_MISSION: Validmusictracks + """Valid music tracks supported by the game.""" + + ORBIT_CHANGE: Validmusictracks + """Valid music tracks supported by the game.""" + + OBJECTIVE_COMPLETE: Validmusictracks + """Valid music tracks supported by the game.""" + + SERRIS_YAKUZA_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + VARIA_CORE_X_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + NIGHTMARE_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + NEO_RIDLEY_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_STATUE_CORE_X_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + NETTORI_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + TITLE: Validmusictracks + """Valid music tracks supported by the game.""" + + SA_X_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + class MarsschemamfLocationsMajorlocationsItem(typ.TypedDict): Source: Validsources @@ -578,7 +682,7 @@ class Marsschemamf(typ.TypedDict, total=False): SeedHash: typ.Required[typ.Annotated[str, '/^[0-9A-Z]{8}$/']] """A seed hash that will be displayed on the file select screen.""" - MusicMapping: MarsschemamfMusicmapping + MusicReplacement: MarsschemamfMusicreplacement """Shuffles the in-game music.""" Locations: typ.Required[MarsschemamfLocations] diff --git a/src/mars_patcher/mf/data/schema.json b/src/mars_patcher/mf/data/schema.json index 9476363..85945e9 100644 --- a/src/mars_patcher/mf/data/schema.json +++ b/src/mars_patcher/mf/data/schema.json @@ -9,21 +9,87 @@ "type": "string", "pattern": "^[0-9A-Z]{8}$" }, - "MusicMapping": { + "MusicReplacement": { "description": "Shuffles the in-game music.", "type": "object", "properties": { - "Original": { - "type": "array", - "items": { - "type": "string" - } + "SECTOR_1": { + "$ref": "#/$defs/ValidMusicTracks" }, - "New": { - "type": "array", - "items": { - "type": "string" - } + "SECTOR_2": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SECTOR_3": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SECTOR_5": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SECTOR_4": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SECTOR_6": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "NAVIGATION_ROOM": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ITEM_FANFARE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SA_X_CHASE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "BOSS_TENSION": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ARACHNUS_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ZAZABI_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "BOX_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "OPERATIONS_DECK_ELEVATOR_OFFLINE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "MAIN_BOILER_COOLDOWN_MISSION": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ORBIT_CHANGE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "OBJECTIVE_COMPLETE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SERRIS_YAKUZA_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "VARIA_CORE_X_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "NIGHTMARE_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "NEO_RIDLEY_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_STATUE_CORE_X_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "NETTORI_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "TITLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SA_X_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" } } }, @@ -483,7 +549,7 @@ "default": null }, "TitleText": { - "type":"array", + "type": "array", "description": "Lines of ascii text to write to the title screen.", "items": { "type": "object", @@ -719,7 +785,11 @@ "maxLength": 112 } }, - "required": ["Area", "Room", "Name"] + "required": [ + "Area", + "Room", + "Name" + ] } }, "RevealHiddenTiles": { @@ -917,7 +987,6 @@ "Randovania", "ArchipelagoColor", "ArchipelagoMonochrome" - ] }, "ValidAbilities": { @@ -989,12 +1058,46 @@ "Spanish" ] }, + "ValidMusicTracks": { + "type": "string", + "description": "Valid music tracks supported by the game.", + "enum": [ + "SECTOR_1", + "SECTOR_2", + "SECTOR_3", + "SECTOR_5", + "SECTOR_4", + "SECTOR_6", + "NAVIGATION_ROOM", + "ITEM_FANFARE", + "SA_X_CHASE", + "BOSS_TENSION", + "ARACHNUS_BATTLE", + "ZAZABI_BATTLE", + "BOX_BATTLE", + "OPERATIONS_DECK_ELEVATOR_OFFLINE", + "OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE", + "MAIN_BOILER_COOLDOWN_MISSION", + "ORBIT_CHANGE", + "OBJECTIVE_COMPLETE", + "SERRIS_YAKUZA_BATTLE", + "VARIA_CORE_X_BATTLE", + "NIGHTMARE_BATTLE", + "NEO_RIDLEY_BATTLE", + "CHOZO_STATUE_CORE_X_BATTLE", + "NETTORI_BATTLE", + "TITLE", + "SA_X_BATTLE" + ] + }, "MessageLanguages": { "type": "object", "propertyNames": { "$ref": "#/$defs/ValidLanguages" }, - "required": ["English"], + "required": [ + "English" + ], "additionalProperties": { "type": "string", "description": "Specifies what text should appear for a 2 line message. Text will auto-wrap if the next word doesn't fit on the line. If the text is too long, it will be truncated. Use \n to force a line break. If not provided, a message based on the Item will be shown. If a language is not provided, it will use the provided English message." @@ -1007,10 +1110,14 @@ "$ref": "#/$defs/ItemMessagesKind" } }, - "required": ["Kind"], + "required": [ + "Kind" + ], "if": { "properties": { - "Kind": {"const": "CustomMessage" } + "Kind": { + "const": "CustomMessage" + } } }, "then": { @@ -1026,7 +1133,9 @@ "default": true } }, - "required": ["Languages"], + "required": [ + "Languages" + ], "additionalProperties": false }, "else": { @@ -1041,17 +1150,25 @@ "description": "The Message ID, will display one of the predefined messages in the ROM" } }, - "required": ["MessageID"], + "required": [ + "MessageID" + ], "additionalProperties": false } }, - "ItemMessagesKind":{ + "ItemMessagesKind": { "type": "string", - "enum": ["CustomMessage", "MessageID"] + "enum": [ + "CustomMessage", + "MessageID" + ] }, - "Jingle":{ + "Jingle": { "type": "string", - "enum": ["Minor", "Major"] + "enum": [ + "Minor", + "Major" + ] }, "BlockLayer": { "type": "array", @@ -1088,4 +1205,4 @@ "default": "OPEN" } } -} +} \ No newline at end of file diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/music.py index b713455..0765ede 100644 --- a/src/mars_patcher/mf/music.py +++ b/src/mars_patcher/mf/music.py @@ -1,128 +1,58 @@ -from mars_patcher.mf.auto_generated_types import MarsschemamfMusicmapping +from enum import IntEnum + +from mars_patcher.mf.auto_generated_types import MarsschemamfMusicreplacement from mars_patcher.mf.constants.game_data import sound_entries from mars_patcher.rom import Rom -MUSIC_LIBRARY = { - "MUSIC_NONE": 0x0, - "MUSIC_1": 0x1, - "MUSIC_2": 0x2, - "MUSIC_3": 0x3, - "MUSIC_SECTOR_1": 0x4, - "MUSIC_5": 0x5, - "MUSIC_SECTOR_2": 0x6, - "MUSIC_SECTOR_3": 0x7, - "MUSIC_SECTOR_5": 0x8, - "MUSIC_SECTOR_4": 0x9, - "MUSIC_SECTOR_6": 0xA, - "MUSIC_NAVIGATION_ROOM": 0xB, - "MUSIC_C": 0xC, - "MUSIC_D": 0xD, - "MUSIC_E": 0xE, - "MUSIC_F": 0xF, - "MUSIC_ITEM_FANFARE": 0x10, - "MUSIC_11": 0x11, - "MUSIC_12": 0x12, - "MUSIC_13": 0x13, - "SOUND_MESSAGE_POPUP": 0x14, - "MUSIC_15": 0x15, - "MUSIC_16": 0x16, - "MUSIC_SA_X_CHASE": 0x17, - "MUSIC_BOSS_TENSION": 0x18, - "MUSIC_ARACHNUS_BATTLE": 0x19, - "MUSIC_ZAZABI_BATTLE": 0x1A, - "MUSIC_BOX_BATTLE": 0x1B, - "MUSIC_1C": 0x1C, - "MUSIC_1D": 0x1D, - "MUSIC_1E": 0x1E, - "MUSIC_1F": 0x1F, - "MUSIC_20": 0x20, - "MUSIC_21": 0x21, - "MUSIC_22": 0x22, - "MUSIC_23": 0x23, - "MUSIC_24": 0x24, - "MUSIC_25": 0x25, - "MUSIC_26": 0x26, - "MUSIC_27": 0x27, - "MUSIC_28": 0x28, - "MUSIC_29": 0x29, - "MUSIC_2A": 0x2A, - "MUSIC_2B": 0x2B, - "MUSIC_2C": 0x2C, - "MUSIC_2D": 0x2D, - "MUSIC_2E": 0x2E, - "MUSIC_2F": 0x2F, - "MUSIC_30": 0x30, - "MUSIC_31": 0x31, - "MUSIC_32": 0x32, - "MUSIC_OPERATIONS_DECK_ELEVATOR_OFFLINE": 0x33, - "MUSIC_OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE": 0x34, - "MUSIC_MAIN_BOILER_COOLDOWN_MISSION": 0x35, - "MUSIC_36": 0x36, - "MUSIC_37": 0x37, - "MUSIC_ORBIT_CHANGE": 0x38, - "MUSIC_39": 0x39, - "MUSIC_3A": 0x3A, - "MUSIC_OBJECTIVE_COMPLETE": 0x3B, - "MUSIC_3C": 0x3C, - "MUSIC_3D": 0x3D, - "MUSIC_3E": 0x3E, - "MUSIC_SERRIS_YAKUZA_BATTLE": 0x3F, - "MUSIC_VARIA_CORE_X_BATTLE": 0x40, - "MUSIC_NIGHTMARE_BATTLE": 0x41, - "MUSIC_NEO_RIDLEY_BATTLE": 0x42, - "MUSIC_CHOZO_STATUE_CORE_X_BATTLE": 0x43, - "MUSIC_NETTORI_BATTLE": 0x44, - "MUSIC_45": 0x45, - "MUSIC_46": 0x46, - "MUSIC_47": 0x47, - "MUSIC_48": 0x48, - "MUSIC_49": 0x49, - "MUSIC_TITLE": 0x4A, - "MUSIC_4B": 0x4B, - "MUSIC_4C": 0x4C, - "MUSIC_4D": 0x4D, - "MUSIC_4E": 0x4E, - "MUSIC_4F": 0x4F, - "MUSIC_50": 0x50, - "MUSIC_SA_X_BATTLE": 0x51, - "MUSIC_52": 0x52, - "MUSIC_53": 0x53, - "MUSIC_54": 0x54, - "MUSIC_55": 0x55, - "MUSIC_56": 0x56, - "MUSIC_57": 0x57, - "MUSIC_58": 0x58, - "MUSIC_59": 0x59, - "MUSIC_5A": 0x5A, - "MUSIC_5B": 0x5B, - "MUSIC_5C": 0x5C, - "MUSIC_5D": 0x5D, - "MUSIC_5E": 0x5E, - "MUSIC_5F": 0x5F, - "MUSIC_60": 0x60, - "MUSIC_61": 0x61, - "MUSIC_62": 0x62, - "MUSIC_63": 0x63, -} - - -def set_sounds(rom: Rom, data: MarsschemamfMusicmapping) -> None: - read_SoundheaderPtr = [] - read_TrackGroupNum1 = [] - read_TrackGroupNum2 = [] + +# In-between spaces are null values +class MusicLibrary(IntEnum): + SECTOR_1 = 0x4 + + SECTOR_2 = 0x6 + SECTOR_3 = 0x7 + SECTOR_5 = 0x8 + SECTOR_4 = 0x9 + SECTOR_6 = 0xA + NAVIGATION_ROOM = 0xB + + ITEM_FANFARE = 0x10 + + SA_X_CHASE = 0x17 + BOSS_TENSION = 0x18 + ARACHNUS_BATTLE = 0x19 + ZAZABI_BATTLE = 0x1A + BOX_BATTLE = 0x1B + + OPERATIONS_DECK_ELEVATOR_OFFLINE = 0x33 + OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE = 0x34 + MAIN_BOILER_COOLDOWN_MISSION = 0x35 + + ORBIT_CHANGE = 0x38 + + OBJECTIVE_COMPLETE = 0x3B + + SERRIS_YAKUZA_BATTLE = 0x3F + VARIA_CORE_X_BATTLE = 0x40 + NIGHTMARE_BATTLE = 0x41 + NEO_RIDLEY_BATTLE = 0x42 + CHOZO_STATUE_CORE_X_BATTLE = 0x43 + NETTORI_BATTLE = 0x44 + + TITLE = 0x4A + + SA_X_BATTLE = 0x51 + + +def set_sounds(rom: Rom, data: MarsschemamfMusicreplacement) -> None: + read_SoundData = [] # Read new data - for New in data["New"]: - read_location = sound_entries(rom) + 8 * MUSIC_LIBRARY[New] - read_SoundheaderPtr.append(rom.read_32(read_location)) - read_TrackGroupNum1.append(rom.read_16(read_location + 4)) - read_TrackGroupNum2.append(rom.read_16(read_location + 6)) + for New in data.values(): + read_location = sound_entries(rom) + 8 * MusicLibrary[New].value + read_SoundData.append(rom.read_bytes(read_location, 8)) # Write to rom - for Original, SoundHdrPtr, TrackGrpNum1, TrackGrpNum2 in zip( - data["Original"], read_SoundheaderPtr, read_TrackGroupNum1, read_TrackGroupNum2 - ): - write_location = sound_entries(rom) + 8 * MUSIC_LIBRARY[Original] - rom.write_32(write_location, SoundHdrPtr) - rom.write_16(write_location + 4, TrackGrpNum1) - rom.write_16(write_location + 6, TrackGrpNum2) + for Original, SoundDatum in zip(data.keys(), read_SoundData): + write_location = sound_entries(rom) + 8 * MusicLibrary[Original].value + rom.write_bytes(write_location, SoundDatum) diff --git a/src/mars_patcher/mf/patcher.py b/src/mars_patcher/mf/patcher.py index 8fe17ea..a77bd45 100644 --- a/src/mars_patcher/mf/patcher.py +++ b/src/mars_patcher/mf/patcher.py @@ -82,9 +82,9 @@ def patch_mf( set_required_metroid_count(rom, patch_data["RequiredMetroidCount"]) # Music - if "MusicMapping" in patch_data: + if "MusicReplacement" in patch_data: status_update("Writing music...", -1) - set_sounds(rom, patch_data["MusicMapping"]) + set_sounds(rom, patch_data["MusicReplacement"]) # Starting location if "StartingLocation" in patch_data: From d4cf6c722dab10466dacb6c3498e32cf580bdd08 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Sat, 7 Feb 2026 18:15:06 +0000 Subject: [PATCH 07/13] used sound_data_entries from non-mf specific constants and copied over to zm --- src/mars_patcher/mf/constants/game_data.py | 16 -- src/mars_patcher/mf/music.py | 6 +- src/mars_patcher/zm/auto_generated_types.py | 257 +++++++++++++++++++ src/mars_patcher/zm/data/schema.json | 260 ++++++++++++++++++++ src/mars_patcher/zm/music.py | 91 +++++++ src/mars_patcher/zm/patcher.py | 6 + 6 files changed, 617 insertions(+), 19 deletions(-) create mode 100644 src/mars_patcher/zm/music.py diff --git a/src/mars_patcher/mf/constants/game_data.py b/src/mars_patcher/mf/constants/game_data.py index f2a14c3..d6698fc 100644 --- a/src/mars_patcher/mf/constants/game_data.py +++ b/src/mars_patcher/mf/constants/game_data.py @@ -41,22 +41,6 @@ def starting_equipment(rom: Rom) -> int: raise ValueError(rom.region) -def sound_entries(rom: Rom) -> int: - """Returns the address of music and sound data.""" - if rom.game != Game.MF: - raise ValueError(rom.game) - if rom.region == Region.U: - return 0xA8D3C - elif rom.region == Region.E: - return 0xA9398 - elif rom.region == Region.J: - return 0xAB0A0 - elif rom.region == Region.C: - return 0xAB0E4 - else: - raise ValueError(rom.region) - - def sprite_vram_sizes(rom: Rom) -> int: """Returns the address of the sprite VRAM sizes.""" if rom.game != Game.MF: diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/music.py index 0765ede..bbd5fa4 100644 --- a/src/mars_patcher/mf/music.py +++ b/src/mars_patcher/mf/music.py @@ -1,7 +1,7 @@ from enum import IntEnum +from mars_patcher.constants.game_data import sound_data_entries from mars_patcher.mf.auto_generated_types import MarsschemamfMusicreplacement -from mars_patcher.mf.constants.game_data import sound_entries from mars_patcher.rom import Rom @@ -49,10 +49,10 @@ def set_sounds(rom: Rom, data: MarsschemamfMusicreplacement) -> None: # Read new data for New in data.values(): - read_location = sound_entries(rom) + 8 * MusicLibrary[New].value + read_location = sound_data_entries(rom) + 8 * MusicLibrary[New].value read_SoundData.append(rom.read_bytes(read_location, 8)) # Write to rom for Original, SoundDatum in zip(data.keys(), read_SoundData): - write_location = sound_entries(rom) + 8 * MusicLibrary[Original].value + write_location = sound_data_entries(rom) + 8 * MusicLibrary[Original].value rom.write_bytes(write_location, SoundDatum) diff --git a/src/mars_patcher/zm/auto_generated_types.py b/src/mars_patcher/zm/auto_generated_types.py index b9b8e50..0d474ba 100644 --- a/src/mars_patcher/zm/auto_generated_types.py +++ b/src/mars_patcher/zm/auto_generated_types.py @@ -145,6 +145,70 @@ 'ITALIAN', 'SPANISH' ] +Validmusictracks = typ.Literal[ + 'BRINSTAR', + 'TITLE_SCREEN', + 'SAVE_ELEVATOR_ROOM', + 'INTRO', + 'CHOZO_STATUE_HINT', + 'NORFAIR', + 'KRAID', + 'ESCAPE', + 'FILE_SELECT', + 'STATUE_ROOM', + 'BOSS_KILLED', + 'MAP_ROOM', + 'CHOZO_RUINS_DEPTH', + 'CHOZO_RUINS', + 'CHOZO_RUINS_LIGHT', + 'RIDLEY_IN_SPACE', + 'RIDLEY_LANDING', + 'CHOZO_STATUE_HINT_DELAY', + 'GETTING_FULLY_POWERED_SUIT_CUTSCENE', + 'ESCAPING_ZEBES_CUTSCENE', + 'CHOZO_VOICE_1', + 'CHOZO_VOICE_2', + 'BEFORE_RUINS_TEST_UNUSED', + 'ELEVATOR_ROOM', + 'BRINSTAR_REMIX', + 'ESCAPE_SUCCESFUL', + 'CREDITS', + 'STATUE_ROOM_OPENED', + 'RIDLEY', + 'KRAID_BATTLE_WITH_INTRO', + 'RIDLEY_BATTLE', + 'LOADING_JINGLE', + 'GETTING_ITEM_JINGLE', + 'INTRO_MOTHER_BRAIN', + 'GETTING_TANK_JINGLE', + 'TOURIAN', + 'WORMS_BATTLE', + 'MOTHER_BRAIN_BATTLE', + 'CATTERPILLARS_BATTLE', + 'IMAGO_COCOON_BATTLE', + 'IMAGO_BATTLE', + 'MECHA_RIDLEY_BATTLE', + 'GETTING_UNKNOWN_ITEM_JINGLE', + 'RUINS_TEST_BATTLE_WITH_INTRO', + 'ENTERING_TOURIAN_CUTSCENE', + 'ALARM_ACTIVATED', + 'STEALTH', + 'ENTERING_NORFAIR_CUTSCENE', + 'CHOZODIA_DETECTED', + 'GETTING_FULLY_POWERED_SUIT_JINGLE', + 'KRAID_BATTLE', + 'RIDLEY_BATTLE_2', + 'MECHA_RIDLEY_BATTLE_2', + 'RUINS_TEST_BATTLE', + 'CATTERPILLARS_BATTLE_2', + 'CRATERIA', + 'GAME_OVER', + 'CHOZODIA_SURFACE', + 'MAP_ROOM_2', + 'SAVE_ELEVATOR_ROOM_2', + 'BEFORE_RUINS_TEST_ROOM', + 'STEALTH_2' +] MessageLanguages: typ.TypeAlias = dict[ValidLanguages, str] class ItemMessages(typ.TypedDict, total=False): @@ -377,6 +441,196 @@ class MarsschemazmPalettes(typ.TypedDict, total=False): """Randomly rotates hues in the positive or negative direction true.""" +class MarsschemazmMusicreplacement(typ.TypedDict, total=False): + """Shuffles the in-game music.""" + + BRINSTAR: Validmusictracks + """Valid music tracks supported by the game.""" + + TITLE_SCREEN: Validmusictracks + """Valid music tracks supported by the game.""" + + SAVE_ELEVATOR_ROOM: Validmusictracks + """Valid music tracks supported by the game.""" + + INTRO: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_STATUE_HINT: Validmusictracks + """Valid music tracks supported by the game.""" + + NORFAIR: Validmusictracks + """Valid music tracks supported by the game.""" + + KRAID: Validmusictracks + """Valid music tracks supported by the game.""" + + ESCAPE: Validmusictracks + """Valid music tracks supported by the game.""" + + FILE_SELECT: Validmusictracks + """Valid music tracks supported by the game.""" + + STATUE_ROOM: Validmusictracks + """Valid music tracks supported by the game.""" + + BOSS_KILLED: Validmusictracks + """Valid music tracks supported by the game.""" + + MAP_ROOM: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_RUINS_DEPTH: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_RUINS: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_RUINS_LIGHT: Validmusictracks + """Valid music tracks supported by the game.""" + + RIDLEY_IN_SPACE: Validmusictracks + """Valid music tracks supported by the game.""" + + RIDLEY_LANDING: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_STATUE_HINT_DELAY: Validmusictracks + """Valid music tracks supported by the game.""" + + GETTING_FULLY_POWERED_SUIT_CUTSCENE: Validmusictracks + """Valid music tracks supported by the game.""" + + ESCAPING_ZEBES_CUTSCENE: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_VOICE_1: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZO_VOICE_2: Validmusictracks + """Valid music tracks supported by the game.""" + + BEFORE_RUINS_TEST_UNUSED: Validmusictracks + """Valid music tracks supported by the game.""" + + ELEVATOR_ROOM: Validmusictracks + """Valid music tracks supported by the game.""" + + BRINSTAR_REMIX: Validmusictracks + """Valid music tracks supported by the game.""" + + ESCAPE_SUCCESFUL: Validmusictracks + """Valid music tracks supported by the game.""" + + CREDITS: Validmusictracks + """Valid music tracks supported by the game.""" + + STATUE_ROOM_OPENED: Validmusictracks + """Valid music tracks supported by the game.""" + + RIDLEY: Validmusictracks + """Valid music tracks supported by the game.""" + + KRAID_BATTLE_WITH_INTRO: Validmusictracks + """Valid music tracks supported by the game.""" + + RIDLEY_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + LOADING_JINGLE: Validmusictracks + """Valid music tracks supported by the game.""" + + GETTING_ITEM_JINGLE: Validmusictracks + """Valid music tracks supported by the game.""" + + INTRO_MOTHER_BRAIN: Validmusictracks + """Valid music tracks supported by the game.""" + + GETTING_TANK_JINGLE: Validmusictracks + """Valid music tracks supported by the game.""" + + TOURIAN: Validmusictracks + """Valid music tracks supported by the game.""" + + WORMS_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + MOTHER_BRAIN_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + CATTERPILLARS_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + IMAGO_COCOON_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + IMAGO_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + MECHA_RIDLEY_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + GETTING_UNKNOWN_ITEM_JINGLE: Validmusictracks + """Valid music tracks supported by the game.""" + + RUINS_TEST_BATTLE_WITH_INTRO: Validmusictracks + """Valid music tracks supported by the game.""" + + ENTERING_TOURIAN_CUTSCENE: Validmusictracks + """Valid music tracks supported by the game.""" + + ALARM_ACTIVATED: Validmusictracks + """Valid music tracks supported by the game.""" + + STEALTH: Validmusictracks + """Valid music tracks supported by the game.""" + + ENTERING_NORFAIR_CUTSCENE: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZODIA_DETECTED: Validmusictracks + """Valid music tracks supported by the game.""" + + GETTING_FULLY_POWERED_SUIT_JINGLE: Validmusictracks + """Valid music tracks supported by the game.""" + + KRAID_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + RIDLEY_BATTLE_2: Validmusictracks + """Valid music tracks supported by the game.""" + + MECHA_RIDLEY_BATTLE_2: Validmusictracks + """Valid music tracks supported by the game.""" + + RUINS_TEST_BATTLE: Validmusictracks + """Valid music tracks supported by the game.""" + + CATTERPILLARS_BATTLE_2: Validmusictracks + """Valid music tracks supported by the game.""" + + CRATERIA: Validmusictracks + """Valid music tracks supported by the game.""" + + GAME_OVER: Validmusictracks + """Valid music tracks supported by the game.""" + + CHOZODIA_SURFACE: Validmusictracks + """Valid music tracks supported by the game.""" + + MAP_ROOM_2: Validmusictracks + """Valid music tracks supported by the game.""" + + SAVE_ELEVATOR_ROOM_2: Validmusictracks + """Valid music tracks supported by the game.""" + + BEFORE_RUINS_TEST_ROOM: Validmusictracks + """Valid music tracks supported by the game.""" + + STEALTH_2: Validmusictracks + """Valid music tracks supported by the game.""" + + class MarsschemazmTitleTextItem(typ.TypedDict, total=False): text: typ.Annotated[str, '/^[ -~]{0,30}$/'] """The ASCII text for this line""" @@ -482,6 +736,9 @@ class Marsschemazm(typ.TypedDict, total=False): palettes: MarsschemazmPalettes = None """Properties for randomized in-game palettes.""" + MusicReplacement: MarsschemazmMusicreplacement + """Shuffles the in-game music.""" + intro_text: dict[ValidLanguages, str] = None """Specifies what text should appear during the new game intro.""" diff --git a/src/mars_patcher/zm/data/schema.json b/src/mars_patcher/zm/data/schema.json index adb6547..b5aee9d 100644 --- a/src/mars_patcher/zm/data/schema.json +++ b/src/mars_patcher/zm/data/schema.json @@ -367,6 +367,198 @@ ], "default": null }, + "MusicReplacement": { + "description": "Shuffles the in-game music.", + "type": "object", + "properties": { + "BRINSTAR": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "TITLE_SCREEN": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SAVE_ELEVATOR_ROOM": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "INTRO": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_STATUE_HINT": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "NORFAIR": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "KRAID": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ESCAPE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "FILE_SELECT": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "STATUE_ROOM": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "BOSS_KILLED": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "MAP_ROOM": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_RUINS_DEPTH": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_RUINS": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_RUINS_LIGHT": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "RIDLEY_IN_SPACE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "RIDLEY_LANDING": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_STATUE_HINT_DELAY": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "GETTING_FULLY_POWERED_SUIT_CUTSCENE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ESCAPING_ZEBES_CUTSCENE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_VOICE_1": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZO_VOICE_2": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "BEFORE_RUINS_TEST_UNUSED": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ELEVATOR_ROOM": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "BRINSTAR_REMIX": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ESCAPE_SUCCESFUL": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CREDITS": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "STATUE_ROOM_OPENED": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "RIDLEY": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "KRAID_BATTLE_WITH_INTRO": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "RIDLEY_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "LOADING_JINGLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "GETTING_ITEM_JINGLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "INTRO_MOTHER_BRAIN": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "GETTING_TANK_JINGLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "TOURIAN": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "WORMS_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "MOTHER_BRAIN_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CATTERPILLARS_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "IMAGO_COCOON_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "IMAGO_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "MECHA_RIDLEY_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "GETTING_UNKNOWN_ITEM_JINGLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "RUINS_TEST_BATTLE_WITH_INTRO": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ENTERING_TOURIAN_CUTSCENE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ALARM_ACTIVATED": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "STEALTH": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "ENTERING_NORFAIR_CUTSCENE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZODIA_DETECTED": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "GETTING_FULLY_POWERED_SUIT_JINGLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "KRAID_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "RIDLEY_BATTLE_2": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "MECHA_RIDLEY_BATTLE_2": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "RUINS_TEST_BATTLE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CATTERPILLARS_BATTLE_2": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CRATERIA": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "GAME_OVER": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "CHOZODIA_SURFACE": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "MAP_ROOM_2": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "SAVE_ELEVATOR_ROOM_2": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "BEFORE_RUINS_TEST_ROOM": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "STEALTH_2": { + "$ref": "#/$defs/ValidMusicTracks" + } + } + }, "intro_text": { "type": "object", "description": "Specifies what text should appear during the new game intro.", @@ -785,6 +977,74 @@ "SPANISH" ] }, + "ValidMusicTracks": { + "type": "string", + "description": "Valid music tracks supported by the game.", + "enum": [ + "BRINSTAR", + "TITLE_SCREEN", + "SAVE_ELEVATOR_ROOM", + "INTRO", + "CHOZO_STATUE_HINT", + "NORFAIR", + "KRAID", + "ESCAPE", + "FILE_SELECT", + "STATUE_ROOM", + "BOSS_KILLED", + "MAP_ROOM", + "CHOZO_RUINS_DEPTH", + "CHOZO_RUINS", + "CHOZO_RUINS_LIGHT", + "RIDLEY_IN_SPACE", + "RIDLEY_LANDING", + "CHOZO_STATUE_HINT_DELAY", + "GETTING_FULLY_POWERED_SUIT_CUTSCENE", + "ESCAPING_ZEBES_CUTSCENE", + "CHOZO_VOICE_1", + "CHOZO_VOICE_2", + "BEFORE_RUINS_TEST_UNUSED", + "ELEVATOR_ROOM", + "BRINSTAR_REMIX", + "ESCAPE_SUCCESFUL", + "CREDITS", + "STATUE_ROOM_OPENED", + "RIDLEY", + "KRAID_BATTLE_WITH_INTRO", + "RIDLEY_BATTLE", + "LOADING_JINGLE", + "GETTING_ITEM_JINGLE", + "INTRO_MOTHER_BRAIN", + "GETTING_TANK_JINGLE", + "TOURIAN", + "WORMS_BATTLE", + "MOTHER_BRAIN_BATTLE", + "CATTERPILLARS_BATTLE", + "IMAGO_COCOON_BATTLE", + "IMAGO_BATTLE", + "MECHA_RIDLEY_BATTLE", + "GETTING_UNKNOWN_ITEM_JINGLE", + "RUINS_TEST_BATTLE_WITH_INTRO", + "ENTERING_TOURIAN_CUTSCENE", + "ALARM_ACTIVATED", + "STEALTH", + "ENTERING_NORFAIR_CUTSCENE", + "CHOZODIA_DETECTED", + "GETTING_FULLY_POWERED_SUIT_JINGLE", + "KRAID_BATTLE", + "RIDLEY_BATTLE_2", + "MECHA_RIDLEY_BATTLE_2", + "RUINS_TEST_BATTLE", + "CATTERPILLARS_BATTLE_2", + "CRATERIA", + "GAME_OVER", + "CHOZODIA_SURFACE", + "MAP_ROOM_2", + "SAVE_ELEVATOR_ROOM_2", + "BEFORE_RUINS_TEST_ROOM", + "STEALTH_2" + ] + }, "message_languages": { "type": "object", "propertyNames": { diff --git a/src/mars_patcher/zm/music.py b/src/mars_patcher/zm/music.py new file mode 100644 index 0000000..ec24960 --- /dev/null +++ b/src/mars_patcher/zm/music.py @@ -0,0 +1,91 @@ +from enum import IntEnum + +from mars_patcher.constants.game_data import sound_data_entries +from mars_patcher.rom import Rom +from mars_patcher.zm.auto_generated_types import MarsschemazmMusicreplacement + + +# In-between spaces are null values +class MusicLibrary(IntEnum): + BRINSTAR = 0x1 + TITLE_SCREEN = 0x2 + SAVE_ELEVATOR_ROOM = 0x3 + INTRO = 0x4 + CHOZO_STATUE_HINT = 0x5 + NORFAIR = 0x6 + KRAID = 0x7 + ESCAPE = 0x8 + FILE_SELECT = 0x9 + STATUE_ROOM = 0xA + BOSS_KILLED = 0xB + MAP_ROOM = 0xC + CHOZO_RUINS_DEPTH = 0xD + CHOZO_RUINS = 0xE + CHOZO_RUINS_LIGHT = 0xF + RIDLEY_IN_SPACE = 0x10 + RIDLEY_LANDING = 0x11 + CHOZO_STATUE_HINT_DELAY = 0x12 + GETTING_FULLY_POWERED_SUIT_CUTSCENE = 0x13 + ESCAPING_ZEBES_CUTSCENE = 0x14 + CHOZO_VOICE_1 = 0x15 + CHOZO_VOICE_2 = 0x16 + BEFORE_RUINS_TEST_UNUSED = 0x17 + ELEVATOR_ROOM = 0x18 + BRINSTAR_REMIX = 0x19 + ESCAPE_SUCCESFUL = 0x1A + CREDITS = 0x1B + STATUE_ROOM_OPENED = 0x1C + + RIDLEY = 0x32 + + KRAID_BATTLE_WITH_INTRO = 0x34 + RIDLEY_BATTLE = 0x35 + LOADING_JINGLE = 0x36 + GETTING_ITEM_JINGLE = 0x37 + + INTRO_MOTHER_BRAIN = 0x39 + GETTING_TANK_JINGLE = 0x3A + TOURIAN = 0x3B + WORMS_BATTLE = 0x3C + MOTHER_BRAIN_BATTLE = 0x3D + CATTERPILLARS_BATTLE = 0x3E + IMAGO_COCOON_BATTLE = 0x3F + IMAGO_BATTLE = 0x40 + MECHA_RIDLEY_BATTLE = 0x41 + GETTING_UNKNOWN_ITEM_JINGLE = 0x42 + RUINS_TEST_BATTLE_WITH_INTRO = 0x43 + ENTERING_TOURIAN_CUTSCENE = 0x44 + ALARM_ACTIVATED = 0x45 + STEALTH = 0x46 + + ENTERING_NORFAIR_CUTSCENE = 0x48 + CHOZODIA_DETECTED = 0x49 + GETTING_FULLY_POWERED_SUIT_JINGLE = 0x4A + KRAID_BATTLE = 0x4B + RIDLEY_BATTLE_2 = 0x4C + MECHA_RIDLEY_BATTLE_2 = 0x4D + RUINS_TEST_BATTLE = 0x4E + CATTERPILLARS_BATTLE_2 = 0x4F + CRATERIA = 0x50 + + GAME_OVER = 0x53 + + CHOZODIA_SURFACE = 0x5A + MAP_ROOM_2 = 0x5B + SAVE_ELEVATOR_ROOM_2 = 0x5C + BEFORE_RUINS_TEST_ROOM = 0x5D + STEALTH_2 = 0x5E + + +def set_sounds(rom: Rom, data: MarsschemazmMusicreplacement) -> None: + read_SoundData = [] + + # Read new data + for New in data.values(): + read_location = sound_data_entries(rom) + 8 * MusicLibrary[New].value + read_SoundData.append(rom.read_bytes(read_location, 8)) + + # Write to rom + for Original, SoundDatum in zip(data.keys(), read_SoundData): + write_location = sound_data_entries(rom) + 8 * MusicLibrary[Original].value + rom.write_bytes(write_location, SoundDatum) diff --git a/src/mars_patcher/zm/patcher.py b/src/mars_patcher/zm/patcher.py index e41a0b1..a4acc08 100644 --- a/src/mars_patcher/zm/patcher.py +++ b/src/mars_patcher/zm/patcher.py @@ -6,6 +6,7 @@ from mars_patcher.zm.constants.game_data import skip_door_transitions_addr from mars_patcher.zm.item_patcher import ItemPatcher, set_tank_increments from mars_patcher.zm.locations import LocationSettings +from mars_patcher.zm.music import set_sounds def patch_zm( @@ -55,6 +56,11 @@ def patch_zm( # status_update("Writing starting items...", -1) # set_starting_items(rom, patch_data["StartingItems"]) + # Music + if "MusicReplacement" in patch_data: + status_update("Writing music...", -1) + set_sounds(rom, patch_data["MusicReplacement"]) + # Tank increments if "tank_increments" in patch_data: status_update("Writing tank increments...", -1) From b7b6b363ddba5168d78f9c0a15acb696592e77e9 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Tue, 17 Feb 2026 22:55:25 +0000 Subject: [PATCH 08/13] snake cases and validmusictracks --- src/mars_patcher/mf/auto_generated_types.py | 84 +------ src/mars_patcher/mf/data/schema.json | 84 +------ src/mars_patcher/mf/music.py | 21 +- src/mars_patcher/zm/auto_generated_types.py | 192 +--------------- src/mars_patcher/zm/data/schema.json | 233 ++++---------------- src/mars_patcher/zm/music.py | 18 +- 6 files changed, 65 insertions(+), 567 deletions(-) diff --git a/src/mars_patcher/mf/auto_generated_types.py b/src/mars_patcher/mf/auto_generated_types.py index 310ab2e..ee86a51 100644 --- a/src/mars_patcher/mf/auto_generated_types.py +++ b/src/mars_patcher/mf/auto_generated_types.py @@ -258,88 +258,6 @@ class BlocklayerItem(typ.TypedDict, total=False): # Schema entries -class MarsschemamfMusicreplacement(typ.TypedDict, total=False): - """Shuffles the in-game music.""" - - SECTOR_1: Validmusictracks - """Valid music tracks supported by the game.""" - - SECTOR_2: Validmusictracks - """Valid music tracks supported by the game.""" - - SECTOR_3: Validmusictracks - """Valid music tracks supported by the game.""" - - SECTOR_5: Validmusictracks - """Valid music tracks supported by the game.""" - - SECTOR_4: Validmusictracks - """Valid music tracks supported by the game.""" - - SECTOR_6: Validmusictracks - """Valid music tracks supported by the game.""" - - NAVIGATION_ROOM: Validmusictracks - """Valid music tracks supported by the game.""" - - ITEM_FANFARE: Validmusictracks - """Valid music tracks supported by the game.""" - - SA_X_CHASE: Validmusictracks - """Valid music tracks supported by the game.""" - - BOSS_TENSION: Validmusictracks - """Valid music tracks supported by the game.""" - - ARACHNUS_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - ZAZABI_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - BOX_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - OPERATIONS_DECK_ELEVATOR_OFFLINE: Validmusictracks - """Valid music tracks supported by the game.""" - - OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE: Validmusictracks - """Valid music tracks supported by the game.""" - - MAIN_BOILER_COOLDOWN_MISSION: Validmusictracks - """Valid music tracks supported by the game.""" - - ORBIT_CHANGE: Validmusictracks - """Valid music tracks supported by the game.""" - - OBJECTIVE_COMPLETE: Validmusictracks - """Valid music tracks supported by the game.""" - - SERRIS_YAKUZA_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - VARIA_CORE_X_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - NIGHTMARE_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - NEO_RIDLEY_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_STATUE_CORE_X_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - NETTORI_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - TITLE: Validmusictracks - """Valid music tracks supported by the game.""" - - SA_X_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - class MarsschemamfLocationsMajorlocationsItem(typ.TypedDict): Source: Validsources """Valid major locations.""" @@ -682,7 +600,7 @@ class Marsschemamf(typ.TypedDict, total=False): SeedHash: typ.Required[typ.Annotated[str, '/^[0-9A-Z]{8}$/']] """A seed hash that will be displayed on the file select screen.""" - MusicReplacement: MarsschemamfMusicreplacement + MusicReplacement: dict[Validmusictracks, Validmusictracks] """Shuffles the in-game music.""" Locations: typ.Required[MarsschemamfLocations] diff --git a/src/mars_patcher/mf/data/schema.json b/src/mars_patcher/mf/data/schema.json index 85945e9..770cd40 100644 --- a/src/mars_patcher/mf/data/schema.json +++ b/src/mars_patcher/mf/data/schema.json @@ -12,85 +12,11 @@ "MusicReplacement": { "description": "Shuffles the in-game music.", "type": "object", - "properties": { - "SECTOR_1": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SECTOR_2": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SECTOR_3": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SECTOR_5": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SECTOR_4": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SECTOR_6": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "NAVIGATION_ROOM": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ITEM_FANFARE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SA_X_CHASE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "BOSS_TENSION": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ARACHNUS_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ZAZABI_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "BOX_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "OPERATIONS_DECK_ELEVATOR_OFFLINE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "MAIN_BOILER_COOLDOWN_MISSION": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ORBIT_CHANGE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "OBJECTIVE_COMPLETE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SERRIS_YAKUZA_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "VARIA_CORE_X_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "NIGHTMARE_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "NEO_RIDLEY_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_STATUE_CORE_X_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "NETTORI_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "TITLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SA_X_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - } + "propertyNames": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "additionalProperties": { + "$ref": "#/$defs/ValidMusicTracks" } }, "Locations": { diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/music.py index bbd5fa4..b38baf0 100644 --- a/src/mars_patcher/mf/music.py +++ b/src/mars_patcher/mf/music.py @@ -1,7 +1,7 @@ from enum import IntEnum from mars_patcher.constants.game_data import sound_data_entries -from mars_patcher.mf.auto_generated_types import MarsschemamfMusicreplacement +from mars_patcher.mf.auto_generated_types import Validmusictracks from mars_patcher.rom import Rom @@ -44,15 +44,18 @@ class MusicLibrary(IntEnum): SA_X_BATTLE = 0x51 -def set_sounds(rom: Rom, data: MarsschemamfMusicreplacement) -> None: - read_SoundData = [] +SOUND_SIZE = 8 + + +def set_sounds(rom: Rom, data: dict[Validmusictracks, Validmusictracks]) -> None: + read_data_entries = [] # Read new data - for New in data.values(): - read_location = sound_data_entries(rom) + 8 * MusicLibrary[New].value - read_SoundData.append(rom.read_bytes(read_location, 8)) + for new in data.values(): + read_location = sound_data_entries(rom) + SOUND_SIZE * MusicLibrary[new].value + read_data_entries.append(rom.read_bytes(read_location, SOUND_SIZE)) # Write to rom - for Original, SoundDatum in zip(data.keys(), read_SoundData): - write_location = sound_data_entries(rom) + 8 * MusicLibrary[Original].value - rom.write_bytes(write_location, SoundDatum) + for original, sound_datum in zip(data.keys(), read_data_entries): + write_location = sound_data_entries(rom) + SOUND_SIZE * MusicLibrary[original].value + rom.write_bytes(write_location, sound_datum) diff --git a/src/mars_patcher/zm/auto_generated_types.py b/src/mars_patcher/zm/auto_generated_types.py index 0d474ba..772346b 100644 --- a/src/mars_patcher/zm/auto_generated_types.py +++ b/src/mars_patcher/zm/auto_generated_types.py @@ -441,196 +441,6 @@ class MarsschemazmPalettes(typ.TypedDict, total=False): """Randomly rotates hues in the positive or negative direction true.""" -class MarsschemazmMusicreplacement(typ.TypedDict, total=False): - """Shuffles the in-game music.""" - - BRINSTAR: Validmusictracks - """Valid music tracks supported by the game.""" - - TITLE_SCREEN: Validmusictracks - """Valid music tracks supported by the game.""" - - SAVE_ELEVATOR_ROOM: Validmusictracks - """Valid music tracks supported by the game.""" - - INTRO: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_STATUE_HINT: Validmusictracks - """Valid music tracks supported by the game.""" - - NORFAIR: Validmusictracks - """Valid music tracks supported by the game.""" - - KRAID: Validmusictracks - """Valid music tracks supported by the game.""" - - ESCAPE: Validmusictracks - """Valid music tracks supported by the game.""" - - FILE_SELECT: Validmusictracks - """Valid music tracks supported by the game.""" - - STATUE_ROOM: Validmusictracks - """Valid music tracks supported by the game.""" - - BOSS_KILLED: Validmusictracks - """Valid music tracks supported by the game.""" - - MAP_ROOM: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_RUINS_DEPTH: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_RUINS: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_RUINS_LIGHT: Validmusictracks - """Valid music tracks supported by the game.""" - - RIDLEY_IN_SPACE: Validmusictracks - """Valid music tracks supported by the game.""" - - RIDLEY_LANDING: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_STATUE_HINT_DELAY: Validmusictracks - """Valid music tracks supported by the game.""" - - GETTING_FULLY_POWERED_SUIT_CUTSCENE: Validmusictracks - """Valid music tracks supported by the game.""" - - ESCAPING_ZEBES_CUTSCENE: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_VOICE_1: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZO_VOICE_2: Validmusictracks - """Valid music tracks supported by the game.""" - - BEFORE_RUINS_TEST_UNUSED: Validmusictracks - """Valid music tracks supported by the game.""" - - ELEVATOR_ROOM: Validmusictracks - """Valid music tracks supported by the game.""" - - BRINSTAR_REMIX: Validmusictracks - """Valid music tracks supported by the game.""" - - ESCAPE_SUCCESFUL: Validmusictracks - """Valid music tracks supported by the game.""" - - CREDITS: Validmusictracks - """Valid music tracks supported by the game.""" - - STATUE_ROOM_OPENED: Validmusictracks - """Valid music tracks supported by the game.""" - - RIDLEY: Validmusictracks - """Valid music tracks supported by the game.""" - - KRAID_BATTLE_WITH_INTRO: Validmusictracks - """Valid music tracks supported by the game.""" - - RIDLEY_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - LOADING_JINGLE: Validmusictracks - """Valid music tracks supported by the game.""" - - GETTING_ITEM_JINGLE: Validmusictracks - """Valid music tracks supported by the game.""" - - INTRO_MOTHER_BRAIN: Validmusictracks - """Valid music tracks supported by the game.""" - - GETTING_TANK_JINGLE: Validmusictracks - """Valid music tracks supported by the game.""" - - TOURIAN: Validmusictracks - """Valid music tracks supported by the game.""" - - WORMS_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - MOTHER_BRAIN_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - CATTERPILLARS_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - IMAGO_COCOON_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - IMAGO_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - MECHA_RIDLEY_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - GETTING_UNKNOWN_ITEM_JINGLE: Validmusictracks - """Valid music tracks supported by the game.""" - - RUINS_TEST_BATTLE_WITH_INTRO: Validmusictracks - """Valid music tracks supported by the game.""" - - ENTERING_TOURIAN_CUTSCENE: Validmusictracks - """Valid music tracks supported by the game.""" - - ALARM_ACTIVATED: Validmusictracks - """Valid music tracks supported by the game.""" - - STEALTH: Validmusictracks - """Valid music tracks supported by the game.""" - - ENTERING_NORFAIR_CUTSCENE: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZODIA_DETECTED: Validmusictracks - """Valid music tracks supported by the game.""" - - GETTING_FULLY_POWERED_SUIT_JINGLE: Validmusictracks - """Valid music tracks supported by the game.""" - - KRAID_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - RIDLEY_BATTLE_2: Validmusictracks - """Valid music tracks supported by the game.""" - - MECHA_RIDLEY_BATTLE_2: Validmusictracks - """Valid music tracks supported by the game.""" - - RUINS_TEST_BATTLE: Validmusictracks - """Valid music tracks supported by the game.""" - - CATTERPILLARS_BATTLE_2: Validmusictracks - """Valid music tracks supported by the game.""" - - CRATERIA: Validmusictracks - """Valid music tracks supported by the game.""" - - GAME_OVER: Validmusictracks - """Valid music tracks supported by the game.""" - - CHOZODIA_SURFACE: Validmusictracks - """Valid music tracks supported by the game.""" - - MAP_ROOM_2: Validmusictracks - """Valid music tracks supported by the game.""" - - SAVE_ELEVATOR_ROOM_2: Validmusictracks - """Valid music tracks supported by the game.""" - - BEFORE_RUINS_TEST_ROOM: Validmusictracks - """Valid music tracks supported by the game.""" - - STEALTH_2: Validmusictracks - """Valid music tracks supported by the game.""" - - class MarsschemazmTitleTextItem(typ.TypedDict, total=False): text: typ.Annotated[str, '/^[ -~]{0,30}$/'] """The ASCII text for this line""" @@ -736,7 +546,7 @@ class Marsschemazm(typ.TypedDict, total=False): palettes: MarsschemazmPalettes = None """Properties for randomized in-game palettes.""" - MusicReplacement: MarsschemazmMusicreplacement + MusicReplacement: dict[Validmusictracks, Validmusictracks] """Shuffles the in-game music.""" intro_text: dict[ValidLanguages, str] = None diff --git a/src/mars_patcher/zm/data/schema.json b/src/mars_patcher/zm/data/schema.json index b5aee9d..8b9bead 100644 --- a/src/mars_patcher/zm/data/schema.json +++ b/src/mars_patcher/zm/data/schema.json @@ -370,193 +370,11 @@ "MusicReplacement": { "description": "Shuffles the in-game music.", "type": "object", - "properties": { - "BRINSTAR": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "TITLE_SCREEN": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SAVE_ELEVATOR_ROOM": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "INTRO": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_STATUE_HINT": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "NORFAIR": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "KRAID": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ESCAPE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "FILE_SELECT": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "STATUE_ROOM": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "BOSS_KILLED": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "MAP_ROOM": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_RUINS_DEPTH": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_RUINS": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_RUINS_LIGHT": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "RIDLEY_IN_SPACE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "RIDLEY_LANDING": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_STATUE_HINT_DELAY": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "GETTING_FULLY_POWERED_SUIT_CUTSCENE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ESCAPING_ZEBES_CUTSCENE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_VOICE_1": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZO_VOICE_2": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "BEFORE_RUINS_TEST_UNUSED": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ELEVATOR_ROOM": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "BRINSTAR_REMIX": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ESCAPE_SUCCESFUL": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CREDITS": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "STATUE_ROOM_OPENED": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "RIDLEY": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "KRAID_BATTLE_WITH_INTRO": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "RIDLEY_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "LOADING_JINGLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "GETTING_ITEM_JINGLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "INTRO_MOTHER_BRAIN": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "GETTING_TANK_JINGLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "TOURIAN": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "WORMS_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "MOTHER_BRAIN_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CATTERPILLARS_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "IMAGO_COCOON_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "IMAGO_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "MECHA_RIDLEY_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "GETTING_UNKNOWN_ITEM_JINGLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "RUINS_TEST_BATTLE_WITH_INTRO": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ENTERING_TOURIAN_CUTSCENE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ALARM_ACTIVATED": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "STEALTH": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "ENTERING_NORFAIR_CUTSCENE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZODIA_DETECTED": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "GETTING_FULLY_POWERED_SUIT_JINGLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "KRAID_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "RIDLEY_BATTLE_2": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "MECHA_RIDLEY_BATTLE_2": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "RUINS_TEST_BATTLE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CATTERPILLARS_BATTLE_2": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CRATERIA": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "GAME_OVER": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "CHOZODIA_SURFACE": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "MAP_ROOM_2": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "SAVE_ELEVATOR_ROOM_2": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "BEFORE_RUINS_TEST_ROOM": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "STEALTH_2": { - "$ref": "#/$defs/ValidMusicTracks" - } + "propertyNames": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "additionalProperties": { + "$ref": "#/$defs/ValidMusicTracks" } }, "intro_text": { @@ -764,7 +582,11 @@ "maxLength": 112 } }, - "required": ["area", "room", "name"] + "required": [ + "area", + "room", + "name" + ] } }, "reveal_hidden_tiles": { @@ -1050,7 +872,9 @@ "propertyNames": { "$ref": "#/$defs/valid_languages" }, - "required": ["ENGLISH"], + "required": [ + "ENGLISH" + ], "additionalProperties": { "type": "string", "description": "Specifies what text should appear for a 2 line message. Text will auto-wrap if the next word doesn't fit on the line. If the text is too long, it will be truncated. Use \n to force a line break. If not provided, a message based on the Item will be shown. If a language is not provided, it will use the provided English message." @@ -1063,10 +887,14 @@ "$ref": "#/$defs/item_messages_kind" } }, - "required": ["kind"], + "required": [ + "kind" + ], "if": { "properties": { - "kind": {"const": "CUSTOM_MESSAGE" } + "kind": { + "const": "CUSTOM_MESSAGE" + } } }, "then": { @@ -1082,7 +910,9 @@ "default": true } }, - "required": ["languages"], + "required": [ + "languages" + ], "additionalProperties": false }, "else": { @@ -1097,18 +927,29 @@ "description": "The Message ID, will display one of the predefined messages in the ROM" } }, - "required": ["message_id"], + "required": [ + "message_id" + ], "additionalProperties": false } }, "item_messages_kind": { "type": "string", - "enum": ["CUSTOM_MESSAGE", "MESSAGE_ID"] + "enum": [ + "CUSTOM_MESSAGE", + "MESSAGE_ID" + ] }, "jingle": { "type": "string", "description": "The sound that plays when an item is collected", - "enum": ["DEFAULT", "MINOR", "MAJOR", "UNKNOWN", "FULLY_POWERED"] + "enum": [ + "DEFAULT", + "MINOR", + "MAJOR", + "UNKNOWN", + "FULLY_POWERED" + ] }, "hint_locations": { "type": "string", @@ -1146,4 +987,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/mars_patcher/zm/music.py b/src/mars_patcher/zm/music.py index ec24960..6021568 100644 --- a/src/mars_patcher/zm/music.py +++ b/src/mars_patcher/zm/music.py @@ -2,7 +2,7 @@ from mars_patcher.constants.game_data import sound_data_entries from mars_patcher.rom import Rom -from mars_patcher.zm.auto_generated_types import MarsschemazmMusicreplacement +from mars_patcher.zm.auto_generated_types import Validmusictracks # In-between spaces are null values @@ -77,15 +77,15 @@ class MusicLibrary(IntEnum): STEALTH_2 = 0x5E -def set_sounds(rom: Rom, data: MarsschemazmMusicreplacement) -> None: - read_SoundData = [] +def set_sounds(rom: Rom, data: dict[Validmusictracks, Validmusictracks]) -> None: + read_data_entries = [] # Read new data - for New in data.values(): - read_location = sound_data_entries(rom) + 8 * MusicLibrary[New].value - read_SoundData.append(rom.read_bytes(read_location, 8)) + for new in data.values(): + read_location = sound_data_entries(rom) + 8 * MusicLibrary[new].value + read_data_entries.append(rom.read_bytes(read_location, 8)) # Write to rom - for Original, SoundDatum in zip(data.keys(), read_SoundData): - write_location = sound_data_entries(rom) + 8 * MusicLibrary[Original].value - rom.write_bytes(write_location, SoundDatum) + for original, sound_datum in zip(data.keys(), read_data_entries): + write_location = sound_data_entries(rom) + 8 * MusicLibrary[original].value + rom.write_bytes(write_location, sound_datum) From 768e0fc21588f4ae3c177857dce0825642bcdcbf Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Wed, 18 Feb 2026 20:15:17 +0000 Subject: [PATCH 09/13] Created universal set sounds --- src/mars_patcher/common_types.py | 2 ++ src/mars_patcher/mf/auto_generated_types.py | 3 ++- .../{music.py => constants/music_library.py} | 21 --------------- src/mars_patcher/mf/data/schema.json | 18 ++++++++----- src/mars_patcher/mf/patcher.py | 2 +- src/mars_patcher/sounds.py | 26 +++++++++++++++++++ src/mars_patcher/zm/auto_generated_types.py | 3 ++- .../{music.py => constants/music_library.py} | 18 ------------- src/mars_patcher/zm/data/schema.json | 18 ++++++++----- src/mars_patcher/zm/patcher.py | 2 +- 10 files changed, 56 insertions(+), 57 deletions(-) rename src/mars_patcher/mf/{music.py => constants/music_library.py} (51%) create mode 100644 src/mars_patcher/sounds.py rename src/mars_patcher/zm/{music.py => constants/music_library.py} (72%) diff --git a/src/mars_patcher/common_types.py b/src/mars_patcher/common_types.py index 0a09c67..10f352b 100644 --- a/src/mars_patcher/common_types.py +++ b/src/mars_patcher/common_types.py @@ -11,3 +11,5 @@ AreaRoomPair = tuple[AreaId, RoomId] MinimapId: TypeAlias = Annotated[int, "0 <= value < 10"] + +MusicMapping: TypeAlias = types_mf.Musicmapping | types_zm.Musicmapping diff --git a/src/mars_patcher/mf/auto_generated_types.py b/src/mars_patcher/mf/auto_generated_types.py index ee86a51..51a47c2 100644 --- a/src/mars_patcher/mf/auto_generated_types.py +++ b/src/mars_patcher/mf/auto_generated_types.py @@ -217,6 +217,7 @@ 'TITLE', 'SA_X_BATTLE' ] +Musicmapping: typ.TypeAlias = dict[Validmusictracks, Validmusictracks] Messagelanguages: typ.TypeAlias = dict[Validlanguages, str] class Itemmessages(typ.TypedDict, total=False): @@ -600,7 +601,7 @@ class Marsschemamf(typ.TypedDict, total=False): SeedHash: typ.Required[typ.Annotated[str, '/^[0-9A-Z]{8}$/']] """A seed hash that will be displayed on the file select screen.""" - MusicReplacement: dict[Validmusictracks, Validmusictracks] + MusicReplacement: Musicmapping """Shuffles the in-game music.""" Locations: typ.Required[MarsschemamfLocations] diff --git a/src/mars_patcher/mf/music.py b/src/mars_patcher/mf/constants/music_library.py similarity index 51% rename from src/mars_patcher/mf/music.py rename to src/mars_patcher/mf/constants/music_library.py index b38baf0..baa46c6 100644 --- a/src/mars_patcher/mf/music.py +++ b/src/mars_patcher/mf/constants/music_library.py @@ -1,9 +1,5 @@ from enum import IntEnum -from mars_patcher.constants.game_data import sound_data_entries -from mars_patcher.mf.auto_generated_types import Validmusictracks -from mars_patcher.rom import Rom - # In-between spaces are null values class MusicLibrary(IntEnum): @@ -42,20 +38,3 @@ class MusicLibrary(IntEnum): TITLE = 0x4A SA_X_BATTLE = 0x51 - - -SOUND_SIZE = 8 - - -def set_sounds(rom: Rom, data: dict[Validmusictracks, Validmusictracks]) -> None: - read_data_entries = [] - - # Read new data - for new in data.values(): - read_location = sound_data_entries(rom) + SOUND_SIZE * MusicLibrary[new].value - read_data_entries.append(rom.read_bytes(read_location, SOUND_SIZE)) - - # Write to rom - for original, sound_datum in zip(data.keys(), read_data_entries): - write_location = sound_data_entries(rom) + SOUND_SIZE * MusicLibrary[original].value - rom.write_bytes(write_location, sound_datum) diff --git a/src/mars_patcher/mf/data/schema.json b/src/mars_patcher/mf/data/schema.json index 770cd40..c5a479b 100644 --- a/src/mars_patcher/mf/data/schema.json +++ b/src/mars_patcher/mf/data/schema.json @@ -11,13 +11,7 @@ }, "MusicReplacement": { "description": "Shuffles the in-game music.", - "type": "object", - "propertyNames": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "additionalProperties": { - "$ref": "#/$defs/ValidMusicTracks" - } + "$ref": "#/$defs/MusicMapping" }, "Locations": { "type": "object", @@ -1016,6 +1010,16 @@ "SA_X_BATTLE" ] }, + "MusicMapping": { + "description": "Maps music tracks to each other", + "type": "object", + "propertyNames": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "additionalProperties": { + "$ref": "#/$defs/ValidMusicTracks" + } + }, "MessageLanguages": { "type": "object", "propertyNames": { diff --git a/src/mars_patcher/mf/patcher.py b/src/mars_patcher/mf/patcher.py index a77bd45..f01e0e2 100644 --- a/src/mars_patcher/mf/patcher.py +++ b/src/mars_patcher/mf/patcher.py @@ -30,13 +30,13 @@ skip_door_transitions, stereo_default, ) -from mars_patcher.mf.music import set_sounds from mars_patcher.mf.navigation_text import NavigationText from mars_patcher.mf.room_names import write_room_names from mars_patcher.mf.starting import set_starting_items, set_starting_location from mars_patcher.minimap import apply_minimap_edits from mars_patcher.random_palettes import PaletteRandomizer, PaletteSettings from mars_patcher.rom import Rom +from mars_patcher.sounds import set_sounds from mars_patcher.text import write_seed_hash from mars_patcher.titlescreen_text import write_title_text diff --git a/src/mars_patcher/sounds.py b/src/mars_patcher/sounds.py new file mode 100644 index 0000000..471866d --- /dev/null +++ b/src/mars_patcher/sounds.py @@ -0,0 +1,26 @@ +from mars_patcher.common_types import MusicMapping +from mars_patcher.constants.game_data import sound_data_entries +from mars_patcher.mf.constants.music_library import MusicLibrary as MusicLibraryMF +from mars_patcher.rom import Game, Rom +from mars_patcher.zm.constants.music_library import MusicLibrary as MusicLibraryZM + +SOUND_SIZE = 8 + + +def set_sounds(rom: Rom, data: MusicMapping) -> None: + read_data_entries = [] + + if rom.game == Game.MF: + MusicLibrary = MusicLibraryMF + elif rom.game == Game.ZM: + MusicLibrary = MusicLibraryZM + + # Read new data + for new in data.values(): + read_location = sound_data_entries(rom) + SOUND_SIZE * MusicLibrary[new].value + read_data_entries.append(rom.read_bytes(read_location, SOUND_SIZE)) + + # Write to rom + for original, sound_data in zip(data.keys(), read_data_entries): + write_location = sound_data_entries(rom) + SOUND_SIZE * MusicLibrary[original].value + rom.write_bytes(write_location, sound_data) diff --git a/src/mars_patcher/zm/auto_generated_types.py b/src/mars_patcher/zm/auto_generated_types.py index 772346b..5aebd8f 100644 --- a/src/mars_patcher/zm/auto_generated_types.py +++ b/src/mars_patcher/zm/auto_generated_types.py @@ -209,6 +209,7 @@ 'BEFORE_RUINS_TEST_ROOM', 'STEALTH_2' ] +Musicmapping: typ.TypeAlias = dict[Validmusictracks, Validmusictracks] MessageLanguages: typ.TypeAlias = dict[ValidLanguages, str] class ItemMessages(typ.TypedDict, total=False): @@ -546,7 +547,7 @@ class Marsschemazm(typ.TypedDict, total=False): palettes: MarsschemazmPalettes = None """Properties for randomized in-game palettes.""" - MusicReplacement: dict[Validmusictracks, Validmusictracks] + MusicReplacement: Musicmapping """Shuffles the in-game music.""" intro_text: dict[ValidLanguages, str] = None diff --git a/src/mars_patcher/zm/music.py b/src/mars_patcher/zm/constants/music_library.py similarity index 72% rename from src/mars_patcher/zm/music.py rename to src/mars_patcher/zm/constants/music_library.py index 6021568..501a945 100644 --- a/src/mars_patcher/zm/music.py +++ b/src/mars_patcher/zm/constants/music_library.py @@ -1,9 +1,5 @@ from enum import IntEnum -from mars_patcher.constants.game_data import sound_data_entries -from mars_patcher.rom import Rom -from mars_patcher.zm.auto_generated_types import Validmusictracks - # In-between spaces are null values class MusicLibrary(IntEnum): @@ -75,17 +71,3 @@ class MusicLibrary(IntEnum): SAVE_ELEVATOR_ROOM_2 = 0x5C BEFORE_RUINS_TEST_ROOM = 0x5D STEALTH_2 = 0x5E - - -def set_sounds(rom: Rom, data: dict[Validmusictracks, Validmusictracks]) -> None: - read_data_entries = [] - - # Read new data - for new in data.values(): - read_location = sound_data_entries(rom) + 8 * MusicLibrary[new].value - read_data_entries.append(rom.read_bytes(read_location, 8)) - - # Write to rom - for original, sound_datum in zip(data.keys(), read_data_entries): - write_location = sound_data_entries(rom) + 8 * MusicLibrary[original].value - rom.write_bytes(write_location, sound_datum) diff --git a/src/mars_patcher/zm/data/schema.json b/src/mars_patcher/zm/data/schema.json index 8b9bead..5511f32 100644 --- a/src/mars_patcher/zm/data/schema.json +++ b/src/mars_patcher/zm/data/schema.json @@ -369,13 +369,7 @@ }, "MusicReplacement": { "description": "Shuffles the in-game music.", - "type": "object", - "propertyNames": { - "$ref": "#/$defs/ValidMusicTracks" - }, - "additionalProperties": { - "$ref": "#/$defs/ValidMusicTracks" - } + "$ref": "#/$defs/MusicMapping" }, "intro_text": { "type": "object", @@ -867,6 +861,16 @@ "STEALTH_2" ] }, + "MusicMapping": { + "description": "Maps music tracks to each other", + "type": "object", + "propertyNames": { + "$ref": "#/$defs/ValidMusicTracks" + }, + "additionalProperties": { + "$ref": "#/$defs/ValidMusicTracks" + } + }, "message_languages": { "type": "object", "propertyNames": { diff --git a/src/mars_patcher/zm/patcher.py b/src/mars_patcher/zm/patcher.py index a4acc08..03dec62 100644 --- a/src/mars_patcher/zm/patcher.py +++ b/src/mars_patcher/zm/patcher.py @@ -2,11 +2,11 @@ from os import PathLike from mars_patcher.rom import Rom +from mars_patcher.sounds import set_sounds from mars_patcher.zm.auto_generated_types import MarsSchemaZM from mars_patcher.zm.constants.game_data import skip_door_transitions_addr from mars_patcher.zm.item_patcher import ItemPatcher, set_tank_increments from mars_patcher.zm.locations import LocationSettings -from mars_patcher.zm.music import set_sounds def patch_zm( From 1e52df55df6f42beba9d28b90b8b46981d1ec53a Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Wed, 18 Feb 2026 20:22:20 +0000 Subject: [PATCH 10/13] made mypy happy --- src/mars_patcher/sounds.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mars_patcher/sounds.py b/src/mars_patcher/sounds.py index 471866d..55c0712 100644 --- a/src/mars_patcher/sounds.py +++ b/src/mars_patcher/sounds.py @@ -10,6 +10,7 @@ def set_sounds(rom: Rom, data: MusicMapping) -> None: read_data_entries = [] + MusicLibrary: type[MusicLibraryMF] | type[MusicLibraryZM] if rom.game == Game.MF: MusicLibrary = MusicLibraryMF elif rom.game == Game.ZM: From 7f7d0ff45aca1883e20a4e0b3ef8a5d3425a7422 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Thu, 19 Feb 2026 00:25:39 +0000 Subject: [PATCH 11/13] Update src/mars_patcher/sounds.py Co-authored-by: Miepee <38186597+Miepee@users.noreply.github.com> --- src/mars_patcher/sounds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mars_patcher/sounds.py b/src/mars_patcher/sounds.py index 55c0712..20fdc42 100644 --- a/src/mars_patcher/sounds.py +++ b/src/mars_patcher/sounds.py @@ -11,9 +11,9 @@ def set_sounds(rom: Rom, data: MusicMapping) -> None: read_data_entries = [] MusicLibrary: type[MusicLibraryMF] | type[MusicLibraryZM] - if rom.game == Game.MF: + if rom.is_mf(): MusicLibrary = MusicLibraryMF - elif rom.game == Game.ZM: + elif rom.is_zm(): MusicLibrary = MusicLibraryZM # Read new data From c34d481593b7815d6851580890cee28264f804f3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 00:26:10 +0000 Subject: [PATCH 12/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/mars_patcher/sounds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mars_patcher/sounds.py b/src/mars_patcher/sounds.py index 20fdc42..ebc515d 100644 --- a/src/mars_patcher/sounds.py +++ b/src/mars_patcher/sounds.py @@ -1,7 +1,7 @@ from mars_patcher.common_types import MusicMapping from mars_patcher.constants.game_data import sound_data_entries from mars_patcher.mf.constants.music_library import MusicLibrary as MusicLibraryMF -from mars_patcher.rom import Game, Rom +from mars_patcher.rom import Rom from mars_patcher.zm.constants.music_library import MusicLibrary as MusicLibraryZM SOUND_SIZE = 8 From 757c7ac95039fac3d627c04c49420b54cc7c3156 Mon Sep 17 00:00:00 2001 From: Wollom-code Date: Sat, 21 Feb 2026 09:22:45 +0000 Subject: [PATCH 13/13] updated mf music library --- src/mars_patcher/mf/auto_generated_types.py | 41 +++++++++++++++-- .../mf/constants/music_library.py | 44 +++++++++++++++++-- src/mars_patcher/mf/data/schema.json | 41 +++++++++++++++-- 3 files changed, 115 insertions(+), 11 deletions(-) diff --git a/src/mars_patcher/mf/auto_generated_types.py b/src/mars_patcher/mf/auto_generated_types.py index 51a47c2..221e13d 100644 --- a/src/mars_patcher/mf/auto_generated_types.py +++ b/src/mars_patcher/mf/auto_generated_types.py @@ -190,6 +190,8 @@ 'Spanish' ] Validmusictracks = typ.Literal[ + 'UNUSED_1', + 'AFTER_EVENT', 'SECTOR_1', 'SECTOR_2', 'SECTOR_3', @@ -197,25 +199,56 @@ 'SECTOR_4', 'SECTOR_6', 'NAVIGATION_ROOM', - 'ITEM_FANFARE', + 'SECURITY_DATA_ROOM', + 'ITEM_JINGLE', + 'LOADING_SAVE', + 'MESSAGE_POPUP', + 'SA_X_APPEARANCE', 'SA_X_CHASE', 'BOSS_TENSION', 'ARACHNUS_BATTLE', 'ZAZABI_BATTLE', 'BOX_BATTLE', - 'OPERATIONS_DECK_ELEVATOR_OFFLINE', + 'MAIN_DECK_AMBIENCE', + 'UNUSED_1F', + 'UNUSED_20', + 'SILENCE_1_SHIP', + 'TENSION', + 'MAIN_DECK_LIVELY', + 'OMEGA_METROID_DEFEATED', + 'OPERATIONS_DECK', + 'OPERATIONS_DECK_ELEVATOR_OFFLINE_SOUND_AND_AMBIENCE', + 'X_INVASION_DETECTION', + 'SA_X_ELEVATOR', + 'HEADING_TO_NIGHTMARE_RIDLEY', + 'OPERATIONS_DECK_ELEVATOR_OFFLINE_SOUND', 'OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE', 'MAIN_BOILER_COOLDOWN_MISSION', - 'ORBIT_CHANGE', + 'STATION_ESCAPE', 'OBJECTIVE_COMPLETE', + 'SECTOR_4_UNDERWATER', + 'SECTOR_4_UNDERWATER_UNUSED', 'SERRIS_YAKUZA_BATTLE', 'VARIA_CORE_X_BATTLE', 'NIGHTMARE_BATTLE', 'NEO_RIDLEY_BATTLE', 'CHOZO_STATUE_CORE_X_BATTLE', 'NETTORI_BATTLE', + 'PRE_TITLE_END', 'TITLE', - 'SA_X_BATTLE' + 'SA_X_BATTLE', + 'EPILOGUE_END', + 'ENDING', + 'EPILOGUE', + 'DISQUIETING', + 'SHOCK', + 'SILENCE_1', + 'MAIN_BOILER_OVERHEATING', + 'FINAL_ORDER', + 'SILENCE_2', + 'INTRIGUE', + 'UNUSED_5E', + 'UNEASE' ] Musicmapping: typ.TypeAlias = dict[Validmusictracks, Validmusictracks] Messagelanguages: typ.TypeAlias = dict[Validlanguages, str] diff --git a/src/mars_patcher/mf/constants/music_library.py b/src/mars_patcher/mf/constants/music_library.py index baa46c6..19df627 100644 --- a/src/mars_patcher/mf/constants/music_library.py +++ b/src/mars_patcher/mf/constants/music_library.py @@ -3,6 +3,9 @@ # In-between spaces are null values class MusicLibrary(IntEnum): + UNUSED_1 = 0x1 # Short track with mainly percussion + + AFTER_EVENT = 0x3 SECTOR_1 = 0x4 SECTOR_2 = 0x6 @@ -12,7 +15,12 @@ class MusicLibrary(IntEnum): SECTOR_6 = 0xA NAVIGATION_ROOM = 0xB - ITEM_FANFARE = 0x10 + SECURITY_DATA_ROOM = 0xF + ITEM_JINGLE = 0x10 + LOADING_SAVE = 0x11 + + MESSAGE_POPUP = 0x14 + SA_X_APPEARANCE = 0x15 SA_X_CHASE = 0x17 BOSS_TENSION = 0x18 @@ -20,14 +28,29 @@ class MusicLibrary(IntEnum): ZAZABI_BATTLE = 0x1A BOX_BATTLE = 0x1B - OPERATIONS_DECK_ELEVATOR_OFFLINE = 0x33 + MAIN_DECK_AMBIENCE = 0x1E + UNUSED_1F = 0x1F # Combination of MAIN_DECK_AMBIENCE and TENSION + UNUSED_20 = 0x20 # Dramatic track combined with MAIN_DECK_AMBIENCE + + SILENCE_1_SHIP = 0x2A + TENSION = 0x2B + MAIN_DECK_LIVELY = 0x2C + OMEGA_METROID_DEFEATED = 0x2D + OPERATIONS_DECK = 0x2E + OPERATIONS_DECK_ELEVATOR_OFFLINE_SOUND_AND_AMBIENCE = 0x2F + X_INVASION_DETECTION = 0x30 + SA_X_ELEVATOR = 0x31 + HEADING_TO_NIGHTMARE_RIDLEY = 0x32 + OPERATIONS_DECK_ELEVATOR_OFFLINE_SOUND = 0x33 OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE = 0x34 MAIN_BOILER_COOLDOWN_MISSION = 0x35 - ORBIT_CHANGE = 0x38 + STATION_ESCAPE = 0x38 OBJECTIVE_COMPLETE = 0x3B + SECTOR_4_UNDERWATER = 0x3C + SECTOR_4_UNDERWATER_UNUSED = 0x3E SERRIS_YAKUZA_BATTLE = 0x3F VARIA_CORE_X_BATTLE = 0x40 NIGHTMARE_BATTLE = 0x41 @@ -35,6 +58,21 @@ class MusicLibrary(IntEnum): CHOZO_STATUE_CORE_X_BATTLE = 0x43 NETTORI_BATTLE = 0x44 + PRE_TITLE_END = 0x49 TITLE = 0x4A SA_X_BATTLE = 0x51 + + EPILOGUE_END = 0x53 + + ENDING = 0x55 + EPILOGUE = 0x56 + DISQUIETING = 0x57 + SHOCK = 0x58 + SILENCE_1 = 0x59 + MAIN_BOILER_OVERHEATING = 0x5A + FINAL_ORDER = 0x5B + SILENCE_2 = 0x5C + INTRIGUE = 0x5D + UNUSED_5E = 0x5E # Suspenseful track + UNEASE = 0x5F diff --git a/src/mars_patcher/mf/data/schema.json b/src/mars_patcher/mf/data/schema.json index c5a479b..f87519e 100644 --- a/src/mars_patcher/mf/data/schema.json +++ b/src/mars_patcher/mf/data/schema.json @@ -982,6 +982,8 @@ "type": "string", "description": "Valid music tracks supported by the game.", "enum": [ + "UNUSED_1", + "AFTER_EVENT", "SECTOR_1", "SECTOR_2", "SECTOR_3", @@ -989,25 +991,56 @@ "SECTOR_4", "SECTOR_6", "NAVIGATION_ROOM", - "ITEM_FANFARE", + "SECURITY_DATA_ROOM", + "ITEM_JINGLE", + "LOADING_SAVE", + "MESSAGE_POPUP", + "SA_X_APPEARANCE", "SA_X_CHASE", "BOSS_TENSION", "ARACHNUS_BATTLE", "ZAZABI_BATTLE", "BOX_BATTLE", - "OPERATIONS_DECK_ELEVATOR_OFFLINE", + "MAIN_DECK_AMBIENCE", + "UNUSED_1F", + "UNUSED_20", + "SILENCE_1_SHIP", + "TENSION", + "MAIN_DECK_LIVELY", + "OMEGA_METROID_DEFEATED", + "OPERATIONS_DECK", + "OPERATIONS_DECK_ELEVATOR_OFFLINE_SOUND_AND_AMBIENCE", + "X_INVASION_DETECTION", + "SA_X_ELEVATOR", + "HEADING_TO_NIGHTMARE_RIDLEY", + "OPERATIONS_DECK_ELEVATOR_OFFLINE_SOUND", "OPERATIONS_DECK_ELEVATOR_OFFLINE_AMBIENCE", "MAIN_BOILER_COOLDOWN_MISSION", - "ORBIT_CHANGE", + "STATION_ESCAPE", "OBJECTIVE_COMPLETE", + "SECTOR_4_UNDERWATER", + "SECTOR_4_UNDERWATER_UNUSED", "SERRIS_YAKUZA_BATTLE", "VARIA_CORE_X_BATTLE", "NIGHTMARE_BATTLE", "NEO_RIDLEY_BATTLE", "CHOZO_STATUE_CORE_X_BATTLE", "NETTORI_BATTLE", + "PRE_TITLE_END", "TITLE", - "SA_X_BATTLE" + "SA_X_BATTLE", + "EPILOGUE_END", + "ENDING", + "EPILOGUE", + "DISQUIETING", + "SHOCK", + "SILENCE_1", + "MAIN_BOILER_OVERHEATING", + "FINAL_ORDER", + "SILENCE_2", + "INTRIGUE", + "UNUSED_5E", + "UNEASE" ] }, "MusicMapping": {