musicplus-jingle 2.2 -> 2.1 backport

This commit is contained in:
mazmazz 2018-09-18 15:10:00 -04:00
parent e4f48cfb71
commit c60d61a493
12 changed files with 605 additions and 63 deletions

View File

@ -7190,6 +7190,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

@ -3056,10 +3056,10 @@ void A_Invincibility(mobj_t *actor)
if (P_IsLocalPlayer(player) && !player->powers[pw_super])
{
S_StopMusic();
if (mariomode)
G_GhostAddColor(GHC_INVINCIBLE);
S_ChangeMusicInternal((mariomode) ? "minvnc" : "invinc", false);
P_PlayJingle(player, (mariomode) ? JT_MINV : JT_INV);
}
}
@ -3093,10 +3093,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);
}
}

View File

@ -2088,10 +2088,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
if (target->player->lives <= 0) // Tails 03-14-2000
{
if (P_IsLocalPlayer(target->player)/* && target->player == &players[consoleplayer] */)
{
S_StopMusic(); // Stop the Music! Tails 03-14-2000
S_ChangeMusicInternal("gmover", false); // Yousa dead now, Okieday? Tails 03-14-2000
}
P_PlayJingle(target->player, JT_GOVER); // Yousa dead now, Okieday? Tails 03-14-2000
}
}
target->player->playerstate = PST_DEAD;
@ -2466,7 +2463,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
&& player->nightstime < 10*TICRATE)
{
//S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
S_ChangeMusicInternal("drown",false);
P_PlayJingle(player, ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? JT_NIGHTSTIMEOUT : JT_SSTIMEOUT);
}
}
}

View File

@ -184,6 +184,46 @@ void P_PlayLivesJingle(player_t *player);
#define P_PlayDeathSound(s) S_StartSound(s, sfx_altdi1 + P_RandomKey(4));
#define P_PlayVictorySound(s) S_StartSound(s, sfx_victr1 + P_RandomKey(4));
/// ------------------------
/// 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

@ -1514,19 +1514,33 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
{
M_Memcpy(process,msd->bottomtexture,8);
process[8] = '\0';
sd->bottomtexture = get_number(process)-1;
sd->bottomtexture = get_number(process);
}
M_Memcpy(process,msd->toptexture,8);
process[8] = '\0';
sd->text = Z_Malloc(7, PU_LEVEL, NULL);
// If they type in O_ or D_ and their music name, just shrug,
// then copy the rest instead.
if ((process[0] == 'O' || process[0] == 'D') && process[7])
M_Memcpy(sd->text, process+2, 6);
else // Assume it's a proper music name.
M_Memcpy(sd->text, process, 6);
sd->text[6] = 0;
if (!(msd->midtexture[0] == '-' && msd->midtexture[1] == '\0') || msd->midtexture[1] != '\0')
{
M_Memcpy(process,msd->midtexture,8);
process[8] = '\0';
sd->midtexture = get_number(process);
}
// always process if back sidedef, because we need that - symbol
sd->text = Z_Malloc(7, PU_LEVEL, NULL);
if (i == 1 || msd->toptexture[0] != '-' || msd->toptexture[1] != '\0')
{
M_Memcpy(process,msd->toptexture,8);
process[8] = '\0';
// If they type in O_ or D_ and their music name, just shrug,
// then copy the rest instead.
if ((process[0] == 'O' || process[0] == 'D') && process[7])
M_Memcpy(sd->text, process+2, 6);
else // Assume it's a proper music name.
M_Memcpy(sd->text, process, 6);
sd->text[6] = 0;
}
else
sd->text[0] = 0;
break;
}
case 414: // Play SFX

View File

