From 51a005a7dec4c076ea0dc582d143ca5e8c275ea7 Mon Sep 17 00:00:00 2001 From: yamamama Date: Sat, 29 Nov 2025 20:51:25 -0500 Subject: [PATCH] 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) --- src/d_netcmd.c | 194 ++++++++------------- src/deh_soc.c | 18 +- src/deh_soc.h | 2 - src/deh_tables.c | 20 +-- src/deh_tables.h | 4 +- src/dehacked.c | 4 +- src/f_finale.c | 10 +- src/g_demo.c | 25 +-- src/g_game.c | 2 +- src/info.c | 15 -- src/lua_baselib.c | 35 ---- src/lua_skinlib.c | 8 +- src/lua_voicelib.c | 117 +------------ src/p_mobj.c | 20 +-- src/p_saveg.c | 13 +- src/p_user.c | 2 +- src/r_skins.c | 414 +++++++++++++++++++++++++++++++++++++++------ src/r_skins.h | 30 ++-- 18 files changed, 490 insertions(+), 443 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9791e1ed8..07d8ff576 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -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); diff --git a/src/deh_soc.c b/src/deh_soc.c index 5a9425ba4..62990b4cc 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -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; } diff --git a/src/deh_soc.h b/src/deh_soc.h index ed97e3338..143c21a3d 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -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" diff --git a/src/deh_tables.c b/src/deh_tables.c index 9d9705bf7..d17947f2b 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -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) diff --git a/src/deh_tables.h b/src/deh_tables.h index d5ca7bf64..3c558cb48 100644 --- a/src/deh_tables.h +++ b/src/deh_tables.h @@ -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; diff --git a/src/dehacked.c b/src/dehacked.c index 4a7b8959f..f582be246 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -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 diff --git a/src/f_finale.c b/src/f_finale.c index 29a79c042..0a54a60d4 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -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); } diff --git a/src/g_demo.c b/src/g_demo.c index b94142a8f..a15fc2028 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -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 { diff --git a/src/g_game.c b/src/g_game.c index 5f865acae..22c1b98e1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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; diff --git a/src/info.c b/src/info.c index 438a56d3c..4a48dc8e3 100644 --- a/src/info.c +++ b/src/info.c @@ -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(); - } } diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c1a90b5c4..817de91f0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -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}, diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index e6c56fd59..01a483057 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -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; } diff --git a/src/lua_voicelib.c b/src/lua_voicelib.c index cea205069..4bee3ac81 100644 --- a/src/lua_voicelib.c +++ b/src/lua_voicelib.c @@ -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; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 3d598418d..d71f3cfa4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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; diff --git a/src/p_saveg.c b/src/p_saveg.c index e60bedc95..7874caebd 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -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) diff --git a/src/p_user.c b/src/p_user.c index e70bbaf0f..379d22f34 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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) { diff --git a/src/r_skins.c b/src/r_skins.c index 056a60d6d..1724e92eb 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -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) diff --git a/src/r_skins.h b/src/r_skins.h index 5dacf2b7c..88813c902 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -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);