There are now captions for specific types of music! (Currently signified with an M, but I'll change that in a bit...) A whole lotta things needed to be modified for this, though.

* Serious refactor of - and internal exposure of - what has become S_StartCaption().
* Renaming of a few existing captions.
* The prevention of access to - or writing over - sfx_None's stuff in SOC or Lua.
* The new Lua wrapper function S_StartMusicCaption(string, tics, optional player), which essentially allows custom music captions to be created. (This is best used for stuff like final lap music in SRB2 Kart or bonus time in a thokker-like game, not a comprehensive Now Playing expy. That'd be a different kettle of fish.)

Also, updated all the lock-on stuff to use P_IsLocalPlayer instead of rolling my own.
This commit is contained in:
toasterbabe 2017-04-29 16:27:52 +01:00
parent 94add11fab
commit 73f1550242
10 changed files with 163 additions and 141 deletions

View File

@ -3631,11 +3631,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_sfx(word2); // find a sound by name
if (i < NUMSFX && i >= 0)
if (i < NUMSFX && i > 0)
readsound(f, i, savesfxnames);
else
{
deh_warning("Sound %d out of range (0 - %d)", i, NUMSFX-1);
deh_warning("Sound %d out of range (1 - %d)", i, NUMSFX-1);
ignorelines(f);
}
DEH_WriteUndoline(word, word2, UNDO_HEADER);

View File

@ -462,7 +462,7 @@ static int lib_pSpawnLockOn(lua_State *L)
return LUA_ErrInvalid(L, "mobj_t");
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (player == &players[consoleplayer] || player == &players[secondarydisplayplayer] || player == &players[displayplayer]) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
@ -2181,6 +2181,31 @@ static int lib_sSoundPlaying(lua_State *L)
return 1;
}
// This doesn't really exist, but we're providing it as a handy netgame-safe wrapper for stuff that should be locally handled.
static int lib_sStartMusicCaption(lua_State *L)
{
player_t *player = NULL;
const char *caption = luaL_checkstring(L, 1);
UINT16 lifespan = (UINT16)luaL_checkinteger(L, 2);
//HUDSAFE
INLEVEL
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (lifespan && (!player || P_IsLocalPlayer(player)))
{
strlcpy(S_sfx[sfx_None].caption, caption, sizeof(S_sfx[sfx_None].caption));
S_StartCaption(sfx_None, -1, lifespan);
}
return 0;
}
// G_GAME
////////////
@ -2493,6 +2518,7 @@ static luaL_Reg lib[] = {
{"S_OriginPlaying",lib_sOriginPlaying},
{"S_IdPlaying",lib_sIdPlaying},
{"S_SoundPlaying",lib_sSoundPlaying},
{"S_StartMusicCaption", lib_sStartMusicCaption},
// g_game
{"G_BuildMapName",lib_gBuildMapName},

View File

@ -773,8 +773,8 @@ static int lib_getSfxInfo(lua_State *L)
lua_remove(L, 1);
i = luaL_checkinteger(L, 1);
if (i >= NUMSFX)
return luaL_error(L, "sfxinfo[] index %d out of range (0 - %d)", i, NUMSFX-1);
if (i == 0 || i >= NUMSFX)
return luaL_error(L, "sfxinfo[] index %d out of range (1 - %d)", i, NUMSFX-1);
LUA_PushUserdata(L, &S_sfx[i], META_SFXINFO);
return 1;
}
@ -787,9 +787,9 @@ static int lib_setSfxInfo(lua_State *L)
lua_remove(L, 1);
{
UINT32 i = luaL_checkinteger(L, 1);
if (i >= NUMSFX)
return luaL_error(L, "sfxinfo[] index %d out of range (0 - %d)", i, NUMSFX-1);
info = &S_sfx[i]; // get the mobjinfo to assign to.
if (i == 0 || i >= NUMSFX)
return luaL_error(L, "sfxinfo[] index %d out of range (1 - %d)", i, NUMSFX-1);
info = &S_sfx[i]; // get the sfxinfo to assign to.
}
luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
lua_remove(L, 1); // pop mobjtype num, don't need it any more.

View File

@ -3170,6 +3170,8 @@ void A_Invincibility(mobj_t *actor)
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);
}
}
@ -3201,6 +3203,9 @@ void A_SuperSneakers(mobj_t *actor)
if (P_IsLocalPlayer(player) && !player->powers[pw_super])
{
strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
S_SpeedMusic(1.4f);
else

View File

@ -257,6 +257,8 @@ void P_DoMatchSuper(player_t *player)
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);
}
@ -278,6 +280,8 @@ void P_DoMatchSuper(player_t *player)
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);
}
}

