SECRET_COLOR

This commit is contained in:
Sally Coolatta 2023-04-21 21:22:53 -04:00 committed by toaster
parent 7554943f02
commit c486ec19af
21 changed files with 519 additions and 590 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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 <graue@oceanbase.org>
*/
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 <graue@oceanbase.org>
*/
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.

View file

@ -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;

View file

@ -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"))

View file

@ -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
{

View file

@ -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

View file

@ -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]);
}
//}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);
/*--------------------------------------------------

View file

@ -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];

View file

@ -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;

View file

@ -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;
}

View file

@ -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},

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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; i<numskincolors; i++)
M_AddMenuColor(i);
}
UINT16 M_GetColorAfter(setup_player_colors_t *colors, UINT16 value, INT32 amount)
{
const INT32 sign = (amount < 0) ? -1 : 1;
INT32 index = -1;
size_t i = SIZE_MAX;
void M_FreePlayerSetupColors(void) {
menucolor_t *look = menucolorhead, *tmp;
if (amount == 0 || colors->listLen == 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);
}

View file

@ -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();

View file

@ -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);