@ -2419,18 +2419,60 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// console player only unless NOCLIMB is set
if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player)))
{
UINT16 tracknum = (UINT16)sides[line->sidenum[0]].bottomtexture;
boolean musicsame = (!sides[line->sidenum[0]].text[0] || !strnicmp(sides[line->sidenum[0]].text, S_MusicName(), 7));
UINT16 tracknum = (UINT16)max(sides[line->sidenum[0]].bottomtexture, 0);
INT32 position = (INT32)max(sides[line->sidenum[0]].midtexture, 0);
UINT32 prefadems = (UINT32)max(sides[line->sidenum[0]].textureoffset >> FRACBITS, 0);
UINT32 postfadems = (UINT32)max(sides[line->sidenum[0]].rowoffset >> FRACBITS, 0);
UINT8 fadetarget = (UINT8)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].textureoffset >> FRACBITS : 0, 0);
INT16 fadesource = (INT16)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].rowoffset >> FRACBITS : 0, -1);
strncpy(mapmusname, sides[line->sidenum[0]].text, 7);
mapmusname[6] = 0;
if (line->flags & ML_EFFECT1)
{
// adjust for loop point if subtracting
if (position < 0 && S_GetMusicLength() &&
S_GetMusicPosition() > S_GetMusicLoopPoint() &&
S_GetMusicPosition() + position < S_GetMusicLoopPoint())
position = max(S_GetMusicLength() - (S_GetMusicLoopPoint() - (S_GetMusicPosition() + position)), 0);
else
position = max(S_GetMusicPosition() + position, 0);
}
mapmusflags = tracknum & MUSIC_TRACKMASK;
if (!(line->flags & ML_BLOCKMONSTERS))
mapmusflags |= MUSIC_RELOADRESET;
if ((line->flags & ML_EFFECT2) && fadetarget && musicsame)
{
if (!postfadems)
S_SetInternalMusicVolume(fadetarget);
else
S_FadeMusicFromVolume(fadetarget, fadesource, postfadems);
mapmusposition = 0;
if (position)
S_SetMusicPosition(position);
}
else
{
strncpy(mapmusname, sides[line->sidenum[0]].text, 7);
mapmusname[6] = 0;
S_ChangeMusic(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4));
mapmusflags = tracknum & MUSIC_TRACKMASK;
if (!(line->flags & ML_BLOCKMONSTERS))
mapmusflags |= MUSIC_RELOADRESET;
if (line->flags & ML_BOUNCY)
mapmusflags |= MUSIC_FORCERESET;
mapmusposition = position;
S_ChangeMusicEx(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4), position,
!(line->flags & ML_EFFECT2) ? prefadems : 0,
!(line->flags & ML_EFFECT2) ? postfadems : 0);
if ((line->flags & ML_EFFECT2) && fadetarget)
{
if (!postfadems)
S_SetInternalMusicVolume(fadetarget);
else
S_FadeMusicFromVolume(fadetarget, fadesource, postfadems);
}
}
// Except, you can use the ML_BLOCKMONSTERS flag to change this behavior.
// if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn.

View File

