diff --git a/src/command.c b/src/command.c index 157cb87bc..7184ace42 100644 --- a/src/command.c +++ b/src/command.c @@ -38,6 +38,7 @@ #include "r_skins.h" #include "m_random.h" #include "p_local.h" // P_ResetPlayerCheats +#include "k_color.h" //======== // protos. @@ -109,6 +110,8 @@ CV_PossibleValue_t gpdifficulty_cons_t[] = { {0, NULL} }; +CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; + // Filter consvars by EXECVERSION // First implementation is 2 (1.0.2), so earlier configs default at 1 (1.0.0) // Also set CV_HIDDEN during runtime, after config is loaded @@ -909,17 +912,28 @@ static void COM_Help_f(void) CONS_Printf(" Yes or No (On or Off, 1 or 0)\n"); else if (cvar->PossibleValue == CV_OnOff) CONS_Printf(" On or Off (Yes or No, 1 or 0)\n"); - else if (cvar->PossibleValue == Color_cons_t) + else if (cvar->PossibleValue == Color_cons_t || cvar->PossibleValue == Followercolor_cons_t) { - for (i = 1; i < numskincolors; ++i) + boolean follower = (cvar->PossibleValue == Followercolor_cons_t); + for (i = SKINCOLOR_NONE; i < numskincolors; ++i) { - if (skincolors[i].accessible) + if (K_ColorUsable(i, follower) == true) { - CONS_Printf(" %-2d : %s\n", i, skincolors[i].name); + CONS_Printf(" %-3d : %s\n", i, skincolors[i].name); if (i == cvar->value) cvalue = skincolors[i].name; } } + + if (follower) + { + CONS_Printf(" %-3d : %s\n", FOLLOWERCOLOR_MATCH, "Match"); + if (FOLLOWERCOLOR_MATCH == cvar->value) + cvalue = "Match"; + CONS_Printf(" %-3d : %s\n", FOLLOWERCOLOR_MATCH, "Opposite"); + if (FOLLOWERCOLOR_OPPOSITE == cvar->value) + cvalue = "Opposite"; + } } else { @@ -2248,6 +2262,11 @@ void CV_AddValue(consvar_t *var, INT32 increment) max = KARTSPEED_HARD+1; } } + else if (var->PossibleValue == kartvoices_cons_t + && !M_SecretUnlocked(SECRET_MEMETAUNTS, true)) + { + max--; + } #ifdef PARANOIA if (currentindice == -1) I_Error("CV_AddValue: current value %d not found in possible value\n", diff --git a/src/command.h b/src/command.h index 8ad27bfbc..b3bae86a7 100644 --- a/src/command.h +++ b/src/command.h @@ -176,6 +176,7 @@ extern CV_PossibleValue_t CV_Natural[]; // SRB2kart // the KARTSPEED and KARTGP were previously defined here, but moved to doomstat to avoid circular dependencies extern CV_PossibleValue_t kartspeed_cons_t[], dummykartspeed_cons_t[], gpdifficulty_cons_t[]; +extern CV_PossibleValue_t kartvoices_cons_t[]; extern consvar_t cv_execversion; diff --git a/src/d_main.c b/src/d_main.c index dfacb1606..6cb34996d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -136,7 +136,7 @@ boolean digital_disabled = false; INT32 debugload = 0; #endif -UINT16 numskincolors; +UINT16 numskincolors = SKINCOLOR_FIRSTFREESLOT; menucolor_t *menucolorhead, *menucolortail; char savegamename[256]; @@ -1411,10 +1411,6 @@ void D_SRB2Main(void) if (M_CheckParm("-password") && M_IsNextParm()) D_SetPassword(M_GetNextParm()); - // player setup menu colors must be initialized before - // any wad file is added, as they may contain colors themselves - M_InitPlayerSetupColors(); - CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); Z_Init(); CON_SetLoadingProgress(LOADED_ZINIT); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 15daae677..b58334da6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -123,11 +123,11 @@ static void Lagless_OnChange (void); static void Gravity_OnChange(void); static void ForceSkin_OnChange(void); -static void Name_OnChange(void); +static void Name1_OnChange(void); static void Name2_OnChange(void); static void Name3_OnChange(void); static void Name4_OnChange(void); -static void Skin_OnChange(void); +static void Skin1_OnChange(void); static void Skin2_OnChange(void); static void Skin3_OnChange(void); static void Skin4_OnChange(void); @@ -141,7 +141,7 @@ static void Followercolor2_OnChange(void); static void Followercolor3_OnChange(void); static void Followercolor4_OnChange(void); -static void Color_OnChange(void); +static void Color1_OnChange(void); static void Color2_OnChange(void); static void Color3_OnChange(void); static void Color4_OnChange(void); @@ -280,7 +280,7 @@ consvar_t cv_seenames = CVAR_INIT ("seenames", "On", CV_SAVE, CV_OnOff, NULL); // names consvar_t cv_playername[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("name", "Dr. Eggman", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name_OnChange), + CVAR_INIT ("name", "Dr. Eggman", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name1_OnChange), CVAR_INIT ("name2", "Tails", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name2_OnChange), CVAR_INIT ("name3", "Sonic", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name3_OnChange), CVAR_INIT ("name4", "Knuckles", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name4_OnChange) @@ -288,14 +288,14 @@ consvar_t cv_playername[MAXSPLITSCREENPLAYERS] = { // player colors UINT16 lastgoodcolor[MAXSPLITSCREENPLAYERS] = {SKINCOLOR_BLUE, SKINCOLOR_BLUE, SKINCOLOR_BLUE, SKINCOLOR_BLUE}; consvar_t cv_playercolor[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("color", "Red", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color_OnChange), + CVAR_INIT ("color", "Red", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color1_OnChange), CVAR_INIT ("color2", "Orange", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color2_OnChange), CVAR_INIT ("color3", "Blue", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color3_OnChange), CVAR_INIT ("color4", "Red", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color4_OnChange) }; // player's skin, saved for commodity, when using a favorite skins wad.. consvar_t cv_skin[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("skin", DEFAULTSKIN, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin_OnChange), + CVAR_INIT ("skin", DEFAULTSKIN, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin1_OnChange), CVAR_INIT ("skin2", DEFAULTSKIN2, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin2_OnChange), CVAR_INIT ("skin3", DEFAULTSKIN3, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin3_OnChange), CVAR_INIT ("skin4", DEFAULTSKIN4, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin4_OnChange) @@ -410,8 +410,8 @@ static CV_PossibleValue_t kartencore_cons_t[] = {{-1, "Auto"}, {0, "Off"}, {1, " consvar_t cv_kartencore = CVAR_INIT ("encore", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartencore_cons_t, KartEncore_OnChange); static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Percentage"}, {2, "Kilometers"}, {3, "Miles"}, {4, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = CVAR_INIT ("speedometer", "Percentage", CV_SAVE, kartspeedometer_cons_t, NULL); // use tics in display -static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; consvar_t cv_kartvoices = CVAR_INIT ("tauntvoices", "Tasteful", CV_SAVE, kartvoices_cons_t, NULL); +consvar_t cv_karthorns = CVAR_INIT ("taunthorns", "Tasteful", CV_SAVE, kartvoices_cons_t, NULL); static CV_PossibleValue_t kartbot_cons_t[] = { {0, "Off"}, @@ -1475,113 +1475,61 @@ static INT32 chmappending = 0; // name, color, or skin has changed // -static void SendNameAndColor(UINT8 n) +static void SendNameAndColor(const UINT8 n) { const INT32 playernum = g_localplayers[n]; - player_t *player = &players[playernum]; - - char buf[MAXPLAYERNAME+12]; - char *p; - - UINT16 i = 0; + player_t *player = NULL; if (splitscreen < n) + { return; // can happen if skin4/color4/name4 changed + } if (playernum == -1) + { return; + } - p = buf; + player = &players[playernum]; + + UINT16 sendColor = cv_playercolor[n].value; + UINT16 sendFollowerColor = cv_followercolor[n].value; // don't allow inaccessible colors - if (!skincolors[cv_playercolor[n].value].accessible) + if (sendColor != SKINCOLOR_NONE && K_ColorUsable(sendColor, false) == false) { - if (player->skincolor && skincolors[player->skincolor].accessible) + if (player->skincolor && K_ColorUsable(player->skincolor, false) == true) + { + // Use our previous color CV_StealthSetValue(&cv_playercolor[n], player->skincolor); - else if (skins[player->skin].prefcolor && skincolors[skins[player->skin].prefcolor].accessible) - CV_StealthSetValue(&cv_playercolor[n], skins[player->skin].prefcolor); - else if (skincolors[atoi(cv_playercolor[n].defaultvalue)].accessible) - CV_StealthSet(&cv_playercolor[n], cv_playercolor[n].defaultvalue); + } else { - while (i < numskincolors && !skincolors[i].accessible) - i++; - CV_StealthSetValue(&cv_playercolor[n], (i != numskincolors) ? i : SKINCOLOR_BLUE); + // Use our default color + CV_StealthSetValue(&cv_playercolor[n], SKINCOLOR_NONE); } + + sendColor = cv_playercolor[n].value; } // ditto for follower colour: - if (!cv_followercolor[n].value) - CV_StealthSet(&cv_followercolor[n], "Match"); // set it to "Match". I don't care about your stupidity! - - if (!strcmp(cv_playername[n].string, player_names[playernum]) - && cv_playercolor[n].value == player->skincolor - && !stricmp(cv_skin[n].string, skins[player->skin].name) - && !stricmp(cv_follower[n].string, - (player->followerskin < 0 ? "None" : followers[player->followerskin].name)) - && cv_followercolor[n].value == player->followercolor) - return; + if (sendFollowerColor != SKINCOLOR_NONE && K_ColorUsable(sendFollowerColor, true) == false) + { + CV_StealthSet(&cv_followercolor[n], "Default"); // set it to "Default". I don't care about your stupidity! + sendFollowerColor = cv_followercolor[n].value; + } // We'll handle it later if we're not playing. if (!Playing()) - return; - - // If you're not in a netgame, merely update the skin, color, and name. - if (!netgame) { - INT32 foundskin; - - CleanupPlayerName(playernum, cv_playername[n].zstring); - strcpy(player_names[playernum], cv_playername[n].zstring); - - player->skincolor = cv_playercolor[n].value; - - K_KartResetPlayerColor(player); - - foundskin = R_SkinAvailable(cv_skin[n].string); - if (foundskin != -1 && R_SkinUsable(playernum, foundskin, false)) - { - SetPlayerSkin(playernum, cv_skin[n].string); - CV_StealthSet(&cv_skin[n], skins[foundskin].name); - cv_skin[n].value = foundskin; - } - else - { - CV_StealthSet(&cv_skin[n], skins[player->skin].name); - cv_skin[n].value = player->skin; - // will always be same as current - SetPlayerSkin(playernum, cv_skin[n].string); - } - - player->followercolor = cv_followercolor[n].value; - - // Update follower for local games: - foundskin = K_FollowerAvailable(cv_follower[n].string); - if (!K_FollowerUsable(foundskin)) - foundskin = -1; - CV_StealthSet(&cv_follower[n], (foundskin == -1) ? "None" : followers[foundskin].name); - cv_follower[n].value = foundskin; - K_SetFollowerByNum(playernum, foundskin); - return; } - snacpending[n]++; - - // Don't change name if muted - if (player_name_changes[playernum] >= MAXNAMECHANGES) - { - CV_StealthSet(&cv_playername[n], player_names[playernum]); - HU_AddChatText("\x85*You must wait to change your name again", false); - } - else if (cv_mute.value && !(server || IsPlayerAdmin(playernum))) - CV_StealthSet(&cv_playername[n], player_names[playernum]); - else // Cleanup name if changing it - CleanupPlayerName(playernum, cv_playername[n].zstring); - // Don't change skin if the server doesn't want you to. if (!CanChangeSkin(playernum)) + { CV_StealthSet(&cv_skin[n], skins[player->skin].name); + } // check if player has the skin loaded (cv_skin may have // the name of a skin that was available in the previous game) @@ -1599,13 +1547,61 @@ static void SendNameAndColor(UINT8 n) cv_follower[n].value = -1; } + if (sendColor == SKINCOLOR_NONE) + { + sendColor = skins[cv_skin[n].value].prefcolor; + } + + if (sendFollowerColor == SKINCOLOR_NONE) + { + if (cv_follower[n].value >= 0) + { + sendFollowerColor = followers[cv_follower[n].value].defaultcolor; + } + else + { + sendFollowerColor = SKINCOLOR_RED; // picked by dice roll, guaranteed to be random + } + } + + // Don't send if everything was identical. + if (!strcmp(cv_playername[n].string, player_names[playernum]) + && sendColor == player->skincolor + && !stricmp(cv_skin[n].string, skins[player->skin].name) + && !stricmp(cv_follower[n].string, + (player->followerskin < 0 ? "None" : followers[player->followerskin].name)) + && sendFollowerColor == player->followercolor) + { + return; + } + + snacpending[n]++; + + // Don't change name if muted + if (player_name_changes[playernum] >= MAXNAMECHANGES) + { + CV_StealthSet(&cv_playername[n], player_names[playernum]); + HU_AddChatText("\x85* You must wait to change your name again.", false); + } + else if (cv_mute.value && !(server || IsPlayerAdmin(playernum))) + { + CV_StealthSet(&cv_playername[n], player_names[playernum]); + } + else // Cleanup name if changing it + { + CleanupPlayerName(playernum, cv_playername[n].zstring); + } + + char buf[MAXPLAYERNAME+12]; + char *p = buf; + // Finally write out the complete packet and send it off. WRITESTRINGN(p, cv_playername[n].zstring, MAXPLAYERNAME); - WRITEUINT16(p, (UINT16)cv_playercolor[n].value); + WRITEUINT16(p, sendColor); WRITEUINT8(p, (UINT8)cv_skin[n].value); WRITEINT16(p, (INT16)cv_follower[n].value); //CONS_Printf("Sending follower id %d\n", (INT16)cv_follower[n].value); - WRITEUINT16(p, (UINT16)cv_followercolor[n].value); + WRITEUINT16(p, sendFollowerColor); SendNetXCmdForPlayer(n, XD_NAMEANDCOLOR, buf, p - buf); } @@ -1727,8 +1723,10 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) boolean kick = false; // don't allow inaccessible colors - if (skincolors[p->skincolor].accessible == false) + if (K_ColorUsable(p->skincolor, false) == false) + { kick = true; + } if (kick) { @@ -6662,50 +6660,36 @@ static void ForceSkin_OnChange(void) } //Allows the player's name to be changed if cv_mute is off. -static void Name_OnChange(void) +static void Name_OnChange(const UINT8 p) { - if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer))) + if (cv_mute.value && !(server || IsPlayerAdmin(g_localplayers[p]))) { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername[0], player_names[consoleplayer]); + CV_StealthSet(&cv_playername[p], player_names[g_localplayers[p]]); return; } - else - SendNameAndColor(0); + SendNameAndColor(p); +} + +static void Name1_OnChange(void) +{ + Name_OnChange(0); } static void Name2_OnChange(void) { - if (cv_mute.value) //Secondary player can't be admin. - { - CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername[1], player_names[g_localplayers[1]]); - } - else - SendNameAndColor(1); + Name_OnChange(1); } static void Name3_OnChange(void) { - if (cv_mute.value) //Third player can't be admin. - { - CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername[2], player_names[g_localplayers[2]]); - } - else - SendNameAndColor(2); + Name_OnChange(2); } static void Name4_OnChange(void) { - if (cv_mute.value) //Secondary player can't be admin. - { - CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername[3], player_names[g_localplayers[3]]); - } - else - SendNameAndColor(3); + Name_OnChange(3); } // sends the follower change for players @@ -6766,29 +6750,40 @@ static void Followercolor4_OnChange(void) * \sa cv_skin, Skin2_OnChange, Color_OnChange * \author Graue */ -static void Skin_OnChange(void) +static void Skin_OnChange(const UINT8 p) { - if (!Playing()) - return; // do whatever you want - - if (!CV_CheatsEnabled() && !(multiplayer || netgame) // In single player. - && (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y + if (!Playing() || splitscreen < p) { - CV_StealthSet(&cv_skin[0], skins[players[consoleplayer].skin].name); + // do whatever you want return; } - if (CanChangeSkin(consoleplayer)) + if (p == 0) { - SendNameAndColor(0); + if (!CV_CheatsEnabled() && !(multiplayer || netgame) // In single player. + && (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y + { + CV_StealthSet(&cv_skin[p], skins[players[g_localplayers[p]].skin].name); + return; + } + } + + if (CanChangeSkin(g_localplayers[p])) + { + SendNameAndColor(p); } else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin[0], skins[players[consoleplayer].skin].name); + CV_StealthSet(&cv_skin[p], skins[players[g_localplayers[p]].skin].name); } } +static void Skin1_OnChange(void) +{ + Skin_OnChange(0); +} + /** Sends a skin change for the secondary splitscreen player, unless that * player is moving. Forces spectate the player if the change is done during gameplay. * \sa cv_skin2, Skin_OnChange, Color2_OnChange @@ -6796,79 +6791,56 @@ static void Skin_OnChange(void) */ static void Skin2_OnChange(void) { - if (!Playing() || !splitscreen) - return; // do whatever you want - - if (CanChangeSkin(g_localplayers[1])) - SendNameAndColor(1); - else - { - CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin[1], skins[players[g_localplayers[1]].skin].name); - } + Skin_OnChange(1); } static void Skin3_OnChange(void) { - if (!Playing() || splitscreen < 2) - return; // do whatever you want - - if (CanChangeSkin(g_localplayers[2])) - SendNameAndColor(2); - else - { - CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin[2], skins[players[g_localplayers[2]].skin].name); - } + Skin_OnChange(2); } static void Skin4_OnChange(void) { - if (!Playing() || splitscreen < 3) - return; // do whatever you want - - if (CanChangeSkin(g_localplayers[3])) - SendNameAndColor(3); - else - { - CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin[3], skins[players[g_localplayers[3]].skin].name); - } + Skin_OnChange(3); } /** Sends a color change for the console player, unless that player is moving. * \sa cv_playercolor, Color2_OnChange, Skin_OnChange * \author Graue */ -static void Color_OnChange(void) +static void Color_OnChange(const UINT8 p) { - if (!Playing()) - { - if (!cv_playercolor[0].value || !skincolors[cv_playercolor[0].value].accessible) - CV_StealthSetValue(&cv_playercolor[0], lastgoodcolor[0]); - } - else - { - if (!CV_CheatsEnabled() && !(multiplayer || netgame)) // In single player. - { - CV_StealthSet(&cv_skin[0], skins[players[consoleplayer].skin].name); - return; - } + I_Assert(p < MAXSPLITSCREENPLAYERS); - if (!P_PlayerMoving(consoleplayer) && skincolors[players[consoleplayer].skincolor].accessible == true) + UINT16 color = cv_playercolor[p].value; + boolean colorisgood = (color == SKINCOLOR_NONE || K_ColorUsable(color, false) == true); + + if (Playing() && splitscreen < p) + { + if (P_PlayerMoving(g_localplayers[p]) == true) + { + colorisgood = false; + } + else if (colorisgood == true) { // Color change menu scrolling fix is no longer necessary - SendNameAndColor(0); - } - else - { - CV_StealthSetValue(&cv_playercolor[0], - players[consoleplayer].skincolor); + SendNameAndColor(p); } } - lastgoodcolor[0] = cv_playercolor[0].value; - G_SetPlayerGamepadIndicatorToPlayerColor(0); + if (colorisgood == false) + { + CV_StealthSetValue(&cv_playercolor[p], lastgoodcolor[p]); + return; + } + + lastgoodcolor[p] = color; + G_SetPlayerGamepadIndicatorToPlayerColor(p); +} + +static void Color1_OnChange(void) +{ + Color_OnChange(0); } /** Sends a color change for the secondary splitscreen player, unless that @@ -6878,77 +6850,17 @@ static void Color_OnChange(void) */ static void Color2_OnChange(void) { - if (!Playing() || splitscreen < 1) - { - if (!cv_playercolor[1].value || !skincolors[cv_playercolor[1].value].accessible) - CV_StealthSetValue(&cv_playercolor[1], lastgoodcolor[1]); - } - else - { - if (!P_PlayerMoving(g_localplayers[1]) && skincolors[players[g_localplayers[1]].skincolor].accessible == true) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(1); - } - else - { - CV_StealthSetValue(&cv_playercolor[1], - players[g_localplayers[1]].skincolor); - } - } - lastgoodcolor[1] = cv_playercolor[1].value; - - G_SetPlayerGamepadIndicatorToPlayerColor(1); + Color_OnChange(1); } static void Color3_OnChange(void) { - if (!Playing() || splitscreen < 2) - { - if (!cv_playercolor[2].value || !skincolors[cv_playercolor[2].value].accessible) - CV_StealthSetValue(&cv_playercolor[2], lastgoodcolor[2]); - } - else - { - if (!P_PlayerMoving(g_localplayers[2]) && skincolors[players[g_localplayers[2]].skincolor].accessible == true) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(2); - } - else - { - CV_StealthSetValue(&cv_playercolor[2], - players[g_localplayers[2]].skincolor); - } - } - lastgoodcolor[2] = cv_playercolor[2].value; - - G_SetPlayerGamepadIndicatorToPlayerColor(2); + Color_OnChange(2); } static void Color4_OnChange(void) { - if (!Playing() || splitscreen < 3) - { - if (!cv_playercolor[3].value || !skincolors[cv_playercolor[3].value].accessible) - CV_StealthSetValue(&cv_playercolor[3], lastgoodcolor[3]); - } - else - { - if (!P_PlayerMoving(g_localplayers[3]) && skincolors[players[g_localplayers[3]].skincolor].accessible == true) - { - // Color change menu scrolling fix is no longer necessary - SendNameAndColor(3); - } - else - { - CV_StealthSetValue(&cv_playercolor[3], - players[g_localplayers[3]].skincolor); - } - } - lastgoodcolor[3] = cv_playercolor[3].value; - - G_SetPlayerGamepadIndicatorToPlayerColor(3); + Color_OnChange(3); } /** Displays the result of the chat being muted or unmuted. diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 93ad42bbf..154c09717 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -86,6 +86,7 @@ extern consvar_t cv_kartfrantic; extern consvar_t cv_kartencore; extern consvar_t cv_kartspeedometer; extern consvar_t cv_kartvoices; +extern consvar_t cv_karthorns; extern consvar_t cv_kartbot; extern consvar_t cv_karteliminatelast; extern consvar_t cv_thunderdome; diff --git a/src/d_player.h b/src/d_player.h index 843f31b65..39a25a8fd 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -277,6 +277,7 @@ typedef enum khud_enginesnd, // Engine sound offset this player is using. khud_voices, // Used to stop the player saying more voices than it should khud_tauntvoices, // Used to specifically stop taunt voice spam + khud_taunthorns, // Used to specifically stop taunt horn spam // Battle khud_cardanimation, // Used to determine the position of some full-screen Battle Mode graphics diff --git a/src/deh_lua.c b/src/deh_lua.c index b3ad0f1c5..6309859bd 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -142,7 +142,7 @@ static inline int lib_freeslot(lua_State *L) CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_SKINCOLORS[i],word); - M_AddMenuColor(numskincolors++); + numskincolors++; lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT + i); r++; break; diff --git a/src/deh_soc.c b/src/deh_soc.c index 6139aac4a..48f4f6828 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -319,7 +319,7 @@ void readfreeslots(MYFILE *f) CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_SKINCOLORS[i],word); - M_AddMenuColor(numskincolors++); + numskincolors++; break; } if (i == NUMCOLORFREESLOTS) @@ -2338,6 +2338,8 @@ void readunlockable(MYFILE *f, INT32 num) unlockables[num].type = SECRET_SKIN; else if (fastcmp(word2, "FOLLOWER")) unlockables[num].type = SECRET_FOLLOWER; + else if (fastcmp(word2, "COLOR")) + unlockables[num].type = SECRET_COLOR; else if (fastcmp(word2, "HARDSPEED")) unlockables[num].type = SECRET_HARDSPEED; else if (fastcmp(word2, "MASTERMODE")) @@ -2362,6 +2364,8 @@ void readunlockable(MYFILE *f, INT32 num) unlockables[num].type = SECRET_SOUNDTEST; else if (fastcmp(word2, "ALTTITLE")) unlockables[num].type = SECRET_ALTTITLE; + else if (fastcmp(word2, "MEMETAUNTS")) + unlockables[num].type = SECRET_MEMETAUNTS; else if (fastcmp(word2, "ITEMFINDER")) unlockables[num].type = SECRET_ITEMFINDER; else @@ -3600,7 +3604,7 @@ void readfollower(MYFILE *f) INT32 res; INT32 i; - if (numfollowers >= MAXSKINS) + if (numfollowers >= MAXFOLLOWERS) { I_Error("Out of Followers\nLoad less addons to fix this."); } @@ -3623,6 +3627,7 @@ void readfollower(MYFILE *f) followers[numfollowers].hitconfirmtime = TICRATE; followers[numfollowers].defaultcolor = FOLLOWERCOLOR_MATCH; followers[numfollowers].category = UINT8_MAX; + followers[numfollowers].hornsound = sfx_horn00; strcpy(followers[numfollowers].icon, "MISSING"); do @@ -3708,6 +3713,10 @@ void readfollower(MYFILE *f) deh_warning("Follower %d: unknown follower color '%s'", numfollowers, word2); } } + else if (fastcmp(word, "HORNSOUND")) + { + followers[numfollowers].hornsound = get_number(word2); + } else if (fastcmp(word, "SCALE")) { followers[numfollowers].scale = (fixed_t)get_number(word2); diff --git a/src/deh_tables.c b/src/deh_tables.c index 26b0ae763..9c4b19c88 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3308,6 +3308,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_SERVANTHAND", + "S_HORNCODE", + // Signpost sparkles "S_SIGNSPARK1", "S_SIGNSPARK2", @@ -5359,6 +5361,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_SERVANTHAND", + "MT_HORNCODE", + "MT_SIGNSPARKLE", "MT_FASTLINE", diff --git a/src/doomdef.h b/src/doomdef.h index 8eac43761..75264bbd0 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -236,7 +236,7 @@ struct skincolor_t #define FOLLOWERCOLOR_MATCH UINT16_MAX #define FOLLOWERCOLOR_OPPOSITE (UINT16_MAX-1) -UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor); +UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, follower_t *follower, UINT16 playercolor, skin_t *playerskin); typedef enum { diff --git a/src/info.c b/src/info.c index 0940b3ac1..37e2a9034 100644 --- a/src/info.c +++ b/src/info.c @@ -563,6 +563,8 @@ char sprnames[NUMSPRITES + 1][5] = "DHND", // Servant Hand + "HORN", // Horncode + "WIPD", // Wipeout dust trail "DRIF", // Drift Sparks "BDRF", // Brake drift sparks @@ -3980,6 +3982,8 @@ state_t states[NUMSTATES] = {SPR_DHND, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SERVANTHAND + {SPR_HORN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HORNCODE + {SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3 @@ -22840,6 +22844,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, + + { // MT_HORNCODE + -1, // doomednum + S_HORNCODE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 36*FRACUNIT, // radius + 36*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, { // MT_SIGNSPARKLE -1, // doomednum @@ -29868,7 +29899,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }; skincolor_t skincolors[MAXSKINCOLORS] = { - {"None", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_NONE + {"Default", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_NONE {"White", { 0, 0, 0, 0, 1, 2, 5, 8, 9, 11, 14, 17, 20, 22, 25, 28}, SKINCOLOR_BLACK, 8, 0, true}, // SKINCOLOR_WHITE {"Silver", { 0, 1, 2, 3, 5, 7, 9, 12, 13, 15, 18, 20, 23, 25, 27, 30}, SKINCOLOR_NICKEL, 8, 0, true}, // SKINCOLOR_SILVER diff --git a/src/info.h b/src/info.h index 8d3e85031..289bbe438 100644 --- a/src/info.h +++ b/src/info.h @@ -1114,6 +1114,8 @@ typedef enum sprite SPR_DHND, // Servant Hand + SPR_HORN, // Horncode + SPR_WIPD, // Wipeout dust trail SPR_DRIF, // Drift Sparks SPR_BDRF, // Brake drift sparks @@ -4390,6 +4392,8 @@ typedef enum state S_SERVANTHAND, + S_HORNCODE, + // Signpost sparkles S_SIGNSPARK1, S_SIGNSPARK2, @@ -6476,6 +6480,8 @@ typedef enum mobj_type MT_SERVANTHAND, + MT_HORNCODE, + MT_SIGNSPARKLE, MT_FASTLINE, diff --git a/src/k_color.c b/src/k_color.c index d73a938e7..9078fc6bc 100644 --- a/src/k_color.c +++ b/src/k_color.c @@ -16,6 +16,9 @@ #include "r_draw.h" #include "r_things.h" #include "v_video.h" +#include "m_cond.h" +#include "g_demo.h" +#include "k_follower.h" /*-------------------------------------------------- UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b) @@ -213,4 +216,63 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) } } +/*-------------------------------------------------- + boolean K_ColorUsable(skincolornum_t color, boolean follower) + + See header file for description. +--------------------------------------------------*/ +boolean K_ColorUsable(skincolornum_t color, boolean follower) +{ + INT32 i = MAXUNLOCKABLES; + + if (color == FOLLOWERCOLOR_MATCH || color == FOLLOWERCOLOR_OPPOSITE) + { + // Special follower colors, always allow if follower. + return follower; + } + + if (skincolors[color].accessible == false) + { + // Never intended to be used. + return false; + } + + if (demo.playback) + { + // Simplifies things elsewhere... + return true; + } + + // Determine if this follower is supposed to be unlockable or not + for (i = 0; i < MAXUNLOCKABLES; i++) + { + skincolornum_t cid = SKINCOLOR_NONE; + + if (unlockables[i].type != SECRET_COLOR) + { + continue; + } + + cid = M_UnlockableColorNum(&unlockables[i]); + + if (cid != color) + { + continue; + } + + // i is now the unlockable index, we can use this later + break; + } + + if (i == MAXUNLOCKABLES) + { + // Didn't trip anything, so we can use this color. + return true; + } + + // Use the unlockables table directly + // DEFINITELY not M_CheckNetUnlockByID + return (boolean)(gamedata->unlocked[i]); +} + //} diff --git a/src/k_color.h b/src/k_color.h index bd2fea5dc..b835f9194 100644 --- a/src/k_color.h +++ b/src/k_color.h @@ -112,8 +112,27 @@ void K_HitlagColormap(UINT8 *dest_colormap); Return:- None --------------------------------------------------*/ + void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); + +/*-------------------------------------------------- + boolean K_ColorUsable(skincolornum_t color, skin_t *skin, follower_t *follower); + + Determines whenever or not we meet the unlockable conditions + to use a certain color. + + Input Arguments:- + color - Color we want to use. + follower - Set to include the special follower-only color options. + + Return:- + true if we can use it, otherwise false. +--------------------------------------------------*/ + +boolean K_ColorUsable(skincolornum_t color, boolean follower); + + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_follower.c b/src/k_follower.c index 48b9646e2..511e81932 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -11,10 +11,11 @@ #include "r_skins.h" #include "p_local.h" #include "p_mobj.h" +#include "s_sound.h" #include "m_cond.h" INT32 numfollowers = 0; -follower_t followers[MAXSKINS]; +follower_t followers[MAXFOLLOWERS]; INT32 numfollowercategories; followercategory_t followercategories[MAXFOLLOWERCATEGORIES]; @@ -142,6 +143,11 @@ void K_RemoveFollower(player_t *player) bub = tmp; } + // And the honk. + bub = player->follower->hprev; + if (!P_MobjWasRemoved(bub)) + P_RemoveMobj(bub); + P_RemoveMobj(player->follower); P_SetTarget(&player->follower, NULL); } @@ -234,19 +240,39 @@ static void K_SetFollowerState(mobj_t *f, statenum_t state) } /*-------------------------------------------------- - UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor) + UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, follower_t *follower, UINT16 playercolor, skin_t *playerskin) See header file for description. --------------------------------------------------*/ -UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor) +UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, follower_t *follower, UINT16 playercolor, skin_t *playerskin) { - if (followercolor < numskincolors) // bog standard + if (followercolor == SKINCOLOR_NONE && follower != NULL) // "Default" + { + followercolor = follower->defaultcolor; + } + + if (followercolor > SKINCOLOR_NONE && followercolor < numskincolors) // bog standard + { return followercolor; + } + + if (playercolor == SKINCOLOR_NONE) // get default color + { + if (playerskin == NULL) + { + // Nothing from this line down is valid if playerskin is invalid, just guess Eggman? + playerskin = &skins[0]; + } + + playercolor = playerskin->prefcolor; + } if (followercolor == FOLLOWERCOLOR_OPPOSITE) // "Opposite" + { return skincolors[playercolor].invcolor; + } - //if (followercolor == FOLLOWERCOLOR_MATCH) -- "Match" + // "Match" return playercolor; } @@ -286,7 +312,7 @@ static void K_UpdateFollowerState(mobj_t *f, statenum_t state, followerstate_t t --------------------------------------------------*/ void K_HandleFollower(player_t *player) { - follower_t fl; + follower_t *fl; angle_t an; fixed_t zoffs; fixed_t ourheight; @@ -326,22 +352,22 @@ void K_HandleFollower(player_t *player) } // Before we do anything, let's be sure of where we're supposed to be - fl = followers[player->followerskin]; + fl = &followers[player->followerskin]; - an = player->mo->angle + fl.atangle; - zoffs = fl.zoffs; - bubble = fl.bubblescale; // 0 if no bubble to spawn. + an = player->mo->angle + fl->atangle; + zoffs = fl->zoffs; + bubble = fl->bubblescale; // 0 if no bubble to spawn. // do you like angle maths? I certainly don't... - sx = player->mo->x + player->mo->momx + FixedMul(FixedMul(player->mo->scale, fl.dist), FINECOSINE((an) >> ANGLETOFINESHIFT)); - sy = player->mo->y + player->mo->momy + FixedMul(FixedMul(player->mo->scale, fl.dist), FINESINE((an) >> ANGLETOFINESHIFT)); + sx = player->mo->x + player->mo->momx + FixedMul(FixedMul(player->mo->scale, fl->dist), FINECOSINE((an) >> ANGLETOFINESHIFT)); + sy = player->mo->y + player->mo->momy + FixedMul(FixedMul(player->mo->scale, fl->dist), FINESINE((an) >> ANGLETOFINESHIFT)); // interp info helps with stretchy fix deltaz = (player->mo->z - player->mo->old_z); // for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P sz = player->mo->z + player->mo->momz + FixedMul(player->mo->scale, zoffs * P_MobjFlip(player->mo)); - ourheight = FixedMul(fl.height, player->mo->scale); + ourheight = FixedMul(fl->height, player->mo->scale); if (player->mo->eflags & MFE_VERTICALFLIP) { sz += ourheight; @@ -350,7 +376,7 @@ void K_HandleFollower(player_t *player) fh = player->mo->floorz; ch = player->mo->ceilingz - ourheight; - switch (fl.mode) + switch (fl->mode) { case FOLLOWERMODE_GROUND: { @@ -369,9 +395,9 @@ void K_HandleFollower(player_t *player) { // finally, add a cool floating effect to the z height. // not stolen from k_kart I swear!! - fixed_t sine = FixedMul(fl.bobamp, + fixed_t sine = FixedMul(fl->bobamp, FINESINE((( - FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * leveltime + FixedMul(4 * M_TAU_FIXED, fl->bobspeed) * leveltime ) >> ANGLETOFINESHIFT) & FINEMASK)); sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo); break; @@ -379,7 +405,7 @@ void K_HandleFollower(player_t *player) } // Set follower colour - color = K_GetEffectiveFollowerColor(player->followercolor, player->skincolor); + color = K_GetEffectiveFollowerColor(player->followercolor, fl, player->skincolor, &skins[player->skin]); if (player->follower == NULL || P_MobjWasRemoved(player->follower)) // follower doesn't exist / isn't valid { @@ -390,7 +416,7 @@ void K_HandleFollower(player_t *player) if (player->follower == NULL) return; - K_UpdateFollowerState(player->follower, fl.idlestate, FOLLOWERSTATE_IDLE); + K_UpdateFollowerState(player->follower, fl->idlestate, FOLLOWERSTATE_IDLE); P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear player->follower->angle = player->follower->old_angle = player->mo->angle; @@ -422,12 +448,12 @@ void K_HandleFollower(player_t *player) } // move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)! - player->follower->momx = FixedDiv(sx - player->follower->x, fl.horzlag); - player->follower->momy = FixedDiv(sy - player->follower->y, fl.horzlag); + player->follower->momx = FixedDiv(sx - player->follower->x, fl->horzlag); + player->follower->momy = FixedDiv(sy - player->follower->y, fl->horzlag); - player->follower->z += FixedDiv(deltaz, fl.vertlag); + player->follower->z += FixedDiv(deltaz, fl->vertlag); - if (fl.mode == FOLLOWERMODE_GROUND) + if (fl->mode == FOLLOWERMODE_GROUND) { sector_t *sec = R_PointInSubsector(sx, sy)->sector; @@ -448,12 +474,12 @@ void K_HandleFollower(player_t *player) // Player is on the ground ... try to get the follower // back to the ground also if it is above it. - player->follower->momz += FixedDiv(fg * 6, fl.vertlag); // Scaled against the default value of vertlag + player->follower->momz += FixedDiv(fg * 6, fl->vertlag); // Scaled against the default value of vertlag } } else { - player->follower->momz = FixedDiv(sz - player->follower->z, fl.vertlag); + player->follower->momz = FixedDiv(sz - player->follower->z, fl->vertlag); } if (player->mo->colorized) @@ -467,7 +493,7 @@ void K_HandleFollower(player_t *player) player->follower->colorized = player->mo->colorized; - P_SetScale(player->follower, FixedMul(fl.scale, player->mo->scale)); + P_SetScale(player->follower, FixedMul(fl->scale, player->mo->scale)); K_GenericExtraFlagsNoZAdjust(player->follower, player->mo); // Not K_MatchGenericExtraFlag because the Z adjust it has only works properly if master & mo have the same Z height. // Match how the player is being drawn @@ -501,20 +527,20 @@ void K_HandleFollower(player_t *player) if (angleDiff != 0) { - player->follower->angle += FixedDiv(angleDiff, fl.anglelag); + player->follower->angle += FixedDiv(angleDiff, fl->anglelag); } // Ground follower slope rotation - if (fl.mode == FOLLOWERMODE_GROUND) + if (fl->mode == FOLLOWERMODE_GROUND) { if (player->follower->z <= fh) { player->follower->z = fh; - if (!(player->mo->eflags & MFE_VERTICALFLIP) && player->follower->momz <= 0 && fl.bobamp != 0) + if (!(player->mo->eflags & MFE_VERTICALFLIP) && player->follower->momz <= 0 && fl->bobamp != 0) { // Ground bounce - player->follower->momz = P_GetMobjZMovement(player->mo) + FixedMul(fl.bobamp, player->follower->scale); + player->follower->momz = P_GetMobjZMovement(player->mo) + FixedMul(fl->bobamp, player->follower->scale); player->follower->extravalue1 = FOLLOWERSTATE_RESET; } else if (player->follower->momz < 0) @@ -527,10 +553,10 @@ void K_HandleFollower(player_t *player) { player->follower->z = ch; - if ((player->mo->eflags & MFE_VERTICALFLIP) && player->follower->momz >= 0 && fl.bobamp != 0) + if ((player->mo->eflags & MFE_VERTICALFLIP) && player->follower->momz >= 0 && fl->bobamp != 0) { // Ground bounce - player->follower->momz = P_GetMobjZMovement(player->mo) - FixedMul(fl.bobamp, player->follower->scale); + player->follower->momz = P_GetMobjZMovement(player->mo) - FixedMul(fl->bobamp, player->follower->scale); player->follower->extravalue1 = FOLLOWERSTATE_RESET; } else if (player->follower->momz > 0) @@ -559,7 +585,7 @@ void K_HandleFollower(player_t *player) // match follower's momentums and (e)flags(2). bmobj->momx = player->follower->momx; bmobj->momy = player->follower->momy; - bmobj->z += FixedDiv(deltaz, fl.vertlag); + bmobj->z += FixedDiv(deltaz, fl->vertlag); bmobj->momz = player->follower->momz; P_SetScale(bmobj, FixedMul(bubble, player->mo->scale)); @@ -594,7 +620,7 @@ void K_HandleFollower(player_t *player) // spin out player->follower->angle = player->drawangle; - K_UpdateFollowerState(player->follower, fl.hurtstate, FOLLOWERSTATE_HURT); + K_UpdateFollowerState(player->follower, fl->hurtstate, FOLLOWERSTATE_HURT); if (player->mo->health <= 0) { @@ -608,26 +634,70 @@ void K_HandleFollower(player_t *player) if (K_IsPlayerLosing(player)) { // L - K_UpdateFollowerState(player->follower, fl.losestate, FOLLOWERSTATE_LOSE); + K_UpdateFollowerState(player->follower, fl->losestate, FOLLOWERSTATE_LOSE); } else { // W - K_UpdateFollowerState(player->follower, fl.winstate, FOLLOWERSTATE_WIN); + K_UpdateFollowerState(player->follower, fl->winstate, FOLLOWERSTATE_WIN); } } else if (player->follower->movecount) { - K_UpdateFollowerState(player->follower, fl.hitconfirmstate, FOLLOWERSTATE_HITCONFIRM); + K_UpdateFollowerState(player->follower, fl->hitconfirmstate, FOLLOWERSTATE_HITCONFIRM); player->follower->movecount--; } else if (player->speed > 10*player->mo->scale) // animation for moving fast enough { - K_UpdateFollowerState(player->follower, fl.followstate, FOLLOWERSTATE_FOLLOW); + K_UpdateFollowerState(player->follower, fl->followstate, FOLLOWERSTATE_FOLLOW); } else { - K_UpdateFollowerState(player->follower, fl.idlestate, FOLLOWERSTATE_IDLE); + K_UpdateFollowerState(player->follower, fl->idlestate, FOLLOWERSTATE_IDLE); + } + + // Horncode + if (P_MobjWasRemoved(player->follower->hprev) == false) + { + mobj_t *honk = player->follower->hprev; + + honk->flags2 &= ~MF2_AMBUSH; + + honk->color = player->skincolor; + + P_MoveOrigin( + honk, + player->follower->x, + player->follower->y, + player->follower->z + player->follower->height + ); + + K_FlipFromObject(honk, player->follower); + + honk->angle = R_PointToAngle2( + player->mo->x, + player->mo->y, + player->follower->x, + player->follower->y + ); + + honk->destscale = (2*player->mo->scale)/3; + + fixed_t offsetamount = 0; + if (honk->fuse > 1) + { + offsetamount = (honk->fuse-1)*honk->destscale/2; + if (leveltime & 1) + offsetamount = -offsetamount; + } + else if (S_SoundPlaying(honk, fl->hornsound)) + { + honk->fuse++; + } + + honk->sprxoff = P_ReturnThrustX(honk, honk->angle, offsetamount); + honk->spryoff = P_ReturnThrustY(honk, honk->angle, offsetamount); + honk->sprzoff = -honk->sprxoff; } } @@ -638,3 +708,76 @@ void K_HandleFollower(player_t *player) return; } } + +/*-------------------------------------------------- + void K_FollowerHornTaunt(player_t *taunter, player_t *victim) + + See header file for description. +--------------------------------------------------*/ +void K_FollowerHornTaunt(player_t *taunter, player_t *victim) +{ + if ( + (cv_karthorns.value == 0) + || taunter == NULL + || victim == NULL + || taunter->followerskin < 0 + || taunter->followerskin >= numfollowers + || (P_IsLocalPlayer(victim) == false && cv_karthorns.value != 2) + || P_MobjWasRemoved(taunter->mo) == true + || P_MobjWasRemoved(taunter->follower) == true + ) + return; + + const follower_t *fl = &followers[taunter->followerskin]; + + const boolean tasteful = (taunter->karthud[khud_taunthorns] == 0); + + if (tasteful || cv_karthorns.value == 2) + { + mobj_t *honk = taunter->follower->hprev; + const fixed_t desiredscale = (2*taunter->mo->scale)/3; + + if (P_MobjWasRemoved(honk) == true) + { + honk = P_SpawnMobj( + taunter->follower->x, + taunter->follower->y, + taunter->follower->z + taunter->follower->height, + MT_HORNCODE + ); + + if (P_MobjWasRemoved(honk) == true) + return; // Permit lua override of horn production + + P_SetTarget(&taunter->follower->hprev, honk); + P_SetTarget(&honk->target, taunter->follower); + + K_FlipFromObject(honk, taunter->follower); + + honk->color = taunter->skincolor; + + honk->angle = honk->old_angle = R_PointToAngle2( + taunter->mo->x, + taunter->mo->y, + taunter->follower->x, + taunter->follower->y + ); + } + + // Only do for the first activation this tic. + if (!(honk->flags2 & MF2_AMBUSH)) + { + honk->destscale = desiredscale; + + P_SetScale(honk, (11*desiredscale)/10); + honk->fuse = TICRATE/2; + honk->renderflags |= RF_DONTDRAW; + + S_StartSound(taunter->follower, fl->hornsound); + + honk->flags2 |= MF2_AMBUSH; + } + + honk->renderflags &= ~K_GetPlayerDontDrawFlag(victim); + } +} diff --git a/src/k_follower.h b/src/k_follower.h index 288bb34b8..9da3d4e73 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -20,6 +20,13 @@ extern "C" { #endif +// The important collorary to "Hornmod is universally hated in dev" is +// the simple phrase "this is why" -- 1024 is obscene yet will fill up. +// By the way, this comment will grow stronger and stronger every time +// somebody comes here to double it, so I encourage you to leave a new +// (dated) comment every time you do so. ~toast 280623 +#define MAXFOLLOWERS 1024 + #define FOLLOWERCOLOR_MATCH UINT16_MAX #define FOLLOWERCOLOR_OPPOSITE (UINT16_MAX-1) @@ -85,12 +92,14 @@ struct follower_t statenum_t losestate; // state when the player has lost statenum_t hitconfirmstate; // state for hit confirm tic_t hitconfirmtime; // time to keep the above playing for + + sfxenum_t hornsound; // Press (B) to announce you are pressing (B) }; extern INT32 numfollowers; -extern follower_t followers[MAXSKINS]; +extern follower_t followers[MAXFOLLOWERS]; -#define MAXFOLLOWERCATEGORIES 32 +#define MAXFOLLOWERCATEGORIES 64 struct followercategory_t { @@ -170,20 +179,22 @@ void K_SetFollowerByNum(INT32 playernum, INT32 skinnum); /*-------------------------------------------------- - UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor) + UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, follower_t *follower, UINT16 playercolor, skin_t *playerskin) Updates a player's follower pointer, and does its positioning and animations. Input Arguments:- followercolor - The raw color setting for the follower + follower - Follower struct to retrieve default color from. Can be NULL playercolor - The player's associated colour, for reference + playerskin - Skin struct to retrieve default color from. Can be NULL Return:- The resultant skincolor enum for the follower --------------------------------------------------*/ -UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor); +UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, follower_t *follower, UINT16 playercolor, skin_t *playerskin); /*-------------------------------------------------- @@ -215,6 +226,21 @@ void K_HandleFollower(player_t *player); void K_RemoveFollower(player_t *player); +/*-------------------------------------------------- + void K_FollowerHornTaunt(player_t *taunter, player_t *victim) + + Plays horn and spawns object (MOSTLY non-netsynced) + + Input Arguments:- + taunter - Source player with a follower + victim - Player that hears and sees the honk + + Return:- + None +--------------------------------------------------*/ + +void K_FollowerHornTaunt(player_t *taunter, player_t *victim); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_kart.c b/src/k_kart.c index 2adcfa4ea..ed58a5b19 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -359,6 +359,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartencore); CV_RegisterVar(&cv_kartspeedometer); CV_RegisterVar(&cv_kartvoices); + CV_RegisterVar(&cv_karthorns); CV_RegisterVar(&cv_kartbot); CV_RegisterVar(&cv_karteliminatelast); CV_RegisterVar(&cv_thunderdome); @@ -2055,13 +2056,29 @@ void K_SpawnMagicianParticles(mobj_t *mo, int spread) } } -static SINT8 K_GlanceAtPlayers(player_t *glancePlayer) +static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) { const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); const angle_t blindSpotSize = ANG10; // ANG5 UINT8 i; SINT8 glanceDir = 0; SINT8 lastValidGlance = 0; + boolean podiumspecial = (K_PodiumSequence() == true && glancePlayer->nextwaypoint == NULL && glancePlayer->speed == 0); + + if (podiumspecial) + { + if (glancePlayer->position > 3) + { + // Loser valley, focused on the mountain. + return 0; + } + + if (glancePlayer->position == 1) + { + // Sitting on the stand, I ammm thebest! + return 0; + } + } // See if there's any players coming up behind us. // If so, your character will glance at 'em. @@ -2099,9 +2116,17 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer) continue; } - distance = R_PointToDist2(glancePlayer->mo->x, glancePlayer->mo->y, p->mo->x, p->mo->y); + if (!podiumspecial) + { + distance = R_PointToDist2(glancePlayer->mo->x, glancePlayer->mo->y, p->mo->x, p->mo->y); - if (distance > maxdistance) + if (distance > maxdistance) + { + // Too far away + continue; + } + } + else if (p->position >= glancePlayer->position) { continue; } @@ -2115,7 +2140,7 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer) dir = -dir; } - if (diff > ANGLE_90) + if (diff > (podiumspecial ? (ANGLE_180 - blindSpotSize) : ANGLE_90)) { // Not behind the player continue; @@ -2127,16 +2152,33 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer) continue; } - if (P_CheckSight(glancePlayer->mo, p->mo) == true) + if (!podiumspecial && P_CheckSight(glancePlayer->mo, p->mo) == false) { - // Not blocked by a wall, we can glance at 'em! - // Adds, so that if there's more targets on one of your sides, it'll glance on that side. - glanceDir += dir; - - // That poses a limitation if there's an equal number of targets on both sides... - // In that case, we'll pick the last chosen glance direction. - lastValidGlance = dir; + // Blocked by a wall, we can't glance at 'em! + continue; } + + // Adds, so that if there's more targets on one of your sides, it'll glance on that side. + glanceDir += dir; + + // That poses a limitation if there's an equal number of targets on both sides... + // In that case, we'll pick the last chosen glance direction. + lastValidGlance = dir; + + if (horn == true) + { + K_FollowerHornTaunt(glancePlayer, p); + } + } + + if (horn == true && lastValidGlance != 0) + { + const boolean tasteful = (glancePlayer->karthud[khud_taunthorns] == 0); + + K_FollowerHornTaunt(glancePlayer, glancePlayer); + + if (tasteful && glancePlayer->karthud[khud_taunthorns] < 2*TICRATE) + glancePlayer->karthud[khud_taunthorns] = 2*TICRATE; } if (glanceDir > 0) @@ -2215,7 +2257,8 @@ void K_KartMoveAnimation(player_t *player) { // Only try glancing if you're driving straight. // This avoids all-players loops when we don't need it. - destGlanceDir = K_GlanceAtPlayers(player); + const boolean horn = lookback && !(player->pflags & PF_GAINAX); + destGlanceDir = K_GlanceAtPlayers(player, horn); if (lookback == true) { @@ -2649,7 +2692,9 @@ void K_TryHurtSoundExchange(mobj_t *victim, mobj_t *attacker) attacker->player->confirmVictim = (victim->player - players); attacker->player->confirmVictimDelay = TICRATE/2; - if (attacker->player->follower != NULL) + if (attacker->player->follower != NULL + && attacker->player->followerskin >= 0 + && attacker->player->followerskin < numfollowers) { const follower_t *fl = &followers[attacker->player->followerskin]; attacker->player->follower->movecount = fl->hitconfirmtime; // movecount is used to play the hitconfirm animation for followers. @@ -7415,6 +7460,9 @@ void K_KartPlayerHUDUpdate(player_t *player) if (player->karthud[khud_tauntvoices]) player->karthud[khud_tauntvoices]--; + if (player->karthud[khud_taunthorns]) + player->karthud[khud_taunthorns]--; + if (player->karthud[khud_trickcool]) player->karthud[khud_trickcool]--; diff --git a/src/k_menu.h b/src/k_menu.h index 3e3294f2e..d49d02ca3 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -642,17 +642,12 @@ void M_MenuTypingInput(INT32 key); void M_QuitResponse(INT32 ch); void M_QuitSRB2(INT32 choice); -extern UINT16 nummenucolors; -void M_AddMenuColor(UINT16 color); -void M_MoveColorBefore(UINT16 color, UINT16 targ); -void M_MoveColorAfter(UINT16 color, UINT16 targ); -UINT16 M_GetColorBefore(UINT16 color, UINT16 amount, boolean follower); -UINT16 M_GetColorAfter(UINT16 color, UINT16 amount, boolean follower); -void M_InitPlayerSetupColors(void); -void M_FreePlayerSetupColors(void); +UINT16 M_GetColorAfter(setup_player_colors_t *colors, UINT16 value, INT32 amount); +#define M_GetColorBefore(a, b, c) M_GetColorAfter(a, b, -c) // If you want to waste a bunch of memory for a limit no one will hit, feel free to boost this to MAXSKINS :P // I figure this will be enough clone characters to fit onto one grid space. +// TODO: Dynamically allocate instead, you KNOW this limit will get hit by someone eventually #define MAXCLONES MAXSKINS/8 extern struct setup_chargrid_s { @@ -677,6 +672,13 @@ typedef enum CSSTEP_READY } setup_mdepth_t; +struct setup_player_colors_t +{ + UINT16 *list; + size_t listLen; + size_t listCap; +}; + struct setup_player_t { SINT8 gridx, gridy; @@ -704,6 +706,8 @@ struct setup_player_t tic_t follower_timer; UINT8 follower_frame; state_t *follower_state; + + setup_player_colors_t colors; }; extern setup_player_t setup_player[MAXSPLITSCREENPLAYERS]; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 40f96c9c7..152629e7f 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1226,7 +1226,8 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) numoptions = setup_chargrid[p->gridx][p->gridy].numskins; break; case CSSTEP_COLORS: - numoptions = nummenucolors; + case CSSTEP_FOLLOWERCOLORS: + numoptions = p->colors.listLen; break; case CSSTEP_FOLLOWERCATEGORY: numoptions = setup_numfollowercategories+1; @@ -1234,9 +1235,6 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) case CSSTEP_FOLLOWER: numoptions = setup_followercategories[p->followercategory][0]; break; - case CSSTEP_FOLLOWERCOLORS: - numoptions = nummenucolors+2; - break; default: return; } @@ -1289,20 +1287,20 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) if (i == 0) { - n = l = r = M_GetColorBefore(p->color, numoptions/2, false); + n = l = r = M_GetColorBefore(&p->colors, p->color, (numoptions/2) - 1); } else if (subtract) { - n = l = M_GetColorBefore(l, 1, false); + n = l = M_GetColorBefore(&p->colors, l, 1); } else { - n = r = M_GetColorAfter(r, 1, false); + n = r = M_GetColorAfter(&p->colors, r, 1); } - colormap = R_GetTranslationColormap(TC_DEFAULT, n, GTC_MENUCACHE); + colormap = R_GetTranslationColormap(TC_DEFAULT, (n == SKINCOLOR_NONE) ? skins[p->skin].prefcolor : n, GTC_MENUCACHE); - diff = (numoptions - i)/2; // only 0 when i == numoptions-1 + diff = (numoptions - i) / 2; // only 0 when i == numoptions-1 if (diff == 0) patch = W_CachePatchName("COLORSP2", PU_CACHE); @@ -1399,7 +1397,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) patch = W_CachePatchName(fl->icon, PU_CACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, - K_GetEffectiveFollowerColor(fl->defaultcolor, p->color), + K_GetEffectiveFollowerColor(fl->defaultcolor, fl, p->color, &skins[p->skin]), GTC_MENUCACHE ); } @@ -1418,18 +1416,18 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) if (i == 0) { - n = l = r = M_GetColorBefore(p->followercolor, numoptions/2, true); + n = l = r = M_GetColorBefore(&p->colors, p->followercolor, (numoptions/2) - 1); } else if (subtract) { - n = l = M_GetColorBefore(l, 1, true); + n = l = M_GetColorBefore(&p->colors, l, 1); } else { - n = r = M_GetColorAfter(r, 1, true); + n = r = M_GetColorAfter(&p->colors, r, 1); } - col = K_GetEffectiveFollowerColor(n, p->color); + col = K_GetEffectiveFollowerColor(n, &followers[p->followern], p->color, &skins[p->skin]); colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); @@ -1517,14 +1515,13 @@ static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, U // if a setup_player_t is specified instead, its data will be used to animate the follower sprite. static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charflip, INT32 addflags, UINT8 *colormap, setup_player_t *p) { - spritedef_t *sprdef; spriteframe_t *sprframe; patch_t *patch; INT32 followernum; state_t *usestate; UINT32 useframe; - follower_t fl; + follower_t *fl; UINT8 rotation = (charflip ? 1 : 7); if (p != NULL) @@ -1536,7 +1533,7 @@ static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charfli if (followernum < 0 || followernum >= numfollowers) return false; - fl = followers[followernum]; + fl = &followers[followernum]; if (p != NULL) { @@ -1569,13 +1566,16 @@ static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charfli if (p != NULL) { UINT16 color = K_GetEffectiveFollowerColor( - (p->mdepth < CSSTEP_FOLLOWERCOLORS) ? fl.defaultcolor : p->followercolor, - p->color); - sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * p->follower_timer)>>ANGLETOFINESHIFT) & FINEMASK)); + (p->mdepth < CSSTEP_FOLLOWERCOLORS) ? fl->defaultcolor : p->followercolor, + fl, + p->color, + &skins[p->skin] + ); + sine = FixedMul(fl->bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl->bobspeed) * p->follower_timer)>>ANGLETOFINESHIFT) & FINEMASK)); colormap = R_GetTranslationColormap(TC_DEFAULT, color, GTC_MENUCACHE); } - V_DrawFixedPatch((x*FRACUNIT), ((y-12)*FRACUNIT) + sine, fl.scale, addflags, patch, colormap); + V_DrawFixedPatch((x*FRACUNIT), ((y-12)*FRACUNIT) + sine, fl->scale, addflags, patch, colormap); return true; } @@ -1587,12 +1587,24 @@ static void M_DrawCharSelectSprite(UINT8 num, INT16 x, INT16 y, boolean charflip UINT8 *colormap; if (p->skin < 0) + { return; + } if (p->mdepth < CSSTEP_COLORS) + { color = skins[p->skin].prefcolor; + } else + { color = p->color; + } + + if (color == SKINCOLOR_NONE) + { + color = skins[p->skin].prefcolor; + } + colormap = R_GetTranslationColormap(p->skin, color, GTC_MENUCACHE); M_DrawCharacterSprite(x, y, p->skin, SPR2_STIN, (charflip ? 1 : 7), ((p->mdepth == CSSTEP_READY) ? setup_animcounter : 0), 0, colormap); @@ -1639,9 +1651,9 @@ static void M_DrawCharSelectPreview(UINT8 num) M_DrawFollowerSprite(x+32+((charflip ? 1 : -1)*16), y+75, -1, charflip, 0, 0, p); } - if ((setup_animcounter/10) & 1 && gamestate == GS_MENU) // Not drawn outside of GS_MENU. + if ((setup_animcounter/10) & 1) { - if (p->mdepth == CSSTEP_NONE && num == setup_numplayers) + if (p->mdepth == CSSTEP_NONE && num == setup_numplayers && gamestate == GS_MENU) { V_DrawScaledPatch(x+1, y+36, 0, W_CachePatchName("4PSTART", PU_CACHE)); } @@ -1872,6 +1884,7 @@ static void M_DrawCharSelectCursor(UINT8 num) setup_player_t *p = &setup_player[num]; char letter = 'A' + num; + UINT16 color = SKINCOLOR_NONE; UINT8 *colormap; INT16 x, y; INT16 quadx, quady; @@ -1889,7 +1902,20 @@ static void M_DrawCharSelectCursor(UINT8 num) if (optionsmenu.profile) x += 64; - colormap = R_GetTranslationColormap(TC_DEFAULT, (p->color != SKINCOLOR_NONE ? p->color : SKINCOLOR_GREY), GTC_MENUCACHE); + color = p->color; + if (color == SKINCOLOR_NONE) + { + if (p->skin >= 0) + { + color = skins[p->skin].prefcolor; + } + else + { + color = SKINCOLOR_GREY; + } + } + + colormap = R_GetTranslationColormap(TC_DEFAULT, color, GTC_MENUCACHE); if (p->mdepth >= CSSTEP_READY) { @@ -1930,22 +1956,34 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) if (p != NULL && p->version) { - truecol = PR_GetProfileColor(p); - colormap = R_GetTranslationColormap(TC_DEFAULT, truecol, GTC_CACHE); - strcpy(pname, p->profilename); + truecol = p->color; skinnum = R_SkinAvailable(p->skinname); + strcpy(pname, p->profilename); } - // check setup_player for colormap for the card. - // we'll need to check again for drawing afterwards unfortunately. if (sp->mdepth >= CSSTEP_CHARS) { - truecol = PR_GetProfileColor(p); - colormap = R_GetTranslationColormap(skinnum, sp->color, GTC_MENUCACHE); + truecol = sp->color; + skinnum = setup_chargrid[sp->gridx][sp->gridy].skinlist[sp->clonenum]; + } + + if (truecol == SKINCOLOR_NONE) + { + if (skinnum >= 0) + { + truecol = skins[skinnum].prefcolor; + } + else + { + truecol = SKINCOLOR_RED; + } } // Card - V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, greyedout ? V_TRANSLUCENT : 0, card, colormap); + { + colormap = R_GetTranslationColormap(TC_DEFAULT, truecol, GTC_CACHE); + V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, greyedout ? V_TRANSLUCENT : 0, card, colormap); + } if (greyedout) return; // only used for profiles we can't select. @@ -1960,12 +1998,12 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) // check what setup_player is doing in priority. if (sp->mdepth >= CSSTEP_CHARS) { - skinnum = setup_chargrid[sp->gridx][sp->gridy].skinlist[sp->clonenum]; - if (skinnum >= 0) { - if (M_DrawCharacterSprite(x-22, y+119, skinnum, SPR2_STIN, 7, 0, 0, colormap)) - V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], colormap); + UINT8 *ccolormap = R_GetTranslationColormap(skinnum, truecol, GTC_MENUCACHE); + + if (M_DrawCharacterSprite(x-22, y+119, skinnum, SPR2_STIN, 7, 0, 0, ccolormap)) + V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], ccolormap); } M_DrawCharSelectCircle(sp, x-22, y+104); @@ -1974,7 +2012,7 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) { if (M_DrawFollowerSprite(x-22 - 16, y+119, 0, false, 0, 0, sp)) { - UINT16 col = K_GetEffectiveFollowerColor(sp->followercolor, sp->color);; + UINT16 col = K_GetEffectiveFollowerColor(sp->followercolor, &followers[sp->followern], sp->color, &skins[sp->skin]); patch_t *ico = W_CachePatchName(followers[sp->followern].icon, PU_CACHE); UINT8 *fcolormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); V_DrawMappedPatch(x+14+18, y+66, 0, ico, fcolormap); @@ -1983,28 +2021,36 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) } else if (skinnum > -1) // otherwise, read from profile. { - UINT8 *ccolormap, *fcolormap; - UINT16 col = K_GetEffectiveFollowerColor(p->followercolor, p->color); - UINT8 fln = K_FollowerAvailable(p->follower); + UINT8 *ccolormap; + INT32 fln = K_FollowerAvailable(p->follower); if (R_SkinUsable(g_localplayers[0], skinnum, false)) - ccolormap = colormap; + ccolormap = R_GetTranslationColormap(skinnum, truecol, GTC_MENUCACHE); else ccolormap = R_GetTranslationColormap(TC_BLINK, truecol, GTC_MENUCACHE); - fcolormap = R_GetTranslationColormap( - (K_FollowerUsable(fln) ? TC_DEFAULT : TC_BLINK), - col, GTC_MENUCACHE); - if (M_DrawCharacterSprite(x-22, y+119, skinnum, SPR2_STIN, 7, 0, 0, ccolormap)) { V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], ccolormap); } - if (M_DrawFollowerSprite(x-22 - 16, y+119, fln, false, 0, fcolormap, NULL)) + if (fln >= 0) { - patch_t *ico = W_CachePatchName(followers[fln].icon, PU_CACHE); - V_DrawMappedPatch(x+14+18, y+66, 0, ico, fcolormap); + UINT16 fcol = K_GetEffectiveFollowerColor( + p->followercolor, + &followers[fln], + p->color, + &skins[skinnum] + ); + UINT8 *fcolormap = R_GetTranslationColormap( + (K_FollowerUsable(fln) ? TC_DEFAULT : TC_BLINK), + fcol, GTC_MENUCACHE); + + if (M_DrawFollowerSprite(x-22 - 16, y+119, fln, false, 0, fcolormap, NULL)) + { + patch_t *ico = W_CachePatchName(followers[fln].icon, PU_CACHE); + V_DrawMappedPatch(x+14+18, y+66, 0, ico, fcolormap); + } } } @@ -5021,12 +5067,15 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili case SECRET_FOLLOWER: categoryid = '2'; break; - /*case SECRET_COLOR: + case SECRET_COLOR: categoryid = '3'; - break;*/ + break; case SECRET_CUP: categoryid = '4'; break; + case SECRET_MAP: + categoryid = '8'; + break; case SECRET_HARDSPEED: case SECRET_MASTERMODE: case SECRET_ENCORE: @@ -5035,8 +5084,9 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili case SECRET_ONLINE: case SECRET_ADDONS: case SECRET_EGGTV: - case SECRET_ALTTITLE: case SECRET_SOUNDTEST: + case SECRET_ALTTITLE: + case SECRET_MEMETAUNTS: categoryid = '6'; break; case SECRET_TIMEATTACK: @@ -5086,12 +5136,27 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili INT32 skin = M_UnlockableFollowerNum(ref); if (skin != -1) { - UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value); + INT32 psk = R_SkinAvailable(cv_skin[0].string); + UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, &followers[skin], cv_playercolor[0].value, (psk != -1) ? &skins[psk] : &skins[0]); colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); pat = W_CachePatchName(followers[skin].icon, PU_CACHE); } break; } + case SECRET_COLOR: + { + INT32 colorid = M_UnlockableColorNum(ref); + if (colorid != SKINCOLOR_NONE) + { + colormap = R_GetTranslationColormap(TC_DEFAULT, colorid, GTC_MENUCACHE); + } + iconid = 2; + break; + } + + case SECRET_MAP: + iconid = 14; + break; case SECRET_HARDSPEED: iconid = 3; @@ -5112,11 +5177,14 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili case SECRET_EGGTV: iconid = 11; break; + case SECRET_SOUNDTEST: + iconid = 1; + break; case SECRET_ALTTITLE: iconid = 6; break; - case SECRET_SOUNDTEST: - iconid = 1; + case SECRET_MEMETAUNTS: + iconid = 13; break; case SECRET_TIMEATTACK: @@ -5129,7 +5197,7 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili iconid = 9; break; case SECRET_SPBATTACK: - iconid = 0; // TEMPORARY + iconid = 15; break; default: @@ -5324,7 +5392,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) // Draw follower next to them if (fskin != -1) { - UINT16 col = K_GetEffectiveFollowerColor(followers[fskin].defaultcolor, cv_playercolor[0].value); + UINT16 col = K_GetEffectiveFollowerColor(followers[fskin].defaultcolor, &followers[fskin], cv_playercolor[0].value, &skins[skin]); colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); M_DrawFollowerSprite(x - 16, y, fskin, false, 0, colormap, NULL); @@ -5338,6 +5406,20 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) } break; } + case SECRET_COLOR: + { + INT32 colorid = M_UnlockableColorNum(ref); + if (colorid == SKINCOLOR_NONE) + break; + INT32 skin = R_SkinAvailable(cv_skin[0].string); + if (skin == -1) + skin = 0; + colormap = R_GetTranslationColormap(skin, colorid, GTC_MENUCACHE); + + // Draw reference for character bathed in coloured slime + M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap); + break; + } case SECRET_CUP: { levelsearch_t templevelsearch; diff --git a/src/k_profiles.c b/src/k_profiles.c index 48cf6472d..63dccc8b7 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -20,6 +20,7 @@ #include "r_skins.h" #include "monocypher/monocypher.h" #include "stun.h" +#include "k_color.h" // List of all the profiles. static profile_t *profilesList[MAXPROFILES+1]; // +1 because we're gonna add a default "GUEST' profile. @@ -372,7 +373,7 @@ void PR_LoadProfiles(void) ; // Valid, even outside the bounds } else if (profilesList[i]->color >= numskincolors - || skincolors[profilesList[i]->color].accessible == false) + || K_ColorUsable(profilesList[i]->color, false) == false) { profilesList[i]->color = PROFILEDEFAULTCOLOR; } @@ -388,7 +389,7 @@ void PR_LoadProfiles(void) } else if (profilesList[i]->followercolor >= numskincolors || profilesList[i]->followercolor == SKINCOLOR_NONE - || skincolors[profilesList[i]->followercolor].accessible == false) + || K_ColorUsable(profilesList[i]->followercolor, true) == false) { profilesList[i]->followercolor = PROFILEDEFAULTFOLLOWERCOLOR; } @@ -443,29 +444,10 @@ void PR_LoadProfiles(void) profilesList[PROFILE_GUEST] = dprofile; } -skincolornum_t PR_GetProfileColor(profile_t *p) -{ - if (p->color == SKINCOLOR_NONE) - { - // Get skin's prefcolor. - INT32 foundskin = R_SkinAvailable(p->skinname); - if (foundskin == -1) - { - // Return random default value - return SKINCOLOR_RED; - } - - return skins[foundskin].prefcolor; - } - - // Get exact color. - return p->color; -} - static void PR_ApplyProfile_Appearance(profile_t *p, UINT8 playernum) { CV_StealthSet(&cv_skin[playernum], p->skinname); - CV_StealthSetValue(&cv_playercolor[playernum], PR_GetProfileColor(p)); + CV_StealthSetValue(&cv_playercolor[playernum], p->color); CV_StealthSet(&cv_playername[playernum], p->playername); // Followers diff --git a/src/k_profiles.h b/src/k_profiles.h index f0ac07d56..d08c350be 100644 --- a/src/k_profiles.h +++ b/src/k_profiles.h @@ -131,10 +131,6 @@ void PR_SaveProfiles(void); // This also loads void PR_LoadProfiles(void); -// PR_GetProfileColor(profile_t *p) -// Returns the profile's color, or the skin's prefcolor if set to none. -skincolornum_t PR_GetProfileColor(profile_t *p); - // PR_ApplyProfile(UINT8 profilenum, UINT8 playernum) // Applies the given profile's settings to the given player. void PR_ApplyProfile(UINT8 profilenum, UINT8 playernum); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index ef76bfb89..5e6db3967 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -338,49 +338,11 @@ static int lib_reserveLuabanks(lua_State *L) // M_MENU ////////////// -static int lib_pMoveColorBefore(lua_State *L) -{ - UINT16 color = (UINT16)luaL_checkinteger(L, 1); - UINT16 targ = (UINT16)luaL_checkinteger(L, 2); - - NOHUD - M_MoveColorBefore(color, targ); - return 0; -} - -static int lib_pMoveColorAfter(lua_State *L) -{ - UINT16 color = (UINT16)luaL_checkinteger(L, 1); - UINT16 targ = (UINT16)luaL_checkinteger(L, 2); - - NOHUD - M_MoveColorAfter(color, targ); - return 0; -} - -static int lib_pGetColorBefore(lua_State *L) -{ - UINT16 color = (UINT16)luaL_checkinteger(L, 1); - UINT16 amount = (UINT16)luaL_checkinteger(L, 2); - boolean follower = lua_optboolean(L, 3); - lua_pushinteger(L, M_GetColorBefore(color, amount, follower)); - return 1; -} - -static int lib_pGetColorAfter(lua_State *L) -{ - UINT16 color = (UINT16)luaL_checkinteger(L, 1); - UINT16 amount = (UINT16)luaL_checkinteger(L, 2); - boolean follower = lua_optboolean(L, 3); - lua_pushinteger(L, M_GetColorAfter(color, amount, follower)); - return 1; -} - static int lib_pGetEffectiveFollowerColor(lua_State *L) { UINT16 followercolor = (UINT16)luaL_checkinteger(L, 1); UINT16 playercolor = (UINT16)luaL_checkinteger(L, 2); - lua_pushinteger(L, K_GetEffectiveFollowerColor(followercolor, playercolor)); + lua_pushinteger(L, K_GetEffectiveFollowerColor(followercolor, NULL, playercolor, NULL)); // FIXME: follower / skin return 1; } @@ -3976,12 +3938,6 @@ static luaL_Reg lib[] = { {"IsPlayerAdmin", lib_isPlayerAdmin}, {"reserveLuabanks", lib_reserveLuabanks}, - // m_menu - {"M_MoveColorAfter",lib_pMoveColorAfter}, - {"M_MoveColorBefore",lib_pMoveColorBefore}, - {"M_GetColorAfter",lib_pGetColorAfter}, - {"M_GetColorBefore",lib_pGetColorBefore}, - // m_random {"P_RandomFixed",lib_pRandomFixed}, {"P_RandomByte",lib_pRandomByte}, diff --git a/src/m_cond.c b/src/m_cond.c index 2e69a211f..417b554a9 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -2219,6 +2219,42 @@ INT32 M_UnlockableFollowerNum(unlockable_t *unlock) return -1; } +INT32 M_UnlockableColorNum(unlockable_t *unlock) +{ + if (unlock->type != SECRET_COLOR) + { + // This isn't a color unlockable... + return -1; + } + + if (unlock->stringVar && unlock->stringVar[0]) + { + skincolornum_t colornum = SKINCOLOR_NONE; + + if (unlock->stringVarCache != -1) + { + return unlock->stringVarCache; + } + + // Get the skin from the string. + colornum = R_GetColorByName(unlock->stringVar); + if (colornum != SKINCOLOR_NONE) + { + unlock->stringVarCache = colornum; + return colornum; + } + } + + if (unlock->variable > SKINCOLOR_NONE && unlock->variable < numskincolors) + { + // Use the number directly. + return unlock->variable; + } + + // Invalid color unlockable. + return -1; +} + cupheader_t *M_UnlockableCup(unlockable_t *unlock) { cupheader_t *cup = kartcupheaders; diff --git a/src/m_cond.h b/src/m_cond.h index e3975a957..6ca875ab5 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -184,6 +184,7 @@ typedef enum // Player restrictions SECRET_SKIN, // Permit this character SECRET_FOLLOWER, // Permit this follower + SECRET_COLOR, // Permit this color // Difficulty restrictions SECRET_HARDSPEED, // Permit Hard gamespeed @@ -202,6 +203,7 @@ typedef enum SECRET_EGGTV, // Permit replay playback menu SECRET_SOUNDTEST, // Permit Sound Test SECRET_ALTTITLE, // Permit alternate titlescreen + SECRET_MEMETAUNTS, // Permit "Meme" for kartvoices_cons_t // Assist restrictions SECRET_ITEMFINDER, // Permit locating in-level secrets @@ -375,6 +377,7 @@ boolean M_GotLowEnoughTime(INT32 tictime); INT32 M_UnlockableSkinNum(unlockable_t *unlock); INT32 M_UnlockableFollowerNum(unlockable_t *unlock); +INT32 M_UnlockableColorNum(unlockable_t *unlock); cupheader_t *M_UnlockableCup(unlockable_t *unlock); UINT16 M_UnlockableMapNum(unlockable_t *unlock); diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 5c50c4eef..ff35d2ed6 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -531,10 +531,13 @@ void M_ChallengesTick(void) } case SECRET_FOLLOWER: { - INT32 skin = M_UnlockableFollowerNum(ref); - if (skin != -1) + INT32 fskin = M_UnlockableFollowerNum(ref); + if (fskin != -1) { - bombcolor = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value); + INT32 psk = R_SkinAvailable(cv_skin[0].string); + if (psk == -1) + psk = 0; + bombcolor = K_GetEffectiveFollowerColor(followers[fskin].defaultcolor, &followers[fskin], cv_playercolor[0].value, &skins[psk]); } break; } @@ -545,6 +548,13 @@ void M_ChallengesTick(void) if (bombcolor == SKINCOLOR_NONE) { bombcolor = cv_playercolor[0].value; + if (bombcolor == SKINCOLOR_NONE) + { + INT32 psk = R_SkinAvailable(cv_skin[0].string); + if (psk == -1) + psk = 0; + bombcolor = skins[psk].prefcolor; + } } i = (ref->majorunlock && M_RandomChance(FRACUNIT/2)) ? 1 : 0; diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index edd3c99c8..111c24ed8 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -6,6 +6,8 @@ #include "../s_sound.h" #include "../k_grandprix.h" // K_CanChangeRules #include "../m_cond.h" // Condition Sets +#include "../k_color.h" +#include "../z_zone.h" //#define CHARSELECT_DEVICEDEBUG @@ -38,8 +40,6 @@ static void Splitplayers_OnChange(void); CV_PossibleValue_t splitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; consvar_t cv_splitplayers = CVAR_INIT ("splitplayers", "One", CV_CALL, splitplayers_cons_t, Splitplayers_OnChange); -UINT16 nummenucolors = 0; - // Character Select! // @TODO: Splitscreen handling when profiles are added into the game. ...I probably won't be the one to handle this however. -Lat' @@ -55,261 +55,116 @@ tic_t setup_animcounter = 0; UINT8 setup_page = 0; UINT8 setup_maxpage = 0; // For charsel page to identify alts easier... -void M_AddMenuColor(UINT16 color) { - menucolor_t *c; - - if (color >= numskincolors) { - CONS_Printf("M_AddMenuColor: color %d does not exist.",color); - return; - } - - // SRB2Kart: I do not understand vanilla doesn't need this but WE do???!?!??! - if (!skincolors[color].accessible) { - return; - } - - c = (menucolor_t *)malloc(sizeof(menucolor_t)); - c->color = color; - if (menucolorhead == NULL) { - c->next = c; - c->prev = c; - menucolorhead = c; - menucolortail = c; - } else { - c->next = menucolorhead; - c->prev = menucolortail; - menucolortail->next = c; - menucolorhead->prev = c; - menucolortail = c; - } - - nummenucolors++; -} - -void M_MoveColorBefore(UINT16 color, UINT16 targ) { - menucolor_t *look, *c = NULL, *t = NULL; - - if (color == targ) - return; - if (color >= numskincolors) { - CONS_Printf("M_MoveColorBefore: color %d does not exist.",color); - return; - } - if (targ >= numskincolors) { - CONS_Printf("M_MoveColorBefore: target color %d does not exist.",targ); - return; - } - - for (look=menucolorhead;;look=look->next) { - if (look->color == color) - c = look; - else if (look->color == targ) - t = look; - if (c != NULL && t != NULL) - break; - if (look==menucolortail) - return; - } - - if (c == t->prev) - return; - - if (t==menucolorhead) - menucolorhead = c; - if (c==menucolortail) - menucolortail = c->prev; - - c->prev->next = c->next; - c->next->prev = c->prev; - - c->prev = t->prev; - c->next = t; - t->prev->next = c; - t->prev = c; -} - -void M_MoveColorAfter(UINT16 color, UINT16 targ) { - menucolor_t *look, *c = NULL, *t = NULL; - - if (color == targ) - return; - if (color >= numskincolors) { - CONS_Printf("M_MoveColorAfter: color %d does not exist.\n",color); - return; - } - if (targ >= numskincolors) { - CONS_Printf("M_MoveColorAfter: target color %d does not exist.\n",targ); - return; - } - - for (look=menucolorhead;;look=look->next) { - if (look->color == color) - c = look; - else if (look->color == targ) - t = look; - if (c != NULL && t != NULL) - break; - if (look==menucolortail) - return; - } - - if (t == c->prev) - return; - - if (t==menucolortail) - menucolortail = c; - else if (c==menucolortail) - menucolortail = c->prev; - - c->prev->next = c->next; - c->next->prev = c->prev; - - c->next = t->next; - c->prev = t; - t->next->prev = c; - t->next = c; -} - -UINT16 M_GetColorBefore(UINT16 color, UINT16 amount, boolean follower) +static void M_PushMenuColor(setup_player_colors_t *colors, UINT16 newColor) { - menucolor_t *look = NULL; - - for (; amount > 0; amount--) + if (colors->listLen >= colors->listCap) { - if (follower == true) + if (colors->listCap == 0) { - if (color == FOLLOWERCOLOR_OPPOSITE) - { - look = menucolortail; - color = menucolortail->color; - continue; - } - - if (color == FOLLOWERCOLOR_MATCH) - { - look = NULL; - color = FOLLOWERCOLOR_OPPOSITE; - continue; - } - - if (color == menucolorhead->color) - { - look = NULL; - color = FOLLOWERCOLOR_MATCH; - continue; - } + colors->listCap = 64; + } + else + { + colors->listCap *= 2; } - if (color == 0 || color >= numskincolors) - { - CONS_Printf("M_GetColorBefore: color %d does not exist.\n",color); - return 0; - } - - if (look == NULL) - { - for (look = menucolorhead;; look = look->next) - { - if (look->color == color) - { - break; - } - if (look == menucolortail) - { - return 0; - } - } - } - - look = look->prev; - color = look->color; + colors->list = Z_ReallocAlign( + colors->list, + sizeof(UINT16) * colors->listCap, + PU_STATIC, + NULL, + sizeof(UINT16) * 8 + ); } - return color; + + colors->list[colors->listLen] = newColor; + colors->listLen++; } -UINT16 M_GetColorAfter(UINT16 color, UINT16 amount, boolean follower) +static void M_ClearMenuColors(setup_player_colors_t *colors) { - menucolor_t *look = NULL; - - for (; amount > 0; amount--) + if (colors->list != NULL) { - if (follower == true) - { - if (color == menucolortail->color) - { - look = NULL; - color = FOLLOWERCOLOR_OPPOSITE; - continue; - } - - if (color == FOLLOWERCOLOR_OPPOSITE) - { - look = NULL; - color = FOLLOWERCOLOR_MATCH; - continue; - } - - if (color == FOLLOWERCOLOR_MATCH) - { - look = menucolorhead; - color = menucolorhead->color; - continue; - } - } - - if (color == 0 || color >= numskincolors) - { - CONS_Printf("M_GetColorAfter: color %d does not exist.\n",color); - return 0; - } - - if (look == NULL) - { - for (look = menucolorhead;; look = look->next) - { - if (look->color == color) - { - break; - } - if (look == menucolortail) - { - return 0; - } - } - } - - look = look->next; - color = look->color; + Z_Free(colors->list); + colors->list = NULL; } - return color; + + colors->listLen = colors->listCap = 0; } -void M_InitPlayerSetupColors(void) { - UINT8 i; - numskincolors = SKINCOLOR_FIRSTFREESLOT; - menucolorhead = menucolortail = NULL; - for (i=0; ilistLen == 0) + { + return value; + } - if (menucolorhead==NULL) - return; - - while (true) { - if (look != menucolortail) { - tmp = look; - look = look->next; - free(tmp); - } else { - free(look); - return; + for (i = 0; i < colors->listLen; i++) + { + if (colors->list[i] == value) + { + index = i; + break; } } - menucolorhead = menucolortail = NULL; + if (index == -1) + { + // Not in list, so no real correct behavior here. + // Just try to get back to the list. + return colors->list[0]; + } + + amount = abs(amount); + + while (amount > 0) + { + index += sign; + + if (index < 0) + { + index = colors->listLen - 1; + } + else if (index >= (INT32)colors->listLen) + { + index = 0; + } + + amount--; + } + + return colors->list[index]; +} + +static void M_NewPlayerColors(setup_player_t *p) +{ + const boolean follower = (p->mdepth >= CSSTEP_FOLLOWER); + INT32 i = INT32_MAX; + + M_ClearMenuColors(&p->colors); + + // Add all unlocked colors + for (i = SKINCOLOR_NONE+1; i < numskincolors; i++) + { + if (K_ColorUsable(i, follower) == true) + { + M_PushMenuColor(&p->colors, i); + } + } + + // Add special colors + M_PushMenuColor(&p->colors, SKINCOLOR_NONE); + + if (follower == true) + { + // Add special follower colors + M_PushMenuColor(&p->colors, FOLLOWERCOLOR_MATCH); + M_PushMenuColor(&p->colors, FOLLOWERCOLOR_OPPOSITE); + } } // sets up the grid pos for the skin used by the profile. @@ -346,7 +201,7 @@ static void M_SetupProfileGridPos(setup_player_t *p) alt++; p->clonenum = alt; - p->color = PR_GetProfileColor(pr); + p->color = pr->color; } static void M_SetupMidGameGridPos(setup_player_t *p, UINT8 num) @@ -403,7 +258,7 @@ void M_CharacterSelectInit(void) // Default to no follower / match colour. setup_player[i].followern = -1; setup_player[i].followercategory = -1; - setup_player[i].followercolor = FOLLOWERCOLOR_MATCH; + setup_player[i].followercolor = SKINCOLOR_NONE; // If we're on prpfile select, skip straight to CSSTEP_CHARS // do the same if we're midgame, but make sure to consider splitscreen properly. @@ -876,6 +731,7 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num) else { p->mdepth = CSSTEP_COLORS; + M_NewPlayerColors(p); S_StartSound(NULL, sfx_s3k63); } } @@ -889,9 +745,14 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num) else { if (setup_page+1 == setup_chargrid[p->gridx][p->gridy].numskins) + { p->mdepth = CSSTEP_COLORS; // Skip clones menu if there are none on this page. + M_NewPlayerColors(p); + } else + { p->mdepth = CSSTEP_ALTS; + } S_StartSound(NULL, sfx_s3k63); } @@ -964,8 +825,30 @@ static void M_HandleCharRotate(setup_player_t *p, UINT8 num) if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) { p->mdepth = CSSTEP_COLORS; - S_StartSound(NULL, sfx_s3k63); - M_SetMenuDelay(num); + M_NewPlayerColors(p); + if (p->colors.listLen == 1) + { + p->color = p->colors.list[0]; + if (setup_numfollowercategories == 0) + { + p->followern = -1; + p->mdepth = CSSTEP_READY; + p->delay = TICRATE; + M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); + S_StartSound(NULL, sfx_s3k4e); + } + else + { + p->mdepth = CSSTEP_FOLLOWERCATEGORY; + S_StartSound(NULL, sfx_s3k63); + M_SetMenuDelay(num); + } + } + else + { + S_StartSound(NULL, sfx_s3k63); + M_SetMenuDelay(num); + } } else if (M_MenuBackPressed(num)) { @@ -992,14 +875,14 @@ static void M_HandleColorRotate(setup_player_t *p, UINT8 num) if (menucmd[num].dpad_lr > 0) { - p->color = M_GetColorAfter(p->color, 1, false); + p->color = M_GetColorAfter(&p->colors, p->color, 1); p->rotate = CSROTATETICS; M_SetMenuDelay(num); //CSROTATETICS S_StartSound(NULL, sfx_s3k5b); //sfx_s3kc3s } else if (menucmd[num].dpad_lr < 0) { - p->color = M_GetColorBefore(p->color, 1, false); + p->color = M_GetColorBefore(&p->colors, p->color, 1); p->rotate = -CSROTATETICS; M_SetMenuDelay(num); //CSROTATETICS S_StartSound(NULL, sfx_s3k5b); //sfx_s3kc3s @@ -1007,9 +890,20 @@ static void M_HandleColorRotate(setup_player_t *p, UINT8 num) if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) { - p->mdepth = CSSTEP_FOLLOWERCATEGORY; - S_StartSound(NULL, sfx_s3k63); - M_SetMenuDelay(num); + if (setup_numfollowercategories == 0) + { + p->followern = -1; + p->mdepth = CSSTEP_READY; + p->delay = TICRATE; + M_SetupReadyExplosions(true, p->gridx, p->gridy, p->color); + S_StartSound(NULL, sfx_s3k4e); + } + else + { + p->mdepth = CSSTEP_FOLLOWERCATEGORY; + S_StartSound(NULL, sfx_s3k63); + M_SetMenuDelay(num); + } } else if (M_MenuBackPressed(num)) { @@ -1029,7 +923,7 @@ static void M_HandleColorRotate(setup_player_t *p, UINT8 num) { if (p->skin >= 0) { - p->color = skins[p->skin].prefcolor; + p->color = SKINCOLOR_NONE; p->rotate = CSROTATETICS; p->hitlag = true; S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s @@ -1131,6 +1025,7 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num) else if (M_MenuBackPressed(num)) { p->mdepth = CSSTEP_COLORS; + M_NewPlayerColors(p); S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } @@ -1196,6 +1091,7 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num) if (p->followern > -1) { p->mdepth = CSSTEP_FOLLOWERCOLORS; + M_NewPlayerColors(p); S_StartSound(NULL, sfx_s3k63); } else @@ -1234,14 +1130,14 @@ static void M_HandleFollowerColorRotate(setup_player_t *p, UINT8 num) if (menucmd[num].dpad_lr > 0) { - p->followercolor = M_GetColorAfter(p->followercolor, 1, true); + p->followercolor = M_GetColorAfter(&p->colors, p->followercolor, 1); p->rotate = CSROTATETICS; M_SetMenuDelay(num); //CSROTATETICS S_StartSound(NULL, sfx_s3k5b); //sfx_s3kc3s } else if (menucmd[num].dpad_lr < 0) { - p->followercolor = M_GetColorBefore(p->followercolor, 1, true); + p->followercolor = M_GetColorBefore(&p->colors, p->followercolor, 1); p->rotate = -CSROTATETICS; M_SetMenuDelay(num); //CSROTATETICS S_StartSound(NULL, sfx_s3k5b); //sfx_s3kc3s @@ -1266,10 +1162,10 @@ static void M_HandleFollowerColorRotate(setup_player_t *p, UINT8 num) { if (p->followercolor == FOLLOWERCOLOR_MATCH) p->followercolor = FOLLOWERCOLOR_OPPOSITE; - else if (p->followercolor == followers[p->followern].defaultcolor) + else if (p->followercolor == SKINCOLOR_NONE) p->followercolor = FOLLOWERCOLOR_MATCH; else - p->followercolor = followers[p->followern].defaultcolor; + p->followercolor = SKINCOLOR_NONE; p->rotate = CSROTATETICS; p->hitlag = true; S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s @@ -1343,6 +1239,7 @@ boolean M_CharacterSelectHandler(INT32 choice) if (M_MenuBackPressed(i)) { p->mdepth = CSSTEP_COLORS; + M_NewPlayerColors(p); S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(i); } diff --git a/src/p_saveg.c b/src/p_saveg.c index 8806af267..6fea134e7 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2466,6 +2466,31 @@ static UINT32 SaveSlope(const pslope_t *slope) return 0xFFFFFFFF; } +static boolean TypeIsNetSynced(mobjtype_t type) +{ + // Ignore stationary hoops - these will be respawned from mapthings. + if (type == MT_HOOP) + return false; + + // These are NEVER saved. + if (type == MT_HOOPCOLLIDE) + return false; + + // This hoop has already been collected. + if (type == MT_HOOPCENTER)// && mobj->threshold == 4242) + return false; + + // MT_SPARK: used for debug stuff + if (type == MT_SPARK) + return false; + + // MT_HORNCODE: So it turns out hornmod is fundamentally incompatible with netsync + if (type == MT_HORNCODE) + return false; + + return true; +} + static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const mobj_t *mobj = (const mobj_t *)th; @@ -2473,20 +2498,7 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 UINT32 diff2; size_t j; - // Ignore stationary hoops - these will be respawned from mapthings. - if (mobj->type == MT_HOOP) - return; - - // These are NEVER saved. - if (mobj->type == MT_HOOPCOLLIDE) - return; - - // This hoop has already been collected. - if (mobj->type == MT_HOOPCENTER && mobj->threshold == 4242) - return; - - // MT_SPARK: used for debug stuff - if (mobj->type == MT_SPARK) + if (TypeIsNetSynced(mobj->type) == false) return; diff2 = 0; @@ -5117,9 +5129,7 @@ static void P_RelinkPointers(void) mobj = (mobj_t *)currentthinker; - if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER - // MT_SPARK: used for debug stuff - || mobj->type == MT_SPARK) + if (TypeIsNetSynced(mobj->type) == false) continue; if (mobj->tracer) @@ -6042,9 +6052,7 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending) continue; mobj = (mobj_t *)th; - if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER - // MT_SPARK: used for debug stuff - || mobj->type == MT_SPARK) + if (TypeIsNetSynced(mobj->type) == false) continue; mobj->mobjnum = i++; } diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 47a2c8412..0ab23236b 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -1675,7 +1675,6 @@ void I_Quit(void) D_QuitNetGame(); CL_AbortDownloadResume(); - M_FreePlayerSetupColors(); I_ShutdownMusic(); I_ShutdownSound(); // use this for 1.28 19990220 by Kin @@ -1801,7 +1800,6 @@ void I_Error(const char *error, ...) D_QuitNetGame(); CL_AbortDownloadResume(); - M_FreePlayerSetupColors(); I_ShutdownMusic(); I_ShutdownGraphics(); diff --git a/src/sounds.c b/src/sounds.c index 3accd6b79..61003c11d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1183,8 +1183,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"clawk1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SF_X8AWAYSOUND {"clawk2", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SF_X8AWAYSOUND - {"monch", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"etexpl", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Game crash"}, + {"horn00", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "/"}, // HORNCODE + {"monch", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"etexpl", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Game crash"}, {"iwhp", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Instawhip attack {"gbrk", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Guard break! diff --git a/src/sounds.h b/src/sounds.h index 033728e37..5c2aea153 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1252,6 +1252,7 @@ typedef enum sfx_clawk1, sfx_clawk2, + sfx_horn00, sfx_monch, sfx_etexpl, diff --git a/src/typedef.h b/src/typedef.h index 013bf7f18..59b187f9e 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -190,6 +190,7 @@ TYPEDEF (menucolor_t); TYPEDEF (menuitem_t); TYPEDEF (menu_t); TYPEDEF (menucmd_t); +TYPEDEF (setup_player_colors_t); TYPEDEF (setup_player_t); TYPEDEF (modedesc_t);