From ec2a0452ffdb26ce0a8e8ecc3b5f74c95e24f878 Mon Sep 17 00:00:00 2001 From: lahm86 <33758420+lahm86@users.noreply.github.com> Date: Thu, 17 Apr 2025 15:03:18 +0100 Subject: [PATCH] tr2/savegame: save and load current music This allows the current music track and position to be saved and restored on load, similar to TR1X. Resolves #2579. --- docs/tr2/CHANGELOG.md | 1 + docs/tr2/README.md | 1 + src/libtrx/config/map_tr2.def | 1 + src/libtrx/include/libtrx/config/types.h | 6 +++ src/libtrx/include/libtrx/config/types_tr1.h | 6 --- src/libtrx/include/libtrx/config/types_tr2.h | 1 + src/libtrx/include/libtrx/game/enum_map.def | 4 ++ src/tr1/global/enum_map.def | 4 -- src/tr2/game/savegame/savegame_bson.c | 40 +++++++++++++++++++ .../TR1X_ConfigTool/Resources/Lang/en.json | 5 --- .../TR1X_ConfigTool/Resources/Lang/it.json | 12 ------ .../TR2X_ConfigTool/Resources/Lang/en.json | 4 ++ .../TR2X_ConfigTool/Resources/Lang/it.json | 11 ++--- .../Resources/specification.json | 11 +++++ .../TRX_ConfigToolLib/Resources/Lang/en.json | 5 +++ .../TRX_ConfigToolLib/Resources/Lang/it.json | 14 +++++++ 16 files changed, 92 insertions(+), 34 deletions(-) diff --git a/docs/tr2/CHANGELOG.md b/docs/tr2/CHANGELOG.md index 3ef16b025..949543742 100644 --- a/docs/tr2/CHANGELOG.md +++ b/docs/tr2/CHANGELOG.md @@ -11,6 +11,7 @@ - added BSON savegame support, removing the limits imposed by the OG 8KB file size, so allowing for storing more data and offering improved feature support (legacy save files can still be read, similar to TR1) (#2662) - added NG+, Japanese, and Japanese NG+ game mode options to the New Game page in the passport (#2731) - added the ability for spike walls to be reset (antitriggered) +- added the current music track and timestamp to the savegame so they now persist on load (#2579) - added waterfalls to the savegame so that they now persist on load (#2686) - changed savegame files to be stored in the `saves` directory (#2087) - changed the default fog distance to 22 tiles cutting off at 30 tiles to match TR1X (#1622) diff --git a/docs/tr2/README.md b/docs/tr2/README.md index ec5f25d4e..cc4a32ad5 100644 --- a/docs/tr2/README.md +++ b/docs/tr2/README.md @@ -303,6 +303,7 @@ as Notepad. #### Audio - added an option to control how music is played while underwater rather than simply muting it +- added the current music track and timestamp to the savegame so they now persist on load - fixed music not playing with certain game versions - fixed the audio not being in sync when Lara strikes the gong in Ice Palace - fixed sound settings resuming the music diff --git a/src/libtrx/config/map_tr2.def b/src/libtrx/config/map_tr2.def index 07deab438..7f4ce06ed 100644 --- a/src/libtrx/config/map_tr2.def +++ b/src/libtrx/config/map_tr2.def @@ -60,5 +60,6 @@ CFG_INT32(g_Config, audio.sound_volume, 10) CFG_INT32(g_Config, audio.music_volume, 10) CFG_BOOL(g_Config, audio.enable_lara_mic, false) CFG_ENUM(g_Config, audio.underwater_music_mode, UMM_FULL, UNDERWATER_MUSIC_MODE) +CFG_ENUM(g_Config, audio.music_load_condition, MUSIC_LOAD_NON_AMBIENT, MUSIC_LOAD_CONDITION) CFG_BOOL(g_Config, gameplay.enable_game_modes, true) CFG_BOOL(g_Config, profile.new_game_plus_unlock, false) diff --git a/src/libtrx/include/libtrx/config/types.h b/src/libtrx/include/libtrx/config/types.h index 185abd51c..9320f729d 100644 --- a/src/libtrx/include/libtrx/config/types.h +++ b/src/libtrx/include/libtrx/config/types.h @@ -1,5 +1,11 @@ #pragma once +typedef enum { + MUSIC_LOAD_NEVER, + MUSIC_LOAD_NON_AMBIENT, + MUSIC_LOAD_ALWAYS, +} MUSIC_LOAD_CONDITION; + #if TR_VERSION == 1 #include "./types_tr1.h" #elif TR_VERSION == 2 diff --git a/src/libtrx/include/libtrx/config/types_tr1.h b/src/libtrx/include/libtrx/config/types_tr1.h index a81f5c3c3..65f38efb0 100644 --- a/src/libtrx/include/libtrx/config/types_tr1.h +++ b/src/libtrx/include/libtrx/config/types_tr1.h @@ -47,12 +47,6 @@ typedef enum { BC_PURPLE, } BAR_COLOR; -typedef enum { - MUSIC_LOAD_NEVER, - MUSIC_LOAD_NON_AMBIENT, - MUSIC_LOAD_ALWAYS, -} MUSIC_LOAD_CONDITION; - typedef enum { TLM_FULL, TLM_SEMI, diff --git a/src/libtrx/include/libtrx/config/types_tr2.h b/src/libtrx/include/libtrx/config/types_tr2.h index bfe78509a..5fd453e0d 100644 --- a/src/libtrx/include/libtrx/config/types_tr2.h +++ b/src/libtrx/include/libtrx/config/types_tr2.h @@ -69,6 +69,7 @@ typedef struct { int32_t music_volume; bool enable_lara_mic; UNDERWATER_MUSIC_MODE underwater_music_mode; + MUSIC_LOAD_CONDITION music_load_condition; } audio; struct { diff --git a/src/libtrx/include/libtrx/game/enum_map.def b/src/libtrx/include/libtrx/game/enum_map.def index 4530737fe..2811c315f 100644 --- a/src/libtrx/include/libtrx/game/enum_map.def +++ b/src/libtrx/include/libtrx/game/enum_map.def @@ -51,6 +51,10 @@ ENUM_MAP_DEFINE(GAME_BUFFER, GBUF_CREATURE_LOT, "Creature pathfinding") ENUM_MAP_DEFINE(GAME_BUFFER, GBUF_SAMPLE_INFOS, "Sample information") ENUM_MAP_DEFINE(GAME_BUFFER, GBUF_SAMPLES, "Samples") +ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NEVER, "never") +ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NON_AMBIENT, "non-ambient") +ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_ALWAYS, "always") + ENUM_MAP_DEFINE(UNDERWATER_MUSIC_MODE, UMM_FULL, "full") ENUM_MAP_DEFINE(UNDERWATER_MUSIC_MODE, UMM_QUIET, "quiet") ENUM_MAP_DEFINE(UNDERWATER_MUSIC_MODE, UMM_FULL_NO_AMBIENT, "full_no_ambient") diff --git a/src/tr1/global/enum_map.def b/src/tr1/global/enum_map.def index 1367705f0..4dc74c1d0 100644 --- a/src/tr1/global/enum_map.def +++ b/src/tr1/global/enum_map.def @@ -30,10 +30,6 @@ ENUM_MAP_DEFINE(TARGET_LOCK_MODE, TLM_FULL, "full-lock") ENUM_MAP_DEFINE(TARGET_LOCK_MODE, TLM_SEMI, "semi-lock") ENUM_MAP_DEFINE(TARGET_LOCK_MODE, TLM_NONE, "no-lock") -ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NEVER, "never") -ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NON_AMBIENT, "non-ambient") -ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_ALWAYS, "always") - ENUM_MAP_DEFINE(STAT_DETAIL_MODE, SDM_MINIMAL, "minimal") ENUM_MAP_DEFINE(STAT_DETAIL_MODE, SDM_DETAILED, "detailed") ENUM_MAP_DEFINE(STAT_DETAIL_MODE, SDM_FULL, "full") diff --git a/src/tr2/game/savegame/savegame_bson.c b/src/tr2/game/savegame/savegame_bson.c index 9acd45bbe..63ab2457f 100644 --- a/src/tr2/game/savegame/savegame_bson.c +++ b/src/tr2/game/savegame/savegame_bson.c @@ -2,11 +2,13 @@ #include "game/game_flow.h" #include "game/inventory.h" #include "game/lara/control.h" +#include "game/music.h" #include "game/objects/general/lift.h" #include "game/savegame.h" #include "global/vars.h" #include +#include #include #include #include @@ -303,6 +305,15 @@ static JSON_OBJECT *M_DumpMusic(void) JSON_ArrayAppendInt(track_arr, Music_GetTrackFlags(i)); } JSON_ObjectAppendArray(music_obj, "flags", track_arr); + + const MUSIC_TRACK_ID current_track = Music_GetCurrentPlayingTrack(); + const bool is_ambient = current_track == Music_GetCurrentLoopedTrack(); + JSON_OBJECT *const current_obj = JSON_ObjectNew(); + JSON_ObjectAppendInt(current_obj, "current_track", current_track); + JSON_ObjectAppendDouble(current_obj, "timestamp", Music_GetTimestamp()); + JSON_ObjectAppendBool(current_obj, "is_ambient", is_ambient); + JSON_ObjectAppendObject(music_obj, "current", current_obj); + return music_obj; } @@ -330,6 +341,35 @@ static bool M_LoadMusic(JSON_OBJECT *const music_obj) Music_SetTrackFlags(i, JSON_ArrayGetInt(track_arr, i, 0)); } + const JSON_OBJECT *const current_obj = + JSON_ObjectGetObject(music_obj, "current"); + if (current_obj == nullptr + || g_Config.audio.music_load_condition == MUSIC_LOAD_NEVER) { + return true; + } + + const int16_t current_track = + JSON_ObjectGetInt(current_obj, "current_track", -1); + double timestamp = JSON_ObjectGetDouble(current_obj, "timestamp", -1.0); + if (current_track != MX_INACTIVE) { + const bool is_ambient = + JSON_ObjectGetBool(music_obj, "is_ambient", false); + if (is_ambient) { + if (g_Config.audio.music_load_condition == MUSIC_LOAD_NON_AMBIENT) { + return true; + } + Music_Play(current_track, MPM_LOOPED); + } else { + Music_Play(current_track, MPM_ALWAYS); + } + + if (!Music_SeekTimestamp(timestamp)) { + LOG_WARNING( + "Could not load current track %d at timestamp %" PRId64 ".", + current_track, timestamp); + } + } + return true; } diff --git a/tools/config/TR1X_ConfigTool/Resources/Lang/en.json b/tools/config/TR1X_ConfigTool/Resources/Lang/en.json index fc2e785dd..80daa2023 100644 --- a/tools/config/TR1X_ConfigTool/Resources/Lang/en.json +++ b/tools/config/TR1X_ConfigTool/Resources/Lang/en.json @@ -54,11 +54,6 @@ "semi-lock": "Semi lock", "no-lock": "No lock" }, - "music_load_condition": { - "never": "Never", - "non-ambient": "Non-ambient", - "always": "Always" - }, "stat_mode": { "minimal": "Minimal", "detailed": "Detailed", diff --git a/tools/config/TR1X_ConfigTool/Resources/Lang/it.json b/tools/config/TR1X_ConfigTool/Resources/Lang/it.json index adf9eebc4..37d85b362 100644 --- a/tools/config/TR1X_ConfigTool/Resources/Lang/it.json +++ b/tools/config/TR1X_ConfigTool/Resources/Lang/it.json @@ -58,18 +58,6 @@ "semi-lock": "Parziale", "no-lock": "Nessuno" }, - "underwater_music": { - "full": "Completa", - "quiet": "Attenuata", - "full_no_ambient": "Completa ma senza suoni ambientali", - "quiet_no_ambient": "Attenuata ma senza suoni ambientali", - "none": "Assente" - }, - "music_load_condition": { - "never": "Mai", - "non-ambient": "Non ambientale", - "always": "Sempre" - }, "stat_mode": { "minimal": "Minimo", "detailed": "Dettagliato", diff --git a/tools/config/TR2X_ConfigTool/Resources/Lang/en.json b/tools/config/TR2X_ConfigTool/Resources/Lang/en.json index ca404c30f..1b8a1e18a 100644 --- a/tools/config/TR2X_ConfigTool/Resources/Lang/en.json +++ b/tools/config/TR2X_ConfigTool/Resources/Lang/en.json @@ -114,6 +114,10 @@ "Title": "Gun/explosion lighting", "Description": "Enables dynamic lighting to be generated for gunshots and explosions." }, + "music_load_condition": { + "Title": "Load music track", + "Description": "Loads the music track that was playing when the game was saved.\n- Never: do not restore music tracks on load.\n- Non-ambient: restore only non-ambient music tracks on load.\n- Always: restore any kind of music track on load." + }, "enable_lara_mic" : { "Title": "Microphone at Lara", "Description": "Set the microphone to be at Lara's position. If disabled, the microphone will be at the camera's position." diff --git a/tools/config/TR2X_ConfigTool/Resources/Lang/it.json b/tools/config/TR2X_ConfigTool/Resources/Lang/it.json index 1b6c2c703..15a1e7c6f 100644 --- a/tools/config/TR2X_ConfigTool/Resources/Lang/it.json +++ b/tools/config/TR2X_ConfigTool/Resources/Lang/it.json @@ -15,13 +15,6 @@ "any": "Qualsiasi", "16:9": "16:9", "4:3": "4:3" - }, - "underwater_music": { - "full": "Completa", - "quiet": "Attenuata", - "full_no_ambient": "Completa ma senza suoni ambientali", - "quiet_no_ambient": "Attenuata ma senza suoni ambientali", - "none": "Assente" } }, "Properties": { @@ -121,6 +114,10 @@ "Title": "Illuminazione spari/esplosioni", "Description": "Abilita l'illuminazione dinamica per spari ed esplosioni." }, + "music_load_condition": { + "Title": "Carica la traccia musicale", + "Description": "Carica la traccia musicale che era in riproduzione al momento del salvataggio della partita.\n- Mai: non ripristina le tracce musicali al caricamento.\n- Non ambientale: ripristina le tracce musicali ma non le tracce ambientali al caricamento.\n- Sempre: ripristina qualsiasi tipo di traccia musicale al caricamento." + }, "enable_lara_mic" : { "Title": "Microfono su Lara", "Description": "Imposta il microfono nella posizione in cui si trova Lara. Se disabilitato, il microfono sarĂ  nella posizione della telecamera." diff --git a/tools/config/TR2X_ConfigTool/Resources/specification.json b/tools/config/TR2X_ConfigTool/Resources/specification.json index e0944faae..2fa813a6c 100644 --- a/tools/config/TR2X_ConfigTool/Resources/specification.json +++ b/tools/config/TR2X_ConfigTool/Resources/specification.json @@ -19,6 +19,11 @@ "full_no_ambient", "quiet_no_ambient", "none" + ], + "music_load_condition": [ + "never", + "non-ambient", + "always" ] }, "CategorisedProperties": [ @@ -189,6 +194,12 @@ "DataType": "Bool", "DefaultValue": false }, + { + "Field": "music_load_condition", + "DataType": "Enum", + "EnumKey": "music_load_condition", + "DefaultValue": "non-ambient" + }, { "Field": "underwater_music_mode", "DataType": "Enum", diff --git a/tools/config/TRX_ConfigToolLib/Resources/Lang/en.json b/tools/config/TRX_ConfigToolLib/Resources/Lang/en.json index bdfc136a1..5efe27e19 100644 --- a/tools/config/TRX_ConfigToolLib/Resources/Lang/en.json +++ b/tools/config/TRX_ConfigToolLib/Resources/Lang/en.json @@ -44,6 +44,11 @@ "jpg": "JPEG", "png": "PNG" }, + "music_load_condition": { + "never": "Never", + "non-ambient": "Non-ambient", + "always": "Always" + }, "underwater_music": { "full": "Full", "quiet": "Quiet", diff --git a/tools/config/TRX_ConfigToolLib/Resources/Lang/it.json b/tools/config/TRX_ConfigToolLib/Resources/Lang/it.json index bf5a3dd09..7cce646e4 100644 --- a/tools/config/TRX_ConfigToolLib/Resources/Lang/it.json +++ b/tools/config/TRX_ConfigToolLib/Resources/Lang/it.json @@ -38,5 +38,19 @@ "graphics": "Grafica", "sound": "Suono", "ui": "Interfaccia utente" + }, + "Enums": { + "underwater_music": { + "full": "Completa", + "quiet": "Attenuata", + "full_no_ambient": "Completa ma senza suoni ambientali", + "quiet_no_ambient": "Attenuata ma senza suoni ambientali", + "none": "Assente" + }, + "music_load_condition": { + "never": "Mai", + "non-ambient": "Non ambientale", + "always": "Sempre" + } } }