View File

@ -1134,8 +1134,10 @@ void P_PlayLivesJingle(player_t *player)
else
{
if (player)
player->powers[pw_extralife] = extralifetics + 1;
player->powers[pw_extralife] = extralifetics+1;
S_StopMusic(); // otherwise it won't restart if this is done twice in a row
strlcpy(S_sfx[sfx_None].caption, "One-up", 7);
S_StartCaption(sfx_None, -1, extralifetics+1);
S_ChangeMusicInternal("_1up", false);
}
}
@ -1156,9 +1158,15 @@ void P_RestoreMusic(player_t *player)
if (player->powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC))
S_ChangeMusicInternal("_super", true);
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);
}
else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super])
{
strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
{
S_SpeedMusic(1.4f);
@ -2341,7 +2349,7 @@ static void P_DoPlayerHeadSigns(player_t *player)
// If you're "IT", show a big "IT" over your head for others to see.
if (player->pflags & PF_TAGIT)
{
if (!(player == &players[consoleplayer] || player == &players[secondarydisplayplayer] || player == &players[displayplayer])) // Don't display it on your own view.
if (!P_IsLocalPlayer(player)) // Don't display it on your own view.
{
if (!(player->mo->eflags & MFE_VERTICALFLIP))
P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height, MT_TAG);
@ -3858,7 +3866,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
mobj_t *lockon = P_LookForEnemies(player, false, true);
if (lockon)
{
if (player == &players[consoleplayer] || player == &players[secondarydisplayplayer] || player == &players[displayplayer]) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
@ -4126,7 +4134,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) && (lockon = P_LookForEnemies(player, true, false)))
{
if (player == &players[consoleplayer] || player == &players[secondarydisplayplayer] || player == &players[displayplayer]) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
@ -7194,7 +7202,7 @@ static void P_MovePlayer(player_t *player)
{
if ((lockon = P_LookForEnemies(player, false, false)))
{
if (player == &players[consoleplayer] || player == &players[secondarydisplayplayer] || player == &players[displayplayer]) // Only display it on your own view.
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;

View File

@ -140,6 +140,7 @@ void ResetCaptions(void)
closedcaptions[i].c = NULL;
closedcaptions[i].s = NULL;
closedcaptions[i].t = 0;
closedcaptions[i].b = 0;
}
}
@ -391,6 +392,92 @@ void S_StopSoundByNum(sfxenum_t sfxnum)
}
}
void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan)
{
UINT8 i, set, moveup, start;
boolean same;
sfxinfo_t *sfx;
if (!cv_closedcaptioning.value) // no captions at all
return;
// check for bogus sound #
I_Assert(sfx_id >= 0); // allows sfx_None; this shouldn't be allowed directly if S_StartCaption is ever exposed to Lua by itself
I_Assert(sfx_id < NUMSFX);
sfx = &S_sfx[sfx_id];
if (sfx->caption[0] == '/') // no caption for this one
return;
start = ((closedcaptions[0].s && (closedcaptions[0].s-S_sfx == sfx_None)) ? 1 : 0);
if (sfx_id)
{
for (i = start; i < (set = NUMCAPTIONS-1); i++)
{
same = ((sfx == closedcaptions[i].s) || (closedcaptions[i].s && fastcmp(sfx->caption, closedcaptions[i].s->caption)));
if (same)
{
set = i;
break;
}
}
}
else
{
set = 0;
same = (closedcaptions[0].s == sfx);
}
moveup = 255;
if (!same)
{
for (i = start; i < set; i++)
{
if (!(closedcaptions[i].c || closedcaptions[i].s) || (sfx->priority >= closedcaptions[i].s->priority))
{
set = i;
if (closedcaptions[i].s && (sfx->priority >= closedcaptions[i].s->priority))
moveup = i;
break;
}
}
for (i = NUMCAPTIONS-1; i > set; i--)
{
if (sfx == closedcaptions[i].s)
{
closedcaptions[i].c = NULL;
closedcaptions[i].s = NULL;
closedcaptions[i].t = 0;
closedcaptions[i].b = 0;
}
}
}
if (moveup != 255)
{
for (i = moveup; i < NUMCAPTIONS-1; i++)
{
if (!(closedcaptions[i].c || closedcaptions[i].s))
break;
}
for (; i > set; i--)
{
closedcaptions[i].c = closedcaptions[i-1].c;
closedcaptions[i].s = closedcaptions[i-1].s;
closedcaptions[i].t = closedcaptions[i-1].t;
closedcaptions[i].b = closedcaptions[i-1].b;
}
}
closedcaptions[set].c = ((cnum == -1) ? NULL : &channels[cnum]);
closedcaptions[set].s = sfx;
closedcaptions[set].t = lifespan;
closedcaptions[set].b = 2; // bob
}
void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
{
INT32 sep, pitch, priority, cnum;
@ -532,62 +619,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
#endif
// Handle closed caption input.
if (cv_closedcaptioning.value && sfx->caption[0] != '/')
{
UINT8 i, set = NUMCAPTIONS-1, moveup = 255;
boolean same = false;
for (i = 0; i < set; i++)
{
same = ((sfx == closedcaptions[i].s) || (closedcaptions[i].s && fastcmp(sfx->caption, closedcaptions[i].s->caption)));
if (same)
{
set = i;
break;
}
}
if (!same)
{
for (i = 0; i < set; i++)
{
if (!(closedcaptions[i].c || closedcaptions[i].s) || (sfx->priority >= closedcaptions[i].s->priority))
{
set = i;
if (closedcaptions[i].s && (sfx->priority >= closedcaptions[i].s->priority))
moveup = i;
break;
}
}
for (i = NUMCAPTIONS-1; i > set; i--)
{
if (sfx == closedcaptions[i].s)
{
closedcaptions[i].c = NULL;
closedcaptions[i].s = NULL;
closedcaptions[i].t = 0;
}
}
}
if (moveup != 255)
{
for (i = moveup; i < NUMCAPTIONS-1; i++)
{
if (!(closedcaptions[i].c || closedcaptions[i].s))
break;
}
for (; i > set; i--)
{
closedcaptions[i].c = closedcaptions[i-1].c;
closedcaptions[i].s = closedcaptions[i-1].s;
closedcaptions[i].t = closedcaptions[i-1].t;
}
}
closedcaptions[set].c = &channels[cnum];
closedcaptions[set].s = sfx;
closedcaptions[set].t = MAXCAPTIONTICS+2;
}
S_StartCaption(sfx_id, cnum, MAXCAPTIONTICS);
// Assigns the handle to one of the channels in the
// mix/output buffer.
@ -640,62 +672,7 @@ dontplay:
#endif
// Handle closed caption input.
if (cv_closedcaptioning.value && sfx->caption[0] != '/')
{
UINT8 i, set = NUMCAPTIONS-1, moveup = 255;
boolean same = false;
for (i = 0; i < set; i++)
{
same = ((sfx == closedcaptions[i].s) || (closedcaptions[i].s && fastcmp(sfx->caption, closedcaptions[i].s->caption)));
if (same)
{
set = i;
break;
}
}
if (!same)
{
for (i = 0; i < set; i++)
{
if (!(closedcaptions[i].c || closedcaptions[i].s) || (sfx->priority >= closedcaptions[i].s->priority))
{
set = i;
if (closedcaptions[i].s && (sfx->priority >= closedcaptions[i].s->priority))
moveup = i;
break;
}
}
for (i = NUMCAPTIONS-1; i > set; i--)
{
if (sfx == closedcaptions[i].s)
{
closedcaptions[i].c = NULL;
closedcaptions[i].s = NULL;
closedcaptions[i].t = 0;
}
}
}
if (moveup != 255)
{
for (i = moveup; i < NUMCAPTIONS-1; i++)
{
if (!(closedcaptions[i].c || closedcaptions[i].s))
break;
}
for (; i > set; i--)
{
closedcaptions[i].c = closedcaptions[i-1].c;
closedcaptions[i].s = closedcaptions[i-1].s;
closedcaptions[i].t = closedcaptions[i-1].t;
}
}
closedcaptions[set].c = &channels[cnum];
closedcaptions[set].s = sfx;
closedcaptions[set].t = MAXCAPTIONTICS+2;
}
S_StartCaption(sfx_id, cnum, MAXCAPTIONTICS);
// Assigns the handle to one of the channels in the
// mix/output buffer.
@ -976,10 +953,7 @@ notinlevel:
if (!closedcaptions[i].s)
continue;
if (closedcaptions[i].t <= MAXCAPTIONTICS)
closedcaptions[i].t--;
if (!closedcaptions[i].t)
if (!(--closedcaptions[i].t))
{
closedcaptions[i].c = NULL;
closedcaptions[i].s = NULL;

View File

@ -82,7 +82,8 @@ typedef struct
typedef struct {
channel_t *c;
sfxinfo_t *s;
UINT8 t;
UINT16 t;
UINT8 b;
} caption_t;
#define NUMCAPTIONS 8
@ -90,6 +91,7 @@ typedef struct {
#define CAPTIONFADETICS 20
extern caption_t closedcaptions[NUMCAPTIONS];
void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan);
// register sound vars and commands at game startup
void S_RegisterSoundStuff(void);

View File

@ -448,15 +448,17 @@ void SCR_ClosedCaptions(void)
{
INT32 flags = V_NOSCALESTART|V_ALLOWLOWERCASE;
INT32 y = vid.height-((i + 2)*10*vid.dupy);
char dir = ' ';
char dot = ' ';
if (closedcaptions[i].b)
y -= (closedcaptions[i].b--)*vid.dupy;
if (closedcaptions[i].t < CAPTIONFADETICS)
flags |= (((CAPTIONFADETICS-closedcaptions[i].t)/2)*V_10TRANS);
else if (closedcaptions[i].t > MAXCAPTIONTICS)
y -= (closedcaptions[i].t-- - MAXCAPTIONTICS)*vid.dupy;
if (closedcaptions[i].c && closedcaptions[i].c->origin)
dir = '\x1E';
dot = '\x1E';
else if (closedcaptions[i].s-S_sfx == sfx_None)
dot = 'M';
V_DrawRightAlignedString(vid.width-(20*vid.dupx), y,
flags, va("%c [%s]", dir, (closedcaptions[i].s->caption[0] ? closedcaptions[i].s->caption : closedcaptions[i].s->name)));
flags, va("%c [%s]", dot, (closedcaptions[i].s->caption[0] ? closedcaptions[i].s->caption : closedcaptions[i].s->name)));
}
}
}

