diff --git a/src/g_game.c b/src/g_game.c index bfb58032b4ad63178cdf4069261a1467fcbffa9f..3dc64918320810fb901666768ece50ebc858ed53 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2037,7 +2037,7 @@ void G_Ticker(boolean run) if (Playing() == true) { - P_InvincGrowMusic(); + P_InvincGrowMusic_Control(); K_TickMidVote(); } diff --git a/src/music.cpp b/src/music.cpp index 44f1edb3cf971386f33994f83bc5fc3d2f1efa01..ed9b2e2b0fc6310d566819986f4c8ef2eacda79a 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -13,6 +13,7 @@ #include "doomtype.h" #include "music.h" +#include "z_zone.h" using namespace srb2::music; @@ -23,8 +24,31 @@ TuneManager g_tunes; }; // namespace +skin_t* music_observableSkin = nullptr; + +static Tune* Music_Find(const char *id, SINT8 *skintuneIndexOut) +{ + if(skintuneIndexOut) + *skintuneIndexOut = -1; + + SINT8 skintuneIndex = R_FindSkintuneIndex(music_observableSkin, id); + + if(skintuneIndex < 0) + return g_tunes.find(id); + + if(skintuneIndexOut) + *skintuneIndexOut = skintuneIndex; + + char* swaptunename = R_TryAllocSkintuneTuneName(skintuneIndex); + Tune* ret = g_tunes.find(swaptunename); + Z_Free(swaptunename); + return ret; +} + void Music_Init(void) { + music_observableSkin = nullptr; + { Tune& tune = g_tunes.insert("level"); @@ -217,6 +241,26 @@ void Music_Init(void) tune.priority = 35; tune.loop = false; } + + UINT8 i; + + for(i = 0; i < NUMSKINTUNES; i++) + { + Tune* src = g_tunes.find(skins_skintunenames[i]); + + if(!src) + continue; + + char newtunename[5 + MAXSKINTUNENAMELEN + 1]; + memset(newtunename, 0, (5 + MAXSKINTUNENAMELEN + 1) * sizeof(char)); + sprintf(newtunename, "skin_%s", skins_skintunenames[i]); + + Tune& dest = g_tunes.insert(newtunename); + dest.priority = src->priority; + dest.resume_fade_in = src->resume_fade_in; + dest.use_level_volume = src->use_level_volume; + // fill out more deep-copy assignments as needed here + } } @@ -249,9 +293,13 @@ void Music_AddTune(const char* id, int priority, int tuneflags) void Music_Play(const char* id) { - Tune* tune = g_tunes.find(id); + SINT8 skintuneIndex; + Tune* tune = Music_Find(id, &skintuneIndex); - if (tune) + if(skintuneIndex >= 0) + tune->song = music_observableSkin->skintunes[skintuneIndex]; + + if(tune) { tune->play(); g_tunes.tick(); // play this immediately @@ -260,7 +308,7 @@ void Music_Play(const char* id) void Music_SetFadeOut(const char* id, int fade_out) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -277,7 +325,7 @@ void Music_SetFadeOut(const char* id, int fade_out) void Music_SetFadeIn(const char* id, int fade_in, boolean resume) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -301,7 +349,7 @@ void Music_SetFadeIn(const char* id, int fade_in, boolean resume) void Music_DelayEnd(const char* id, tic_t duration) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -318,7 +366,7 @@ void Music_DelayEnd(const char* id, tic_t duration) void Music_Seek(const char* id, UINT32 set) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -329,7 +377,7 @@ void Music_Seek(const char* id, UINT32 set) void Music_Stop(const char* id) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -340,7 +388,7 @@ void Music_Stop(const char* id) void Music_Pause(const char* id) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -351,7 +399,7 @@ void Music_Pause(const char* id) void Music_UnPause(const char* id) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -362,7 +410,7 @@ void Music_UnPause(const char* id) void Music_Suspend(const char* id) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -373,7 +421,7 @@ void Music_Suspend(const char* id) void Music_UnSuspend(const char* id) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -402,7 +450,7 @@ void Music_StopAll(void) void Music_Remap(const char* id, const char* song) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -412,7 +460,7 @@ void Music_Remap(const char* id, const char* song) boolean Music_TuneExists(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -423,49 +471,49 @@ boolean Music_TuneExists(const char* id) boolean Music_Playing(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune && tune->playing(); } boolean Music_Paused(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune && tune->paused(); } boolean Music_Suspended(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune && tune->suspend; } tic_t Music_Elapsed(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune ? tune->elapsed() : 0u; } tic_t Music_DurationLeft(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune ? tune->time_remaining() : 0u; } tic_t Music_TotalDuration(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune ? tune->duration() : 0u; } unsigned int Music_FadeOutDuration(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune ? tune->fade_out : 0; } void Music_Loop(const char* id, boolean loop) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { @@ -477,19 +525,19 @@ void Music_Loop(const char* id, boolean loop) boolean Music_CanLoop(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune && tune->loop; } boolean Music_CanEnd(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune && tune->can_end(); } const char* Music_Song(const char* id) { - const Tune* tune = g_tunes.find(id); + const Tune* tune = Music_Find(id, nullptr); return tune ? tune->song.c_str() : ""; } @@ -505,7 +553,7 @@ const char* Music_CurrentId(void) void Music_BatchExempt(const char* id) { - Tune* tune = g_tunes.find(id); + Tune* tune = Music_Find(id, nullptr); if (tune) { diff --git a/src/music.h b/src/music.h index 630c7a98ce72698d1426ad2ed8ef2d1ef740e2bf..3b64f17a09be44a241fb02933cfb1f7d5ba23aec 100644 --- a/src/music.h +++ b/src/music.h @@ -30,6 +30,7 @@ #define MUSIC_H #include "doomtype.h" +#include "r_skins.h" // skin_t, skins_skintunenames, etc. #ifdef __cplusplus extern "C" { @@ -63,6 +64,7 @@ extern "C" { // Get the currently playing tune. // +extern skin_t* music_observableSkin; // Returns the song name for the currently playing tune. // Returns empty string if no tune is playing. diff --git a/src/p_local.h b/src/p_local.h index 19e311911487982182307ba9bd8f0d84379a1160..7b33e359859cd84d3d95595ee42c6beca9505944 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -185,7 +185,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, an void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_StartPositionMusic(boolean exact); void P_EndingMusic(void); -void P_InvincGrowMusic(void); +void P_InvincGrowMusic_Control(void); mobj_t *P_SpawnGhostMobj(mobj_t *mobj); mobj_t *P_SpawnFakeShadow(mobj_t *mobj, UINT8 offset); INT32 P_GivePlayerRings(player_t *player, INT32 num_rings); diff --git a/src/p_user.c b/src/p_user.c index ecff343eeec5469e345b20e4a36c06b086ed2709..64e195a905c00f520e841f28397f980546f71ad5 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -738,10 +738,22 @@ skippingposition: Music_Play("finish"); } -void P_InvincGrowMusic(void) +static void P_InvincGrowMusic_Play(UINT8 skintuneIndex, INT32 timer) { - INT32 invinc = 0; - INT32 grow = 0; + char* tunename = skins_skintunenames[skintuneIndex]; + + if (timer && !Music_Playing(tunename)) + Music_Play(tunename); + + Music_DelayEnd(tunename, timer); +} + +void P_InvincGrowMusic_Control(void) +{ + INT32 timerSlots[NUMSKINTUNES]; + memset(timerSlots, 0, NUMSKINTUNES * sizeof(INT32)); + + skin_t *prevObservable = music_observableSkin; UINT8 i; @@ -759,29 +771,23 @@ void P_InvincGrowMusic(void) // Find the longest running timer among splitscreen // players and use that. - if (player->invincibilitytimer > invinc) + if (player->invincibilitytimer > timerSlots[0]) { - invinc = player->invincibilitytimer; + timerSlots[0] = player->invincibilitytimer; } - if (player->growshrinktimer > grow) + if (player->growshrinktimer > timerSlots[1]) { - grow = player->growshrinktimer; + timerSlots[1] = player->growshrinktimer; } - } - if (invinc && !Music_Playing("invinc")) - { - Music_Play("invinc"); + music_observableSkin = (timerSlots[0] || timerSlots[1]) ? &skins[player->skin] : NULL; } - if (grow && !Music_Playing("grow")) - { - Music_Play("grow"); - } + for(i = 0; i < NUMSKINTUNES; i++) + P_InvincGrowMusic_Play(i, timerSlots[i]); - Music_DelayEnd("invinc", invinc); - Music_DelayEnd("grow", grow); + music_observableSkin = prevObservable; } // diff --git a/src/r_skins.c b/src/r_skins.c index 994ce64fbbd372b01b49846a8ffb0f1993d5be9c..9811c65a6e3869bad92c49e0e98487ee18e69888 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -54,6 +54,11 @@ CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; CV_PossibleValue_t Forceskin_cons_t[MAXSKINS+2]; +char skins_skintunenames[NUMSKINTUNES][MAXSKINTUNENAMELEN + 1] = { + "invinc", + "grow" +}; + // // P_GetSkinSprite2 // For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing. @@ -103,6 +108,39 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) return spr2; } +SINT8 R_FindSkintuneIndex(skin_t *skin, const char *tunename) +{ + if(!skin || !tunename) + return -1; + + UINT8 i; + + for(i = 0; i < NUMSKINTUNES; i++) + { + if(stricmp(skins_skintunenames[i], tunename)) + continue; + + if(!skin->definedSkintunes[i]) + continue; + + return i; + } + + return -1; +} + +char* R_TryAllocSkintuneTuneName(UINT8 skintuneIndex) +{ + if(skintuneIndex >= NUMSKINTUNES) + return NULL; + + int allocAmt = (MAXSKINTUNENAMELEN + 5 + 1) * sizeof(char); // i'm aware that a char is 1 byte big, doing the mult for posterity + char *ret = (char*)Z_Malloc(allocAmt, PU_STATIC, NULL); + memset(ret, 0, allocAmt); + sprintf(ret, "skin_%s", skins_skintunenames[skintuneIndex]); + return ret; +} + static void Sk_SetDefaultValue(skin_t *skin) { INT32 i; @@ -892,40 +930,66 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) GETFLAG(BADNIK) #undef GETFLAG - else // let's check if it's a sound, otherwise error out + else // let's check if it's a sound or skintune, otherwise error out { - boolean found = false; - sfxenum_t i; - size_t stokenadjust; - - // Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.) - if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS* - stokenadjust = 2; - else // sfx_* - stokenadjust = 4; - - // Remove the prefix. (We can affect this directly since we're not going to use it again.) - if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS* - value += 2; - else // sfx_* - value += 4; - - // copy name of sounds that are remapped - // for this skin - for (i = 0; i < sfx_skinsoundslot0; i++) + SINT8 skindex = -1; + UINT8 skini; + + for(skini = 0; skini < NUMSKINTUNES; skini++) { - if (!S_sfx[i].name) - continue; - if (S_sfx[i].skinsound != -1 - && !stricmp(S_sfx[i].name, - stoken + stokenadjust)) + char tokenConditionBuffer[3 + MAXSKINTUNENAMELEN + 1]; // +3 for 'MUS', +1 for null terminator + memset(tokenConditionBuffer, 0, (3 + MAXSKINTUNENAMELEN + 1) * sizeof(char)); + sprintf(tokenConditionBuffer, "MUS%s", skins_skintunenames[skini]); + + if(!stricmp(tokenConditionBuffer, stoken)) + { + skindex=skini; + break; + } + } + + if(skindex >= 0) + skin->definedSkintunes[skindex] = true; + + if(skin->definedSkintunes[skindex]) // IS skintune... + { + strncpy(skin->skintunes[skindex], value, min(8, strlen(value))); // assumes before now that all skintunes[] buffers are full of null terminators from the skin init process + } + else + { + boolean found = false; + sfxenum_t i; + size_t stokenadjust; + + // Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.) + if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS* + stokenadjust = 2; + else // sfx_* + stokenadjust = 4; + + // Remove the prefix. (We can affect this directly since we're not going to use it again.) + if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS* + value += 2; + else // sfx_* + value += 4; + + // copy name of sounds that are remapped + // for this skin + for (i = 0; i < sfx_skinsoundslot0; i++) { - skin->soundsid[S_sfx[i].skinsound] = - S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true); - found = true; + if (!S_sfx[i].name) + continue; + if (S_sfx[i].skinsound != -1 + && !stricmp(S_sfx[i].name, + stoken + stokenadjust)) + { + skin->soundsid[S_sfx[i].skinsound] = + S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true); + found = true; + } } + return found; } - return found; } return true; } diff --git a/src/r_skins.h b/src/r_skins.h index 9a05129f998e509c61f85a6fc5138b60b08acf96..56d74d1965c97195548a634c29fa7bc093ebc827 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -35,6 +35,11 @@ extern "C" { #define DEFAULTSKIN3 "sonic" // third player #define DEFAULTSKIN4 "knuckles" // fourth player +#define NUMSKINTUNES 2 +#define MAXSKINTUNENAMELEN 6 + +extern char skins_skintunenames[NUMSKINTUNES][MAXSKINTUNENAMELEN + 1]; + /// The skin_t struct struct skin_t { @@ -70,6 +75,9 @@ struct skin_t // contains super versions too spritedef_t sprites[NUMPLAYERSPRITES*2]; spriteinfo_t sprinfo[NUMPLAYERSPRITES*2]; + + char skintunes[NUMSKINTUNES][9]; // sound lump names that can be remapped when one of the tunes from skins_skintunenames plays + boolean definedSkintunes[NUMSKINTUNES]; // whether or not this skin had definitions for each skintune during R_ProcessPatchableFields(), not to be confused on whether or not this skin had lumps present for those definitions which is what would be better to check for instead but I don't know how :S. }; enum facepatches { @@ -137,6 +145,10 @@ UINT32 R_GetLocalRandomSkin(void); // Sprite2 UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player); +SINT8 R_FindSkintuneIndex(skin_t *skin, const char *tunename); + +char* R_TryAllocSkintuneTuneName(UINT8 skintuneIndex); + #ifdef __cplusplus } // extern "C" #endif