From 1656242563d14fa564bab8d4bc40054ab8998553 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 27 Feb 2021 12:05:45 -0500 Subject: Added background music (defined on a per-map basis) --- res/maps/hallucination_beach.tmx | 3 ++ res/maps/hallucination_cliff.tmx | 3 ++ res/maps/hallucination_hot_spring.tmx | 3 ++ res/maps/hallucination_interior.tmx | 3 ++ res/music/red_green_yellow_yellow.wav | Bin 0 -> 7078446 bytes res/scripts/common.lua | 8 ++++- src/main.cpp | 4 +++ src/map.cpp | 6 ++++ src/map.h | 5 +++ src/mixer.cpp | 58 ++++++++++++++++++++++++++++++++++ src/mixer.h | 36 +++++++++++++++++++++ src/script_system.cpp | 18 ++++++++--- 12 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 res/music/red_green_yellow_yellow.wav diff --git a/res/maps/hallucination_beach.tmx b/res/maps/hallucination_beach.tmx index c6fd1cb..ce6c830 100644 --- a/res/maps/hallucination_beach.tmx +++ b/res/maps/hallucination_beach.tmx @@ -1,5 +1,8 @@ + + + diff --git a/res/maps/hallucination_cliff.tmx b/res/maps/hallucination_cliff.tmx index e6bd65e..8159d54 100644 --- a/res/maps/hallucination_cliff.tmx +++ b/res/maps/hallucination_cliff.tmx @@ -1,5 +1,8 @@ + + + diff --git a/res/maps/hallucination_hot_spring.tmx b/res/maps/hallucination_hot_spring.tmx index 2bb840d..b019681 100644 --- a/res/maps/hallucination_hot_spring.tmx +++ b/res/maps/hallucination_hot_spring.tmx @@ -1,5 +1,8 @@ + + + diff --git a/res/maps/hallucination_interior.tmx b/res/maps/hallucination_interior.tmx index e792133..ee7a5cd 100644 --- a/res/maps/hallucination_interior.tmx +++ b/res/maps/hallucination_interior.tmx @@ -1,5 +1,8 @@ + + + diff --git a/res/music/red_green_yellow_yellow.wav b/res/music/red_green_yellow_yellow.wav new file mode 100644 index 0000000..e1cd6dd Binary files /dev/null and b/res/music/red_green_yellow_yellow.wav differ diff --git a/res/scripts/common.lua b/res/scripts/common.lua index 2a51419..a5e7873 100644 --- a/res/scripts/common.lua +++ b/res/scripts/common.lua @@ -260,7 +260,13 @@ function ChangeMap(map, warp, options) FadeToBlack(150) end loadMap(map) - character():transplantParty(playerId, getWarpPoint(warp), direction) + character():transplantParty(playerId, getMap():getWarpPoint(warp), direction) + + if (mixer():isPlayingMusic() and not getMap():hasMusic()) then + mixer():fadeoutMusic(150) + elseif (getMap():hasMusic() and (not mixer():isPlayingMusic() or not mixer():getPlayingTrack() == getMap():getMusic())) then + mixer():playMusic(getMap():getMusic(), 150) + end coroutine.yield() if (options & ChangeMapOptions.DO_NOT_FADE == 0) then diff --git a/src/main.cpp b/src/main.cpp index 25e7013..b98c8f1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,6 +70,10 @@ void loop(Renderer& renderer, std::mt19937& rng) { renderer.render(game); + if (game.getMap().hasMusic()) { + game.getMixer().playMusic(game.getMap().getMusic()); + } + size_t lastTime = SDL_GetTicks(); while (!game.shouldQuit()) { diff --git a/src/map.cpp b/src/map.cpp index a5ecbdd..7a3de78 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -153,6 +153,12 @@ Map::Map(std::string_view name) : name_(name) { } } } + + for (const tmx::Property& property : mapfile.getProperties()) { + if (property.getName() == "music") { + music_ = property.getStringValue(); + } + } } bool Map::isBlocked(int x, int y) const { diff --git a/src/map.h b/src/map.h index 9f5a93b..ee88920 100644 --- a/src/map.h +++ b/src/map.h @@ -77,6 +77,10 @@ public: const Zone& getZone(const std::string& name) const { return zones_.at(name); } + bool hasMusic() const { return !music_.empty(); } + + const std::string& getMusic() const { return music_; } + private: std::string name_; @@ -90,6 +94,7 @@ private: std::map warpPoints_; std::vector triggers_; std::map zones_; + std::string music_; }; #endif /* end of include guard: MAP_H_D95D6D47 */ diff --git a/src/mixer.cpp b/src/mixer.cpp index bdcb7ce..37c2177 100644 --- a/src/mixer.cpp +++ b/src/mixer.cpp @@ -23,6 +23,49 @@ void Mixer::stopChannel(int channel) { Mix_HaltChannel(channel); } +void Mixer::playMusic(std::string_view name, int ms) { + Mix_Music* song = getMusicByName(name); + int ret; + + if (ms == 0) { + ret = Mix_PlayMusic(song, -1); + } else { + ret = Mix_FadeInMusic(song, -1, ms); + } + + if (ret == -1) { + throw mix_error(); + } + + playingTrack_ = name; +} + +void Mixer::fadeoutMusic(int ms) { + if (Mix_FadeOutMusic(ms) == 0) { + throw mix_error(); + } + + playingTrack_ = ""; +} + +void Mixer::muteMusic() { + Mix_VolumeMusic(0); + musicMuted_ = true; +} + +void Mixer::unmuteMusic() { + Mix_VolumeMusic(musicVolume_); + musicMuted_ = false; +} + +void Mixer::pauseMusic() { + Mix_PauseMusic(); +} + +void Mixer::unpauseMusic() { + Mix_ResumeMusic(); +} + Mix_Chunk* Mixer::getChunkByFilename(std::string filename) { if (!sounds_.count(filename)) { Mix_Chunk* sample = Mix_LoadWAV(filename.c_str()); @@ -35,3 +78,18 @@ Mix_Chunk* Mixer::getChunkByFilename(std::string filename) { return sounds_[filename].get(); } + +Mix_Music* Mixer::getMusicByName(std::string_view name) { + std::string filename = "../res/music/" + std::string(name) + ".wav"; + + if (!music_.count(filename)) { + Mix_Music* song = Mix_LoadMUS(filename.c_str()); + if (!song) { + throw mix_error(); + } + + music_[filename] = music_ptr(song); + } + + return music_[filename].get(); +} diff --git a/src/mixer.h b/src/mixer.h index 7f6ef72..b049118 100644 --- a/src/mixer.h +++ b/src/mixer.h @@ -52,6 +52,16 @@ public: using chunk_ptr = std::unique_ptr; +class music_deleter { +public: + + void operator()(Mix_Music* music) { + Mix_FreeMusic(music); + } +}; + +using music_ptr = std::unique_ptr; + // MUST create the Renderer first! class Mixer { public: @@ -62,12 +72,38 @@ public: void stopChannel(int channel); + // name is the name of the file, not containing the extension + // ms is the time in milliseconds to fade in + void playMusic(std::string_view name, int ms = 0); + + bool isPlayingMusic() const { return !playingTrack_.empty(); } + + const std::string& getPlayingTrack() const { return playingTrack_; } + + void fadeoutMusic(int ms); + + void muteMusic(); + + void unmuteMusic(); + + bool isMusicMuted() const { return musicMuted_; } + + void pauseMusic(); + + void unpauseMusic(); + private: Mix_Chunk* getChunkByFilename(std::string filename); + Mix_Music* getMusicByName(std::string_view name); + mix_wrapper mix_; std::map sounds_; + std::map music_; + std::string playingTrack_; + int musicVolume_ = MIX_MAX_VOLUME; + bool musicMuted_ = false; }; #endif /* end of include guard: MIXER_H_6DF82000 */ diff --git a/src/script_system.cpp b/src/script_system.cpp index 1846de2..7f9f908 100644 --- a/src/script_system.cpp +++ b/src/script_system.cpp @@ -97,7 +97,17 @@ ScriptSystem::ScriptSystem(Game& game) : game_(game) { "mixer", "playSound", &Mixer::playSound, "loopSound", &Mixer::loopSound, - "stopChannel", &Mixer::stopChannel); + "stopChannel", &Mixer::stopChannel, + "playMusic", &Mixer::playMusic, + "fadeoutMusic", &Mixer::fadeoutMusic, + "isPlayingMusic", &Mixer::isPlayingMusic, + "getPlayingTrack", &Mixer::getPlayingTrack); + + engine_.new_usertype( + "map", + "getWarpPoint", &Map::getWarpPoint, + "hasMusic", &Map::hasMusic, + "getMusic", &Map::getMusic); engine_.set_function( "message", @@ -190,9 +200,9 @@ ScriptSystem::ScriptSystem(Game& game) : game_(game) { }); engine_.set_function( - "getWarpPoint", - [&] (std::string warp) { - return game_.getMap().getWarpPoint(warp); + "getMap", + [&] () -> const Map& { + return game_.getMap(); }); engine_.set_function( -- cgit 1.4.1