Merge branch 'public-notpublic-musicplus-jingle' into internal-musicplus-jingle

This commit is contained in:
mazmazz 2019-06-29 18:33:45 -04:00
commit 923dc34215
11 changed files with 575 additions and 56 deletions

View File

@ -8658,6 +8658,23 @@ struct {
{"GT_HIDEANDSEEK",GT_HIDEANDSEEK},
{"GT_CTF",GT_CTF},
// Jingles (jingletype_t)
{"JT_NONE",JT_NONE},
{"JT_OTHER",JT_OTHER},
{"JT_MASTER",JT_MASTER},
{"JT_1UP",JT_1UP},
{"JT_SHOES",JT_SHOES},
{"JT_INV",JT_INV},
{"JT_MINV",JT_MINV},
{"JT_DROWN",JT_DROWN},
{"JT_SUPER",JT_SUPER},
{"JT_GOVER",JT_GOVER},
{"JT_NIGHTSTIMEOUT",JT_NIGHTSTIMEOUT},
{"JT_SSTIMEOUT",JT_SSTIMEOUT},
// {"JT_LCLEAR",JT_LCLEAR},
// {"JT_RACENT",JT_RACENT},
// {"JT_CONTSC",JT_CONTSC},
// Player state (playerstate_t)
{"PST_LIVE",PST_LIVE}, // Playing or camping.
{"PST_DEAD",PST_DEAD}, // Dead on the ground, view follows killer.

View File

@ -4074,12 +4074,11 @@ void A_Invincibility(mobj_t *actor)
if (P_IsLocalPlayer(player) && !player->powers[pw_super])
{
S_StopMusic();
if (mariomode)
G_GhostAddColor(GHC_INVINCIBLE);
strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
P_PlayJingle(player, (mariomode) ? JT_MINV : JT_INV);
}
}
@ -4113,10 +4112,7 @@ void A_SuperSneakers(mobj_t *actor)
if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
S_SpeedMusic(1.4f);
else
{
S_StopMusic();
S_ChangeMusicInternal("_shoes", false);
}
P_PlayJingle(player, JT_SHOES);
strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
}

View File

@ -1669,7 +1669,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Eaten by player!
if ((!player->bot) && (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1))
{
player->powers[pw_underwater] = underwatertics + 1;
P_RestoreMusic(player);
}
if (player->powers[pw_underwater] < underwatertics + 1)
player->powers[pw_underwater] = underwatertics + 1;
@ -2436,10 +2439,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
gameovermus = true;
if (gameovermus)
{
S_StopMusic(); // Stop the Music! Tails 03-14-2000
S_ChangeMusicInternal("_gover", false); // Yousa dead now, Okieday? Tails 03-14-2000
}
P_PlayJingle(target->player, JT_GOVER); // Yousa dead now, Okieday? Tails 03-14-2000
if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && numgameovers < maxgameovers)
{
@ -2881,7 +2881,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
}
else
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
P_PlayJingle(player, ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? JT_NIGHTSTIMEOUT : JT_SSTIMEOUT);
}
}
}

View File

@ -200,6 +200,47 @@ boolean P_GetLives(player_t *player);
boolean P_SpectatorJoinGame(player_t *player);
void P_RestoreMultiMusic(player_t *player);
/// ------------------------
/// Jingle stuff
/// ------------------------
typedef enum
{
JT_NONE, // Null state
JT_OTHER, // Other state
JT_MASTER, // Main level music
JT_1UP, // Extra life
JT_SHOES, // Speed shoes
JT_INV, // Invincibility
JT_MINV, // Mario Invincibility
JT_DROWN, // Drowning
JT_SUPER, // Super Sonic
JT_GOVER, // Game Over
JT_NIGHTSTIMEOUT, // NiGHTS Time Out (10 seconds)
JT_SSTIMEOUT, // NiGHTS Special Stage Time Out (10 seconds)
// these are not jingles
// JT_LCLEAR, // Level Clear
// JT_RACENT, // Multiplayer Intermission
// JT_CONTSC, // Continue
NUMJINGLES
} jingletype_t;
typedef struct
{
char musname[7];
boolean looping;
} jingle_t;
extern jingle_t jingleinfo[NUMJINGLES];
#define JINGLEPOSTFADE 1000
void P_PlayJingle(player_t *player, jingletype_t jingletype);
boolean P_EvaluateMusicStatus(UINT16 status);
void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, boolean looping, UINT16 status);
//
// P_MOBJ
//

