diff --git a/CMakeLists.txt b/CMakeLists.txt
index 78307ec3de..7380c4104b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,9 +72,9 @@ set(OPENSFX_VERSION "1.0.3")
set(OPENSFX_URL "https://github.com/OpenRCT2/OpenSoundEffects/releases/download/v${OPENSFX_VERSION}/opensound.zip")
set(OPENSFX_SHA1 "ffec5a97bd5035860c4c9a43fe32cf51886478e3")
-set(OPENMSX_VERSION "1.3.0")
+set(OPENMSX_VERSION "1.3.1")
set(OPENMSX_URL "https://github.com/OpenRCT2/OpenMusic/releases/download/v${OPENMSX_VERSION}/openmusic.zip")
-set(OPENMSX_SHA1 "b0cec998a3679f1cde17d91f2508ec4923c1a25c")
+set(OPENMSX_SHA1 "cb7b05af97aaf7949fb509063d45df6613f20521")
set(REPLAYS_VERSION "0.0.78")
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
diff --git a/contributors.md b/contributors.md
index 4d79b03284..9df1200171 100644
--- a/contributors.md
+++ b/contributors.md
@@ -277,6 +277,13 @@ The following people are not part of the development team, but have been contrib
## Music
* Karst "Jalmaan" van Galen Last (AuraSpecs)
* (Flyxxpy)
+* Jan Büchner (Greyfade)
+* Allister Brimble
+* Herman Riddering
+
+## Sound Effects
+* Karst van Galen Last (AuraSpecs)
+* (ThatGuyYouKnow)
## RollerCoaster Tycoon 2 credits
Design and programming by Chris Sawyer
diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt
index 8f0fa47df9..43b81094af 100644
--- a/data/language/en-GB.txt
+++ b/data/language/en-GB.txt
@@ -3691,6 +3691,10 @@ STR_6583 :{WINDOW_COLOUR_2}Reversed Trains
STR_6584 :Select to run trains backwards
STR_6585 :Can’t make changes…
+STR_6586 :OpenRCT2
+STR_6587 :The OpenRCT2 Title Theme is a work of Allister Brimble,{NEWLINE}licenced CC BY-SA 4.0.
+STR_6588 :Thanks to Herman Riddering for allowing us to record the 35er Voigt.
+
#############
# Scenarios #
################
diff --git a/distribution/changelog.txt b/distribution/changelog.txt
index c4600d5484..d2c814d257 100644
--- a/distribution/changelog.txt
+++ b/distribution/changelog.txt
@@ -1,5 +1,6 @@
0.4.6 (in development)
------------------------------------------------------------------------
+- Feature: [OpenMusic#41] Official Title Theme by Allister Brimble.
- Improved: [#20200] Allow audio files to play to up to 44100hz sample rate (from 22050hz).
- Change: [#20110] Fix a few RCT1 build height parity discrepancies.
- Fix: [#19823] Parkobj, disallow overriding objects of different object types.
diff --git a/openrct2.proj b/openrct2.proj
index 8d84896507..4a232ac015 100644
--- a/openrct2.proj
+++ b/openrct2.proj
@@ -49,8 +49,8 @@
02ddf6c685a2da8bac98a57b34be95d63192443d
https://github.com/OpenRCT2/OpenSoundEffects/releases/download/v1.0.3/opensound.zip
ffec5a97bd5035860c4c9a43fe32cf51886478e3
- https://github.com/OpenRCT2/OpenMusic/releases/download/v1.3.0/openmusic.zip
- b0cec998a3679f1cde17d91f2508ec4923c1a25c
+ https://github.com/OpenRCT2/OpenMusic/releases/download/v1.3.1/openmusic.zip
+ cb7b05af97aaf7949fb509063d45df6613f20521
https://github.com/OpenRCT2/replays/releases/download/v0.0.78/replays.zip
31C5D07EED8481D5C6D57F9E4FE9443AAEDE7739
diff --git a/src/openrct2-ui/windows/About.cpp b/src/openrct2-ui/windows/About.cpp
index 188abd94cf..1230ea7c35 100644
--- a/src/openrct2-ui/windows/About.cpp
+++ b/src/openrct2-ui/windows/About.cpp
@@ -74,10 +74,12 @@ static Widget _windowAboutOpenRCT2Widgets[] = {
MakeWidget({168, 115 + 40}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_CHANGELOG_ELLIPSIS), // changelog button
MakeWidget({168, 115 + 60}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_JOIN_DISCORD ), // "join discord" button
MakeWidget({10, 250}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_OPENRCT2_DESCRIPTION_2), // More info
- MakeWidget({10, 300}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_OPENRCT2_DESCRIPTION_3), // Copyright
- MakeWidget({10, 350}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_SPECIAL_THANKS_1), // Special Thanks
+ MakeWidget({10, 280}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_OPENRCT2_DESCRIPTION_3), // Copyright
+ MakeWidget({10, 360}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_SPECIAL_THANKS_1), // Special Thanks
MakeWidget({10, 375}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_SPECIAL_THANKS_2), // Company names
MakeWidget({168, 115 + 80}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_CONTRIBUTORS_WINDOW_BUTTON), // "contributors" button
+ MakeWidget({10, 310}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_OPENRCT2_TITLE), // Title Theme
+ MakeWidget({10, 338}, {WW - 20, 50}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_FAIRGROUND_ORGAN), // Fairground organ
WIDGETS_END,
};
diff --git a/src/openrct2-ui/windows/Options.cpp b/src/openrct2-ui/windows/Options.cpp
index a45c659922..2c395aa061 100644
--- a/src/openrct2-ui/windows/Options.cpp
+++ b/src/openrct2-ui/windows/Options.cpp
@@ -1349,32 +1349,22 @@ private:
break;
case WIDX_TITLE_MUSIC_DROPDOWN:
{
- if (!IsRCT1TitleMusicAvailable())
+ const bool rct1MusicThemeIsAvailable = IsRCT1TitleMusicAvailable();
+ int32_t numItems{};
+ int32_t checkedIndex{};
+ for (auto theme : TitleThemeOptions)
{
- // Only show None and RCT2
- int32_t numItems{};
+ if (theme.Kind == TitleMusicKind::RCT1 && !rct1MusicThemeIsAvailable)
+ continue;
+
+ if (gConfigSound.TitleMusic == theme.Kind)
+ checkedIndex = numItems;
+
gDropdownItems[numItems].Format = STR_DROPDOWN_MENU_LABEL;
- gDropdownItems[numItems++].Args = TitleMusicNames[0];
- gDropdownItems[numItems].Format = STR_DROPDOWN_MENU_LABEL;
- gDropdownItems[numItems++].Args = TitleMusicNames[2];
- ShowDropdown(widget, numItems);
- if (gConfigSound.TitleMusic == TitleMusicKind::None)
- Dropdown::SetChecked(0, true);
- else if (gConfigSound.TitleMusic == TitleMusicKind::RCT2)
- Dropdown::SetChecked(1, true);
- }
- else
- {
- // Show None, RCT1, RCT2 and random
- int32_t numItems{};
- for (auto musicName : TitleMusicNames)
- {
- gDropdownItems[numItems].Format = STR_DROPDOWN_MENU_LABEL;
- gDropdownItems[numItems++].Args = musicName;
- }
- ShowDropdown(widget, numItems);
- Dropdown::SetChecked(EnumValue(gConfigSound.TitleMusic), true);
+ gDropdownItems[numItems++].Args = theme.Name;
}
+ ShowDropdown(widget, numItems);
+ Dropdown::SetChecked(checkedIndex, true);
break;
}
}
@@ -1407,18 +1397,20 @@ private:
break;
case WIDX_TITLE_MUSIC_DROPDOWN:
{
- auto titleMusic = static_cast(dropdownIndex);
- if (!IsRCT1TitleMusicAvailable() && dropdownIndex != 0)
+ // HACK: When RCT1 is not available, it's not in the dropdown, so indices higher than it should be incremented
+ const bool rct1MusicThemeIsAvailable = IsRCT1TitleMusicAvailable();
+ for (size_t i = 0; i < std::size(TitleThemeOptions) && static_cast(i) <= dropdownIndex; i++)
{
- titleMusic = TitleMusicKind::RCT2;
+ if (TitleThemeOptions[i].Kind == TitleMusicKind::RCT1 && !rct1MusicThemeIsAvailable)
+ dropdownIndex++;
}
- gConfigSound.TitleMusic = titleMusic;
+ gConfigSound.TitleMusic = TitleThemeOptions[dropdownIndex].Kind;
ConfigSaveDefault();
Invalidate();
OpenRCT2::Audio::StopTitleMusic();
- if (titleMusic != TitleMusicKind::None)
+ if (gConfigSound.TitleMusic != TitleMusicKind::None)
{
OpenRCT2::Audio::PlayTitleMusic();
}
@@ -1465,14 +1457,14 @@ private:
return { 500, 0 };
}
- StringId GetTitleMusicName()
+ StringId GetTitleMusicName() const
{
- auto index = EnumValue(gConfigSound.TitleMusic);
- if (index < 0 || static_cast(index) >= std::size(TitleMusicNames))
- {
- index = EnumValue(TitleMusicKind::None);
- }
- return TitleMusicNames[index];
+ auto theme = std::find_if(std::begin(TitleThemeOptions), std::end(TitleThemeOptions), [](auto&& option) {
+ return gConfigSound.TitleMusic == option.Kind;
+ });
+ if (theme != std::end(TitleThemeOptions))
+ return theme->Name;
+ return STR_OPENRCT2_DROPDOWN;
}
void AudioPrepareDraw()
@@ -2146,11 +2138,16 @@ private:
STR_SAVE_EVERY_30MINUTES, STR_SAVE_EVERY_HOUR, STR_SAVE_NEVER,
};
- static constexpr StringId TitleMusicNames[] = {
- STR_OPTIONS_MUSIC_VALUE_NONE,
- STR_ROLLERCOASTER_TYCOON_1_DROPDOWN,
- STR_ROLLERCOASTER_TYCOON_2_DROPDOWN,
- STR_OPTIONS_MUSIC_VALUE_RANDOM,
+ static constexpr struct
+ {
+ TitleMusicKind Kind;
+ StringId Name;
+ } TitleThemeOptions[] = {
+ { TitleMusicKind::None, STR_OPTIONS_MUSIC_VALUE_NONE },
+ { TitleMusicKind::OpenRCT2, STR_OPENRCT2_DROPDOWN },
+ { TitleMusicKind::RCT1, STR_ROLLERCOASTER_TYCOON_1_DROPDOWN },
+ { TitleMusicKind::RCT2, STR_ROLLERCOASTER_TYCOON_2_DROPDOWN },
+ { TitleMusicKind::Random, STR_OPTIONS_MUSIC_VALUE_RANDOM },
};
static constexpr StringId FullscreenModeNames[] = {
diff --git a/src/openrct2/audio/Audio.cpp b/src/openrct2/audio/Audio.cpp
index e9ef18924c..9ff0e79b76 100644
--- a/src/openrct2/audio/Audio.cpp
+++ b/src/openrct2/audio/Audio.cpp
@@ -271,19 +271,32 @@ namespace OpenRCT2::Audio
static ObjectEntryDescriptor GetTitleMusicDescriptor()
{
+ static constexpr std::array selectableAudioIds{
+ AudioObjectIdentifiers::OpenRCT2Title,
+ AudioObjectIdentifiers::RCT1Title,
+ AudioObjectIdentifiers::RCT2Title,
+ };
+ int32_t IdIndex{};
switch (gConfigSound.TitleMusic)
{
default:
- return {};
+ case TitleMusicKind::OpenRCT2:
+ IdIndex = 0;
+ break;
case TitleMusicKind::RCT1:
- return ObjectEntryDescriptor(ObjectType::Audio, AudioObjectIdentifiers::RCT1Title);
+ IdIndex = 1;
+ break;
case TitleMusicKind::RCT2:
- return ObjectEntryDescriptor(ObjectType::Audio, AudioObjectIdentifiers::RCT2Title);
+ IdIndex = 2;
+ break;
case TitleMusicKind::Random:
- return ObjectEntryDescriptor(
- ObjectType::Audio,
- (UtilRand() & 1) ? AudioObjectIdentifiers::RCT1Title : AudioObjectIdentifiers::RCT2Title);
+ IdIndex = UtilRand() % std::size(selectableAudioIds);
+ break;
+ case TitleMusicKind::None:
+ return {};
}
+
+ return ObjectEntryDescriptor(ObjectType::Audio, selectableAudioIds[IdIndex]);
}
void PlayTitleMusic()
diff --git a/src/openrct2/audio/audio.h b/src/openrct2/audio/audio.h
index 34849ad5f2..583d6019ff 100644
--- a/src/openrct2/audio/audio.h
+++ b/src/openrct2/audio/audio.h
@@ -142,6 +142,7 @@ namespace OpenRCT2::Audio
constexpr std::string_view RCT2Base = "rct2.audio.base";
constexpr std::string_view RCTCBase = "rct2.audio.base.rctc";
constexpr std::string_view RCT2Title = "rct2.audio.title";
+ constexpr std::string_view OpenRCT2Title = "openrct2.audio.title";
constexpr std::string_view RCT2Circus = "rct2.audio.circus";
constexpr std::string_view OpenRCT2Additional = "openrct2.audio.additional";
} // namespace AudioObjectIdentifiers
diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp
index d6caff1787..1e75cff005 100644
--- a/src/openrct2/config/Config.cpp
+++ b/src/openrct2/config/Config.cpp
@@ -362,7 +362,8 @@ namespace Config
model->Device = reader->GetString("audio_device", "");
model->MasterSoundEnabled = reader->GetBoolean("master_sound", true);
model->MasterVolume = reader->GetInt32("master_volume", 100);
- model->TitleMusic = static_cast(reader->GetInt32("title_music", EnumValue(TitleMusicKind::RCT2)));
+ model->TitleMusic = static_cast(
+ reader->GetInt32("title_theme", EnumValue(TitleMusicKind::OpenRCT2)));
model->SoundEnabled = reader->GetBoolean("sound", true);
model->SoundVolume = reader->GetInt32("sound_volume", 100);
model->RideMusicEnabled = reader->GetBoolean("ride_music", true);
@@ -378,7 +379,7 @@ namespace Config
writer->WriteString("audio_device", model->Device);
writer->WriteBoolean("master_sound", model->MasterSoundEnabled);
writer->WriteInt32("master_volume", model->MasterVolume);
- writer->WriteInt32("title_music", EnumValue(model->TitleMusic));
+ writer->WriteInt32("title_theme", EnumValue(model->TitleMusic));
writer->WriteBoolean("sound", model->SoundEnabled);
writer->WriteInt32("sound_volume", model->SoundVolume);
writer->WriteBoolean("ride_music", model->RideMusicEnabled);
diff --git a/src/openrct2/config/Config.h b/src/openrct2/config/Config.h
index 9992cf0f49..5dd801bfba 100644
--- a/src/openrct2/config/Config.h
+++ b/src/openrct2/config/Config.h
@@ -251,9 +251,10 @@ enum class MeasurementFormat : int32_t
enum class TitleMusicKind : int32_t
{
None,
+ Random,
+ OpenRCT2,
RCT1,
RCT2,
- Random
};
extern GeneralConfiguration gConfigGeneral;
diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h
index 5ae21eff8b..36054623c9 100644
--- a/src/openrct2/localisation/StringIds.h
+++ b/src/openrct2/localisation/StringIds.h
@@ -3990,6 +3990,10 @@ enum : uint16_t
STR_OPTION_REVERSE_TRAINS_TIP = 6584,
STR_RIDE_SET_VEHICLE_REVERSED_FAIL = 6585,
+ STR_OPENRCT2_DROPDOWN = 6586,
+ STR_ABOUT_OPENRCT2_TITLE = 6587,
+ STR_ABOUT_FAIRGROUND_ORGAN = 6588,
+
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
/* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings
};