@ -582,13 +582,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.
//
@ -636,6 +659,7 @@ static void P_DeNightserizePlayer(player_t *player)
}
// Restore from drowning music
music_stack_fadein = 0; // HACK: Change fade-in for restore music
P_RestoreMusic(player);
}
//
@ -675,6 +699,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->nightstime = player->startedtime = nighttime*TICRATE;
player->bonustime = false;
music_stack_fadein = 0; // HACK: Change fade-in for restore music
P_RestoreMusic(player);
P_SetMobjState(player->mo->tracer, S_SUPERTRANS1);
@ -961,8 +986,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("supers", true);
P_PlayJingle(player, JT_SUPER);
}
S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
@ -1097,11 +1121,111 @@ void P_PlayLivesJingle(player_t *player)
{
if (player)
player->powers[pw_extralife] = extralifetics + 1;
S_StopMusic(); // otherwise it won't restart if this is done twice in a row
S_ChangeMusicInternal("xtlife", 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
//
@ -1112,25 +1236,46 @@ 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("supers", 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)
S_ChangeMusicInternal((mariomode) ? "minvnc" : "invinc", 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])
{
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);
}
}
//
@ -2017,10 +2162,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);
@ -2105,15 +2246,18 @@ 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;
P_RestoreMusic(player);
}
// Underwater audio cues
@ -2122,8 +2266,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);
}
if (player->powers[pw_underwater] == 25*TICRATE + 1)
@ -2185,10 +2328,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);
}
@ -3410,6 +3549,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);
@ -3511,6 +3652,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.
@ -5576,13 +5719,14 @@ static void P_NiGHTSMovement(player_t *player)
P_DeNightserizePlayer(player);
S_StartScreamSound(player->mo, sfx_s3k66);
// S_StopSoundByNum(sfx_timeup); // Kill the "out of time" music, if it's playing. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
music_stack_fadein = 0; // HACK: Change fade-in for restore music
P_RestoreMusic(player); // I have my doubts that this is the right place for this...
return;
}
else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE)
// S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
S_ChangeMusicInternal("drown",false);
P_PlayJingle(player, ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? JT_NIGHTSTIMEOUT : JT_SSTIMEOUT);
if (player->mo->z < player->mo->floorz)
@ -8754,7 +8898,7 @@ void P_PlayerThink(player_t *player)
if (countdown == 11*TICRATE - 1)
{
if (P_IsLocalPlayer(player))
S_ChangeMusicInternal("drown", false);
P_PlayJingle(player, JT_DROWN);
}
// If you've hit the countdown and you haven't made

View File