View File

@ -573,13 +573,20 @@ void P_Ticker(boolean run)
OP_ObjectplaceMovement(&players[0]);
P_MoveChaseCamera(&players[0], &camera, false);
P_MapEnd();
S_SetStackAdjustmentStart();
return;
}
}
// Check for pause or menu up in single player
if (paused || P_AutoPause())
{
S_SetStackAdjustmentStart();
return;
}
if (!S_MusicPaused())
S_AdjustMusicStackTics();
postimgtype = postimgtype2 = postimg_none;

View File

@ -56,6 +56,29 @@
static void P_NukeAllPlayers(player_t *player);
#endif
//
// Jingle stuff.
//
jingle_t jingleinfo[NUMJINGLES] = {
// {musname, looping, reset, nest}
{"" , false}, // JT_NONE
{"" , false}, // JT_OTHER
{"" , false}, // JT_MASTER
{"xtlife" , false},
{"shoes" , true},
{"invinc" , false},
{"minvnc" , false},
{"drown" , false},
{"supers" , true},
{"gmover" , false},
{"drown" , false}, // JT_NIGHTSTIMEOUT
{"drown" , false} // JT_SSTIMEOUT
// {"lclear" , false},
// {"racent" , true},
// {"contsc" , true}
};
//
// Movement.
//
@ -664,7 +687,10 @@ static void P_DeNightserizePlayer(player_t *player)
S_SetMusicPosition(0);
}
else
{
music_stack_fadein = 0; // HACK: Change fade-in for restore music
P_RestoreMusic(player);
}
P_RunDeNightserizeExecutors(player->mo);
}
@ -720,7 +746,10 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
S_SetInternalMusicVolume(100);
}
else
{
music_stack_fadein = 0; // HACK: Change fade-in for restore music
P_RestoreMusic(player);
}
P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_TRANS1);
@ -1121,10 +1150,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
{
player->powers[pw_super] = 1;
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
{
S_StopMusic();
S_ChangeMusicInternal("_super", true);
}
P_PlayJingle(player, JT_SUPER);
S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
@ -1290,14 +1316,114 @@ void P_PlayLivesJingle(player_t *player)
else
{
if (player)
player->powers[pw_extralife] = extralifetics+1;
S_StopMusic(); // otherwise it won't restart if this is done twice in a row
player->powers[pw_extralife] = extralifetics + 1;
strlcpy(S_sfx[sfx_None].caption, "One-up", 7);
S_StartCaption(sfx_None, -1, extralifetics+1);
S_ChangeMusicInternal("_1up", false);
P_PlayJingle(player, JT_1UP);
}
}
void P_PlayJingle(player_t *player, jingletype_t jingletype)
{
const char *musname = jingleinfo[jingletype].musname;
UINT16 musflags = 0;
boolean looping = jingleinfo[jingletype].looping;
char newmusic[7];
strncpy(newmusic, musname, 7);
#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
if(LUAh_MusicJingle(jingletype, newmusic, &musflags, &looping))
return;
#endif
newmusic[6] = 0;
P_PlayJingleMusic(player, newmusic, musflags, looping, jingletype);
}
//
// P_PlayJingleMusic
//
void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, boolean looping, UINT16 status)
{
if (!P_IsLocalPlayer(player))
return;
S_RetainMusic(musname, musflags, looping, 0, status);
S_StopMusic();
S_ChangeMusicInternal(musname, looping);
}
boolean P_EvaluateMusicStatus(UINT16 status)
{
// \todo lua hook
int i;
boolean result = false;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!P_IsLocalPlayer(&players[i]))
continue;
switch(status)
{
case JT_1UP: // Extra life
result = (players[i].powers[pw_extralife] > 1);
break;
case JT_SHOES: // Speed shoes
if (players[i].powers[pw_sneakers] > 1 && !players[i].powers[pw_super])
{
//strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
//S_StartCaption(sfx_None, -1, players[i].powers[pw_sneakers]);
result = true;
}
else
result = false;
break;
case JT_INV: // Invincibility
case JT_MINV: // Mario Invincibility
if (players[i].powers[pw_invulnerability] > 1)
{
//strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
//S_StartCaption(sfx_None, -1, players[i].powers[pw_invulnerability]);
result = true;
}
else
result = false;
break;
case JT_DROWN: // Drowning
result = (players[i].powers[pw_underwater] && players[i].powers[pw_underwater] <= 11*TICRATE + 1);
break;
case JT_SUPER: // Super Sonic
result = (players[i].powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC));
break;
case JT_GOVER: // Game Over
result = (players[i].lives <= 0);
break;
case JT_NIGHTSTIMEOUT: // NiGHTS Time Out (10 seconds)
case JT_SSTIMEOUT:
result = (players[i].nightstime && players[i].nightstime <= 10*TICRATE);
break;
case JT_NONE: // Null state
case JT_OTHER: // Other state
case JT_MASTER: // Main level music
default:
result = true;
}
if (result)
break;
}
return result;
}
//
// P_RestoreMusic
//
@ -1308,17 +1434,30 @@ void P_RestoreMusic(player_t *player)
if (!P_IsLocalPlayer(player)) // Only applies to a local player
return;
S_SpeedMusic(1.0f);
// Jingles have a priority in this order, so follow it
// and as a default case, go down the music stack.
// Extra life
if (player->powers[pw_extralife] > 1)
return;
S_SpeedMusic(1.0f);
if (player->powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC))
S_ChangeMusicInternal("_super", true);
// Super
else if (player->powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC)
&& !S_RecallMusic(JT_SUPER, false))
P_PlayJingle(player, JT_SUPER);
// Invulnerability
else if (player->powers[pw_invulnerability] > 1)
{
strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false);
if (!S_RecallMusic(JT_INV, false) && !S_RecallMusic(JT_MINV, false))
P_PlayJingle(player, (mariomode) ? JT_MINV : JT_INV);
}
// Shoes
else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super])
{
strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
@ -1326,13 +1465,19 @@ void P_RestoreMusic(player_t *player)
if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
{
S_SpeedMusic(1.4f);
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
if (!S_RecallMusic(JT_MASTER, true))
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
}
else
S_ChangeMusicInternal("_shoes", true);
else if (!S_RecallMusic(JT_SHOES, false))
P_PlayJingle(player, JT_SHOES);
}
else
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
// Default
else if (!S_RecallMusic(JT_NONE, false)) // go down the stack
{
CONS_Debug(DBG_BASIC, "Cannot find any music in resume stack!\n");
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
}
}
//
@ -1655,9 +1800,12 @@ void P_SwitchShield(player_t *player, UINT16 shieldtype)
if (shieldtype & SH_PROTECTWATER)
{
if (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)
{
player->powers[pw_underwater] = 0;
P_RestoreMusic(player);
player->powers[pw_underwater] = 0;
}
else
player->powers[pw_underwater] = 0;
if (player->powers[pw_spacetime] > 1)
{
@ -2444,10 +2592,6 @@ static void P_CheckQuicksand(player_t *player)
//
static void P_CheckSneakerAndLivesTimer(player_t *player)
{
if ((player->powers[pw_underwater] <= 11*TICRATE + 1)
&& (player->powers[pw_underwater] > 1))
return; // don't restore music if drowning music is playing
if (player->powers[pw_extralife] == 1) // Extra Life!
P_RestoreMusic(player);
@ -2515,16 +2659,16 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
if (!(player->mo->eflags & MFE_UNDERWATER) && player->powers[pw_underwater])
{
if (player->powers[pw_underwater] <= 12*TICRATE + 1)
{
player->powers[pw_underwater] = 0;
P_RestoreMusic(player);
player->powers[pw_underwater] = 0;
}
else
player->powers[pw_underwater] = 0;
}
if (player->powers[pw_spacetime] > 1 && !P_InSpaceSector(player->mo))
{
P_RestoreMusic(player);
player->powers[pw_spacetime] = 0;
}
// Underwater audio cues
if (P_IsLocalPlayer(player) && !player->bot)
@ -2537,8 +2681,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
if (player->powers[pw_underwater] == 11*TICRATE + 1
&& player == &players[consoleplayer])
{
S_StopMusic();
S_ChangeMusicInternal("_drown", false);
P_PlayJingle(player, JT_DROWN);
}
}
}
@ -2585,10 +2728,6 @@ static void P_CheckInvincibilityTimer(player_t *player)
P_SpawnShieldOrb(player);
}
if ((player->powers[pw_underwater] <= 11*TICRATE + 1)
&& (player->powers[pw_underwater] > 1))
return; // don't restore music if drowning music is playing
if (!player->powers[pw_super] || (mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC))
P_RestoreMusic(player);
}
@ -3801,6 +3940,8 @@ static void P_DoSuperStuff(player_t *player)
{
player->powers[pw_super] = 0;
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
music_stack_noposition = true; // HACK: Do not reposition next music
music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music
P_RestoreMusic(player);
P_SpawnShieldOrb(player);
@ -3882,6 +4023,8 @@ static void P_DoSuperStuff(player_t *player)
}
// Resume normal music if you're the console player
music_stack_noposition = true; // HACK: Do not reposition next music
music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music
P_RestoreMusic(player);
// If you had a shield, restore its visual significance.
@ -6388,7 +6531,7 @@ static void P_NiGHTSMovement(player_t *player)
S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
}
else
S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
P_PlayJingle(player, ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? JT_NIGHTSTIMEOUT : JT_SSTIMEOUT);
}
if (player->mo->z < player->mo->floorz)
@ -10272,7 +10415,7 @@ void P_PlayerThink(player_t *player)
// If 11 seconds are left on the timer,
// begin the drown music for countdown!
if (countdown == 11*TICRATE - 1 && P_IsLocalPlayer(player))
S_ChangeMusicInternal("_drown", false);
P_PlayJingle(player, JT_DROWN);
// If you've hit the countdown and you haven't made
// it to the exit, you're a goner!
@ -10761,9 +10904,12 @@ void P_PlayerThink(player_t *player)
if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER)))
{
if (player->powers[pw_underwater] <= 12*TICRATE+1)
{
player->powers[pw_underwater] = 0;
P_RestoreMusic(player); //incase they were about to drown
player->powers[pw_underwater] = 0;
}
else
player->powers[pw_underwater] = 0;
}
else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer
player->powers[pw_underwater]--;

