From 766f7f035fa64e09f0b67f54bc8c4f5f30ef07b9 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Mon, 4 May 2020 18:08:41 +0200 Subject: [PATCH] Let followers change colour separatly from players --- src/d_netcmd.c | 118 +++++++++++++++++++++++++++++++++++++++----- src/d_player.h | 1 + src/dehacked.c | 19 ++++++- src/g_game.c | 17 ++++++- src/lua_playerlib.c | 6 ++- src/p_saveg.c | 2 + src/p_user.c | 15 +++++- src/r_data.h | 1 + src/r_draw.c | 1 + src/r_things.c | 2 +- src/r_things.h | 2 + 11 files changed, 166 insertions(+), 18 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b8b9f98a7..d4ef8f22c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -113,10 +113,16 @@ static void Skin_OnChange(void); static void Skin2_OnChange(void); static void Skin3_OnChange(void); static void Skin4_OnChange(void); + static void Follower_OnChange(void); static void Follower2_OnChange(void); static void Follower3_OnChange(void); static void Follower4_OnChange(void); +static void Followercolor_OnChange(void); +static void Followercolor2_OnChange(void); +static void Followercolor3_OnChange(void); +static void Followercolor4_OnChange(void); + static void Color_OnChange(void); static void Color2_OnChange(void); static void Color3_OnChange(void); @@ -300,6 +306,13 @@ consvar_t cv_follower2 = {"follower2", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Fo consvar_t cv_follower3 = {"follower3", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower3_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_follower4 = {"follower4", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower4_OnChange, 0, NULL, NULL, 0, 0, NULL}; +// player's follower colors... Also saved... +consvar_t cv_followercolor = {"followercolor", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_followercolor2 = {"followercolor2", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor2_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_followercolor3 = {"followercolor3", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor3_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_followercolor4 = {"followercolor4", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor4_OnChange, 0, NULL, NULL, 0, 0, NULL}; + + // Follower toggle static CV_PossibleValue_t followers_cons_t[] = {{0, "Yours only"}, {1, "Everyone's"}, {0, NULL}}; consvar_t cv_showfollowers = {"showfollowers", "Everyone's", CV_SAVE, followers_cons_t, 0, 0, NULL, NULL, 0, 0, NULL}; @@ -803,11 +816,14 @@ void D_RegisterClientCommands(void) for (i = 0; i < MAXSKINCOLORS; i++) { - Color_cons_t[i].value = i; - Color_cons_t[i].strvalue = KartColor_Names[i]; // SRB2kart + Color_cons_t[i].value = Followercolor_cons_t[i].value = i; + Color_cons_t[i].strvalue = Followercolor_cons_t[i].strvalue = KartColor_Names[i]; // SRB2kart } - Color_cons_t[MAXSKINCOLORS].value = 0; - Color_cons_t[MAXSKINCOLORS].strvalue = NULL; + Color_cons_t[MAXSKINCOLORS].value = Followercolor_cons_t[MAXSKINCOLORS+1].value = 0; + Color_cons_t[MAXSKINCOLORS].strvalue = Followercolor_cons_t[MAXSKINCOLORS+1].strvalue = NULL; + + Followercolor_cons_t[MAXSKINCOLORS].value = MAXSKINCOLORS; + Followercolor_cons_t[MAXSKINCOLORS].strvalue = "Match"; // Add "Match" option, which will make the follower color match the player's if (dedicated) return; @@ -880,22 +896,26 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_playercolor); CV_RegisterVar(&cv_skin); // r_things.c (skin NAME) CV_RegisterVar(&cv_follower); + CV_RegisterVar(&cv_followercolor); CV_RegisterVar(&cv_showfollowers); // secondary player (splitscreen) CV_RegisterVar(&cv_playername2); CV_RegisterVar(&cv_playercolor2); CV_RegisterVar(&cv_skin2); CV_RegisterVar(&cv_follower2); + CV_RegisterVar(&cv_followercolor2); // third player CV_RegisterVar(&cv_playername3); CV_RegisterVar(&cv_playercolor3); CV_RegisterVar(&cv_skin3); CV_RegisterVar(&cv_follower3); + CV_RegisterVar(&cv_followercolor3); // fourth player CV_RegisterVar(&cv_playername4); CV_RegisterVar(&cv_playercolor4); CV_RegisterVar(&cv_skin4); CV_RegisterVar(&cv_follower4); + CV_RegisterVar(&cv_followercolor4); // preferred number of players CV_RegisterVar(&cv_splitplayers); @@ -1478,16 +1498,14 @@ static void SendNameAndColor(void) CV_StealthSet(&cv_playercolor, cv_playercolor.defaultvalue); } + // ditto for follower colour: + if (!cv_followercolor.value) + CV_StealthSet(&cv_followercolor, "Match"); // set it to "Match". I don't care about your stupidity! + // so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game: if (cv_follower.value > numfollowers-1 || cv_follower.value < -1) CV_StealthSet(&cv_follower, "-1"); - if (!strcmp(cv_playername.string, player_names[consoleplayer]) - && cv_playercolor.value == players[consoleplayer].skincolor - && !strcmp(cv_skin.string, skins[players[consoleplayer].skin].name) - && cv_follower.value == players[consoleplayer].followerskin) - return; - // We'll handle it later if we're not playing. if (!Playing()) return; @@ -1573,6 +1591,7 @@ static void SendNameAndColor(void) WRITEUINT8(p, (UINT8)cv_playercolor.value); WRITEUINT8(p, (UINT8)cv_skin.value); WRITESINT8(p, (UINT8)cv_follower.value); + WRITESINT8(p, (UINT8)cv_followercolor.value); SendNetXCmd(XD_NAMEANDCOLOR, buf, p - buf); } @@ -1616,6 +1635,10 @@ static void SendNameAndColor2(void) CV_StealthSet(&cv_playercolor2, cv_playercolor2.defaultvalue); } + // ditto for follower colour: + if (!cv_followercolor2.value) + CV_StealthSet(&cv_followercolor2, "Match"); // set it to "Match". I don't care about your stupidity! + // so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game: if (cv_follower2.value > numfollowers-1 || cv_follower2.value < -1) CV_StealthSet(&cv_follower2, "-1"); @@ -1706,6 +1729,7 @@ static void SendNameAndColor2(void) WRITEUINT8(p, (UINT8)cv_playercolor2.value); WRITEUINT8(p, (UINT8)cv_skin2.value); WRITESINT8(p, (UINT8)cv_follower2.value); + WRITESINT8(p, (UINT8)cv_followercolor2.value); SendNetXCmd2(XD_NAMEANDCOLOR, buf, p - buf); } @@ -1737,6 +1761,10 @@ static void SendNameAndColor3(void) CV_StealthSetValue(&cv_playercolor3, skincolor_blueteam); } + // ditto for follower colour: + if (!cv_followercolor3.value) + CV_StealthSet(&cv_followercolor3, "Match"); // set it to "Match". I don't care about your stupidity! + // never allow the color "none" if (!cv_playercolor3.value) { @@ -1830,6 +1858,7 @@ static void SendNameAndColor3(void) WRITEUINT8(p, (UINT8)cv_playercolor3.value); WRITEUINT8(p, (UINT8)cv_skin3.value); WRITESINT8(p, (UINT8)cv_follower3.value); + WRITESINT8(p, (UINT8)cv_followercolor3.value); SendNetXCmd3(XD_NAMEANDCOLOR, buf, p - buf); } @@ -1861,6 +1890,10 @@ static void SendNameAndColor4(void) CV_StealthSetValue(&cv_playercolor4, skincolor_blueteam); } + // ditto for follower colour: + if (!cv_followercolor4.value) + CV_StealthSet(&cv_followercolor4, "Match"); // set it to "Match". I don't care about your stupidity! + // never allow the color "none" if (!cv_playercolor4.value) { @@ -1962,6 +1995,7 @@ static void SendNameAndColor4(void) WRITEUINT8(p, (UINT8)cv_playercolor4.value); WRITEUINT8(p, (UINT8)cv_skin4.value); WRITESINT8(p, (UINT8)cv_follower4.value); + WRITESINT8(p, (UINT8)cv_followercolor4.value); SendNetXCmd4(XD_NAMEANDCOLOR, buf, p - buf); } @@ -1969,7 +2003,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) { player_t *p = &players[playernum]; char name[MAXPLAYERNAME+1]; - UINT8 color, skin; + UINT8 color, skin, followercolor; SINT8 follower; #ifdef PARANOIA @@ -1995,6 +2029,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) color = READUINT8(*cp); skin = READUINT8(*cp); follower = READSINT8(*cp); + followercolor = READSINT8(*cp); // set name if (strcasecmp(player_names[playernum], name) != 0) @@ -2055,7 +2090,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) else SetPlayerSkinByNum(playernum, skin); - // set follower: + // set follower colour: + // Don't bother doing garbage and kicking if we receive None, this is both silly and a waste of time, this will be handled properly in P_HandleFollower. + p->followercolor = followercolor; + + // set follower SetFollower(playernum, follower); } @@ -6208,6 +6247,22 @@ static void Follower_OnChange(void) SendNameAndColor(); } +// About the same as Color_OnChange but for followers. +static void Followercolor_OnChange(void) +{ + + if (!Playing()) + return; // do whatever you want if you aren't in the game or don't have a follower. + + if (!P_PlayerMoving(consoleplayer)) + { + // Color change menu scrolling fix is no longer necessary + SendNameAndColor(); + } +} + +// repeat for the 3 other players + static void Follower2_OnChange(void) { char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1]; @@ -6239,6 +6294,19 @@ static void Follower2_OnChange(void) SendNameAndColor2(); } +static void Followercolor2_OnChange(void) +{ + + if (!Playing()) + return; // do whatever you want if you aren't in the game or don't have a follower. + + if (!P_PlayerMoving(g_localplayers[1])) + { + // Color change menu scrolling fix is no longer necessary + SendNameAndColor2(); + } +} + static void Follower3_OnChange(void) { char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1]; @@ -6269,6 +6337,19 @@ static void Follower3_OnChange(void) SendNameAndColor3(); } +static void Followercolor3_OnChange(void) +{ + + if (!Playing()) + return; // do whatever you want if you aren't in the game or don't have a follower. + + if (!P_PlayerMoving(g_localplayers[2])) + { + // Color change menu scrolling fix is no longer necessary + SendNameAndColor3(); + } +} + static void Follower4_OnChange(void) { char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1]; @@ -6299,6 +6380,19 @@ static void Follower4_OnChange(void) SendNameAndColor4(); } +static void Followercolor4_OnChange(void) +{ + + if (!Playing()) + return; // do whatever you want if you aren't in the game or don't have a follower. + + if (!P_PlayerMoving(g_localplayers[3])) + { + // Color change menu scrolling fix is no longer necessary + SendNameAndColor4(); + } +} + /** Sends a skin change for the console player, unless that player is moving. * \sa cv_skin, Skin2_OnChange, Color_OnChange * \author Graue diff --git a/src/d_player.h b/src/d_player.h index c6288bc58..313f654b4 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -493,6 +493,7 @@ typedef struct player_s INT32 followerskin; // Kart: This player's follower "skin" boolean followerready; // Kart: Used to know when we can have a follower or not. (This is set on the first NameAndColor follower update) + UINT8 followercolor; // Kart: Used to store the follower colour the player wishes to use mobj_t *follower; // Kart: This is the follower object we have. (If any) // diff --git a/src/dehacked.c b/src/dehacked.c index 6d08e5f33..3d633e518 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -720,7 +720,7 @@ static void readfollower(MYFILE *f) // Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead. followers[numfollowers].scale = FRACUNIT; followers[numfollowers].atangle = 230; - followers[numfollowers].dist = 16; + followers[numfollowers].dist = 32; // changed from 16 to 32 to better account for ogl models followers[numfollowers].height = 16; followers[numfollowers].zoffs = 32; followers[numfollowers].horzlag = 2; @@ -728,6 +728,7 @@ static void readfollower(MYFILE *f) followers[numfollowers].bobspeed = TICRATE*2; followers[numfollowers].bobamp = 4; followers[numfollowers].hitconfirmtime = TICRATE; + followers[numfollowers].defaultcolor = 1; do { @@ -762,6 +763,12 @@ static void readfollower(MYFILE *f) strcpy(followers[numfollowers].name, word2); nameset = true; } + else if (fastcmp(word, "DEFAULTCOLOR")) + { + DEH_WriteUndoline(word, va("%d", followers[numfollowers].defaultcolor), UNDO_NONE); + followers[numfollowers].defaultcolor = get_number(word2); + } + else if (fastcmp(word, "SCALE")) { DEH_WriteUndoline(word, va("%d", followers[numfollowers].scale), UNDO_NONE); @@ -806,7 +813,7 @@ static void readfollower(MYFILE *f) { DEH_WriteUndoline(word, va("%d", followers[numfollowers].height), UNDO_NONE); followers[numfollowers].height = (INT32)atoi(word2); - } + } else if (fastcmp(word, "IDLESTATE")) { if (word2) @@ -910,6 +917,14 @@ if (followers[numfollowers].field < threshold) \ FALLBACK(bobamp, "BOBAMP", 0, 0); FALLBACK(bobspeed, "BOBSPEED", 0, 0); FALLBACK(hitconfirmtime, "HITCONFIRMTIME", 1, 1); + + // Special case for color I suppose + if (followers[numfollowers].defaultcolor < 0 || followers[numfollowers].defaultcolor > MAXSKINCOLORS-1) + { + followers[numfollowers].defaultcolor = 1; + deh_warning("Follower \'%s\': Value for 'color' should be between 1 and %d.\n", dname, MAXSKINCOLORS-1); + } + #undef FALLBACK // also check if we forgot states. If we did, we will set any missing state to the follower's idlestate. diff --git a/src/g_game.c b/src/g_game.c index 2fa4b8e7a..838f1f244 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2561,6 +2561,7 @@ void G_PlayerReborn(INT32 player) UINT8 kartweight; boolean followerready; INT32 followerskin; + UINT8 followercolor; mobj_t *follower; // old follower, will probably be removed by the time we're dead but you never know. // INT32 charflags; @@ -2624,6 +2625,7 @@ void G_PlayerReborn(INT32 player) kartweight = players[player].kartweight; follower = players[player].follower; followerready = players[player].followerready; + followercolor = players[player].followercolor; followerskin = players[player].followerskin; // charflags = players[player].charflags; @@ -2740,6 +2742,7 @@ void G_PlayerReborn(INT32 player) p->followerready = followerready; p->followerskin = followerskin; + p->followercolor = followercolor; p->follower = NULL; // respawn a new one with you, it looks better. @@ -5010,6 +5013,18 @@ void G_ReadDemoExtraData(void) M_Memcpy(name, demo_p, 16); demo_p += 16; SetPlayerFollower(p, name); + + // Follower's color + M_Memcpy(name, demo_p, 16); + demo_p += 16; + for (i = 0; i < MAXSKINCOLORS; i++) + if (!stricmp(KartColor_Names[i], name)) // SRB2kart + { + players[p].followercolor = i; + break; + } + + } if (extradata & DXD_PLAYSTATE) { @@ -5740,7 +5755,7 @@ void G_GhostTicker(void) if (ziptic & DXD_NAME) g->p += 16; // yea if (ziptic & DXD_FOLLOWER) - g->p += 16; // ok + g->p += 32; // ok (32 because there's both the skin and the colour) if (ziptic & DXD_PLAYSTATE && READUINT8(g->p) != DXD_PST_PLAYING) I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this } diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 3276bfa73..5a5b770b3 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -158,6 +158,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->followerskin); else if (fastcmp(field,"followerready")) lua_pushboolean(L, plr->followerready); + else if (fastcmp(field,"followercolor")) + lua_pushinteger(L, plr->followercolor); else if (fastcmp(field,"follower")) LUA_PushUserdata(L, plr->follower, META_MOBJ); // @@ -297,7 +299,7 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->awayviewtics); else if (fastcmp(field,"awayviewaiming")) lua_pushangle(L, plr->awayviewaiming); - + else if (fastcmp(field,"spectator")) lua_pushboolean(L, plr->spectator); else if (fastcmp(field,"bot")) @@ -411,6 +413,8 @@ static int player_set(lua_State *L) plr->kartweight = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"followerskin")) plr->followerskin = luaL_checkinteger(L, 3); + else if (fastcmp(field,"followercolor")) + plr->followercolor = luaL_checkinteger(L, 3); else if (fastcmp(field,"followerready")) plr->followerready = luaL_checkboolean(L, 3); else if (fastcmp(field,"follower")) // it's probably best we don't allow the follower mobj to change. diff --git a/src/p_saveg.c b/src/p_saveg.c index da2e77b00..a7f13a874 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -283,6 +283,7 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].followerskin); WRITEUINT8(save_p, players[i].followerready); // booleans are really just numbers eh?? + WRITEUINT8(save_p, players[i].followercolor); if (flags & FOLLOWER) WRITEUINT32(save_p, players[i].follower->mobjnum); @@ -463,6 +464,7 @@ static void P_NetUnArchivePlayers(void) players[i].followerskin = READUINT8(save_p); players[i].followerready = READUINT8(save_p); + players[i].followercolor = READUINT8(save_p); if (flags & FOLLOWER) players[i].follower = (mobj_t *)(size_t)READUINT32(save_p); diff --git a/src/p_user.c b/src/p_user.c index f49c3bc97..e4cd92061 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8082,6 +8082,7 @@ static void P_HandleFollower(player_t *player) angle_t an; fixed_t zoffs; fixed_t sx, sy, sz; + UINT8 color; if (!player->followerready) return; // we aren't ready to perform anything follower related yet. @@ -8120,6 +8121,12 @@ static void P_HandleFollower(player_t *player) fixed_t sine = fl.bobamp * FINESINE((((8*pi*(fl.bobspeed)) * leveltime)>>ANGLETOFINESHIFT) & FINEMASK); sz += FixedMul(player->mo->scale, sine)*P_MobjFlip(player->mo); + // extra step, give the follower a color !? + color = player->followercolor; + // little extra check to make sure this isn't garbage: + if (!color || color > MAXSKINCOLORS-1) + color = player->skincolor; // "Match" option. Essentially a fallback as well. + if (!player->follower) // follower doesn't exist / isn't valid { //CONS_Printf("Spawning follower...\n"); @@ -8127,6 +8134,7 @@ static void P_HandleFollower(player_t *player) player->follower = P_SpawnMobj(sx, sy, sz, MT_FOLLOWER); P_SetFollowerState(player->follower, fl.idlestate); P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear + player->follower->angle = player->mo->angle; player->follower->extravalue1 = 0; // extravalue1 is used to know what "state set" to use. /* @@ -8158,7 +8166,12 @@ static void P_HandleFollower(player_t *player) player->follower->momy = (sy - player->follower->y)/fl.horzlag; player->follower->momz = (sz - player->follower->z)/fl.vertlag; player->follower->angle = player->mo->angle; - player->follower->color = player->mo->color; + + if (player->mo->colorized) + player->follower->color = player->mo->color; + else + player->follower->color = color; + player->follower->colorized = player->mo->colorized; P_SetScale(player->follower, FixedMul(fl.scale, player->mo->scale)); diff --git a/src/r_data.h b/src/r_data.h index 86ba0885b..420c2507c 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -60,6 +60,7 @@ extern INT16 color8to16[256]; // remap color index to highcolor extern INT16 *hicolormaps; // remap high colors to high colors.. extern CV_PossibleValue_t Color_cons_t[]; +extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option. // Load TEXTURE1/TEXTURE2/PNAMES definitions, create lookup tables void R_LoadTextures(void); diff --git a/src/r_draw.c b/src/r_draw.c index 70e487342..cede76dae 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -147,6 +147,7 @@ static UINT8** translationtablecache[TT_CACHE_SIZE] = {NULL}; // SKINCOLOR DEFINITIONS HAVE BEEN MOVED TO K_KART.C CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; +CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+2]; /** \brief The R_InitTranslationTables diff --git a/src/r_things.c b/src/r_things.c index 0a718409a..7cd15a7a9 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -3045,7 +3045,7 @@ void SetFollower(INT32 playernum, INT32 skinnum) player_t *player = &players[playernum]; player->followerready = true; // we are ready to perform follower related actions in the player thinker, now. - if (skinnum >= -1 && skinnum <= numfollowers) // Make sure it exists! + if (skinnum >= -1 && skinnum <= numfollowers && player->followerskin != skinnum) // Make sure it exists! { player->followerskin = skinnum; //CONS_Printf("Updated player follower num\n"); diff --git a/src/r_things.h b/src/r_things.h index 304500d6e..859d1be0f 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -110,6 +110,8 @@ typedef struct follower_s char skinname[SKINNAMESIZE+1]; // Skin Name. This is what to refer to when asking the commands anything. char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this. + UINT8 defaultcolor; // default color for menus. + fixed_t scale; // Scale relative to the player's. // some position shenanigans: