diff --git a/src/command.c b/src/command.c index 6cacd3bcd..3d6ec3529 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. @@ -911,9 +912,9 @@ static void COM_Help_f(void) CONS_Printf(" On or Off (Yes or No, 1 or 0)\n"); else if (cvar->PossibleValue == Color_cons_t) { - for (i = 1; i < numskincolors; ++i) + for (i = SKINCOLOR_NONE; i < numskincolors; ++i) { - if (skincolors[i].accessible) + if (K_ColorUsable(i, false) == true) { CONS_Printf(" %-2d : %s\n", i, skincolors[i].name); if (i == cvar->value) diff --git a/src/d_main.c b/src/d_main.c index 1d07c9298..254eeb8ea 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]; @@ -1456,10 +1456,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 f97203ce0..f149bcbb2 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -121,11 +121,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); @@ -139,7 +139,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); @@ -271,7 +271,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) @@ -279,14 +279,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) @@ -1451,94 +1451,69 @@ 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]; + player_t *player = NULL; char buf[MAXPLAYERNAME+12]; char *p; - UINT16 i = 0; + UINT16 sendColor = cv_playercolor[n].value; + UINT16 sendFollowerColor = cv_followercolor[n].value; if (splitscreen < n) + { return; // can happen if skin4/color4/name4 changed + } if (playernum == -1) + { return; + } + + player = &players[playernum]; p = buf; // 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 old color + CV_StealthSetValue(&cv_playercolor[n], SKINCOLOR_NONE); } + + sendColor = cv_playercolor[n].value; } // ditto for follower colour: - if (!cv_followercolor[n].value) + if (sendFollowerColor != SKINCOLOR_NONE && K_ColorUsable(sendFollowerColor, true) == false) + { CV_StealthSet(&cv_followercolor[n], "Match"); // set it to "Match". I don't care about your stupidity! + sendFollowerColor = cv_followercolor[n].value; + } + // Don't send if everything was identical. if (!strcmp(cv_playername[n].string, player_names[playernum]) - && cv_playercolor[n].value == player->skincolor + && 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)) - && cv_followercolor[n].value == player->followercolor) + && sendFollowerColor == player->followercolor) + { return; + } // 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; } @@ -1548,16 +1523,22 @@ static void SendNameAndColor(UINT8 n) 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); + 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) @@ -1575,6 +1556,16 @@ 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) + { + sendFollowerColor = followers[cv_follower[n].value].defaultcolor; + } + // Finally write out the complete packet and send it off. WRITESTRINGN(p, cv_playername[n].zstring, MAXPLAYERNAME); WRITEUINT16(p, (UINT16)cv_playercolor[n].value); @@ -1674,8 +1665,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) { @@ -6425,50 +6418,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 @@ -6529,29 +6508,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 @@ -6559,79 +6549,63 @@ 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()) + UINT16 color = SKINCOLOR_NONE; + + I_Assert(p < MAXSPLITSCREENPLAYERS); + + color = cv_playercolor[p].value; + + if (!Playing() || splitscreen < p) { - if (!cv_playercolor[0].value || !skincolors[cv_playercolor[0].value].accessible) - CV_StealthSetValue(&cv_playercolor[0], lastgoodcolor[0]); + if (color != SKINCOLOR_NONE && K_ColorUsable(color, false) == false) + { + CV_StealthSetValue(&cv_playercolor[p], lastgoodcolor[p]); + color = cv_playercolor[p].value; + } } else { - if (!CV_CheatsEnabled() && !(multiplayer || netgame)) // In single player. - { - CV_StealthSet(&cv_skin[0], skins[players[consoleplayer].skin].name); - return; - } + player_t *const player = &players[ g_localplayers[p] ]; - if (!P_PlayerMoving(consoleplayer) && skincolors[players[consoleplayer].skincolor].accessible == true) + if (P_PlayerMoving(g_localplayers[p]) == false && K_ColorUsable(color, false) == true) { // Color change menu scrolling fix is no longer necessary - SendNameAndColor(0); + SendNameAndColor(p); } else { - CV_StealthSetValue(&cv_playercolor[0], - players[consoleplayer].skincolor); + CV_StealthSetValue(&cv_playercolor[p], player->skincolor); + color = cv_playercolor[p].value; } } - lastgoodcolor[0] = cv_playercolor[0].value; - G_SetPlayerGamepadIndicatorToPlayerColor(0); + 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 @@ -6641,77 +6615,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/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 751c3c07a..af6cff99c 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -321,7 +321,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) @@ -2297,6 +2297,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")) diff --git a/src/doomdef.h b/src/doomdef.h index 99b79c03a..9480e1cd1 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 505ad5373..a31f6b8df 100644 --- a/src/info.c +++ b/src/info.c @@ -29546,7 +29546,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/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 daa7b9d0d..df9735000 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -234,19 +234,33 @@ 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" + { + return follower->defaultcolor; + } + + if (followercolor > SKINCOLOR_NONE && followercolor < numskincolors) // bog standard + { return followercolor; + } if (followercolor == FOLLOWERCOLOR_OPPOSITE) // "Opposite" + { return skincolors[playercolor].invcolor; + } + + // "Match" + if (playercolor == SKINCOLOR_NONE && playerskin != NULL) + { + return playerskin->prefcolor; + } - //if (followercolor == FOLLOWERCOLOR_MATCH) -- "Match" return playercolor; } @@ -286,7 +300,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 +340,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 +364,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 +383,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 +393,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 +404,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 +436,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 +462,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 +481,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 +515,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 +541,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 +573,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 +608,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 +622,26 @@ 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); } } diff --git a/src/k_follower.h b/src/k_follower.h index 288bb34b8..d01939040 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -170,20 +170,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); /*-------------------------------------------------- diff --git a/src/k_menu.h b/src/k_menu.h index 5a343f0f7..5851ad8f5 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -614,17 +614,12 @@ void M_DrawMenuMessage(void); 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 { @@ -649,6 +644,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; @@ -676,6 +678,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 06d8e95d0..f37f86e93 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -972,7 +972,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; @@ -980,9 +981,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; } @@ -1035,20 +1033,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); @@ -1145,7 +1143,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 ); } @@ -1164,18 +1162,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); @@ -1265,14 +1263,13 @@ static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, boolean charf // 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) @@ -1284,7 +1281,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) { @@ -1317,13 +1314,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; } @@ -1335,12 +1335,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, charflip, (p->mdepth == CSSTEP_READY), 0, colormap); @@ -1387,9 +1399,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)); } @@ -1620,6 +1632,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; @@ -1637,7 +1650,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) { @@ -1722,7 +1748,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); @@ -1732,8 +1758,13 @@ 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); + UINT16 col = K_GetEffectiveFollowerColor( + p->followercolor, + K_FollowerUsable(fln) ? &followers[fln] : 0, + p->color, + &skins[skinnum] + ); if (R_SkinUsable(g_localplayers[0], skinnum, false)) ccolormap = colormap; @@ -4857,9 +4888,9 @@ 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; @@ -4922,12 +4953,23 @@ 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 = 0; + break; + } case SECRET_HARDSPEED: iconid = 3; @@ -5160,7 +5202,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); @@ -5174,6 +5216,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, false, false, 0, colormap); + break; + } case SECRET_CUP: { levelsearch_t templevelsearch; diff --git a/src/k_profiles.c b/src/k_profiles.c index e536f95e3..28a3f2e83 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. @@ -367,7 +368,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; } @@ -383,7 +384,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; } diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 5bbbace87..9d1ed857f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -337,49 +337,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; } @@ -3935,12 +3897,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 5b551f646..f81c31fbf 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -2048,6 +2048,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 9fdb5bd2e..81141039e 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -181,6 +181,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 @@ -358,6 +359,7 @@ UINT8 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 93c0f3ffe..341b488b4 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -462,7 +462,8 @@ void M_ChallengesTick(void) INT32 skin = M_UnlockableFollowerNum(ref); if (skin != -1) { - bombcolor = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value); + INT32 psk = R_SkinAvailable(cv_skin[0].string); + bombcolor = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, &followers[skin], cv_playercolor[0].value, (psk != -1) ? &skins[psk] : &skins[0]); } break; } diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 35e918a65..a9acfba2d 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" menuitem_t PLAY_CharSelect[] = { @@ -36,8 +38,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' @@ -53,261 +53,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. @@ -409,7 +264,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; // Set default selected profile to the last used profile for each player: // (Make sure we don't overshoot it somehow if we deleted profiles or whatnot) @@ -878,6 +733,7 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num) else { p->mdepth = CSSTEP_COLORS; + M_NewPlayerColors(p); S_StartSound(NULL, sfx_s3k63); } } @@ -891,9 +747,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); } @@ -966,6 +827,7 @@ static void M_HandleCharRotate(setup_player_t *p, UINT8 num) if (M_MenuConfirmPressed(num) /*|| M_MenuButtonPressed(num, MBT_START)*/) { p->mdepth = CSSTEP_COLORS; + M_NewPlayerColors(p); S_StartSound(NULL, sfx_s3k63); M_SetMenuDelay(num); } @@ -994,14 +856,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 @@ -1031,7 +893,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 @@ -1133,6 +995,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); } @@ -1236,14 +1099,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 @@ -1268,10 +1131,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 @@ -1345,6 +1208,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/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/typedef.h b/src/typedef.h index 6b9649ca3..2ecdba75e 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -185,6 +185,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);