More configurable music (loop end support, different race result music) (#4445)

* Allow setting [again] track reverse mode via command line

* Make composer field in music information files optional

* Add support for loop end of music

* Remove print statements used for checking current music play time

* Support playing different music on race results screen

Also make them configurable in stk_config.xml

* Allow configuring grand prix win/lose and feature unlocked music in stk_config.xml

* Fix coding indentation style

* Fix warning when scrolling track screenshots in grand prix results

* Display the rank a player kart finishes in if not in 1st place
This commit is contained in:
Richard Qian 2020-12-20 19:14:52 -06:00 committed by GitHub
parent 82b7ab0d17
commit 0db8d50359
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 249 additions and 42 deletions

View File

@ -151,8 +151,27 @@
solver-split-impulse-threshold="-0.00001"
solver-mode=""/>
<!-- The title and default musics. -->
<music title="main_theme.music" default="kart_grand_prix.music"/>
<!-- Various replaceable music tracks that play during certain events.
title: Plays on the main menu.
default: Plays if a track's music was not found.
race-win: Plays when a player finishes in 1st place.
race-neutral: Plays when a player finishes anywhere in the top half
of the total karts but 1st place.
race-lose: Plays when a player finishes in the bottom half of the
total karts.
gp-win: Plays when a player finishes a grand prix in one of the top
three positions.
gp-lose: Plays when a player fails a grand prix.
unlock: Plays when a kart, track, or other content is unlocked.
-->
<music title="main_theme.music"
default="kart_grand_prix.music"
race-win="race_win_theme.music"
race-neutral="race_summary.music"
race-lose="lose_theme.music"
gp-win="win_theme.music"
gp-lose="lose_theme.music"
unlock="win_theme.music"/>
<!-- Replay related values, mostly concerned with saving less data
and using interpolation instead.

View File

@ -53,12 +53,11 @@ MusicInformation *MusicInformation::create(const std::string &filename)
}
std::string s;
if(!root->get("title", &s) ||
!root->get("composer", &s) ||
!root->get("file", &s) )
{
Log::error("MusicInformation",
"One of 'title', 'composer' or 'file' attribute "
"One of 'title' or 'file' attribute "
"is missing in the music XML file '%s'!\n",
filename.c_str());
delete root;
@ -83,6 +82,8 @@ MusicInformation::MusicInformation(const XMLNode *root,
m_fast_music = NULL;
m_normal_loop_start = 0.0f;
m_fast_loop_start = 0.0f;
m_normal_loop_end = -1.0f;
m_fast_loop_end = -1.0f;
m_enable_fast = false;
m_music_waiting = false;
m_faster_time = 1.0f;
@ -92,18 +93,21 @@ MusicInformation::MusicInformation(const XMLNode *root,
// Otherwise read config file
// --------------------------
std::string s;
root->get("title", &s );
m_title = StringUtils::xmlDecode(s);
root->get("composer", &s );
m_composer = StringUtils::xmlDecode(s);
std::string title_raw;
std::string composer_raw;
root->get("title", &title_raw );
m_title = StringUtils::xmlDecode(title_raw);
root->get("composer", &composer_raw );
m_composer = StringUtils::xmlDecode(composer_raw);
root->get("file", &m_normal_filename );
root->get("gain", &m_gain );
root->get("tracks", &m_all_tracks );
root->get("fast", &m_enable_fast );
root->get("fast-filename", &m_fast_filename );
root->get("loop-start", &m_normal_loop_start);
root->get("loop-end", &m_normal_loop_end );
root->get("fast-loop-start", &m_fast_loop_start );
root->get("fast-loop-end", &m_fast_loop_end );
// Get the path from the filename and add it to the ogg filename
std::string path = StringUtils::getPath(filename);
@ -175,7 +179,7 @@ void MusicInformation::startMusic()
#ifdef ENABLE_SOUND
if (UserConfigParams::m_enable_sound)
{
m_normal_music = new MusicOggStream(m_normal_loop_start);
m_normal_music = new MusicOggStream(m_normal_loop_start, m_normal_loop_end);
}
else
#endif
@ -214,7 +218,7 @@ void MusicInformation::startMusic()
#ifdef ENABLE_SOUND
if (UserConfigParams::m_enable_sound)
{
m_fast_music = new MusicOggStream(m_fast_loop_start);
m_fast_music = new MusicOggStream(m_fast_loop_start, m_fast_loop_end);
}
else
#endif

View File

@ -61,6 +61,8 @@ private:
float m_normal_loop_start;
float m_fast_loop_start;
float m_normal_loop_end;
float m_fast_loop_end;
/** Either time for fading faster music in, or time to change pitch. */
float m_faster_time;

View File

@ -28,7 +28,7 @@
#include "utils/file_utils.hpp"
#include "utils/log.hpp"
MusicOggStream::MusicOggStream(float loop_start)
MusicOggStream::MusicOggStream(float loop_start, float loop_end)
{
//m_oggStream= NULL;
m_soundBuffers[0] = m_soundBuffers[1]= 0;
@ -36,6 +36,7 @@ MusicOggStream::MusicOggStream(float loop_start)
m_pausedMusic = true;
m_playing.store(false);
m_loop_start = loop_start;
m_loop_end = loop_end;
} // MusicOggStream
//-----------------------------------------------------------------------------
@ -284,9 +285,10 @@ void MusicOggStream::update()
if(!check("alSourceUnqueueBuffers")) return;
active = streamIntoBuffer(buffer);
if(!active)
float cur_time = (float)ov_time_tell(&m_oggStream);
if(!active || (m_loop_end > 0 && (m_loop_end - cur_time) < 1e-3))
{
// no more data. Seek to loop start (causes the sound to loop)
// No more data, or reached loop end. Seek to loop start (causes the sound to loop)
ov_time_seek(&m_oggStream, m_loop_start);
active = streamIntoBuffer(buffer);//now there really should be data
}

View File

@ -50,7 +50,7 @@
class MusicOggStream : public Music
{
public:
MusicOggStream(float loop_start);
MusicOggStream(float loop_start, float loop_end);
virtual ~MusicOggStream();
virtual void update();
@ -75,6 +75,7 @@ private:
bool streamIntoBuffer(ALuint buffer);
float m_loop_start;
float m_loop_end;
std::string m_fileName;
FILE* m_oggFile;
OggVorbis_File m_oggStream;

View File

@ -42,6 +42,12 @@ STKConfig::STKConfig()
m_has_been_loaded = false;
m_title_music = NULL;
m_default_music = NULL;
m_race_win_music = NULL;
m_race_neutral_music = NULL;
m_race_lose_music = NULL;
m_gp_win_music = NULL;
m_gp_lose_music = NULL;
m_unlock_music = NULL;
m_default_kart_properties = new KartProperties();
} // STKConfig
//-----------------------------------------------------------------------------
@ -53,6 +59,24 @@ STKConfig::~STKConfig()
if (m_default_music)
delete m_default_music;
if (m_race_win_music)
delete m_race_win_music;
if (m_race_neutral_music)
delete m_race_neutral_music;
if (m_race_lose_music)
delete m_race_lose_music;
if (m_gp_win_music)
delete m_gp_win_music;
if (m_gp_lose_music)
delete m_gp_lose_music;
if (m_unlock_music)
delete m_unlock_music;
if (m_default_kart_properties)
delete m_default_kart_properties;
@ -216,6 +240,12 @@ void STKConfig::init_defaults()
m_network_steering_reduction = -100;
m_title_music = NULL;
m_default_music = NULL;
m_race_win_music = NULL;
m_race_neutral_music = NULL;
m_race_lose_music = NULL;
m_gp_win_music = NULL;
m_gp_lose_music = NULL;
m_unlock_music = NULL;
m_solver_split_impulse = false;
m_smooth_normals = false;
m_same_powerup_mode = POWERUP_MODE_ONLY_IF_SAME;
@ -400,6 +430,30 @@ void STKConfig::getAllData(const XMLNode * root)
music_node->get("default", &m_default_music_file);
assert(m_default_music_file.size() > 0);
m_default_music_file = file_manager->getAsset(FileManager::MUSIC, m_default_music_file);
music_node->get("race-win", &m_race_win_music_file);
assert(m_race_win_music_file.size() > 0);
m_race_win_music_file = file_manager->getAsset(FileManager::MUSIC, m_race_win_music_file);
music_node->get("race-neutral", &m_race_neutral_music_file);
assert(m_race_neutral_music_file.size() > 0);
m_race_neutral_music_file = file_manager->getAsset(FileManager::MUSIC, m_race_neutral_music_file);
music_node->get("race-lose", &m_race_lose_music_file);
assert(m_race_lose_music_file.size() > 0);
m_race_lose_music_file = file_manager->getAsset(FileManager::MUSIC, m_race_lose_music_file);
music_node->get("gp-win", &m_gp_win_music_file);
assert(m_gp_win_music_file.size() > 0);
m_gp_win_music_file = file_manager->getAsset(FileManager::MUSIC, m_gp_win_music_file);
music_node->get("gp-lose", &m_gp_lose_music_file);
assert(m_gp_lose_music_file.size() > 0);
m_gp_lose_music_file = file_manager->getAsset(FileManager::MUSIC, m_gp_lose_music_file);
music_node->get("unlock", &m_unlock_music_file);
assert(m_unlock_music_file.size() > 0);
m_unlock_music_file = file_manager->getAsset(FileManager::MUSIC, m_unlock_music_file);
}
if(const XMLNode *skidmarks_node = root->getNode("skid-marks"))
@ -592,6 +646,48 @@ void STKConfig::initMusicFiles()
Log::error("StkConfig", "Cannot load default music: %s.",
m_default_music_file.c_str());
}
m_race_win_music = MusicInformation::create(m_race_win_music_file);
if (!m_race_win_music)
{
Log::error("StkConfig", "Cannot load race win music: %s.",
m_race_win_music_file.c_str());
}
m_race_neutral_music = MusicInformation::create(m_race_neutral_music_file);
if (!m_race_neutral_music)
{
Log::error("StkConfig", "Cannot load race neutral music: %s.",
m_race_neutral_music_file.c_str());
}
m_race_lose_music = MusicInformation::create(m_race_lose_music_file);
if (!m_race_lose_music)
{
Log::error("StkConfig", "Cannot load race lose music: %s.",
m_race_lose_music_file.c_str());
}
m_gp_win_music = MusicInformation::create(m_gp_win_music_file);
if (!m_gp_win_music)
{
Log::error("StkConfig", "Cannot load grand prix win music: %s.",
m_gp_win_music_file.c_str());
}
m_gp_lose_music = MusicInformation::create(m_gp_lose_music_file);
if (!m_gp_lose_music)
{
Log::error("StkConfig", "Cannot load grand prix lose music: %s.",
m_gp_lose_music_file.c_str());
}
m_unlock_music = MusicInformation::create(m_unlock_music_file);
if (!m_unlock_music)
{
Log::error("StkConfig", "Cannot load unlock music: %s.",
m_unlock_music_file.c_str());
}
} // initMusicFiles
// ----------------------------------------------------------------------------

