2020-09-28 04:15:06 +02:00
|
|
|
#define MUSIC_DEFINITION
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "Music.h"
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
#include <SDL.h>
|
2020-07-30 23:06:07 +02:00
|
|
|
#include <physfsrwops.h>
|
2020-07-19 21:43:29 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "BinaryBlob.h"
|
2021-04-02 21:02:01 +02:00
|
|
|
#include "Game.h"
|
Replace main game music with music area map
The main game used a set of copy-pasted code to set the music of each
area. There WAS some redundancy built-in, but only three rooms in each
direction from the entrance of a zone.
Given this, it's completely possible for players to mismatch the music
of the area and level. In fact, it's easy to do it even on accident,
especially since 2.3 now lets you quicksave and quit during cutscenes.
Just play a cutscene that has Pause music, then quicksave, quit, and
reload. Also some other accidental ways that I've forgotten about.
To fix this, I've done what mapclass has and made an areamap. Except for
music. This map is the map of the track number of every single room,
except for three special cases: -1 for do nothing and don't change music
(usually because multiple different tracks can be played in this room),
-2 for Tower music (needs to be track 2 or 9 depending on Flip Mode),
and -3 for the start of Space Station 2 (track 1 in time trials, track 4
otherwise).
I've thoroughly tested this areamap by playing through the game and
entering every single room. Additionally I've also thoroughly tested all
special cases (entering the Ship through the teleporter or main
entrance, using the Ship's jukebox, the Tower in Flip Mode and regular
mode, and the start of Space Station 2 in time trial and in regular
mode).
Closes #449.
2021-05-12 04:59:02 +02:00
|
|
|
#include "Graphics.h"
|
2020-04-04 00:37:59 +02:00
|
|
|
#include "Map.h"
|
Replace main game music with music area map
The main game used a set of copy-pasted code to set the music of each
area. There WAS some redundancy built-in, but only three rooms in each
direction from the entrance of a zone.
Given this, it's completely possible for players to mismatch the music
of the area and level. In fact, it's easy to do it even on accident,
especially since 2.3 now lets you quicksave and quit during cutscenes.
Just play a cutscene that has Pause music, then quicksave, quit, and
reload. Also some other accidental ways that I've forgotten about.
To fix this, I've done what mapclass has and made an areamap. Except for
music. This map is the map of the track number of every single room,
except for three special cases: -1 for do nothing and don't change music
(usually because multiple different tracks can be played in this room),
-2 for Tower music (needs to be track 2 or 9 depending on Flip Mode),
and -3 for the start of Space Station 2 (track 1 in time trials, track 4
otherwise).
I've thoroughly tested this areamap by playing through the game and
entering every single room. Additionally I've also thoroughly tested all
special cases (entering the Ship through the teleporter or main
entrance, using the Ship's jukebox, the Tower in Flip Mode and regular
mode, and the start of Space Station 2 in time trial and in regular
mode).
Closes #449.
2021-05-12 04:59:02 +02:00
|
|
|
#include "Script.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "UtilityClass.h"
|
2021-02-24 00:21:29 +01:00
|
|
|
#include "Vlogging.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
musicclass::musicclass(void)
|
Don't reset entire musicclass when mounting and unmounting assets
musicclass::init() re-initializes every attribute of musicclass
unnecessarily, when initialization should be put in a constructor
instead. This is bad, because music.init() gets called whenever we enter
and exit a custom level that has assets.
Otherwise, this would result in a bug where music.usingmmmmmm would be
reset, causing you to revert to PPPPPP on the title screen whenever you
enter a level with MMMMMM selected and exit it.
This also causes a confusing desync between game.usingmmmmmm and
music.usingmmmmmm since the values of the two variables are now
different (these duplicate variables should probably be removed, too,
and a lot of other duplicate variables like these exist, too, which are
a real headache). Which means despite MMMMMM playing on the title
screen, exiting the game and re-launching it will play PPPPPP instead.
What's even more is that going to game options and switching to PPPPPP
will play PPPPPP, but afterwards launching and re-entering will play
MMMMMM. Again, having duplicate variables is very bad, and should
probably be fixed, but that's a separate patch.
2020-11-13 00:55:58 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
safeToProcessMusic= false;
|
|
|
|
m_doFadeInVol = false;
|
|
|
|
m_doFadeOutVol = false;
|
|
|
|
musicVolume = 0;
|
Don't reset entire musicclass when mounting and unmounting assets
musicclass::init() re-initializes every attribute of musicclass
unnecessarily, when initialization should be put in a constructor
instead. This is bad, because music.init() gets called whenever we enter
and exit a custom level that has assets.
Otherwise, this would result in a bug where music.usingmmmmmm would be
reset, causing you to revert to PPPPPP on the title screen whenever you
enter a level with MMMMMM selected and exit it.
This also causes a confusing desync between game.usingmmmmmm and
music.usingmmmmmm since the values of the two variables are now
different (these duplicate variables should probably be removed, too,
and a lot of other duplicate variables like these exist, too, which are
a real headache). Which means despite MMMMMM playing on the title
screen, exiting the game and re-launching it will play PPPPPP instead.
What's even more is that going to game options and switching to PPPPPP
will play PPPPPP, but afterwards launching and re-entering will play
MMMMMM. Again, having duplicate variables is very bad, and should
probably be fixed, but that's a separate patch.
2020-11-13 00:55:58 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
user_music_volume = USER_VOLUME_MAX;
|
|
|
|
user_sound_volume = USER_VOLUME_MAX;
|
2021-04-12 02:41:46 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
currentsong = 0;
|
|
|
|
nicechange = -1;
|
|
|
|
nicefade = false;
|
|
|
|
quick_fade = true;
|
Don't reset entire musicclass when mounting and unmounting assets
musicclass::init() re-initializes every attribute of musicclass
unnecessarily, when initialization should be put in a constructor
instead. This is bad, because music.init() gets called whenever we enter
and exit a custom level that has assets.
Otherwise, this would result in a bug where music.usingmmmmmm would be
reset, causing you to revert to PPPPPP on the title screen whenever you
enter a level with MMMMMM selected and exit it.
This also causes a confusing desync between game.usingmmmmmm and
music.usingmmmmmm since the values of the two variables are now
different (these duplicate variables should probably be removed, too,
and a lot of other duplicate variables like these exist, too, which are
a real headache). Which means despite MMMMMM playing on the title
screen, exiting the game and re-launching it will play PPPPPP instead.
What's even more is that going to game options and switching to PPPPPP
will play PPPPPP, but afterwards launching and re-entering will play
MMMMMM. Again, having duplicate variables is very bad, and should
probably be fixed, but that's a separate patch.
2020-11-13 00:55:58 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
usingmmmmmm = false;
|
Don't reset entire musicclass when mounting and unmounting assets
musicclass::init() re-initializes every attribute of musicclass
unnecessarily, when initialization should be put in a constructor
instead. This is bad, because music.init() gets called whenever we enter
and exit a custom level that has assets.
Otherwise, this would result in a bug where music.usingmmmmmm would be
reset, causing you to revert to PPPPPP on the title screen whenever you
enter a level with MMMMMM selected and exit it.
This also causes a confusing desync between game.usingmmmmmm and
music.usingmmmmmm since the values of the two variables are now
different (these duplicate variables should probably be removed, too,
and a lot of other duplicate variables like these exist, too, which are
a real headache). Which means despite MMMMMM playing on the title
screen, exiting the game and re-launching it will play PPPPPP instead.
What's even more is that going to game options and switching to PPPPPP
will play PPPPPP, but afterwards launching and re-entering will play
MMMMMM. Again, having duplicate variables is very bad, and should
probably be fixed, but that's a separate patch.
2020-11-13 00:55:58 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void musicclass::init(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
soundTracks.push_back(SoundTrack( "sounds/jump.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/jump2.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/hurt.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/souleyeminijingle.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/coin.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/save.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crumble.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/vanish.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/blip.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/preteleport.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/teleport.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crew1.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crew2.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crew3.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crew4.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crew5.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crew6.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/terminal.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/gamesaved.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crashing.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/blip2.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/countdown.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/go.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/crash.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/combine.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/newrecord.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/trophy.wav" ));
|
|
|
|
soundTracks.push_back(SoundTrack( "sounds/rescue.wav" ));
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
#ifdef VVV_COMPILEMUSIC
|
2021-09-07 03:56:39 +02:00
|
|
|
binaryBlob musicWriteBlob;
|
2020-07-30 23:06:07 +02:00
|
|
|
#define FOREACH_TRACK(blob, track_name) blob.AddFileToBinaryBlob("data/" track_name);
|
2021-09-07 03:56:39 +02:00
|
|
|
TRACK_NAMES(musicWriteBlob)
|
2020-07-01 00:17:02 +02:00
|
|
|
#undef FOREACH_TRACK
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
musicWriteBlob.writeBinaryBlob("data/BinaryMusic.vvv");
|
|
|
|
musicWriteBlob.clear();
|
2020-01-01 21:29:24 +01:00
|
|
|
#endif
|
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
num_mmmmmm_tracks = 0;
|
|
|
|
num_pppppp_tracks = 0;
|
2020-07-01 02:08:37 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
if (!mmmmmm_blob.unPackBinary("mmmmmm.vvv"))
|
|
|
|
{
|
|
|
|
if (pppppp_blob.unPackBinary("vvvvvvmusic.vvv"))
|
|
|
|
{
|
|
|
|
vlog_info("Loading music from PPPPPP blob...");
|
2020-07-30 23:06:07 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
mmmmmm = false;
|
|
|
|
usingmmmmmm=false;
|
2020-07-30 23:06:07 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
int index;
|
|
|
|
SDL_RWops* rw;
|
2020-07-30 23:06:07 +02:00
|
|
|
|
|
|
|
#define FOREACH_TRACK(blob, track_name) \
|
2021-09-07 03:56:39 +02:00
|
|
|
index = blob.getIndex("data/" track_name); \
|
|
|
|
rw = SDL_RWFromMem(blob.getAddress(index), blob.getSize(index)); \
|
|
|
|
musicTracks.push_back(MusicTrack( rw ));
|
2020-07-30 23:06:07 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
TRACK_NAMES(pppppp_blob)
|
2020-07-30 23:06:07 +02:00
|
|
|
|
|
|
|
#undef FOREACH_TRACK
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vlog_info("Loading music from loose files...");
|
2020-07-30 23:06:07 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_RWops* rw;
|
2020-07-30 23:06:07 +02:00
|
|
|
#define FOREACH_TRACK(_, track_name) \
|
2021-09-07 03:56:39 +02:00
|
|
|
rw = PHYSFSRWOPS_openRead(track_name); \
|
|
|
|
musicTracks.push_back(MusicTrack( rw ));
|
2020-07-30 23:06:07 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
TRACK_NAMES(_)
|
2020-07-30 23:06:07 +02:00
|
|
|
|
|
|
|
#undef FOREACH_TRACK
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vlog_info("Loading PPPPPP and MMMMMM blobs...");
|
2020-07-30 23:06:07 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
mmmmmm = true;
|
|
|
|
int index;
|
|
|
|
SDL_RWops *rw;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-02-16 01:38:10 +01:00
|
|
|
#define FOREACH_TRACK(blob, track_name) \
|
2021-09-07 03:56:39 +02:00
|
|
|
index = blob.getIndex("data/" track_name); \
|
|
|
|
if (index >= 0 && index < blob.max_headers) \
|
|
|
|
{ \
|
|
|
|
rw = SDL_RWFromConstMem(blob.getAddress(index), blob.getSize(index)); \
|
|
|
|
if (rw == NULL) \
|
|
|
|
{ \
|
|
|
|
vlog_error("Unable to read music file header: %s", SDL_GetError()); \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
musicTracks.push_back(MusicTrack( rw )); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACK_NAMES(mmmmmm_blob)
|
|
|
|
|
|
|
|
num_mmmmmm_tracks += musicTracks.size();
|
|
|
|
|
|
|
|
size_t index_ = 0;
|
|
|
|
while (mmmmmm_blob.nextExtra(&index_))
|
|
|
|
{
|
|
|
|
rw = SDL_RWFromConstMem(mmmmmm_blob.getAddress(index_), mmmmmm_blob.getSize(index_));
|
|
|
|
musicTracks.push_back(MusicTrack( rw ));
|
|
|
|
|
|
|
|
num_mmmmmm_tracks++;
|
|
|
|
index_++;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ohCrap = pppppp_blob.unPackBinary("vvvvvvmusic.vvv");
|
|
|
|
SDL_assert(ohCrap && "Music not found!");
|
|
|
|
|
|
|
|
TRACK_NAMES(pppppp_blob)
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-07-01 00:17:02 +02:00
|
|
|
#undef FOREACH_TRACK
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
num_pppppp_tracks += musicTracks.size() - num_mmmmmm_tracks;
|
2020-07-01 02:08:37 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_RWops* rw;
|
|
|
|
size_t index_ = 0;
|
|
|
|
while (pppppp_blob.nextExtra(&index_))
|
|
|
|
{
|
|
|
|
rw = SDL_RWFromConstMem(pppppp_blob.getAddress(index_), pppppp_blob.getSize(index_));
|
|
|
|
musicTracks.push_back(MusicTrack( rw ));
|
2020-07-01 02:08:37 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
num_pppppp_tracks++;
|
|
|
|
index_++;
|
|
|
|
}
|
Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.
When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.
I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.
Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.
Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.
Other than that, these commands are now fully functional.
2020-06-27 10:31:09 +02:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void musicclass::destroy(void)
|
2021-02-16 01:24:21 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
for (size_t i = 0; i < soundTracks.size(); ++i)
|
|
|
|
{
|
|
|
|
Mix_FreeChunk(soundTracks[i].sound);
|
|
|
|
}
|
|
|
|
soundTracks.clear();
|
|
|
|
|
|
|
|
// Before we free all the music: stop playing music, else SDL2_mixer
|
|
|
|
// will call SDL_Delay() if we are fading, resulting in no-draw frames
|
|
|
|
Mix_HaltMusic();
|
|
|
|
|
|
|
|
for (size_t i = 0; i < musicTracks.size(); ++i)
|
|
|
|
{
|
|
|
|
Mix_FreeMusic(musicTracks[i].m_music);
|
|
|
|
}
|
|
|
|
musicTracks.clear();
|
|
|
|
|
|
|
|
pppppp_blob.clear();
|
|
|
|
mmmmmm_blob.clear();
|
2021-02-16 01:24:21 +01:00
|
|
|
}
|
|
|
|
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
void musicclass::play(int t)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (mmmmmm && usingmmmmmm)
|
|
|
|
{
|
|
|
|
// Don't conjoin this if-statement with the above one...
|
|
|
|
if (num_mmmmmm_tracks > 0)
|
|
|
|
{
|
|
|
|
t %= num_mmmmmm_tracks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (num_pppppp_tracks > 0)
|
|
|
|
{
|
|
|
|
t %= num_pppppp_tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mmmmmm && !usingmmmmmm)
|
|
|
|
{
|
|
|
|
t += num_mmmmmm_tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
safeToProcessMusic = true;
|
|
|
|
|
|
|
|
if (currentsong == t && !m_doFadeOutVol)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentsong = t;
|
|
|
|
|
|
|
|
if (t == -1)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!INBOUNDS_VEC(t, musicTracks))
|
|
|
|
{
|
|
|
|
vlog_error("play() out-of-bounds!");
|
|
|
|
currentsong = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentsong == 0 || currentsong == 7 || (!map.custommode && (currentsong == 0+num_mmmmmm_tracks || currentsong == 7+num_mmmmmm_tracks)))
|
|
|
|
{
|
|
|
|
// Level Complete theme, no fade in or repeat
|
|
|
|
if (Mix_PlayMusic(musicTracks[t].m_music, 0) == -1)
|
|
|
|
{
|
|
|
|
vlog_error("Mix_PlayMusic: %s", Mix_GetError());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_doFadeInVol = false;
|
|
|
|
m_doFadeOutVol = false;
|
|
|
|
musicVolume = MIX_MAX_VOLUME;
|
|
|
|
Mix_VolumeMusic(musicVolume);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (m_doFadeOutVol)
|
|
|
|
{
|
|
|
|
// We're already fading out
|
|
|
|
nicechange = t;
|
|
|
|
nicefade = true;
|
|
|
|
currentsong = -1;
|
|
|
|
|
|
|
|
if (quick_fade)
|
|
|
|
{
|
|
|
|
fadeMusicVolumeOut(500); // fade out quicker
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
quick_fade = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (Mix_PlayMusic(musicTracks[t].m_music, -1) == -1)
|
|
|
|
{
|
|
|
|
vlog_error("Mix_PlayMusic: %s", Mix_GetError());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_doFadeInVol = false;
|
|
|
|
m_doFadeOutVol = false;
|
|
|
|
fadeMusicVolumeIn(3000);
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
void musicclass::resume()
|
Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.
When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.
I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.
Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.
Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.
Other than that, these commands are now fully functional.
2020-06-27 10:31:09 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
Mix_ResumeMusic();
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
}
|
Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.
When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.
I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.
Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.
Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.
Other than that, these commands are now fully functional.
2020-06-27 10:31:09 +02:00
|
|
|
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
void musicclass::resumefade(const int fadein_ms)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
resume();
|
|
|
|
fadeMusicVolumeIn(fadein_ms);
|
Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.
When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.
I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.
Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.
Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.
Other than that, these commands are now fully functional.
2020-06-27 10:31:09 +02:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void musicclass::fadein(void)
|
Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.
When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.
I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.
Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.
Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.
Other than that, these commands are now fully functional.
2020-06-27 10:31:09 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
resumefade(3000); // 3000 ms fadein
|
Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.
When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.
I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.
Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.
Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.
Other than that, these commands are now fully functional.
2020-06-27 10:31:09 +02:00
|
|
|
}
|
|
|
|
|
2021-04-02 21:07:19 +02:00
|
|
|
void musicclass::pause(void)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
Mix_PauseMusic();
|
2021-04-02 21:07:19 +02:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void musicclass::haltdasmusik(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
/* Just pauses music. This is intended. */
|
|
|
|
pause();
|
|
|
|
currentsong = -1;
|
|
|
|
m_doFadeInVol = false;
|
|
|
|
m_doFadeOutVol = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void musicclass::silencedasmusik(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
musicVolume = 0;
|
2021-09-11 02:02:24 +02:00
|
|
|
m_doFadeInVol = false;
|
|
|
|
m_doFadeOutVol = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
struct FadeState
|
2021-04-02 21:02:01 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
int start_volume;
|
|
|
|
int end_volume;
|
|
|
|
int duration_ms;
|
|
|
|
int step_ms;
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct FadeState fade;
|
|
|
|
|
|
|
|
enum FadeCode
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
Fade_continue,
|
|
|
|
Fade_finished
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static enum FadeCode processmusicfade(struct FadeState* state, int* volume)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
int range;
|
|
|
|
int new_volume;
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
if (state->duration_ms == 0 /* Fast path. */
|
|
|
|
|| state->start_volume == state->end_volume /* Fast path. */
|
|
|
|
|| state->step_ms >= state->duration_ms /* We're finished. */)
|
|
|
|
{
|
|
|
|
*volume = state->end_volume;
|
|
|
|
state->step_ms = 0;
|
|
|
|
return Fade_finished;
|
|
|
|
}
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
range = state->end_volume - state->start_volume;
|
|
|
|
new_volume = range * state->step_ms / state->duration_ms;
|
|
|
|
new_volume += state->start_volume;
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
*volume = new_volume;
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
state->step_ms += game.get_timestep();
|
Fix fade volume durations being incorrect
The previous fade system used only one variable, the amount of volume to
fade per frame. However, this variable was an integer, meaning any
decimal portion would be truncated, and would lead to a longer fade
duration than intended.
The fade per volume is calculated by doing MIX_MAX_VOLUME / (fade_ms /
game.get_timestep()). MIX_MAX_VOLUME is 128, and game.get_timestep() is
usually 34, so a 3000 millisecond fade would be calculated as 128 /
(3000 / 34). 3000 / 34 is 88.235..., but that gets truncated to 88, and
then 128 / 88 becomes 1.454545..., which then gets truncated to 1. This
essentially means 1 is added to or subtracted from the volume every
frame, and given that the max volume is 128, this means that the fade
lasts for 128 frames. Now, instead of the fade duration lasting 3
seconds, the fade now lasts for 128 frames, which is 128 * 34 / 1000 =
4.352 seconds long.
This could be fixed using floats, but when you introduce floats, you now
have 1.9999998 problems. For instance, I'm concerned about
floating-point determinism issues.
What I've done instead is switch the system to use four different
variables instead: the start volume, the end volume, the total duration,
and the duration completed so far (called the "step"). For every frame,
the game interpolates which value should be used based on the step, the
total duration, and the start and end volumes, and then adds the
timestep to the step. This way, fades will be correctly timed, and we
don't have potential determinism issues.
Doing this also fixes inaccuracies with the game timestep changing
during the fade, since the timestep is only used in the calculation
once at the beginning in the previous system.
2021-04-28 01:37:16 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
return Fade_continue;
|
2021-04-02 21:02:01 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void musicclass::fadeMusicVolumeIn(int ms)
|
|
|
|
{
|
2021-09-11 04:37:33 +02:00
|
|
|
if (halted())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
m_doFadeInVol = true;
|
|
|
|
m_doFadeOutVol = false;
|
2021-04-12 19:38:44 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
/* Ensure it starts at 0 */
|
|
|
|
musicVolume = 0;
|
2021-04-12 19:38:44 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
/* Fix 1-frame glitch */
|
|
|
|
Mix_VolumeMusic(0);
|
2021-04-12 19:41:44 +02:00
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
fade.step_ms = 0;
|
|
|
|
fade.duration_ms = ms;
|
|
|
|
fade.start_volume = 0;
|
|
|
|
fade.end_volume = MIX_MAX_VOLUME;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
void musicclass::fadeMusicVolumeOut(const int fadeout_ms)
|
|
|
|
{
|
2021-09-11 04:37:33 +02:00
|
|
|
if (halted())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
m_doFadeInVol = false;
|
|
|
|
m_doFadeOutVol = true;
|
|
|
|
|
|
|
|
fade.step_ms = 0;
|
|
|
|
/* Duration is proportional to current volume. */
|
|
|
|
fade.duration_ms = fadeout_ms * musicVolume / MIX_MAX_VOLUME;
|
|
|
|
fade.start_volume = musicVolume;
|
|
|
|
fade.end_volume = 0;
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
}
|
|
|
|
|
2020-11-06 09:51:04 +01:00
|
|
|
void musicclass::fadeout(const bool quick_fade_ /*= true*/)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
fadeMusicVolumeOut(quick_fade_ ? 500 : 2000);
|
|
|
|
quick_fade = quick_fade_;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void musicclass::processmusicfadein(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
enum FadeCode fade_code = processmusicfade(&fade, &musicVolume);
|
|
|
|
if (fade_code == Fade_finished)
|
|
|
|
{
|
|
|
|
m_doFadeInVol = false;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
void musicclass::processmusicfadeout(void)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
enum FadeCode fade_code = processmusicfade(&fade, &musicVolume);
|
|
|
|
if (fade_code == Fade_finished)
|
|
|
|
{
|
|
|
|
musicVolume = 0;
|
|
|
|
m_doFadeOutVol = false;
|
|
|
|
haltdasmusik();
|
|
|
|
}
|
Re-fix resumemusic/musicfadein once again
So it looks like facb079b3597b380f876537523cd351a0e637b62 (PR #316) had
a few issues.
The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)
Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.
Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).
And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.
There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 21:56:25 +02:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void musicclass::processmusic(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if(!safeToProcessMusic)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_doFadeInVol)
|
|
|
|
{
|
|
|
|
processmusicfadein();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_doFadeOutVol)
|
|
|
|
{
|
|
|
|
processmusicfadeout();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This needs to come after processing fades */
|
2021-09-11 04:35:29 +02:00
|
|
|
if (nicefade && halted())
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
play(nicechange);
|
|
|
|
nicechange = -1;
|
|
|
|
nicefade = false;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void musicclass::niceplay(int t)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
/* important: do nothing if the correct song is playing! */
|
|
|
|
if ((!mmmmmm && currentsong != t)
|
|
|
|
|| (mmmmmm && usingmmmmmm && currentsong != t)
|
|
|
|
|| (mmmmmm && !usingmmmmmm && currentsong != t + num_mmmmmm_tracks))
|
|
|
|
{
|
|
|
|
if (currentsong != -1)
|
|
|
|
{
|
|
|
|
fadeout(false);
|
|
|
|
}
|
|
|
|
nicefade = true;
|
|
|
|
}
|
|
|
|
nicechange = t;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Replace main game music with music area map
The main game used a set of copy-pasted code to set the music of each
area. There WAS some redundancy built-in, but only three rooms in each
direction from the entrance of a zone.
Given this, it's completely possible for players to mismatch the music
of the area and level. In fact, it's easy to do it even on accident,
especially since 2.3 now lets you quicksave and quit during cutscenes.
Just play a cutscene that has Pause music, then quicksave, quit, and
reload. Also some other accidental ways that I've forgotten about.
To fix this, I've done what mapclass has and made an areamap. Except for
music. This map is the map of the track number of every single room,
except for three special cases: -1 for do nothing and don't change music
(usually because multiple different tracks can be played in this room),
-2 for Tower music (needs to be track 2 or 9 depending on Flip Mode),
and -3 for the start of Space Station 2 (track 1 in time trials, track 4
otherwise).
I've thoroughly tested this areamap by playing through the game and
entering every single room. Additionally I've also thoroughly tested all
special cases (entering the Ship through the teleporter or main
entrance, using the Ship's jukebox, the Tower in Flip Mode and regular
mode, and the start of Space Station 2 in time trial and in regular
mode).
Closes #449.
2021-05-12 04:59:02 +02:00
|
|
|
static const int areamap[] = {
|
2021-09-07 03:56:39 +02:00
|
|
|
4, 3, 3, 3, 3, 3, 3, 3, 4,-2, 4, 4, 4,12,12,12,12,12,12,12,
|
|
|
|
4, 3, 3, 3, 3, 3, 3, 4, 4,-2, 4, 4, 4, 4,12,12,12,12,12,12,
|
|
|
|
4, 4, 4, 4, 3, 4, 4, 4, 4,-2, 4, 4, 4, 4,12,12,12,12,12,12,
|
|
|
|
4, 4, 4, 4, 3, 4, 4, 4, 4,-2, 4, 4, 1, 1, 1, 1,12,12,12,12,
|
|
|
|
4, 4, 3, 3, 3, 4, 4, 4, 4,-2,-2,-2, 1, 1, 1, 1, 4, 4, 4, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 1, 1, 1, 1, 1, 1,11,11,-1, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 1, 1, 1, 1, 1, 1, 1,11,11,11,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1,11,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4,-2,-2, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4,
|
|
|
|
4, 4,-1,-1,-1, 4, 4, 4, 4,-2, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4,
|
|
|
|
4, 4,-1,-1,-1, 4, 4, 4, 4,-2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4, 1, 1, 1, 1, 1, 1, 4, 1, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4, 1, 1, 1, 1, 1, 1, 4, 1, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,-2, 4,-1,-3, 4, 4, 4, 4, 4, 1, 4,
|
|
|
|
4, 4, 4, 4, 4, 3, 3, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 4, 3, 3, 3, 3, 3, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 3, 3, 3, 3, 3, 3, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
3, 3, 3, 3, 3, 4, 4, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
3, 3, 3, 3, 3, 4, 4, 3, 4,-2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
Replace main game music with music area map
The main game used a set of copy-pasted code to set the music of each
area. There WAS some redundancy built-in, but only three rooms in each
direction from the entrance of a zone.
Given this, it's completely possible for players to mismatch the music
of the area and level. In fact, it's easy to do it even on accident,
especially since 2.3 now lets you quicksave and quit during cutscenes.
Just play a cutscene that has Pause music, then quicksave, quit, and
reload. Also some other accidental ways that I've forgotten about.
To fix this, I've done what mapclass has and made an areamap. Except for
music. This map is the map of the track number of every single room,
except for three special cases: -1 for do nothing and don't change music
(usually because multiple different tracks can be played in this room),
-2 for Tower music (needs to be track 2 or 9 depending on Flip Mode),
and -3 for the start of Space Station 2 (track 1 in time trials, track 4
otherwise).
I've thoroughly tested this areamap by playing through the game and
entering every single room. Additionally I've also thoroughly tested all
special cases (entering the Ship through the teleporter or main
entrance, using the Ship's jukebox, the Tower in Flip Mode and regular
mode, and the start of Space Station 2 in time trial and in regular
mode).
Closes #449.
2021-05-12 04:59:02 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
SDL_COMPILE_TIME_ASSERT(areamap, SDL_arraysize(areamap) == 20 * 20);
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void musicclass::changemusicarea(int x, int y)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
int room;
|
|
|
|
int track;
|
|
|
|
|
|
|
|
if (script.running)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
room = musicroom(x, y);
|
|
|
|
|
|
|
|
if (!INBOUNDS_ARR(room, areamap))
|
|
|
|
{
|
|
|
|
SDL_assert(0 && "Music map index out-of-bounds!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
track = areamap[room];
|
|
|
|
|
|
|
|
switch (track)
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
/* Don't change music. */
|
|
|
|
return;
|
|
|
|
case -2:
|
|
|
|
/* Special case: Tower music, changes with Flip Mode. */
|
|
|
|
if (graphics.setflipmode)
|
|
|
|
{
|
|
|
|
track = 9; /* ecroF evitisoP */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
track = 2; /* Positive Force */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case -3:
|
|
|
|
/* Special case: start of Space Station 2. */
|
|
|
|
if (game.intimetrial)
|
|
|
|
{
|
|
|
|
track = 1; /* Pushing Onwards */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
track = 4; /* Passion for Exploring */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
niceplay(track);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-02 01:36:35 +02:00
|
|
|
void musicclass::playef(int t)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (!INBOUNDS_VEC(t, soundTracks))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int channel;
|
|
|
|
|
|
|
|
channel = Mix_PlayChannel(-1, soundTracks[t].sound, 0);
|
|
|
|
if(channel == -1)
|
|
|
|
{
|
|
|
|
vlog_error("Unable to play WAV file: %s", Mix_GetError());
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2021-04-02 21:07:19 +02:00
|
|
|
|
|
|
|
void musicclass::pauseef(void)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
Mix_Pause(-1);
|
2021-04-02 21:07:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void musicclass::resumeef(void)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
Mix_Resume(-1);
|
2021-04-02 21:07:19 +02:00
|
|
|
}
|
2021-09-11 04:35:29 +02:00
|
|
|
|
|
|
|
bool musicclass::halted(void)
|
|
|
|
{
|
|
|
|
return Mix_PausedMusic() == 1;
|
|
|
|
}
|