@ -1229,6 +1229,10 @@ static boolean queue_looping;
static UINT32 queue_position;
static UINT32 queue_fadeinms;
static musicstack_t music_stack[NUMMUSICSTACKS];
static tic_t pause_starttic;
/// ------------------------
/// Music Status
/// ------------------------
@ -1327,6 +1331,254 @@ 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 const musicstack_t empty_music_stack_entry = {{0}};
void S_SetStackAdjustmentStart(void)
{
if (!pause_starttic)
pause_starttic = gametic;
}
void S_AdjustMusicStackTics(void)
{
if (pause_starttic)
{
size_t i;
for (i = 0; i < NUMMUSICSTACKS-1; i++)
{
if (!music_stack[i].status)
break;
music_stack[i].tic += gametic - pause_starttic;
}
pause_starttic = 0;
}
}
static void S_ResetMusicStack()
{
size_t i;
for (i = 0; i < NUMMUSICSTACKS; i++)
music_stack[i] = empty_music_stack_entry;
}
static void S_RemoveMusicStackEntry(size_t i)
{
for (; i < NUMMUSICSTACKS-1; i++)
{
strncpy(music_stack[i].musname, music_stack[i+1].musname, 7);
music_stack[i].musname[6] = 0;
music_stack[i].musflags = music_stack[i+1].musflags;
music_stack[i].looping = music_stack[i+1].looping;
music_stack[i].position = music_stack[i+1].position;
music_stack[i].tic = music_stack[i+1].tic;
music_stack[i].status = music_stack[i+1].status;
if (!music_stack[i].status)
break;
}
// clear the last slot
music_stack[NUMMUSICSTACKS-1] = empty_music_stack_entry;
}
static void S_RemoveMusicStackEntryByStatus(UINT16 status)
{
int i;
if (!status)
return;
for (i = 0; i < NUMMUSICSTACKS-1; i++)
{
if (music_stack[i].status == status)
{
S_RemoveMusicStackEntry(i);
i--; // try this position again
}
else if (!music_stack[i].status)
break;
}
}
static void S_AddMusicStackEntry(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status)
{
size_t i;
// if the first entry is empty, force master onto it
if (!music_stack[0].status && status != JT_MASTER)
S_AddMusicStackEntry(mapmusname, mapmusflags, true, S_GetMusicPosition(), JT_MASTER);
// are all slots taken? forget the earliest one (save master) and move down the rest
if (music_stack[NUMMUSICSTACKS-1].status)
S_RemoveMusicStackEntry(1);
// look for an empty slot to park ourselves
for (i = 0; i < NUMMUSICSTACKS; i++)
{
// entry doesn't exist? park ourselves here!
if (!music_stack[i].status)
{
strncpy(music_stack[i].musname, mname, 7);
music_stack[i].musname[6] = 0;
music_stack[i].musflags = mflags;
music_stack[i].looping = looping;
music_stack[i].position = position;
music_stack[i].tic = gametic;
music_stack[i].status = status;
break;
}
}
}
static musicstack_t S_GetMusicStackEntry(UINT16 status, boolean fromfirst, INT16 startindex)
{
size_t i;
// if the first entry is empty, force master onto it
// fixes a memory corruption bug
if (!music_stack[0].status && status != JT_MASTER)
S_AddMusicStackEntry(mapmusname, mapmusflags, true, S_GetMusicPosition(), JT_MASTER);
if (startindex < 0)
startindex = fromfirst ? 0 : NUMMUSICSTACKS-1;
if (fromfirst)
{
for (i = startindex; i < NUMMUSICSTACKS; i++)
{
if (!music_stack[i].status) // we're counting up, so this must mean we reached the end
break;
else if (!status || music_stack[i].status == status)
{
if (P_EvaluateMusicStatus(music_stack[i].status))
{
if (!S_MusicExists(music_stack[i].musname, !midi_disabled, !digital_disabled)) // paranoia
S_RemoveMusicStackEntry(i); // then continue
else
return music_stack[i];
}
else
S_RemoveMusicStackEntry(i); // then continue
}
}
}
else
{
for (i = startindex; i >= 0; i--)
{
if (!music_stack[i].status) // since we're counting down, we have to skip a few...
continue;
else if (!status || music_stack[i].status == status)
{
if (P_EvaluateMusicStatus(music_stack[i].status))
{
if (!S_MusicExists(music_stack[i].musname, !midi_disabled, !digital_disabled)) // paranoia
S_RemoveMusicStackEntry(i); // then continue
else
return music_stack[i];
}
else
S_RemoveMusicStackEntry(i); // then continue
}
}
}
return empty_music_stack_entry;
}
void S_RetainMusic(const char *mname, UINT16 mflags, boolean looping, UINT32 position, UINT16 status)
{
size_t i;
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 (i = 0; i < NUMMUSICSTACKS; i++)
{
if (music_stack[i].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 entry;
if (status)
entry = S_GetMusicStackEntry(status, fromfirst, -1);
else
entry = S_GetMusicStackEntry(JT_NONE, false, -1);
if (!S_MusicExists(entry.musname, !midi_disabled, !digital_disabled))
return false; // bad bad bad!!
// no result, just grab mapmusname
if (!entry.musname[0] || ((status == JT_MASTER || !music_stack[0].status) && !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 = (boolean)strnicmp(entry.musname, mapmusname, 7);
S_ResetMusicStack();
}
else
{
if (!entry.status)
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;
}
return true;
}
/// ------------------------
/// Music Playback
/// ------------------------
@ -1529,6 +1781,8 @@ void S_PauseAudio(void)
#else
I_StopCD();
#endif
S_SetStackAdjustmentStart();
}
void S_ResumeAudio(void)
@ -1538,6 +1792,8 @@ void S_ResumeAudio(void)
// resume cd music
I_ResumeCD();
S_AdjustMusicStackTics();
}
void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume)
@ -1623,4 +1879,9 @@ 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;
}

View File

@ -140,6 +140,30 @@ boolean S_SetMusicPosition(UINT32 position);
// Get Position of Music
UINT32 S_GetMusicPosition(void);
//
// Music Stacking (Jingles)
//
typedef struct {
char musname[7];
UINT16 musflags;
boolean looping;
UINT32 position;
tic_t tic;
UINT16 status;
} musicstack_t;
char music_stack_nextmusname[7];
boolean music_stack_noposition;
UINT32 music_stack_fadeout;
UINT32 music_stack_fadein;
#define NUMMUSICSTACKS 10 // hahaha wait until someone needs > 10 resumes
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

@ -62,7 +62,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"
@ -566,7 +565,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)
{
@ -578,7 +577,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

@ -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;