View File

@ -1392,6 +1392,8 @@ static boolean queue_looping;
static UINT32 queue_position;
static UINT32 queue_fadeinms;
static tic_t pause_starttic;
/// ------------------------
/// Music Status
/// ------------------------
@ -1490,6 +1492,260 @@ UINT32 S_GetMusicPosition(void)
return I_GetSongPosition();
}
/// ------------------------
/// Music Stacking (Jingles)
/// In this section: mazmazz doesn't know how to do dynamic arrays or struct pointers!
/// ------------------------
static musicstack_t *music_stacks = NULL;
static musicstack_t *last_music_stack = NULL;
void S_SetStackAdjustmentStart(void)
{
if (!pause_starttic)
pause_starttic = gametic;
}
void S_AdjustMusicStackTics(void)
{
if (pause_starttic)
{
musicstack_t *mst;
for (mst = music_stacks; mst; mst = mst->next)
mst->tic += gametic - pause_starttic;
pause_starttic = 0;
}
}
static void S_ResetMusicStack(void)
{
musicstack_t *mst, *mst_next;
for (mst = music_stacks; mst; mst = mst_next)
{
mst_next = mst->next;
Z_Free(mst);
}
music_stacks = last_music_stack = NULL;
}
static void S_RemoveMusicStackEntry(musicstack_t *entry)
{
musicstack_t *mst;
for (mst = music_stacks; mst; mst = mst->next)
{
if (mst == entry)
{
// Remove ourselves from the chain and link
// prev and next together
if (mst->prev)
mst->prev->next = mst->next;
else
music_stacks = mst->next;
if (mst->next)
mst->next->prev = mst->prev;
else
last_music_stack = mst->prev;
break;
}
}
Z_Free(entry);
}
static void S_RemoveMusicStackEntryByStatus(UINT16 status)
{
musicstack_t *mst, *mst_next;
if (!status)
return;
for (mst = music_stacks; mst; mst = mst_next)
{
mst_next = mst->next;
if (mst->status == status)
S_RemoveMusicStackEntry(mst);
}
}
static void S_AddMusicStackEntry(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status)
{
musicstack_t *mst, *new_mst;
// if the first entry is empty, force master onto it
if (!music_stacks)
{
music_stacks = Z_Calloc(sizeof (*mst), PU_MUSIC, NULL);
strncpy(music_stacks->musname, (status == JT_MASTER ? mname : mapmusname), 7);
music_stacks->musflags = (status == JT_MASTER ? mflags : mapmusflags);
music_stacks->looping = (status == JT_MASTER ? looping : true);
music_stacks->position = (status == JT_MASTER ? position : S_GetMusicPosition());
music_stacks->tic = gametic;
music_stacks->status = JT_MASTER;
if (status == JT_MASTER)
return; // we just added the user's entry here
}
// look for an empty slot to park ourselves
for (mst = music_stacks; mst->next; mst = mst->next);
// create our new entry
new_mst = Z_Calloc(sizeof (*new_mst), PU_MUSIC, NULL);
strncpy(new_mst->musname, mname, 7);
new_mst->musname[6] = 0;
new_mst->musflags = mflags;
new_mst->looping = looping;
new_mst->position = position;
new_mst->tic = gametic;
new_mst->status = status;
mst->next = new_mst;
new_mst->prev = mst;
new_mst->next = NULL;
last_music_stack = new_mst;
}
static musicstack_t *S_GetMusicStackEntry(UINT16 status, boolean fromfirst, INT16 startindex)
{
musicstack_t *mst, *start_mst = NULL, *mst_next;
// if the first entry is empty, force master onto it
// fixes a memory corruption bug
if (!music_stacks && status != JT_MASTER)
S_AddMusicStackEntry(mapmusname, mapmusflags, true, S_GetMusicPosition(), JT_MASTER);
if (startindex >= 0)
{
INT16 i = 0;
for (mst = music_stacks; mst && i <= startindex; mst = mst->next, i++)
start_mst = mst;
}
else
start_mst = (fromfirst ? music_stacks : last_music_stack);
for (mst = start_mst; mst; mst = mst_next)
{
mst_next = (fromfirst ? mst->next : mst->prev);
if (!status || mst->status == status)
{
if (P_EvaluateMusicStatus(mst->status))
{
if (!S_MusicExists(mst->musname, !midi_disabled, !digital_disabled)) // paranoia
S_RemoveMusicStackEntry(mst); // then continue
else
return mst;
}
else
S_RemoveMusicStackEntry(mst); // then continue
}
}
return NULL;
}
void S_RetainMusic(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status)
{
musicstack_t *mst;
if (!status) // we use this as a null indicator, don't push
{
CONS_Alert(CONS_ERROR, "Music stack entry must have a nonzero status.\n");
return;
}
else if (status == JT_MASTER) // enforce only one JT_MASTER
{
for (mst = music_stacks; mst; mst = mst->next)
{
if (mst->status == JT_MASTER)
{
CONS_Alert(CONS_ERROR, "Music stack can only have one JT_MASTER entry.\n");
return;
}
}
}
else // remove any existing status
S_RemoveMusicStackEntryByStatus(status);
S_AddMusicStackEntry(mname, mflags, looping, position, status);
}
boolean S_RecallMusic(UINT16 status, boolean fromfirst)
{
UINT32 newpos = 0;
boolean mapmuschanged = false;
musicstack_t *result;
musicstack_t *entry = Z_Calloc(sizeof (*result), PU_MUSIC, NULL);
if (status)
result = S_GetMusicStackEntry(status, fromfirst, -1);
else
result = S_GetMusicStackEntry(JT_NONE, false, -1);
if (result && !S_MusicExists(result->musname, !midi_disabled, !digital_disabled))
{
Z_Free(entry);
return false; // music doesn't exist, so don't do anything
}
// make a copy of result, since we make modifications to our copy
if (result)
{
*entry = *result;
strncpy(entry->musname, result->musname, 7);
}
// no result, just grab mapmusname
if (!result || !entry->musname[0] || ((status == JT_MASTER || (music_stacks ? !music_stacks->status : false)) && !entry->status))
{
strncpy(entry->musname, mapmusname, 7);
entry->musflags = mapmusflags;
entry->looping = true;
entry->position = mapmusposition;
entry->tic = gametic;
entry->status = JT_MASTER;
}
if (entry->status == JT_MASTER)
{
mapmuschanged = strnicmp(entry->musname, mapmusname, 7);
S_ResetMusicStack();
}
else if (!entry->status)
{
Z_Free(entry);
return false;
}
if (!mapmuschanged && strncmp(entry->musname, S_MusicName(), 7)) // don't restart music if we're already playing it
{
if (music_stack_fadeout)
S_ChangeMusicEx(entry->musname, entry->musflags, entry->looping, 0, music_stack_fadeout, 0);
else
{
S_ChangeMusicEx(entry->musname, entry->musflags, entry->looping, 0, 0, music_stack_fadein);
if (!music_stack_noposition) // HACK: Global boolean to toggle position resuming, e.g., de-superize
newpos = entry->position + (S_GetMusicLength() ? (UINT32)((float)(gametic - entry->tic)/(float)TICRATE*(float)MUSICRATE) : 0);
if (newpos > 0 && S_MusicPlaying())
S_SetMusicPosition(newpos);
else
{
S_StopFadingMusic();
S_SetInternalMusicVolume(100);
}
}
music_stack_noposition = false;
music_stack_fadeout = 0;
music_stack_fadein = JINGLEPOSTFADE;
}
Z_Free(entry);
return true;
}
/// ------------------------
/// Music Playback
/// ------------------------
@ -1700,6 +1956,8 @@ void S_PauseAudio(void)
#else
I_StopCD();
#endif
S_SetStackAdjustmentStart();
}
void S_ResumeAudio(void)
@ -1709,6 +1967,8 @@ void S_ResumeAudio(void)
// resume cd music
I_ResumeCD();
S_AdjustMusicStackTics();
}
void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume)
@ -1794,6 +2054,11 @@ void S_Start(void)
if (cv_resetmusic.value)
S_StopMusic();
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
S_ResetMusicStack();
music_stack_noposition = false;
music_stack_fadeout = 0;
music_stack_fadein = JINGLEPOSTFADE;
}
static void Command_Tunes_f(void)