View File

@ -164,9 +164,29 @@ public:
/** Filename of the title music to play.*/
MusicInformation *m_title_music;
/** Filename of the music that is played when the track's music was not found */
/** Filename of the music that is played when the track's music was not found.*/
MusicInformation *m_default_music;
/** Filename of the music to play when a player finishes in 1st place.*/
MusicInformation *m_race_win_music;
/** Filename of the music to play when a player finishes anywhere in the top half
* of the total karts but 1st place, rounded down.*/
MusicInformation *m_race_neutral_music;
/** Filename of the music to play when a player finishes in the bottom half of
* the total karts.*/
MusicInformation *m_race_lose_music;
/** Filename of the grand prix win music to play.*/
MusicInformation *m_gp_win_music;
/** Filename of the grand prix lose music to play.*/
MusicInformation *m_gp_lose_music;
/** Filename of the feature unlock music to play.*/
MusicInformation *m_unlock_music;
/** Maximum number of transform events of a replay. */
int m_replay_max_frames;
@ -252,6 +272,13 @@ private:
std::string m_title_music_file;
std::string m_default_music_file;
std::string m_race_win_music_file;
std::string m_race_neutral_music_file;
std::string m_race_lose_music_file;
std::string m_gp_win_music_file;
std::string m_gp_lose_music_file;
std::string m_unlock_music_file;
public:
STKConfig();
~STKConfig();