View File

@ -33,7 +33,7 @@ sfxinfo_t S_sfx[NUMSFX] =
*****/
// S_sfx[0] needs to be a dummy for odd reasons. (don't modify this comment)
// name, singularity, priority, pitch, volume, data, length, skinsound, usefulness, lumpnum, caption
{"none" , false, 0, 0, -1, NULL, 0, -1, -1, LUMPERROR, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, // maximum length
{"none" , false, 0, 0, -1, NULL, 0, -1, -1, LUMPERROR, "///////////////////////////////"}, // maximum length
// Skin Sounds
{"altdi1", false, 192, 16, -1, NULL, 0, SKSPLDET1, -1, LUMPERROR, "Dying"},
@ -198,7 +198,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"emfind", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Radar beep"},
{"flgcap", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flag captured"},
{"menu1", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Menu beep"},
{"oneup", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Extra life"},
{"oneup", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "One-up"},
{"ptally", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Tally"}, // Point tally is identical to menu for now
{"radio", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Notification"},
{"wepchg", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Weapon change"}, // Weapon switch is identical to menu for now
@ -237,7 +237,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"mario7", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"},
{"mario8", false, 48, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"},
{"mario9", true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Emerging"},
{"marioa", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Extra life"},
{"marioa", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "One-up"},
{"thwomp", true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Thwomp"},
// Black Eggman
@ -294,7 +294,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"},
{"s3k45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning zap"},
{"s3k46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"},
{"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising sand"},
{"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising dust"},
{"s3k48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic clink"},
{"s3k49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling rock"},
{"s3k4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Grab"},
@ -389,7 +389,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3ka3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lift"},
{"s3ka4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"},
{"s3ka5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s3ka6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction failure"},
{"s3ka6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction fizzle"},
{"s3ka7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Countdown beep"},
{"s3ka8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"},
{"s3ka9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aquaphobia"},
@ -513,7 +513,8 @@ void S_InitRuntimeSounds (void)
S_sfx[i].skinsound = -1;
S_sfx[i].usefulness = -1;
S_sfx[i].lumpnum = LUMPERROR;
strlcpy(S_sfx[i].caption, "", 9);
//strlcpy(S_sfx[i].caption, "", 1);
S_sfx[i].caption[0] = '\0';
}
}