Refactor voices

* Tie all voices to skins, allocate voices during skin allocation and patching
* Bring back voice.name, kill voice.parent, add voice.id
* Lua compatibility for voices (again) soon (hopefully)
This commit is contained in:
yamamama 2025-11-29 20:51:25 -05:00
parent 14753a4534
commit 51a005a7de
18 changed files with 490 additions and 443 deletions

View file

@ -1424,7 +1424,7 @@ static UINT8 Skin_FindValidDub(consvar_t *cvar, UINT16 skin_id, kartvoice_t *voi
if (!myvoice)
{
myvoice = skins[skin_id].voice;
myvoice = &skins[skin_id].voices[0];
if (!myvoice)
{
@ -1437,36 +1437,19 @@ static UINT8 Skin_FindValidDub(consvar_t *cvar, UINT16 skin_id, kartvoice_t *voi
strlcpy(cvarname, value, sizeof(cvarname));
strupr(cvarname);
i = DEH_FindKartVoice(cvarname);
i = R_FindIDForVoice(&skins[skin_id], cvarname);
if (i != MAXSKINVOICES)
{
// Make sure this voice belongs to the skin we're about to assign it to.
if (skinvoices[i].parent == skin_id || forceme)
{
// Change the cvar to be the value of the name.
strlcpy(cvarname, DEH_KartVoiceName(i), sizeof(cvarname));
strlwr(cvarname);
// Voices are tied to skins; if, SOMEHOW, this voice has a *different* parent,
// something has gone terribly wrong.
CV_StealthSet(cvar, cvarname);
cvar->value = skinvoices[i].id;
}
else
{
// This isn't a valid voice for this skin, so don't assign shit.
if (!silent)
CONS_Alert(CONS_NOTICE, M_GetText("Voice \"%s\" doesn't belong to this skin (%s).\n"), DEH_KartVoiceName(i), skins[skin_id].name);
// Change the cvar to be the value of the name.
strlcpy(cvarname, skins[skin_id].voices[i].name, sizeof(cvarname));
strlwr(cvarname);
// *Reassign* the voice cvar to whatever the current voice is, at least.
strlcpy(cvarname, DEH_KartVoiceName(myvoice->id), sizeof(cvarname));
strlwr(cvarname);
CV_StealthSet(cvar, cvarname);
cvar->value = myvoice->id;
// Signal to networking that we failed to set a voice.
return 1;
}
CV_StealthSet(cvar, cvarname);
cvar->value = skins[skin_id].voices[i].id;
// We've found the voice we were looking for!
return 0;
@ -1474,10 +1457,10 @@ static UINT8 Skin_FindValidDub(consvar_t *cvar, UINT16 skin_id, kartvoice_t *voi
// Found diddly-squat, say as much.
if (!silent)
CONS_Alert(CONS_NOTICE, M_GetText("Voice \"%s\" does not exist.\n"), value);
CONS_Alert(CONS_NOTICE, M_GetText("Voice \"%s\" does not exist for this skin.\n"), value);
// Reassign the voice cvar to our current voice.
strlcpy(cvarname, DEH_KartVoiceName(myvoice->id), sizeof(cvarname));
strlcpy(cvarname, myvoice->name, sizeof(cvarname));
strlwr(cvarname);
CV_StealthSet(cvar, cvarname);
@ -1890,7 +1873,7 @@ static void SendNameAndColor(UINT8 n)
if (!voice)
{
voice = skins[player->skin].voice;
voice = &skins[player->skin].voices[0];
if (!voice)
{
@ -1904,7 +1887,7 @@ static void SendNameAndColor(UINT8 n)
&& !strcmp(cv_skin[n].string, skins[player->skin].name)
&& cv_follower[n].value == player->followerskin
&& cv_followercolor[n].value == player->followercolor
&& (!permamute && !stricmp(cv_voice[n].string, DEH_KartVoiceName(voice->id))))
&& (!permamute && !stricmp(cv_voice[n].string, voice->name)))
return;
player->availabilities = R_GetSkinAvailabilities();
@ -1916,8 +1899,7 @@ static void SendNameAndColor(UINT8 n)
// If you're not in a netgame, merely update the skin, color, and name.
if (!netgame)
{
INT32 foundskin;
kartvoicetype_e vid;
INT32 foundskin, vid;
CleanupPlayerName(playernum, cv_playername[n].zstring);
strcpy(player_names[playernum], cv_playername[n].zstring);
@ -1939,52 +1921,37 @@ static void SendNameAndColor(UINT8 n)
}
else if ((foundskin = R_SkinAvailable(cv_skin[n].string)) != -1 && R_SkinUsable(playernum, foundskin))
{
prevskin = player->skin;
prevskin = skins[cv_skin[n].value].name;
cv_skin[n].value = foundskin;
SetPlayerSkin(playernum, cv_skin[n].string);
CV_StealthSet(&cv_skin[n], skins[cv_skin[n].value].name);
// Reset the voice.
if (prevskin != player->skin && skins[player->skin].voice)
if (prevskin != player->skin)
{
// Try getting the voice from our ID.
valuevoice = &skinvoices[player->voice_id];
if (valuevoice->parent != skins[player->skin].voice->parent)
if (cv_voice[n].string)
{
// Parent mismatch 1; let's try the cvar.
vid = R_FindIDForVoice(&skins[player->skin], cv_voice[n].string);
if (cv_voice[n].string)
if (vid == MAXSKINVOICES)
{
vid = R_FindIDForVoice(cv_voice[n].string);
if (vid == MAXSKINVOICES)
{
// No dice; use the skin.
valuevoice = skins[player->skin].voice;
}
else
{
if (skinvoices[vid].parent == skins[player->skin].voice->parent)
{
valuevoice = &skinvoices[vid];
}
else
{
// Parent mismatch... again.
valuevoice = skins[player->skin].voice;
}
}
// No dice; use the default voice.
valuevoice = &skins[player->skin].voices[0];
}
else
{
// NULL string; default to the skin.
valuevoice = skins[player->skin].voice;
valuevoice = &skins[player->skin].voices[vid];
}
}
else
{
// NULL string; default to the skin's default.
valuevoice = &skins[player->skin].voices[0];
}
strlcpy(voicebuf, DEH_KartVoiceName(valuevoice->id), sizeof(voicebuf));
strlcpy(voicebuf, valuevoice->name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2001,45 +1968,30 @@ static void SendNameAndColor(UINT8 n)
SetPlayerSkin(playernum, cv_skin[n].string);
// Reset the voice.
if (prevskin != player->skin && skins[player->skin].voice)
if (prevskin != player->skin)
{
// Try getting the voice from our ID.
valuevoice = &skinvoices[player->voice_id];
if (valuevoice->parent != skins[player->skin].voice->parent)
if (cv_voice[n].string)
{
// Parent mismatch 1; let's try the cvar.
vid = R_FindIDForVoice(&skins[player->skin], cv_voice[n].string);
if (cv_voice[n].string)
if (vid == MAXSKINVOICES)
{
vid = R_FindIDForVoice(cv_voice[n].string);
if (vid == MAXSKINVOICES)
{
// No dice; use the skin.
valuevoice = skins[player->skin].voice;
}
else
{
if (skinvoices[vid].parent == skins[player->skin].voice->parent)
{
valuevoice = &skinvoices[vid];
}
else
{
// Parent mismatch... again.
valuevoice = skins[player->skin].voice;
}
}
// No dice; use the default voice.
valuevoice = &skins[player->skin].voices[0];
}
else
{
// NULL string; default to the skin.
valuevoice = skins[player->skin].voice;
valuevoice = &skins[player->skin].voices[vid];
}
}
else
{
// NULL string; default to the skin's default.
valuevoice = &skins[player->skin].voices[0];
}
strlcpy(voicebuf, DEH_KartVoiceName(valuevoice->id), sizeof(voicebuf));
strlcpy(voicebuf, valuevoice->name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2050,7 +2002,7 @@ static void SendNameAndColor(UINT8 n)
// Need to update voices after the fact.
if (!cv_voice[n].string)
{
strlcpy(voicebuf, DEH_KartVoiceName(skins[player->skin].voice->id), sizeof(voicebuf));
strlcpy(voicebuf, skins[player->skin].voices[0].name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2062,7 +2014,7 @@ static void SendNameAndColor(UINT8 n)
if (valuevoice)
{
strlcpy(voicebuf, DEH_KartVoiceName(valuevoice->id), sizeof(voicebuf));
strlcpy(voicebuf, valuevoice->name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2070,18 +2022,13 @@ static void SendNameAndColor(UINT8 n)
}
else
{
// Try getting the voice from our ID.
valuevoice = &skinvoices[player->voice_id];
if (valuevoice->parent != skins[player->skin].voice->parent)
{
// Parent mismatch; use the skin's voice.
valuevoice = skins[player->skin].voice;
}
// Get the voice from our ID.
// No need to compare parents,
valuevoice = &skins[player->skin].voices[player->voice_id];
if (valuevoice)
{
strlcpy(voicebuf, DEH_KartVoiceName(valuevoice->id), sizeof(voicebuf));
strlcpy(voicebuf, valuevoice->name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2090,7 +2037,7 @@ static void SendNameAndColor(UINT8 n)
else
{
// ...still nothing?
strlcpy(voicebuf, DEH_KartVoiceName(0), sizeof(voicebuf));
strlcpy(voicebuf, skins[player->skin].voices[0].name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2122,11 +2069,11 @@ static void SendNameAndColor(UINT8 n)
if (Skin_FindValidDub(&cv_voice[n], cv_skin[n].value, voice, false, true))
{
// Our voice is no longer valid, set it to that of our skin's.
strlcpy(voicebuf, DEH_KartVoiceName(skins[player->skin].voice->id), sizeof(voicebuf));
strlcpy(voicebuf, skins[player->skin].voices[0].name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
cv_voice[n].value = skins[player->skin].voice->id;
cv_voice[n].value = skins[player->skin].voices[0].id;
}
}
@ -2145,7 +2092,7 @@ static void SendNameAndColor(UINT8 n)
// Need to update voices after the fact.
if (!cv_voice[n].string)
{
strlcpy(voicebuf, DEH_KartVoiceName(skins[player->skin].voice->id), sizeof(voicebuf));
strlcpy(voicebuf, skins[player->skin].voices[0].name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2159,9 +2106,9 @@ static void SendNameAndColor(UINT8 n)
// rescan our current voice and send that over the network.
valuevoice = P_GetMobjVoice(player->mo);
if (valuevoice && valuevoice->parent == cv_skin[n].value)
if (valuevoice)
{
strlcpy(voicebuf, DEH_KartVoiceName(valuevoice->id), sizeof(voicebuf));
strlcpy(voicebuf, valuevoice->name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2169,18 +2116,13 @@ static void SendNameAndColor(UINT8 n)
}
else
{
// Try getting the voice from our ID.
valuevoice = &skinvoices[player->voice_id];
if (valuevoice->parent != skins[cv_skin[n].value].voice->parent)
{
// Parent mismatch; use the skin's voice.
valuevoice = skins[cv_skin[n].value].voice;
}
// Get the voice from our ID.
// No need to compare parents.
valuevoice = &skins[player->skin].voices[player->voice_id];
if (valuevoice)
{
strlcpy(voicebuf, DEH_KartVoiceName(valuevoice->id), sizeof(voicebuf));
strlcpy(voicebuf, valuevoice->name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2189,7 +2131,7 @@ static void SendNameAndColor(UINT8 n)
else
{
// ...still nothing?
strlcpy(voicebuf, DEH_KartVoiceName(0), sizeof(voicebuf));
strlcpy(voicebuf, skins[player->skin].voices[0].name, sizeof(voicebuf));
strlwr(voicebuf);
CV_StealthSet(&cv_voice[n], voicebuf);
@ -2327,15 +2269,15 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
{
CV_StealthSet(&cv_skin[localplayer], skins[forcedskin].name);
strlcpy(voicename, DEH_KartVoiceName(skins[forcedskin].voice->id), sizeof(voicename));
strlcpy(voicename, skins[forcedskin].voices[0].name, sizeof(voicename));
strlwr(voicename);
CV_StealthSet(&cv_voice[localplayer], voicename);
cv_voice[localplayer].value = skins[forcedskin].voice->id;
cv_voice[localplayer].value = skins[forcedskin].voices[0].id;
}
// set voice
SetPlayerVoiceByNum(playernum, skins[forcedskin].voice->id);
SetPlayerVoiceByNum(playernum, skins[forcedskin].voices[0].id);
}
else
{
@ -2346,11 +2288,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
if (localplayer != -1)
{
strlcpy(voicename, DEH_KartVoiceName(voice), sizeof(voicename));
strlcpy(voicename, skins[p->skin].voices[p->voice_id].name, sizeof(voicename));
strlwr(voicename);
CV_StealthSet(&cv_voice[localplayer], voicename);
cv_voice[localplayer].value = skinvoices[voice].id;
cv_voice[localplayer].value = skins[p->skin].voices[p->voice_id].id;
}
}
@ -7599,7 +7541,7 @@ static void __voice_cvar_func(INT32 pid, UINT8 pnum)
if (!myvoice)
{
myvoice = skins[players[pid].skin].voice;
myvoice = &skins[players[pid].skin].voices[0];
if (!myvoice)
{
@ -7621,7 +7563,7 @@ static void __voice_cvar_func(INT32 pid, UINT8 pnum)
if (!(cht_debug || devparm) && !(multiplayer || netgame) // In single player.
&& (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y
{
strlcpy(cvarname, DEH_KartVoiceName(myvoice->id), sizeof(cvarname));
strlcpy(cvarname, myvoice->name, sizeof(cvarname));
strlwr(cvarname);
CV_StealthSet(&cv_voice[pnum], cvarname);
@ -7636,7 +7578,7 @@ static void __voice_cvar_func(INT32 pid, UINT8 pnum)
{
CONS_Alert(CONS_NOTICE, M_GetText("You can't change your voice at the moment.\n"));
strlcpy(cvarname, DEH_KartVoiceName(myvoice->id), sizeof(cvarname));
strlcpy(cvarname, myvoice->name, sizeof(cvarname));
strlwr(cvarname);
CV_StealthSet(&cv_voice[pnum], cvarname);

View file

@ -4242,8 +4242,9 @@ void readkartresult(MYFILE *f, kartresult_t *result)
#undef WARN
#undef WARN0
#define WARN(str, ...) deh_warning("KartVoice %s: " str, strbuf_get(voicenames, voice->info.nameofs), __VA_ARGS__)
#define WARN0(str) deh_warning("KartVoice %s: " str, strbuf_get(voicenames, voice->info.nameofs))
/*
#define WARN(str, ...) deh_warning("KartVoice %s: " str, voice->name, __VA_ARGS__)
#define WARN0(str) deh_warning("KartVoice %s: " str, voice->name)
// Necessary for sound adding, so we can gather flags and singularity data.
static sfxenum_t skinsoundreroute[] = {
@ -4416,13 +4417,13 @@ void readkartvoice(MYFILE *f, kartvoice_t *voice)
while (!myfeof(f)); // finish when the line is empty
// Set our ID afterwards.
voice->id = (UINT32)(voice - skinvoices);
//voice->id = (UINT32)(voice - skinvoices);
Z_Free(s);
}
#undef WARN
#undef WARN0
#undef WARN0*/
//
//
@ -4604,15 +4605,6 @@ useoddsfunc_f *get_useoddsfunc(const char *word)
return NULL;
}
kartvoicetype_e get_kartvoice(const char *word)
{ // Returns the value of KVOICE_ enumerations
kartvoicetype_e i;
i = DEH_FindKartVoice(word);
if (i == MAXSKINVOICES)
deh_warning("Couldn't find voice named 'KVOICE_%s'", word);
return i;
}
/// \todo Make ANY of this completely over-the-top math craziness obey the order of operations.
static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; }
static fixed_t op_div(fixed_t a, fixed_t b) { return a/b; }

View file

@ -65,7 +65,6 @@ menudrawer_f *get_menudrawer(const char *word);
skincolornum_t get_skincolor(const char *word);
kartitemtype_e get_kartitem(const char *word);
useoddsfunc_f *get_useoddsfunc(const char *word);
kartvoicetype_e get_kartvoice(const char *word);
void readwipes(MYFILE *f);
void readmaincfg(MYFILE *f);
@ -97,7 +96,6 @@ preciptype_t get_precip(const char *word);
void readweather(MYFILE *f, INT32 num);
void readkartitem(MYFILE *f, kartitem_t *item);
void readkartresult(MYFILE *f, kartresult_t *result);
void readkartvoice(MYFILE *f, kartvoice_t *voice);
#ifdef __cplusplus
} // extern "C"

View file

@ -41,7 +41,7 @@ strbuf_t *mobjnames;
strbuf_t *skincolornames;
strbuf_t *menunames;
strbuf_t *kartitemnames;
strbuf_t *voicenames;
UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
const char *DEH_MobjtypeName(mobjtype_t i)
@ -69,11 +69,6 @@ const char *DEH_KartItemName(kartitemtype_e i)
return strbuf_get(kartitemnames, kartitems[i].info.nameofs);
}
const char *DEH_KartVoiceName(kartvoicetype_e i)
{
return strbuf_get(voicenames, skinvoices[i].info.nameofs);
}
mobjtype_t DEH_FindMobjtype(const char *word)
{
mobjtype_t i;
@ -139,19 +134,6 @@ kartitemtype_e DEH_FindKartItem(const char *word)
return MAXKARTITEMS;
}
kartvoicetype_e DEH_FindKartVoice(const char *word)
{
INT32 i;
UINT32 hash = HASH32(word, strlen(word));
for (i = 0; i < numskinvoices; i++) {
if (hash != skinvoices[i].info.namehash)
continue;
if (fastcmp(word, DEH_KartVoiceName(i)))
return (kartvoicetype_e)i;
}
return MAXSKINVOICES;
}
struct flickytypes_s FLICKYTYPES[] = {
{"BLUEBIRD", MT_FLICKY_01}, // Flicky (Flicky)
{"RABBIT", MT_FLICKY_02}, // Pocky (1)

View file

@ -32,7 +32,7 @@ extern strbuf_t *mobjnames;
extern strbuf_t *skincolornames;
extern strbuf_t *menunames;
extern strbuf_t *kartitemnames;
extern strbuf_t *voicenames;
extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
const char *DEH_MobjtypeName(mobjtype_t i);
@ -40,14 +40,12 @@ const char *DEH_StateName(statenum_t i);
const char *DEH_SkincolorName(skincolornum_t i);
const char *DEH_MenutypeName(menutype_t i);
const char *DEH_KartItemName(kartitemtype_e i);
const char *DEH_KartVoiceName(kartvoicetype_e i);
mobjtype_t DEH_FindMobjtype(const char *word);
statenum_t DEH_FindState(const char *word);
skincolornum_t DEH_FindSkincolor(const char *word);
menutype_t DEH_FindMenutype(const char *word);
kartitemtype_e DEH_FindKartItem(const char *word);
kartvoicetype_e DEH_FindKartVoice(const char *word);
struct flickytypes_s {
const char *name;

View file

@ -786,7 +786,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
result = K_RegisterResult(word2, alternate);
readkartresult(f, result);
}
else if (fastncmp(word, "KARTVOICE", 9))
/*else if (fastncmp(word, "KARTVOICE", 9)) (Deprecated; getting merged into skins)
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = DEH_FindKartVoice(word2); // find a voice by name
@ -811,7 +811,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
deh_warning("KartVoice number %d out of range (0 - %d)", i, numskinvoices);
ignorelines(f);
}
}
}*/
else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION"))
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number

View file

@ -415,10 +415,7 @@ void F_IntroTicker(void)
INT32 rskin = M_RandomKey(numskins);
UINT8 rtaunt = M_RandomKey(2);
if (!skins[rskin].voice) // Should NOT happen!
I_Error("F_IntroTicker: Skin no. %d has no voice assigned", rskin);
sfxenum_t rsound = skins[rskin].voice->boost[rtaunt];
sfxenum_t rsound = skins[rskin].voices[0].boost[rtaunt];
S_StartSound(NULL, rsound);
}
}
@ -452,11 +449,8 @@ void F_IntroTicker(void)
char chars[6][10] = {"tails", "chao", "aiai", "sakura", "doom"};
SINT8 random = M_RandomRange(0, 4);
const INT32 rskin = R_SkinAvailable(chars[random]);
if (!skins[rskin].voice) // Should NOT happen!
I_Error("F_IntroTicker: Skin no. %d has no voice assigned", rskin);
sfxenum_t rsound = skins[rskin].voice->win;
sfxenum_t rsound = skins[rskin].voices[0].win;
S_StartSound(NULL, sfx_flgcap);
S_StartSound(NULL, rsound);
}

View file

@ -1268,28 +1268,31 @@ void G_ReadDemoExtraData(void)
FindClosestSkinForStats(p, extra.kartspeed, extra.kartweight);
// Voice
const INT32 vce = R_FindIDForVoice(extra.voicename);
const INT32 vce = R_FindIDForVoice(&skins[players[p].skin], extra.voicename);
if (vce == MAXSKINVOICES)
{
// The above function didn't find a voice, so we'll just fall back
// to the skin's voice.
players[p].voice_id = skins[players[p].skin].voice->id;
players[p].voice_id = 0;
}
else
{
players[p].voice_id = (UINT16)vce;
}
if (skinvoices[players[p].voice_id].parent ==
skins[players[p].skin].voice->parent &&
skinvoices[players[p].voice_id].id !=
skins[players[p].skin].voice->id &&
if (skins[players[p].skin].voices[players[p].voice_id].id == 0)
{
// Default voice for this skin. Just strip the object of its voice.
players[p].mo->voice = NULL;
}
else if (skins[players[p].skin].voices[players[p].voice_id].id !=
skins[players[p].skin].voices[0].id &&
!P_MobjWasRemoved(players[p].mo))
{
// This player's mobj exists, and their voice is valid, and isn't
// the default. So, attach the voice to the mobj!
players[p].mo->voice = &skinvoices[players[p].voice_id];
players[p].mo->voice = &skins[players[p].skin].voices[players[p].voice_id];
}
players[p].kartspeed = extra.kartspeed;
@ -1396,7 +1399,7 @@ void G_WriteDemoExtraData(void)
WRITESTRINGL(demobuf.p, skins[players[i].skin].name, 16+1);
// Voice
WRITESTRINGL(demobuf.p, DEH_KartVoiceName(players[i].voice_id), 32+1);
WRITESTRINGL(demobuf.p, skins[players[i].skin].voices[players[i].voice_id].name, 32+1);
// Stats
WRITEUINT8(demobuf.p, skins[players[i].skin].kartspeed);
@ -2983,7 +2986,7 @@ void G_BeginRecording(void)
WRITESTRINGL(demobuf.p, skincolors[player->skincolor].name, 16+1);
// Voice
WRITESTRINGL(demobuf.p, DEH_KartVoiceName(player->voice_id), 32+1);
WRITESTRINGL(demobuf.p, skins[player->skin].voices[player->voice_id].name, 32+1);
// Save follower's skin name
// PS: We must check for 'follower' to determine if the followerskin is valid. It's going to be 0 if we don't have a follower, but 0 is also absolutely a valid follower!
@ -3859,13 +3862,13 @@ void G_DoPlayDemo(char *defdemoname)
// We'll only assign IDs, since the actual voice assignment happens during
// player spawn.
const INT32 vce = R_FindIDForVoice(plr->voice);
const INT32 vce = R_FindIDForVoice(&skins[players[p].skin], plr->voice);
if (vce == MAXSKINVOICES)
{
// The above function didn't find a voice, so we'll just fall back to
// the skin's voice.
players[p].voice_id = skins[players[p].skin].voice->id;
players[p].voice_id = 0;
}
else
{

View file

@ -2703,7 +2703,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
UINT8 latestlap;
UINT16 skincolor;
INT32 skin;
kartvoicetype_e voice;
UINT16 voice;
UINT32 availabilities;
tic_t jointime;

View file

@ -258,19 +258,4 @@ void P_ResetData(INT32 flags)
K_RegisterItem(i);
}
}
// voices
if (init)
{
for (i = 0; i < MAXSKINVOICES; i++)
{
R_ClearVoice(i);
}
numskinvoices = 0;
if (voicenames)
Z_Free(voicenames);
voicenames = strbuf_alloc();
}
}

View file

@ -2615,38 +2615,6 @@ static int lib_rGetNameByColor(lua_State *L)
}
// R_SKINS
////////////
// Lua-exclusive; allocates a voice into memory, and returns a pointer to said voice.
// Mangled clone of deh_soc's get_kartvoice, modified for Lua.
static int lib_rAddKartVoice(lua_State *L)
{
const char* word = luaL_checkstring(L, 1);
NOHUD
char wordupper[VOICENAMESIZE+1];
strlcpy(wordupper, word, sizeof(wordupper));
strupr(wordupper);
INT32 i = DEH_FindKartVoice(wordupper);
if (i == MAXSKINVOICES)
{
// Freeslot voices that don't exist yet.
const INT32 allocresult = R_AllocKartVoice(false, word, &i);
if (allocresult < 0)
return luaL_error(L, "kartvoice_t '%s' could not be allocated.", word);
else
skinvoices[i].id = (UINT32)(&skinvoices[i] - skinvoices);
}
// If we're down here, we managed to allocate our voice.
LUA_PushUserdata(L, &skinvoices[i], META_VOICE);
return 1;
}
// S_SOUND
////////////
static int GetValidSoundOrigin(lua_State *L, void **origin)
@ -5426,9 +5394,6 @@ static luaL_Reg lib[] = {
{"R_GetSuperColorByName", lib_rGetSuperColorByName},
{"R_GetNameByColor", lib_rGetNameByColor},
// r_skins (voice)
{"R_AddKartVoice", lib_rAddKartVoice},
// s_sound
{"S_StartSound",lib_sStartSound},
{"S_StartSoundAtVolume",lib_sStartSoundAtVolume},

View file

@ -144,8 +144,10 @@ static int skin_get(lua_State *L)
LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID);
break;
case skin_voice:
LUA_PushUserdata(L, skin->voice, META_VOICE);
break;
// ...uuuuuuughhhhh...
return UNIMPLEMENTED;
//LUA_PushUserdata(L, skin->voice, META_VOICE);
//break;
case skin_sprites:
LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
break;
@ -255,7 +257,7 @@ static int soundsid_get(lua_State *L)
if (i >= NUMSKINSOUNDS)
return luaL_error(L, "%s cannot be %s", LUA_QL("skinsound_t"), va("%u", (UINT32)i));
lua_pushinteger(L, P_GetKartVoiceSFX(s->voice, i));
lua_pushinteger(L, P_GetKartVoiceSFX(&s->voices[0], i));
return 1;
}

View file

@ -27,7 +27,6 @@ enum voicevars
{
voicevars_id = 0,
voicevars_name, // Not actually in kartvoice_t; returns the name of the voice
voicevars_parent,
voicevars_win,
voicevars_lose,
voicevars_pain,
@ -41,7 +40,6 @@ enum voicevars
static const char *const voicevars_opt[] = {
"id",
"name",
"parent",
"win",
"lose",
"pain",
@ -74,10 +72,7 @@ static int voice_get(lua_State* L)
case voicevars_id:
return RNOGET;
case voicevars_name:
lua_pushstring(L, DEH_KartVoiceName((kartvoicetype_e)(voice - skinvoices)));
break;
case voicevars_parent:
LUA_PushUserdata(L, &skins[voice->parent], META_SKIN);
lua_pushstring(L, voice->name);
break;
case voicevars_win:
LUA_PushUserdata(L, &S_sfx[voice->win], META_SFXINFO);
@ -134,21 +129,6 @@ static int voice_set(lua_State* L)
return RNOSET;
case voicevars_name:
return RNOSET;
case voicevars_parent:
{
// It would make no sense not to accept a skin struct here.
skin_t* my_new_parent = *((skin_t**)luaL_checkudata(L, 3, META_SKIN));
if (!my_new_parent)
{
luaL_error(L, "skin does not exist.");
}
else
{
voice->parent = (UINT16)(my_new_parent - skins);
}
break;
}
case voicevars_win:
// For the actual sound values, you pass the actual sfxenum_t enums.
// Yes, I know what I said about skin structs literally just above.
@ -190,7 +170,7 @@ static int voice_num(lua_State* L)
// voices are always valid, only added, never removed
I_Assert(voice != NULL);
lua_pushinteger(L, voice - skinvoices);
lua_pushinteger(L, voice->id);
return 1;
}
@ -226,88 +206,6 @@ static int voice_array_num(lua_State *L)
return 1;
}
static int lib_iterateVoices(lua_State* L)
{
INT32 i;
if (lua_gettop(L) < 2)
{
lua_pushcfunction(L, lib_iterateVoices);
return 1;
}
lua_settop(L, 2);
lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1))
i = (INT32)(*((kartvoice_t**)luaL_checkudata(L, 1, META_VOICE)) - skinvoices) + 1;
else
i = 0;
// voices are always valid, only added, never removed
if (i < numskinvoices)
{
LUA_PushUserdata(L, &skinvoices[i], META_VOICE);
return 1;
}
return 0;
}
static int lib_getVoice(lua_State* L)
{
const char* field;
INT32 i;
// find voice by number
if (lua_type(L, 2) == LUA_TNUMBER)
{
i = luaL_checkinteger(L, 2);
if (i < 0 || i >= MAXSKINVOICES)
{
return luaL_error(
L, "skinvoices[] index %d out of range (0 - %d)", i, MAXSKINVOICES - 1);
}
else if (i >= numskinvoices)
{
return 0;
}
LUA_PushUserdata(L, &skinvoices[i], META_VOICE);
return 1;
}
field = luaL_checkstring(L, 2);
// special function iterate
if (fastcmp(field, "iterate"))
{
lua_pushcfunction(L, lib_iterateVoices);
return 1;
}
// find voice by name
// Glad I made a function for this...
i = R_FindIDForVoice(field);
if (i != MAXSKINVOICES)
{
// Found a voice.
LUA_PushUserdata(L, &skinvoices[i], META_VOICE);
return 1;
}
return 0;
}
// In this case: returns TOTAL voices, and not individual table counts.
static int lib_numVoices(lua_State* L)
{
lua_pushinteger(L, numskinvoices);
return 1;
}
int LUA_VoiceLib(lua_State* L)
{
luaL_newmetatable(L, META_VOICE);
@ -332,16 +230,5 @@ int LUA_VoiceLib(lua_State* L)
lua_setfield(L, -2, "__len");
lua_pop(L,1);
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getVoice);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_numVoices);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "skinvoices");
return 0;
}

View file

@ -12381,24 +12381,12 @@ void P_SpawnPlayer(INT32 playernum)
mobj->skin = &skins[p->skin];
P_SetupStateAnimation(mobj, mobj->state);
if (p->voice_id != skins[p->skin].voice->id)
if (p->voice_id)
{
// During respawns, do a quick check on our voice ID to make sure
// our skin can use it.
// This should prevent bots from always having Sonic's voice.
kartvoice_t *tentative_voice = &skinvoices[p->voice_id];
if (tentative_voice->parent == skins[p->skin].voice->parent)
{
// Seems OK, set our voice!
mobj->voice = tentative_voice;
}
else
{
// Parent mismatch; use the skin default.
p->voice_id = skins[p->skin].voice->id;
mobj->voice = NULL;
}
mobj->voice = &skins[p->skin].voices[p->voice_id];
}
mobj->health = 1;
@ -14991,9 +14979,9 @@ kartvoice_t *P_GetMobjVoice(const mobj_t *mo)
{
return mo->voice;
}
else if (mo->skin && ((skin_t *)mo->skin)->voice)
else if (mo->skin)
{
return ((skin_t *)mo->skin)->voice;
return &((skin_t *)mo->skin)->voices[0];
}
return NULL;

View file

@ -2337,12 +2337,19 @@ static thinker_t *SyncMobjThinker(savebuffer_t *save, actionf_p1 thinker, thinke
SYNCF(MD3_EXTVAL3, mobj->extravalue3);
SYNCF(MD3_LIFETIME, mobj->mobjlifetime);
if (GETB(MD3_VOICE))
if (GETB(MD3_VOICE) && mobj->skin)
{
if (save->write)
WRITEUINT16(save->p, (UINT16)((kartvoice_t *)mobj->voice - skinvoices));
WRITEUINT16(save->p, (UINT16)(mobj->voice - &((skin_t *)(mobj->skin))->voices[0]));
else
mobj->voice = &skinvoices[READUINT16(save->p)];
{
UINT16 savedvoice = READUINT16(save->p);
if (savedvoice > ((skin_t *)(mobj->skin))->numvoices)
savedvoice = 0;
mobj->voice = &((skin_t *)(mobj->skin))->voices[savedvoice];
}
}
if (!save->write)

View file

@ -1316,7 +1316,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
//const INT32 sfx_id = (losing ? sfx_klose : sfx_kwin);
skin_t *playerskin = &skins[player->skin];
const kartvoice_t *playervoice = (!P_MobjWasRemoved(player->mo) ? P_GetMobjVoice(player->mo) : playerskin->voice);
const kartvoice_t *playervoice = (!P_MobjWasRemoved(player->mo) ? P_GetMobjVoice(player->mo) : &playerskin->voices[0]);
if (playervoice)
{

View file

@ -43,7 +43,7 @@ INT32 numskins = 0;
INT32 numskinvoices = 0;
skin_t skins[MAXSKINS];
INT32 skinsorted[MAXSKINS];
kartvoice_t skinvoices[MAXSKINVOICES];
//kartvoice_t skinvoices[MAXSKINVOICES];
// FIXTHIS: don't work because it must be inistilised before the config load
//#define SKINVALUES
@ -298,9 +298,9 @@ sfxenum_t P_GetKartVoiceSFX(kartvoice_t *voice, INT32 skinsound)
return sfx_thok;
}
void R_ClearVoice(kartvoicetype_e voicetype)
void R_ClearVoice(skin_t *skin, INT32 voicetype)
{
kartvoice_t *voice = &skinvoices[voicetype];
kartvoice_t *voice = &skin->voices[voicetype];
memset(voice, 0, sizeof(kartvoice_t));
}
@ -343,12 +343,11 @@ static void Sk_SetDefaultValue(skin_t *skin, kartvoice_t *skin_voice)
}
}
// TODO: Make this hexadecimal
skin_voice->parent = (UINT16)(skin - skins);
skin_voice->id = skin_voice-skinvoices;
strlcpy(skin_voice->name, "default", sizeof(skin_voice->name));
strlcpy(skin_voice->realname, "Default", sizeof(skin_voice->realname));
skin->voice = skin_voice;
skin->numvoices++;
CONS_Printf(M_GetText("%d %s allocated for this skin.\n"), skin->numvoices, (skin->numvoices == 1) ? "voice" : "voices");
}
static void R_IHateThatHedgehog(UINT16 wadnum);
@ -718,20 +717,31 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
// Gets the corresponding voice ID for a given voice's name.
// Returns MAXSKINVOICES if nothing is found.
kartvoicetype_e R_FindIDForVoice(const char* voicename)
INT32 R_FindIDForVoice(skin_t *skin, const char* voicename)
{
INT32 i;
const char *checkvoicename;
// Scan through our allocated skin voices for the wanted voice.
for (i = 0; i < numskinvoices; i++)
// First pass: Check the actual name.
for (i = 0; i < MAXSKINVOICES; i++)
{
// Whatever. Go, my code duplication!
checkvoicename = DEH_KartVoiceName(i);
if (strnicmp(voicename, checkvoicename, VOICENAMESIZE) == 0)
if (strnicmp(voicename, skin->voices[i].name, VOICENAMESIZE) == 0)
{
// Found a voice.
return (kartvoicetype_e)i;
return i;
}
}
// Second pass: check the display name.
for (i = 0; i < MAXSKINVOICES; i++)
{
// Whatever. Go, my code duplication!
if (strnicmp(voicename, skin->voices[i].realname, VOICENAMESIZE) == 0)
{
// Found a voice.
return i;
}
}
@ -739,18 +749,18 @@ kartvoicetype_e R_FindIDForVoice(const char* voicename)
return MAXSKINVOICES;
}
static kartvoicetype_e R_FindIDForVoiceNum(UINT16 voicenum)
static INT32 R_FindIDForVoiceNum(skin_t *skin, UINT16 voicenum)
{
INT32 i;
// Scan through our allocated skin voices for the wanted voice.
for (i = 0; i < numskinvoices; i++)
for (i = 0; i < MAXSKINVOICES; i++)
{
// Whatever. Go, my code duplication!
if (skinvoices[i].id == voicenum)
if (skin->voices[i].id == voicenum)
{
// Found a voice.
return (kartvoicetype_e)i;
return i;
}
}
@ -763,12 +773,12 @@ void SetPlayerVoice(INT32 playernum, const char* voicename)
{
player_t* player = &players[playernum];
kartvoicetype_e voxid = R_FindIDForVoice(voicename);
INT32 voxid = R_FindIDForVoice(&skins[player->skin], voicename);
if (voxid == MAXSKINVOICES)
{
// Couldn't find a voice. Default to the skin's.
voxid = skins[player->skin].voice->id;
// Couldn't find a voice. Default to the skin's default.
voxid = 0;
}
if (P_MobjWasRemoved(player->mo))
@ -785,8 +795,7 @@ void SetPlayerVoice(INT32 playernum, const char* voicename)
const kartvoice_t* myvoice = P_GetMobjVoice(player->mo);
const char* myvoicename = DEH_KartVoiceName(myvoice->id);
if (!strnicmp(voicename, myvoicename, VOICENAMESIZE))
if (!strnicmp(voicename, myvoice->name, VOICENAMESIZE))
{
// Hey... this voice is the same as before!
// WAIT! Before we go, reset the player's voice ID!
@ -801,8 +810,8 @@ void SetPlayerVoice(INT32 playernum, const char* voicename)
// for the needed name. If we're down here, we've passed the safeguards and can assign a
// voice.
if (voxid != skins[player->skin].voice->id)
player->mo->voice = &skinvoices[(UINT16)voxid];
if (voxid)
player->mo->voice = &skins[player->skin].voices[(UINT16)voxid];
else
player->mo->voice = NULL;
@ -816,12 +825,12 @@ void SetPlayerVoice(INT32 playernum, const char* voicename)
void SetPlayerVoiceByNum(INT32 playernum, UINT16 voicenum)
{
player_t* player = &players[playernum];
kartvoicetype_e voxid = R_FindIDForVoiceNum(voicenum);
INT32 voxid = R_FindIDForVoiceNum(&skins[player->skin], voicenum);
if (voxid == MAXSKINVOICES)
{
// Couldn't find a voice. Default to the skin's.
voxid = skins[player->skin].voice->id;
// Couldn't find a voice. Default to the skin's default.
voxid = 0;
}
if (P_MobjWasRemoved(player->mo))
@ -853,8 +862,8 @@ void SetPlayerVoiceByNum(INT32 playernum, UINT16 voicenum)
// for the needed name. If we're down here, we've passed the safeguards and can assign a
// voice.
if (voxid != skins[player->skin].voice->id)
player->mo->voice = &skinvoices[(UINT16)voxid];
if (voxid)
player->mo->voice = &skins[player->skin].voices[(UINT16)voxid];
else
player->mo->voice = NULL;
@ -1076,15 +1085,14 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
static void R_IHateThatHedgehog(UINT16 wadnum)
{
skin_t *skin = &skins[0];
kartvoice_t *skin_voice = &skinvoices[0];
kartvoice_t *skin_voice = &skin->voices[0];
Sk_SetDefaultValue(skin, skin_voice);
skin->wadnum = wadnum;
strcpy(skin->name, "sonic");
skin->voice->parent = 0;
// Add voice
INT32 dummy;
if (R_AllocKartVoice(true, skin->name, &dummy) < 0)
if (R_FindIDForVoice(skin, "default") == MAXSKINVOICES)
{
// Hey guy, take care!
I_Error("Failed to allocate initial skin voice\n");
@ -1103,6 +1111,136 @@ static void R_IHateThatHedgehog(UINT16 wadnum)
#endif
}
// Necessary for sound adding, so we can gather flags and singularity data.
static sfxenum_t skinsoundreroute[] = {
sfx_kwin,
sfx_klose,
sfx_khurt1,
sfx_khurt2,
sfx_kattk1, // Offense item taunt
sfx_kattk2,
sfx_kbost1, // Boost item taunt
sfx_kbost2,
sfx_kslow, // Overtake taunt
sfx_khitem, // Hit confirm taunt
sfx_kgloat, // Power item taunt
};
// Extremely shitty and lifted almost entirely from r_skins.c
// Sets the sound effect value for a voice, given a valid skinsound value is passed.
static UINT8 reallygrossvoicesfxadder(INT32 skinsound, const char *value, kartvoice_t *voice)
{
sfxenum_t i, j, reroute;
char printval[6];
// 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;
strncpy(printval, value, 6);
reroute = skinsoundreroute[skinsound];
// Automatically allocate any defined voice sounds.
// Freeslotted voice clips won't ever belong to a skin.
i = sfx_None;
// Find if this sound already exists first.
for (j = 0; j < NUMSFX; j++)
{
if (!S_sfx[j].name)
continue;
if (!stricmp(S_sfx[j].name, value))
{
// Found an existing sound.
i = j;
break;
}
}
// This sound doesn't seem to exist, so let's add a new one.
if (i == sfx_None)
{
CONS_Printf("Sound sfx_%s allocated.\n", value);
i = S_AddSoundFx(value, S_sfx[reroute].singularity, S_sfx[reroute].flags, false);
}
if (i != sfx_None)
{
if (voice)
{
Sk_SetSkinVoiceValue(voice, skinsound, i);
return 0;
}
}
return 1;
}
static kartvoice_t *allocvoice;
static void readkartvoice(skin_t *skin, char *stoken, char *value, kartvoice_t *voice)
{
if (!stricmp(stoken, "voicename"))
{
// Allocate the actual voice,
}
else if (!stricmp(stoken, "GLOAT"))
{
reallygrossvoicesfxadder(SKSKPOWR, value, voice);
}
else if (!stricmp(stoken, "WIN"))
{
reallygrossvoicesfxadder(SKSKWIN, value, voice);
}
else if (!stricmp(stoken, "LOSE"))
{
reallygrossvoicesfxadder(SKSKLOSE, value, voice);
}
else if (!stricmp(stoken, "SLOW") || !stricmp(stoken, "OVERTAKE") || !stricmp(stoken, "PASS"))
{
reallygrossvoicesfxadder(SKSKSLOW, value, voice);
}
else if (!stricmp(stoken, "PAIN1") || !stricmp(stoken, "HURT1") || !stricmp(stoken, "DAMAGE1"))
{
reallygrossvoicesfxadder(SKSKPAN1, value, voice);
}
else if (!stricmp(stoken, "PAIN2") || !stricmp(stoken, "HURT2") || !stricmp(stoken, "DAMAGE2"))
{
reallygrossvoicesfxadder(SKSKPAN2, value, voice);
}
else if (!stricmp(stoken, "ATTACK"))
{
// Needs to be handled like rival allocation
}
else if (!stricmp(stoken, "ATTACK1"))
{
reallygrossvoicesfxadder(SKSKATK1, value, voice);
}
else if (!stricmp(stoken, "ATTACK2"))
{
reallygrossvoicesfxadder(SKSKATK2, value, voice);
}
else if (!stricmp(stoken, "BOOST1"))
{
reallygrossvoicesfxadder(SKSKBST1, value, voice);
}
else if (!stricmp(stoken, "BOOST2"))
{
reallygrossvoicesfxadder(SKSKBST2, value, voice);
}
else if (!stricmp(stoken, "HITEM") || !stricmp(stoken, "HITCONFIRM"))
{
reallygrossvoicesfxadder(SKSKHITM, value, voice);
}
return -1;
}
// returns whether found appropriate property
static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
{
@ -1222,6 +1360,173 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
GETPATCH(facemmap)
#undef GETPATCH
else if (!stricmp(stoken, "voicename"))
{
// Change the current voice.
INT32 vox_id = R_FindIDForVoice(skin, value);
if (vox_id == MAXSKINVOICES)
{
if (!stricmp(stoken, "default"))
{
// "default" should ALWAYS exist!
I_Error("Failed to allocate default voice for skin %s\n", skin->name);
}
// Couldn't find this voice; let's try allocating.
if (R_AllocKartVoice(skin, value, &vox_id) + 1)
{
// Allocated a voice!
allocvoice = &skin->voices[vox_id];
CONS_Printf(M_GetText("%d %s allocated for this skin.\n"), skin->numvoices, (skin->numvoices == 1) ? "voice" : "voices");
}
// Found nothing, or we're full. Let's just keep moving.
}
else
allocvoice = &skin->voices[vox_id];
}
else if (!stricmp(stoken, "voicerealname"))
{
// Set the "realname" field for the current voice.
STRBUFCPY(allocvoice->realname, value);
SYMBOLCONVERT(allocvoice->realname);
}
else if (!stricmp(stoken, "voicegloat"))
{
reallygrossvoicesfxadder(SKSKPOWR, value, allocvoice);
}
else if (!stricmp(stoken, "voicewin"))
{
reallygrossvoicesfxadder(SKSKWIN, value, allocvoice);
}
else if (!stricmp(stoken, "voicelose"))
{
reallygrossvoicesfxadder(SKSKLOSE, value, allocvoice);
}
else if (!stricmp(stoken, "voiceslow") || !stricmp(stoken, "voiceovertake") || !stricmp(stoken, "voicepass"))
{
reallygrossvoicesfxadder(SKSKSLOW, value, allocvoice);
}
else if (!stricmp(stoken, "voicepain1") || !stricmp(stoken, "voicehurt1") || !stricmp(stoken, "voicedamage1"))
{
reallygrossvoicesfxadder(SKSKPAN1, value, allocvoice);
}
else if (!stricmp(stoken, "voicepain2") || !stricmp(stoken, "voicehurt2") || !stricmp(stoken, "voicedamage2"))
{
reallygrossvoicesfxadder(SKSKPAN2, value, allocvoice);
}
else if (!stricmp(stoken, "voiceattack1"))
{
reallygrossvoicesfxadder(SKSKATK1, value, allocvoice);
}
else if (!stricmp(stoken, "voiceattack2"))
{
reallygrossvoicesfxadder(SKSKATK2, value, allocvoice);
}
else if (!stricmp(stoken, "voiceboost1"))
{
reallygrossvoicesfxadder(SKSKBST1, value, allocvoice);
}
else if (!stricmp(stoken, "voiceboost2"))
{
reallygrossvoicesfxadder(SKSKBST2, value, allocvoice);
}
else if (!stricmp(stoken, "voicehitem") || !stricmp(stoken, "voicehitconfirm"))
{
reallygrossvoicesfxadder(SKSKHITM, value, allocvoice);
}
else if (!stricmp(stoken, "voicehurt") || !stricmp(stoken, "voicepain") || !stricmp(stoken, "voicedamage"))
{
// (that one gif of patrick drooling where his mouth is his entire face)
size_t len = strlen(value);
size_t i;
char voicename[VOICENAMESIZE] = "";
UINT8 pos = 0;
UINT8 numvoices = 0;
for (i = 0; i <= len; i++)
{
if (numvoices >= VOICEARRAYSIZE)
{
break;
}
if (value[i] == ',' || i == len)
{
reallygrossvoicesfxadder((numvoices < 1) ? SKSKPAN1 : SKSKPAN2, voicename, allocvoice);
numvoices++;
memset(voicename, 0, sizeof (voicename));
pos = 0;
continue;
}
voicename[pos] = value[i];
pos++;
}
}
else if (!stricmp(stoken, "voiceattack"))
{
size_t len = strlen(value);
size_t i;
char voicename[VOICENAMESIZE] = "";
UINT8 pos = 0;
UINT8 numvoices = 0;
for (i = 0; i <= len; i++)
{
if (numvoices >= VOICEARRAYSIZE)
{
break;
}
if (value[i] == ',' || i == len)
{
reallygrossvoicesfxadder((numvoices < 1) ? SKSKATK1 : SKSKATK2, voicename, allocvoice);
numvoices++;
memset(voicename, 0, sizeof (voicename));
pos = 0;
continue;
}
voicename[pos] = value[i];
pos++;
}
}
else if (!stricmp(stoken, "voiceboost"))
{
size_t len = strlen(value);
size_t i;
char voicename[VOICENAMESIZE] = "";
UINT8 pos = 0;
UINT8 numvoices = 0;
for (i = 0; i <= len; i++)
{
if (numvoices >= VOICEARRAYSIZE)
{
break;
}
if (value[i] == ',' || i == len)
{
reallygrossvoicesfxadder((numvoices < 1) ? SKSKBST1 : SKSKBST2, voicename, allocvoice);
numvoices++;
memset(voicename, 0, sizeof (voicename));
pos = 0;
continue;
}
voicename[pos] = value[i];
pos++;
}
}
else // let's check if it's a sound, otherwise error out
{
boolean found = false;
@ -1252,10 +1557,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
{
newskinsound = S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].flags, true);
if (skin->voice)
{
Sk_SetSkinVoiceValue(skin->voice, S_sfx[i].skinsound, newskinsound);
}
Sk_SetSkinVoiceValue(allocvoice, S_sfx[i].skinsound, newskinsound);
found = true;
}
@ -1269,26 +1571,30 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
// Allocates a voice onto the dehacked list, and iterates the provided output pointer
// (should it exist).
//
INT32 R_AllocKartVoice(boolean skinalloc, const char* name, INT32 *out)
INT32 R_AllocKartVoice(skin_t *skin, const char* name, INT32 *out)
{
char voxname_upper[VOICENAMESIZE];
strlcpy(voxname_upper, name, sizeof(voxname_upper));
strupr(voxname_upper);
*out = DEH_FindKartVoice(voxname_upper);
*out = R_FindIDForVoice(skin, name);
if (*out != MAXSKINVOICES)
return skinalloc ? -1 : 0; // already allocated
return -1; // already allocated
if (numskinvoices == MAXSKINVOICES - 1) {
if (skin->numvoices == MAXSKINVOICES - 1) {
CONS_Alert(CONS_WARNING, "Ran out of free voice slots!\n");
return -1;
}
CONS_Printf("Voice %s allocated.\n",voxname_upper);
DEH_Link(voxname_upper, &skinvoices[numskinvoices].info, &voicenames);
strlcpy(skin->voices[skin->numvoices].name, name, sizeof(skin->voices[skin->numvoices].name));
strlwr(skin->voices[skin->numvoices].name);
*out = numskinvoices++;
skin->voices[skin->numvoices].id = skin->numvoices;
CONS_Printf("Voice %s allocated for skin %s.\n",skin->voices[skin->numvoices].name,skin->name);
*out = skin->numvoices++;
return 0;
}
@ -1334,7 +1640,9 @@ void R_AddSkins(UINT16 wadnum)
// set defaults
skin = &skins[numskins];
skin_voice = &skinvoices[numskinvoices];
skin_voice = &skin->voices[0];
allocvoice = skin_voice;
Sk_SetDefaultValue(skin, skin_voice);
skin->wadnum = wadnum;
realname = false;
@ -1364,7 +1672,6 @@ void R_AddSkins(UINT16 wadnum)
if (skinnum == -1)
{
STRBUFCPY(skin->name, value);
skin->voice->parent = (UINT16)(skin - skins);
}
// the skin name must uniquely identify a single skin
// if the name is already used I make the name 'namex'
@ -1382,7 +1689,6 @@ void R_AddSkins(UINT16 wadnum)
// I'm lazy so if NEW name is already used I leave the 'skin x'
// default skin name set in Sk_SetDefaultValue
STRBUFCPY(skin->name, value2);
skin->voice->parent = (UINT16)(skin - skins);
}
Z_Free(value2);
}
@ -1409,15 +1715,11 @@ void R_AddSkins(UINT16 wadnum)
// Add voice
INT32 dummy;
if (R_AllocKartVoice(true, skin->name, &dummy) < 0)
if (R_FindIDForVoice(skin, "default") == MAXSKINVOICES)
{
// We couldn't allocate our own skin's voice?!
I_Error("Failed to allocate voice for skin %s\n", skin->name);
}
else
{
CONS_Printf(M_GetText("%d voices allocated.\n"), numskinvoices);
}
// Add sprites
R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
@ -1463,6 +1765,7 @@ void R_PatchSkins(UINT16 wadnum)
size_t size;
skin_t *skin;
boolean noskincomplain, realname;
sfxenum_t *array_target;
//
// search for all skin patch markers in pwad
@ -1505,6 +1808,8 @@ void R_PatchSkins(UINT16 wadnum)
value = strtok(NULL, "\r\n= ");
array_target = NULL;
if (!value)
I_Error("R_PatchSkins: syntax error in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
@ -1515,7 +1820,10 @@ void R_PatchSkins(UINT16 wadnum)
strlwr(value);
skinnum = R_SkinAvailable(value);
if (skinnum != -1)
{
skin = &skins[skinnum];
allocvoice = &skins[skinnum].voices[0];
}
else
{
CONS_Debug(DBG_SETUP, "R_PatchSkins: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
@ -1573,6 +1881,8 @@ void R_PatchSkins(UINT16 wadnum)
}
else if (!R_ProcessPatchableFields(skin, stoken, value))
CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
}
if (!skin)

View file

@ -38,26 +38,18 @@ extern "C" {
extern consvar_t cv_skinselectstyle, cv_skinselectsort;
typedef enum
{
KSKVC_FIRSTSLOT = 0,
KSKVC_LASTSLOT = 65535,
MAXSKINVOICES
} kartvoicetype_e;
#define MAXVOICEFREESLOTS (MAXSKINVOICES - KSKVC_FIRSTFREESLOT)
#define MAXSKINVOICES 16 // 16 voices * 4096 skins = 65536 voices in total :^)
// Player voice struct
struct kartvoice_t
{
UINT32 id;
// Dehacked info for the voice's name (hash and pointer within the voicenames array).
dehinfo_t info;
// The voice's name.
char name[VOICENAMESIZE+1];
// UINT16 ID of the parent skin this voice belongs to.
// Checked when the voice is assigned to prevent erroneous dubs.
UINT16 parent;
// Display name, for things such as menus
char realname[VOICENAMESIZE+1];
sfxenum_t win;
sfxenum_t lose;
@ -98,7 +90,9 @@ struct skin_t
// Pointer to a skin's voice, providing specific sounds per-skin.
// If an mobj_t doesn't have a voice, it defaults to this value, given a skin is in use.
kartvoice_t *voice;
kartvoice_t voices[MAXSKINVOICES];
UINT16 numvoices;
// Proxy value for the (now removed) soundsid array.
// This is ONLY used in a Lua context.
@ -133,7 +127,7 @@ enum skinmenusortoption
extern INT32 numskins, numskinvoices;
extern skin_t skins[MAXSKINS];
extern INT32 skinsorted[MAXSKINS];
extern kartvoice_t skinvoices[MAXSKINVOICES];
//extern kartvoice_t skinvoices[MAXSKINVOICES];
extern CV_PossibleValue_t Forceskin_cons_t[];
@ -155,11 +149,11 @@ void R_AddSkins(UINT16 wadnum);
UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player);
UINT8 P_KartFrameToSprite2(skin_t *skin, UINT8 inframe, UINT8 *outframe);
INT32 R_AllocKartVoice(boolean skinalloc, const char* name, INT32 *out);
void R_ClearVoice(kartvoicetype_e voicetype);
INT32 R_AllocKartVoice(skin_t *skin, const char* name, INT32 *out);
void R_ClearVoice(skin_t *skin, INT32 voicetype);
void Sk_SetSkinVoiceValue(kartvoice_t *voice, INT32 skinsound, INT32 writesound);
kartvoicetype_e R_FindIDForVoice(const char *voicename);
INT32 R_FindIDForVoice(skin_t *skin, const char *voicename);
void SetPlayerVoice(INT32 playernum, const char *voicename);
void SetPlayerVoiceByNum(INT32 playernum, UINT16 voicenum);
sfxenum_t P_GetKartVoiceSFX(kartvoice_t *voice, INT32 skinsound);