View File

@ -1018,7 +1018,7 @@ void Kart::finishedRace(float time, bool from_server)
m->addMessage((too_slow ? _("You were too slow!") :
won_the_race ? _("You won the race!") :
_("You finished the race!")),
_("You finished the race in rank %d!", getPosition())),
this, 2.0f, video::SColor(255, 255, 255, 255), true, true, true);
}
}

View File

@ -1487,6 +1487,11 @@ int handleCmdLine(bool has_server_config, bool has_parent_process)
RaceManager::get()->setNumKarts((int)l.size());
} // --aiNP
if(CommandLine::has("--reverse"))
{
RaceManager::get()->setReverseTrack(true);
}
if(CommandLine::has("--track", &s) || CommandLine::has("-t", &s))
{
RaceManager::get()->setTrack(s);

View File

@ -24,6 +24,7 @@
#include "challenges/challenge_data.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/player_manager.hpp"
#include "config/stk_config.hpp"
#include "config/user_config.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/sp/sp_base.hpp"
@ -759,6 +760,6 @@ void FeatureUnlockedCutScene::eventCallback(GUIEngine::Widget* widget,
MusicInformation* FeatureUnlockedCutScene::getInGameMenuMusic() const
{
MusicInformation* mi = music_manager->getMusicInformation("win_theme.music");
MusicInformation* mi = stk_config->m_unlock_music;
return mi;
}

View File

@ -22,6 +22,7 @@
#include "audio/sfx_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/player_manager.hpp"
#include "config/stk_config.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/lod_node.hpp"
@ -237,7 +238,7 @@ void GrandPrixLose::setKarts(std::vector<std::pair<std::string, float> > ident_a
MusicInformation* GrandPrixLose::getInGameMenuMusic() const
{
MusicInformation* mi = music_manager->getMusicInformation("lose_theme.music");
MusicInformation* mi = stk_config->m_gp_lose_music;
return mi;
}

View File

@ -22,6 +22,7 @@
#include "audio/sfx_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/player_manager.hpp"
#include "config/stk_config.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/render_info.hpp"
@ -424,7 +425,7 @@ void GrandPrixWin::setKarts(const std::pair<std::string, float> idents_arg[3])
MusicInformation* GrandPrixWin::getInGameMenuMusic() const
{
MusicInformation* mi = music_manager->getMusicInformation("win_theme.music");
MusicInformation* mi = stk_config->m_gp_win_music;
return mi;
}

View File

@ -24,6 +24,7 @@
#include "challenges/story_mode_timer.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/player_manager.hpp"
#include "config/stk_config.hpp"
#include "config/user_config.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/material.hpp"
@ -95,29 +96,72 @@ void RaceResultGUI::init()
music_manager->stopMusic();
bool human_win = true;
bool has_human_players = false;
bool in_first_place = false;
unsigned int num_karts = RaceManager::get()->getNumberOfKarts();
for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++)
{
const AbstractKart *kart = World::getWorld()->getKart(kart_id);
if (kart->getController()->isLocalPlayerController())
{
has_human_players = true;
human_win = human_win && kart->getRaceResult();
if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
{
// It's possible the winning kart can get ahead of the leader.
in_first_place = kart->getPosition() <= 2;
}
else
{
in_first_place = kart->getPosition() == 1;
}
}
}
m_finish_sound = SFXManager::get()->quickSound(
human_win ? "race_finish_victory" : "race_finish");
//std::string path = (human_win ? Different result music too later
// file_manager->getAsset(FileManager::MUSIC, "race_summary.music") :
// file_manager->getAsset(FileManager::MUSIC, "race_summary.music"));
std::string path = file_manager->getAsset(FileManager::MUSIC, "race_summary.music");
m_race_over_music = music_manager->getMusicInformation(path);
// Play different result music based on player kart positions.
if (has_human_players)
{
if (human_win)
{
if (in_first_place)
{
// At least one player kart is in 1st place.
m_race_over_music = stk_config->m_race_win_music;
}
else
{
// All player karts finished in winning positions, but none in 1st place.
m_race_over_music = stk_config->m_race_neutral_music;
}
}
else
{
// No player karts finished in winning positions.
m_race_over_music = stk_config->m_race_lose_music;
}
}
else
{
// For races with only AI karts and no human players.
m_race_over_music = stk_config->m_race_neutral_music;
}
if (!m_finish_sound)
{
// If there is no finish sound (because sfx are disabled), start
// the race over music here (since the race over music is only started
// when the finish sound has been played).
music_manager->startMusic(m_race_over_music);
try
{music_manager->startMusic(m_race_over_music);}
catch (std::exception& e)
{
Log::error("RaceResultGUI", "Exception caught when "
"trying to load music: %s", e.what());
}
}
// Calculate how many track screenshots can fit into the "result-table" widget
@ -288,21 +332,25 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
const std::string& name, const int playerID)
{
int n_tracks = RaceManager::get()->getGrandPrix().getNumberOfTracks();
if (name == "up_button" && n_tracks > m_max_tracks && m_start_track > 0)
if (name == "up_button")
{
if (n_tracks > m_max_tracks && m_start_track > 0)
{
m_start_track--;
m_end_track--;
displayScreenShots();
}
else if (name == "down_button" && n_tracks > m_max_tracks &&
m_start_track < (n_tracks - m_max_tracks))
}
else if (name == "down_button")
{
if (n_tracks > m_max_tracks && m_start_track < (n_tracks - m_max_tracks))
{
m_start_track++;
m_end_track++;
displayScreenShots();
}
if(name == "operations")
}
else if (name == "operations")
{
const std::string& action =
getWidget<GUIEngine::RibbonWidget>("operations")->getSelectionIDString(PLAYER_ID_GAME_MASTER);