View File

@ -181,6 +181,33 @@ boolean S_SetMusicPosition(UINT32 position);
// Get Position of Music
UINT32 S_GetMusicPosition(void);
//
// Music Stacking (Jingles)
//
typedef struct musicstack_s
{
char musname[7];
UINT16 musflags;
boolean looping;
UINT32 position;
tic_t tic;
UINT16 status;
struct musicstack_s *prev;
struct musicstack_s *next;
} musicstack_t;
char music_stack_nextmusname[7];
boolean music_stack_noposition;
UINT32 music_stack_fadeout;
UINT32 music_stack_fadein;
void S_SetStackAdjustmentStart(void);
void S_AdjustMusicStackTics(void);
void S_RetainMusic(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status);
boolean S_RecallMusic(UINT16 status, boolean fromfirst);
//
// Music Playback
//

View File

@ -64,7 +64,6 @@
#include "../m_menu.h"
#include "../d_main.h"
#include "../s_sound.h"
#include "../i_sound.h" // midi pause/unpause
#include "../i_joy.h"
#include "../st_stuff.h"
#include "../g_game.h"
@ -573,7 +572,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
// Tell game we got focus back, resume music if necessary
window_notinfocus = false;
if (!paused)
I_ResumeSong(); //resume it
S_ResumeAudio(); //resume it
if (!firsttimeonmouse)
{
@ -585,7 +584,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
{
// Tell game we lost focus, pause music
window_notinfocus = true;
I_PauseSong();
S_PauseAudio();
if (!disable_mouse)
{

View File

@ -101,6 +101,7 @@ static UINT32 fading_timer;
static UINT32 fading_duration;
static INT32 fading_id;
static void (*fading_callback)(void);
static boolean fading_nocleanup;
#ifdef HAVE_LIBGME
static Music_Emu *gme;
@ -122,7 +123,12 @@ static void var_cleanup(void)
songpaused = is_looping =\
is_fading = false;
fading_callback = NULL;
// HACK: See music_loop, where we want the fade timing to proceed after a non-looping
// song has stopped playing
if (!fading_nocleanup)
fading_callback = NULL;
else
fading_nocleanup = false; // use it once, set it back immediately
internal_volume = 100;
}
@ -154,6 +160,8 @@ void I_StartupSound(void)
return;
}
fading_nocleanup = false;
var_cleanup();
music = NULL;
@ -598,7 +606,15 @@ static void music_loop(void)
music_bytes = (UINT32)(loop_point*44100.0L*4); //assume 44.1khz, 4-byte length (see I_GetSongPosition)
}
else
{
// HACK: Let fade timing proceed beyond the end of a
// non-looping song. This is a specific case where the timing
// should persist after stopping a song, so I don't believe
// this should apply every time the user stops a song.
// This is auto-unset in var_cleanup, called by I_StopSong
fading_nocleanup = true;
I_StopSong();
}
}
static UINT32 music_fade(UINT32 interval, void *param)
@ -1273,7 +1289,10 @@ boolean I_PlaySong(boolean looping)
void I_StopSong(void)
{
I_StopFadingSong();
// HACK: See music_loop on why we want fade timing to proceed
// after end of song
if (!fading_nocleanup)
I_StopFadingSong();
#ifdef HAVE_LIBGME
if (gme)
@ -1412,6 +1431,8 @@ void I_StopFadingSong(void)
SDL_RemoveTimer(fading_id);
is_fading = false;
fading_source = fading_target = fading_timer = fading_duration = fading_id = 0;
// don't unset fading_nocleanup here just yet; fading_callback is cleaned up
// in var_cleanup()
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))

View File

@ -42,7 +42,7 @@
#include "fabdxlib.h"
#include "win_main.h"
#include "win_dbg.h"
#include "../i_sound.h" // midi pause/unpause
#include "../s_sound.h" // pause sound with handling
#include "../g_input.h" // KEY_MOUSEWHEELxxx
#include "../screen.h" // for BASEVID*
@ -110,9 +110,9 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
// pause music when alt-tab
if (appActive && !paused)
I_ResumeSong();
S_ResumeAudio();
else if (!paused)
I_PauseSong();
S_PauseAudio();
{
HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode;