From 74d9bcb07a1dbbb87c66913f777c7f234539505f Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 23 Jul 2025 15:56:47 -0400 Subject: [PATCH 01/26] The basics of the new tab menu Tab ranking has been refactored to be more flexable and to have a new design --- src/hu_stuff.c | 65 +++++++++++++++++------- src/hu_stuff.h | 4 +- src/k_hud.c | 134 +++++++++++++++++++------------------------------ src/k_hud.h | 2 +- src/screen.c | 2 +- 5 files changed, 102 insertions(+), 105 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 4bd25c826..1242c3cad 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2356,7 +2356,7 @@ Ping_conversion (UINT32 lag) // // HU_drawPing // -void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT32 flags) +void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT32 flags, boolean icon) { INT32 measureid = cv_pingmeasurement.value ? 1 : 0; INT32 gfxnum; // gfx to draw @@ -2366,19 +2366,25 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT3 if (pl) { - V_DrawFill( - -pinggfx[gfxnum]->leftoffset + x + 2 - 1, - -pinggfx[gfxnum]->topoffset + y - 1, - pinggfx[gfxnum]->width + 2, - pinggfx[gfxnum]->height + 2, - PL_gfx_color(pl) | flags - ); + if (icon) + { + V_DrawFill( + -pinggfx[gfxnum]->leftoffset + x + 2 - 1, + -pinggfx[gfxnum]->topoffset + y - 1, + pinggfx[gfxnum]->width + 2, + pinggfx[gfxnum]->height + 2, + PL_gfx_color(pl) | flags + ); + } } if (measureid == 1) V_DrawScaledPatch(x+11 - pingmeasure[measureid]->width, y+11, flags, pingmeasure[measureid]); - V_DrawScaledPatch(x+2, y, flags, pinggfx[gfxnum]); + if (icon) + { + V_DrawScaledPatch(x+2, y, flags, pinggfx[gfxnum]); + } x = V_DrawPingNum(x + (measureid == 1 ? 11 - pingmeasure[measureid]->width : 10), y+11, flags, Ping_conversion(lag), Ping_gfx_colormap(ping, ping <= lag)); @@ -2501,11 +2507,26 @@ static void HU_DrawRankings(void) hilicol = V_YELLOWMAP; } - // draw the current gametype in the lower right - if (modeattacking) - V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, "Record Attack"); + if (!demo.playback) + { + // draw the current map in the lower left + char *maptitle = G_BuildMapTitle(gamemap); + + if (maptitle) + { + V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, maptitle); + Z_Free(maptitle); + } + else + { + V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, "UNKNOWN"); + } + } else - V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, gametype_cons_t[gametype].strvalue); + { + // draw the current gametype in the lower left + V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, (modeattacking) ? "Record Attack" : gametype_cons_t[gametype].strvalue); + } if ((gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT)) && !bossinfo.boss) { @@ -2561,7 +2582,7 @@ static void HU_DrawRankings(void) { tab[i].num = -1; tab[i].name = NULL; - tab[i].count = INT32_MAX; + tab[i].string[0] = '\0'; if (!playeringame[i] || players[i].spectator || !players[i].mo) continue; @@ -2592,13 +2613,19 @@ static void HU_DrawRankings(void) if ((gametyperules & GTR_CIRCUIT)) { - if (circuitmap) - tab[scorelines].count = players[i].laps; + if (circuitmap && !players[i].exiting) + sprintf(tab[scorelines].string, "Lap %d", players[i].laps); else - tab[scorelines].count = players[i].realtime; + { + INT32 min = G_TicsToMinutes(players[i].realtime, true); + INT32 sec = G_TicsToSeconds(players[i].realtime); + INT32 cen = G_TicsToCentiseconds(players[i].realtime); + + sprintf(tab[scorelines].string, "%i'%02i\"%02i", min, sec, cen); + } } else - tab[scorelines].count = players[i].roundscore; + sprintf(tab[scorelines].string, "%d", players[i].roundscore); scorelines++; @@ -2608,7 +2635,7 @@ static void HU_DrawRankings(void) #endif } - K_DrawTabRankings(((scorelines > 8) ? 32 : 40), 33, tab, scorelines, whiteplayer, hilicol); + K_DrawNeoTabRankings(0, 33, tab, scorelines, whiteplayer, hilicol, true); // draw spectators in a ticker across the bottom if (netgame && G_GametypeHasSpectators()) diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 95d49e54a..1664628c4 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -77,7 +77,7 @@ extern char english_shiftxform[]; struct playersort_t { - UINT32 count; + char string[48]; INT32 num; const char *name; }; @@ -132,7 +132,7 @@ void HU_Drawer(void); char HU_dequeueChatChar(void); void HU_Erase(void); void HU_clearChatChars(void); -void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT32 flags); +void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT32 flags, boolean icon); void HU_drawMiniPing (INT32 x, INT32 y, UINT32 ping, UINT32 lag, INT32 flags); INT32 HU_CreateTeamScoresTbl(playersort_t *tab, UINT32 dmtotals[]); diff --git a/src/k_hud.c b/src/k_hud.c index 9af9e7f80..0a1dd94e1 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2062,37 +2062,33 @@ static void K_drawBossHealthBar(void) } // -// HU_DrawTabRankings -- moved here to take advantage of kart stuff! +// K_DrawNeoTabRankings -- A new way to view ingame info! +// returns starting x of right offset for drawing your own info in there! // -void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol) +INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol, boolean split) { - INT32 i, rightoffset = 240; - const UINT8 *colormap; + INT32 i, rightoffset = split ? 160 - 6: BASEVIDWIDTH - 6; + const UINT8 *colormap = NULL; + UINT16 hightlightcolor = 0; INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2; - int basey = y, basex = x, y2; + INT32 basey = y, basex = x, y2, x2; - //this function is designed for 9 or less score lines only - //I_Assert(scorelines <= 9); -- not today bitch, kart fixed it up + scorelines--; + + x += 4; + y += 9*scorelines; V_DrawFill(1-duptweak, 26, dupadjust-2, 1, 0); // Draw a horizontal line because it looks nice! - scorelines--; - if (scorelines >= 8) + if (split) { - V_DrawFill(160, 26, 1, 147, 0); // Draw a vertical line to separate the two sides. - V_DrawFill(1-duptweak, 173, dupadjust-2, 1, 0); // And a horizontal line near the bottom. - rightoffset = (BASEVIDWIDTH/2) - 4 - x; - x = (BASEVIDWIDTH/2) + 4; - y += 18*(scorelines-8); - } - else - { - y += 18*scorelines; + V_DrawFill(x + rightoffset + 6, 26, 1, 162, 0); // Draw a vertical line because it looks nice! } for (i = scorelines; i >= 0; i--) { - char strtime[MAXPLAYERNAME+1]; + INT32 pos = CLAMP(players[tab[i].num].position, 0 , MAXPLAYERS); + char playername[MAXPLAYERNAME+1]; if (players[tab[i].num].spectator || !players[tab[i].num].mo) continue; //ignore them. @@ -2101,22 +2097,21 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN { if (players[tab[i].num].bot) { - V_DrawString(x + ((i < 8) ? -25 : rightoffset + 3), y-2, V_SNAPTOLEFT, "CPU"); + V_DrawThinString(x - 18 + 25, y, 0, "CPU"); } else if (tab[i].num != serverplayer || !server_lagless) { - HU_drawPing(x + ((i < 8) ? -17 : rightoffset + 11), y-4, playerpingtable[tab[i].num], playerdelaytable[tab[i].num], playerpacketlosstable[tab[i].num], 0); + INT32 xoff = cv_pingmeasurement.value == 1 ? 31 : 26; + + HU_drawPing(x - 18 + xoff , y-10, playerpingtable[tab[i].num], playerdelaytable[tab[i].num], playerpacketlosstable[tab[i].num], 0, false); + } + else if (tab[i].num == serverplayer) + { + V_DrawThinString(x - 18 + 25, y, 0, "SRV"); } } - STRBUFCPY(strtime, tab[i].name); - - y2 = y; - - if (scorelines >= 8) - V_DrawThinString(x + 20, y2, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime); - else - V_DrawString(x + 20, y2, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime); + STRBUFCPY(playername, tab[i].name); if (players[tab[i].num].mo->color) { @@ -2126,66 +2121,41 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN else colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); - V_DrawMappedPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin][FACE_RANK], colormap); - /*if (gametype == GT_BATTLE && players[tab[i].num].bumper > 0) -- not enough space for this - { - INT32 bumperx = x+19; - V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumper[0], colormap); - for (j = 1; j < players[tab[i].num].bumper; j++) - { - bumperx += 5; - V_DrawMappedPatch(bumperx, y-4, 0, kp_tinybumper[1], colormap); - } - }*/ + hightlightcolor = skincolors[players[tab[i].num].mo->color].chatcolor; } + V_DrawScaledPatch(x-5, y+1, 0, kp_facenum[pos]); + + x2 = netgame ? x + (BASEVIDWIDTH/20) : x; + y2 = y; + + V_DrawThinString(x2 + 20, y2, ((tab[i].num == whiteplayer) ? hightlightcolor : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, playername); + + V_DrawFixedPatch((x2+11)*FRACUNIT, (y+1)*FRACUNIT, FRACUNIT/2, 0, faceprefix[players[tab[i].num].skin][FACE_RANK], colormap); + + /*if (gametype == GT_BATTLE && players[tab[i].num].bumper > 0) -- not enough space for this + { + INT32 bumperx = x+19; + V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumper[0], colormap); + for (j = 1; j < players[tab[i].num].bumper; j++) + { + bumperx += 5; + V_DrawMappedPatch(bumperx, y-4, 0, kp_tinybumper[1], colormap); + } + }*/ + if (tab[i].num == whiteplayer) - V_DrawScaledPatch(x, y-4, 0, kp_facehighlight[(leveltime / 4) % 8]); + V_DrawFixedPatch((x2+11)*FRACUNIT, (y+1)*FRACUNIT, FRACUNIT/2, 0, kp_facehighlight[(leveltime / 4) % 8], NULL); - if (gametype == GT_BATTLE && players[tab[i].num].bumper <= 0) - V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers); - else - { - INT32 pos = players[tab[i].num].position; - if (pos < 0 || pos > MAXPLAYERS) - pos = 0; - // Draws the little number over the face - V_DrawScaledPatch(x-5, y+6, 0, kp_facenum[pos]); - } + if ((gametyperules & GTR_BUMPERS) && players[tab[i].num].bumper <= 0) + V_DrawScaledPatch(x2-4, y-7, 0, kp_ranknobumpers); - if (gametype == GT_RACE) - { -#define timestring(time) va("%i'%02i\"%02i", G_TicsToMinutes(time, true), G_TicsToSeconds(time), G_TicsToCentiseconds(time)) - if (scorelines >= 8) - { - if (players[tab[i].num].exiting) - V_DrawRightAlignedThinString(x+rightoffset, y-1, hilicol|V_6WIDTHSPACE, timestring(players[tab[i].num].realtime)); - else if (players[tab[i].num].pflags & PF_NOCONTEST) - V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, "NO CONTEST."); - else if (circuitmap) - V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, va("Lap %d", tab[i].count)); - } - else - { - if (players[tab[i].num].exiting) - V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime)); - else if (players[tab[i].num].pflags & PF_NOCONTEST) - V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST."); - else if (circuitmap) - V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count)); - } -#undef timestring - } - else - V_DrawRightAlignedString(x+rightoffset, y, 0, va("%u", tab[i].count)); + if (tab[i].string[0] != '\0') + V_DrawRightAlignedThinString(x+rightoffset+2, y, V_6WIDTHSPACE, tab[i].string); - y -= 18; - if (i == 8) - { - y = basey + 7*18; - x = basex; - } + y -= 9; } + return x+rightoffset; } static void K_drawKartLaps(void) diff --git a/src/k_hud.h b/src/k_hud.h index ff08d3481..246d52575 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -95,7 +95,7 @@ void K_LoadKartHUDGraphics(void); void K_drawKartHUD(void); void K_drawKartFreePlay(void); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); -void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol); +INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol, boolean split); #ifdef __cplusplus } // extern "C" diff --git a/src/screen.c b/src/screen.c index ec1f215ca..c6218dab9 100644 --- a/src/screen.c +++ b/src/screen.c @@ -607,7 +607,7 @@ void SCR_DisplayLocalPing(void) if (( cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping) )) // only show 2 (warning) if our ping is at a bad level { INT32 dispy = cv_ticrate.value ? 160 : 181; - HU_drawPing(307, dispy, ping, mindelay, pl, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS); + HU_drawPing(307, dispy, ping, mindelay, pl, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS, true); } } From 214b3e9957ae44434cbcea8dbbf7ec9333bbb3be Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 23 Jul 2025 16:42:02 -0400 Subject: [PATCH 02/26] Remove circuit map check here --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 1242c3cad..792d18294 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2613,7 +2613,7 @@ static void HU_DrawRankings(void) if ((gametyperules & GTR_CIRCUIT)) { - if (circuitmap && !players[i].exiting) + if (!players[i].exiting) sprintf(tab[scorelines].string, "Lap %d", players[i].laps); else { From bab78e775bd066ba1b899d6cb1952714c198061c Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 23 Jul 2025 17:07:22 -0400 Subject: [PATCH 03/26] Fix MS ping overlap and color ping indicator graphic based on packet loss This lets you track how much packet loss you have in the tab rankings even without the pinggfx --- src/hu_stuff.c | 38 +++++++++++++++++++++++++++----------- src/k_hud.c | 2 +- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 792d18294..2153b6deb 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2310,16 +2310,30 @@ Ping_gfx_color (int lag) } static int -PL_gfx_color (int pl) +PL_gfx_color (int pl, boolean mode) { - if (pl <= 2) - return 72; - else if (pl <= 4) - return 54; - else if (pl <= 6) - return 35; + if (mode) + { + if (pl <= 2) + return SKINCOLOR_GOLD; + else if (pl <= 4) + return SKINCOLOR_ORANGE; + else if (pl <= 6) + return SKINCOLOR_CRIMSON; + else + return SKINCOLOR_MAGENTA; + } else - return 181; + { + if (pl <= 2) + return 72; + else if (pl <= 4) + return 54; + else if (pl <= 6) + return 35; + else + return 181; + } } static const UINT8 * @@ -2361,6 +2375,7 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT3 INT32 measureid = cv_pingmeasurement.value ? 1 : 0; INT32 gfxnum; // gfx to draw UINT32 lag = max(ping, mindelay); + UINT8 *colormap = NULL; gfxnum = Ping_gfx_num(ping); @@ -2373,13 +2388,14 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT3 -pinggfx[gfxnum]->topoffset + y - 1, pinggfx[gfxnum]->width + 2, pinggfx[gfxnum]->height + 2, - PL_gfx_color(pl) | flags + PL_gfx_color(pl, false) | flags ); } + colormap = R_GetTranslationColormap(TC_RAINBOW, PL_gfx_color(pl, true), GTC_CACHE); } if (measureid == 1) - V_DrawScaledPatch(x+11 - pingmeasure[measureid]->width, y+11, flags, pingmeasure[measureid]); + V_DrawMappedPatch(x+11 - pingmeasure[measureid]->width, y+11, flags, pingmeasure[measureid], colormap); if (icon) { @@ -2389,7 +2405,7 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT3 x = V_DrawPingNum(x + (measureid == 1 ? 11 - pingmeasure[measureid]->width : 10), y+11, flags, Ping_conversion(lag), Ping_gfx_colormap(ping, ping <= lag)); if (measureid == 0) - V_DrawScaledPatch(x+1 - pingmeasure[measureid]->width, y+11, flags, pingmeasure[measureid]); + V_DrawMappedPatch(x+1 - pingmeasure[measureid]->width, y+11, flags, pingmeasure[measureid], colormap); } void diff --git a/src/k_hud.c b/src/k_hud.c index 0a1dd94e1..f8eeaf344 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2101,7 +2101,7 @@ INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines } else if (tab[i].num != serverplayer || !server_lagless) { - INT32 xoff = cv_pingmeasurement.value == 1 ? 31 : 26; + INT32 xoff = cv_pingmeasurement.value == 1 ? 33 : 26; HU_drawPing(x - 18 + xoff , y-10, playerpingtable[tab[i].num], playerdelaytable[tab[i].num], playerpacketlosstable[tab[i].num], 0, false); } From cc732c20c5d81cfade3a3837d2a443c843377353 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 23 Jul 2025 18:32:50 -0400 Subject: [PATCH 04/26] Remove V_HUDTRANS from ping --- src/screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screen.c b/src/screen.c index c6218dab9..50f248390 100644 --- a/src/screen.c +++ b/src/screen.c @@ -607,7 +607,7 @@ void SCR_DisplayLocalPing(void) if (( cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping) )) // only show 2 (warning) if our ping is at a bad level { INT32 dispy = cv_ticrate.value ? 160 : 181; - HU_drawPing(307, dispy, ping, mindelay, pl, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS, true); + HU_drawPing(307, dispy, ping, mindelay, pl, V_SNAPTORIGHT | V_SNAPTOBOTTOM, true); } } From 5cb208580cbd83021404eb4bb6808a3f683a331e Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 23 Jul 2025 18:56:14 -0400 Subject: [PATCH 05/26] Fix ping color --- src/hu_stuff.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 2153b6deb..c732bc8a9 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2282,13 +2282,13 @@ void HU_Erase(void) static int Ping_gfx_num (int lag) { - if (lag <= 2) + if (lag < 2) return 0; - else if (lag <= 4) + else if (lag < 4) return 1; - else if (lag <= 7) + else if (lag < 7) return 2; - else if (lag <= 10) + else if (lag < 10) return 3; else return 4; @@ -2297,13 +2297,13 @@ Ping_gfx_num (int lag) static int Ping_gfx_color (int lag) { - if (lag <= 2) + if (lag < 2) return SKINCOLOR_JAWZ; - else if (lag <= 4) + else if (lag < 4) return SKINCOLOR_MINT; - else if (lag <= 7) + else if (lag < 7) return SKINCOLOR_GOLD; - else if (lag <= 10) + else if (lag < 10) return SKINCOLOR_RASPBERRY; else return SKINCOLOR_MAGENTA; @@ -2314,22 +2314,22 @@ PL_gfx_color (int pl, boolean mode) { if (mode) { - if (pl <= 2) + if (pl < 2) return SKINCOLOR_GOLD; - else if (pl <= 4) + else if (pl < 4) return SKINCOLOR_ORANGE; - else if (pl <= 6) + else if (pl < 6) return SKINCOLOR_CRIMSON; else return SKINCOLOR_MAGENTA; } else { - if (pl <= 2) + if (pl < 2) return 72; - else if (pl <= 4) + else if (pl < 4) return 54; - else if (pl <= 6) + else if (pl < 6) return 35; else return 181; @@ -2337,20 +2337,14 @@ PL_gfx_color (int pl, boolean mode) } static const UINT8 * -Ping_gfx_colormap (UINT32 ping, boolean gentleman) +Ping_gfx_colormap (UINT32 ping, UINT32 lag) { - const UINT8 *colormap = NULL; - - colormap = R_GetTranslationColormap(TC_RAINBOW, Ping_gfx_color(ping), GTC_CACHE); + const UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, Ping_gfx_color(lag), GTC_CACHE); if (servermaxping && ping > servermaxping && hu_tick < 4) { // flash ping red if too high - colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE); - } - else if (gentleman) - { - colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PASTEL, GTC_CACHE); + colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_WHITE, GTC_CACHE); } return colormap; @@ -2402,7 +2396,7 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, UINT32 mindelay, UINT32 pl, INT3 V_DrawScaledPatch(x+2, y, flags, pinggfx[gfxnum]); } - x = V_DrawPingNum(x + (measureid == 1 ? 11 - pingmeasure[measureid]->width : 10), y+11, flags, Ping_conversion(lag), Ping_gfx_colormap(ping, ping <= lag)); + x = V_DrawPingNum(x + (measureid == 1 ? 11 - pingmeasure[measureid]->width : 10), y+11, flags, Ping_conversion(lag), Ping_gfx_colormap(ping, lag)); if (measureid == 0) V_DrawMappedPatch(x+1 - pingmeasure[measureid]->width, y+11, flags, pingmeasure[measureid], colormap); From 8e23411bc76fe68a0ef3a142ee00e22ea1b7f6f1 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 18 Aug 2025 22:07:58 -0400 Subject: [PATCH 06/26] Server Desc for scoreboard Kind of like what hostmod has I guess? --- src/d_main.cpp | 2 + src/d_netcmd.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++ src/d_netcmd.h | 2 + src/doomstat.h | 3 ++ src/g_game.c | 1 + src/hu_stuff.c | 5 ++- src/k_hud.c | 8 ++++ src/k_hud.h | 2 + src/p_saveg.c | 2 + 9 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 92101f90f..e6f7fefcb 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1202,6 +1202,8 @@ void D_StartTitle(void) for (i = 0; i < MAXPLAYERS; i++) CL_ClearPlayer(i); + memset(&serverdescription, 0, sizeof(serverdescription)); + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { players[g_localplayers[i]].availabilities = R_GetSkinAvailabilities(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7fb93208f..a6c227c9a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -59,6 +59,7 @@ #include "k_pwrlv.h" #include "y_inter.h" #include "k_color.h" +#include "k_hud.h" #include "k_grandprix.h" #include "k_boss.h" #include "k_follower.h" @@ -102,6 +103,10 @@ static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum); static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum); static void Got_Automatecmd(UINT8 **cp, INT32 playernum); static void Got_Cheat(UINT8 **cp, INT32 playernum); +static void Got_ScoreboardAdd(UINT8 **cp, INT32 playernum); +static void Got_ScoreboardClear(UINT8 **cp, INT32 playernum); +static void Command_ScoreboardAdd(void); +static void Command_ScoreboardClear(void); static void PointLimit_OnChange(void); static void TimeLimit_OnChange(void); @@ -745,6 +750,8 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "SCHEDULECLEAR", // XD_SCHEDULECLEAR "AUTOMATE", // XD_AUTOMATE "CHEAT", // XD_CHEAT + "SCOREBOARDADD", // XD_SCOREBOARDADD + "SCOREBOARDCLEAR", // XD_SCOREBOARDCLEAR }; // ========================================================================= @@ -802,6 +809,10 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd); RegisterNetXCmd(XD_CHEAT, Got_Cheat); + RegisterNetXCmd(XD_SCOREBOARDADD, Got_ScoreboardAdd); + RegisterNetXCmd(XD_SCOREBOARDCLEAR, Got_ScoreboardClear); + COM_AddCommand("scoreboard_addline", Command_ScoreboardAdd); + COM_AddCommand("scoreboard_clear", Command_ScoreboardClear); // Remote Administration COM_AddCommand("password", Command_Changepassword_f); @@ -3647,6 +3658,102 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum) CONS_Printf(M_GetText("Scores have been reset by the server.\n")); } +static void Command_ScoreboardAdd(void) +{ + UINT8 buf[4]; + UINT8 *cp = buf; + + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("addscoreboard : Add text to the scoreboard\n")); + return; + } + + if (server || IsPlayerAdmin(consoleplayer)) + { + size_t i, j = COM_Argc(); + char message[MAXSERVERDESCRIPTIONLINE+1]; + INT32 strlensize = 0; + + //Steal from the motd code so you don't have to put the reason in quotes. + strlcpy(message, COM_Argv(1), sizeof message); + for (i = 2; i < j; i++) + { + strlcat(message, " ", sizeof message); + strlcat(message, COM_Argv(i), sizeof message); + } + + strlensize = strlen(message); + message[strlensize+1] = '\0'; + + message[MAXSERVERDESCRIPTIONLINE] = '\0'; + + if ((strlensize+1) > MAXSERVERDESCRIPTIONLINE) + { + CONS_Alert(CONS_WARNING, M_GetText("Scoreboard line is too long to add.\n")); + return; + } + + WRITESTRINGN(cp, message, MAXSERVERDESCRIPTIONLINE+1); + SendNetXCmd(XD_SCOREBOARDADD, &buf, cp - buf); + } + else + CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); +} + +static void Got_ScoreboardAdd(UINT8 **cp, INT32 playernum) +{ + char tempbuff[MAXSERVERDESCRIPTIONLINE]; + INT32 serverdesclen = 0; + INT32 tempbufflen = 0; + READSTRINGN(*cp, tempbuff, MAXSERVERDESCRIPTIONLINE+1); + + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) // hacked client, or disasterous bug + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal Scoreboard Add command received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL); + return; + } + + serverdesclen = strlen(serverdescription); + tempbufflen = strlen(tempbuff); + + if ((serverdesclen + tempbufflen) > MAXSERVERDESCRIPTION) + { + CONS_Alert(CONS_WARNING, M_GetText("Scoreboard text is full so no more text can be added.\n")); + return; + } + else + { + strncat(serverdescription, va("%s\n%c", tempbuff, '\0'), MAXSERVERDESCRIPTIONLINE); + CONS_Printf(M_GetText("Scoreboard text line has been added.\n")); + } +} + +static void Command_ScoreboardClear(void) +{ + if (!(server || (IsPlayerAdmin(consoleplayer)))) + return; + + SendNetXCmd(XD_SCOREBOARDCLEAR, NULL, 1); +} + +static void Got_ScoreboardClear(UINT8 **cp, INT32 playernum) +{ + (void)cp; + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal Scoreboard Clear command received from %s\n"), player_names[playernum]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL); + return; + } + + memset(&serverdescription, 0, sizeof(serverdescription)); + CONS_Printf(M_GetText("Scoreboard text have been reset by the server.\n")); +} + // Team changing functions static void HandleTeamChangeCommand(UINT8 localplayer) { diff --git a/src/d_netcmd.h b/src/d_netcmd.h index f68586a1a..a94d04534 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -279,6 +279,8 @@ typedef enum XD_SCHEDULECLEAR, // 36 XD_AUTOMATE, // 37 XD_CHEAT, // 38 + XD_SCOREBOARDADD, // 39 + XD_SCOREBOARDCLEAR, // 40 MAXNETXCMD } netxcmd_t; diff --git a/src/doomstat.h b/src/doomstat.h index 56dd8951b..c23f8c8fa 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -676,6 +676,9 @@ extern boolean thwompsactive; extern UINT8 lastLowestLap; extern SINT8 spbplace; extern boolean startedInFreePlay; +#define MAXSERVERDESCRIPTION 320 +#define MAXSERVERDESCRIPTIONLINE 37 +extern char serverdescription[MAXSERVERDESCRIPTION]; extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) extern boolean legitimateexit; diff --git a/src/g_game.c b/src/g_game.c index be69a69e2..528f7e746 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -303,6 +303,7 @@ boolean thwompsactive; // Thwomps activate on lap 2 UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors SINT8 spbplace; // SPB exists, give the person behind better items boolean startedInFreePlay; // Map was started in free play +char serverdescription[MAXSERVERDESCRIPTION]; // Server description for the scoreboard. // Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players) tic_t bombflashtimer = 0; // Cooldown before another FlashPal can be intialized by a bomb exploding near a displayplayer. Avoids seizures. diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7f541099f..7350bc827 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2622,7 +2622,10 @@ static void HU_DrawRankings(void) #endif } - K_DrawNeoTabRankings(0, 33, tab, scorelines, whiteplayer, hilicol, true); + INT32 xoffset = K_DrawNeoTabRankings(0, 33, tab, scorelines, whiteplayer, hilicol, true); + + K_DrawServerDescrption(xoffset+10, 33); + //V_DrawThinString(xoffset+10, 33, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); // draw spectators in a ticker across the bottom if (netgame && G_GametypeHasSpectators()) diff --git a/src/k_hud.c b/src/k_hud.c index 6eb76c589..20cfabe5f 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2170,6 +2170,14 @@ INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines return x+rightoffset; } +void K_DrawServerDescrption(INT32 x, INT32 y) +{ + + if (serverdescription[0] != '\0') + V_DrawThinString(x, y, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, serverdescription); + +} + static void K_drawKartLaps(void) { const boolean uselives = G_GametypeUsesLives(); diff --git a/src/k_hud.h b/src/k_hud.h index cf8306010..a7f59186f 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -99,6 +99,8 @@ void K_drawKartFreePlay(void); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol, boolean split); +void K_DrawServerDescrption(INT32 x, INT32 y); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/p_saveg.c b/src/p_saveg.c index 4d5b01278..4892a286f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5281,6 +5281,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT8(save->p, lastLowestLap); WRITESINT8(save->p, spbplace); WRITEUINT8(save->p, startedInFreePlay); + WRITESTRINGN(save->p, serverdescription, MAXSERVERDESCRIPTION); WRITEUINT32(save->p, introtime); WRITEUINT32(save->p, starttime); @@ -5466,6 +5467,7 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool lastLowestLap = READUINT8(save->p); spbplace = READSINT8(save->p); startedInFreePlay = READUINT8(save->p); + READSTRINGN(save->p, serverdescription, MAXSERVERDESCRIPTION); introtime = READUINT32(save->p); starttime = READUINT32(save->p); From 04939fea7c353bbf708373981b5e33e2f9b3c59f Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 19 Aug 2025 10:41:34 -0400 Subject: [PATCH 07/26] Save server description to replays --- src/g_demo.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index c8b740afe..6aee460d7 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -112,7 +112,7 @@ demoghost *ghosts = NULL; // DEMO RECORDING // -#define DEMOVERSION 0x0009 +#define DEMOVERSION 0x000A #define DEMOHEADER "\xF0" "BlanReplay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -249,6 +249,7 @@ typedef struct UINT32 raflags; UINT8 gametype; UINT8 numlaps; + char serverdescription[MAXSERVERDESCRIPTIONLINE]; UINT8 numfiles; demofile_t *files; @@ -662,6 +663,7 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) UINT8 attack; boolean kart = false, oldkart = false; boolean raflag = true; + boolean serverdesc = true; // these may not be present in old demo formats, so initialize them // also initialize them so the header can be free'd without issues @@ -671,6 +673,7 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) header->mapmusrng = 0; header->numlaps = 0; header->raflags = 0; + memset(header->serverdescription, 0, sizeof(header->serverdescription)); header->empty = false; dp += 12; @@ -685,6 +688,10 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) case DEMOVERSION: // latest always supported break; + case 0x0009: + serverdesc = false; + break; + default: // too old, cannot support. return HEADER_BADVERSION; } @@ -692,6 +699,7 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) else if (!memcmp(startdp, "\xF0" "KartReplay" "\x0F", 12)) { raflag = false; + serverdesc = false; switch (header->demoversion) { case 0x0001: // SRB2Kart 1.0.x (only staff ghosts supported) @@ -745,6 +753,11 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) header->raflags = READUINT32(dp); } + if (serverdesc) + { + READSTRINGN(dp, header->serverdescription, MAXSERVERDESCRIPTION); + } + if (oldkart) { if (header->demoflags & DF_MULTIPLAYER) @@ -2801,6 +2814,7 @@ void G_BeginRecording(void) WRITEUINT8(demobuf.p, demoflags); WRITEUINT32(demobuf.p, raflags); + WRITESTRINGN(demobuf.p, serverdescription, MAXSERVERDESCRIPTION); WRITEUINT8(demobuf.p, gametype & 0xFF); WRITEUINT8(demobuf.p, numlaps); From 9c0428f695493accdbca49dc1b9a1b29a749e28c Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 19 Aug 2025 10:54:06 -0400 Subject: [PATCH 08/26] Copy demoheader server description to serverdescription --- src/g_demo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_demo.c b/src/g_demo.c index 6aee460d7..c8cbfba37 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3579,6 +3579,7 @@ void G_DoPlayDemo(char *defdemoname) demoflags = header.demoflags; raflags = header.raflags; + strncpy(serverdescription, header.serverdescription, MAXSERVERDESCRIPTION); gametype = header.gametype; G_SetGametype(gametype); numlaps = header.numlaps; From 70beec3d5bdc4633c7f154088e80fb4ae628d932 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 19 Aug 2025 11:04:14 -0400 Subject: [PATCH 09/26] Raise max line width --- src/doomstat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doomstat.h b/src/doomstat.h index c23f8c8fa..68ffff992 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -677,7 +677,7 @@ extern UINT8 lastLowestLap; extern SINT8 spbplace; extern boolean startedInFreePlay; #define MAXSERVERDESCRIPTION 320 -#define MAXSERVERDESCRIPTIONLINE 37 +#define MAXSERVERDESCRIPTIONLINE 40 extern char serverdescription[MAXSERVERDESCRIPTION]; extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) From a78fc56e8c2de7cff9cec206b92738b98d02ad2f Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 19 Aug 2025 14:17:55 -0400 Subject: [PATCH 10/26] Display current servername in the scoreboard --- src/k_hud.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 20cfabe5f..24ada1025 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2172,9 +2172,11 @@ INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines void K_DrawServerDescrption(INT32 x, INT32 y) { + if (connectedservername[0] != '\0') + V_DrawThinString(x, y, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedservername); if (serverdescription[0] != '\0') - V_DrawThinString(x, y, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, serverdescription); + V_DrawSmallString(x, y+20, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, serverdescription); } From fbea38e20bcd522543e97abacb5e2ae33451bdc0 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 19 Aug 2025 20:54:31 -0400 Subject: [PATCH 11/26] Allow Caret coloring to work on Description Hex codes do not work as of yet. --- src/d_netcmd.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/k_hud.c | 4 +-- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a6c227c9a..f6aa0047f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3658,6 +3658,79 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum) CONS_Printf(M_GetText("Scores have been reset by the server.\n")); } +ATTRINLINE static FUNCINLINE unsigned char GetColorChar(char *input, size_t *curpos) +{ + char c = input[*curpos++]; + if (c == '^') // oh, nevermind then. + return '^'; + + if (c >= '0' && c <= '9') + return 0x80+(c-'0'); + + c = tolower(c); + + if (c >= 'a' && c <= 'f') + return 0x80+10+(c-'a'); + + return 0x80; // Unhandled -- default to no color +} + +ATTRINLINE static FUNCINLINE char GetHexChar(char *input, size_t *curpos) +{ + char c = input[*curpos++]; + char endchr = 0; + if (c == '\\') // oh, nevermind then. + return '\\'; + + if (c >= '0' && c <= '9') + endchr += (c-'0') << 4; + else if (c >= 'A' && c <= 'F') + endchr += ((c-'A') + 10) << 4; + else if (c >= 'a' && c <= 'f') + endchr += ((c-'a') + 10) << 4; + else // invalid. stop and return a question mark. + return '?'; + + c = input[*curpos++]; + if (c >= '0' && c <= '9') + endchr += (c-'0'); + else if (c >= 'A' && c <= 'F') + endchr += ((c-'A') + 10); + else if (c >= 'a' && c <= 'f') + endchr += ((c-'a') + 10); + else // invalid. stop and return a question mark. + return '?'; + + return endchr; +} + +static char *GetSpecialString(char *buf, char *input, size_t bufsize) +{ + size_t i = 0; + size_t currentpos = 0; + strncpy(buf, input, bufsize); + + // we need one byte for a null terminated string + bufsize--; + while (i < bufsize) + { + char c = buf[currentpos++]; + if (c == '^') + { + buf[i++] = GetColorChar(buf, ¤tpos); + currentpos++; + } + /*else if (c == '\\') + { + buf[i++] = GetHexChar(buf, ¤tpos); + }*/ + else if (c != '\r') + buf[i++] = c; + } + + return buf; +} + static void Command_ScoreboardAdd(void) { UINT8 buf[4]; @@ -3673,6 +3746,7 @@ static void Command_ScoreboardAdd(void) { size_t i, j = COM_Argc(); char message[MAXSERVERDESCRIPTIONLINE+1]; + char *finalstring; INT32 strlensize = 0; //Steal from the motd code so you don't have to put the reason in quotes. @@ -3685,17 +3759,23 @@ static void Command_ScoreboardAdd(void) strlensize = strlen(message); message[strlensize+1] = '\0'; - message[MAXSERVERDESCRIPTIONLINE] = '\0'; + finalstring = Z_Calloc(MAXSERVERDESCRIPTIONLINE*sizeof(char), PU_STATIC, NULL); + + GetSpecialString(finalstring, message, MAXSERVERDESCRIPTIONLINE); + + strlensize = strlen(finalstring); + if ((strlensize+1) > MAXSERVERDESCRIPTIONLINE) { CONS_Alert(CONS_WARNING, M_GetText("Scoreboard line is too long to add.\n")); return; } - WRITESTRINGN(cp, message, MAXSERVERDESCRIPTIONLINE+1); + WRITESTRINGN(cp, finalstring, MAXSERVERDESCRIPTIONLINE+1); SendNetXCmd(XD_SCOREBOARDADD, &buf, cp - buf); + Z_Free(finalstring); } else CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); diff --git a/src/k_hud.c b/src/k_hud.c index 24ada1025..b71fe3650 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2173,10 +2173,10 @@ INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines void K_DrawServerDescrption(INT32 x, INT32 y) { if (connectedservername[0] != '\0') - V_DrawThinString(x, y, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedservername); + V_DrawThinString(x, y, V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedservername); if (serverdescription[0] != '\0') - V_DrawSmallString(x, y+20, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, serverdescription); + V_DrawSmallString(x, y+20, V_6WIDTHSPACE|V_ALLOWLOWERCASE, serverdescription); } From 97ca2d8d6e5dc5a3c258e227c95dd419f63122b8 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 20 Aug 2025 17:21:01 -0400 Subject: [PATCH 12/26] Fix stringop --- src/g_demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index 2bb2c7ab1..9bbbbbd26 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3574,7 +3574,7 @@ void G_DoPlayDemo(char *defdemoname) // demo title memcpy(demo.titlename, header.demotitle, 64); - memcpy(serverdescription, header.serverdescription, MAXSERVERDESCRIPTION); + strncpy(serverdescription, header.serverdescription, MAXSERVERDESCRIPTION); if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. ;//G_SkipDemoExtraFiles(&demobuf.p); From e9fb6ca9a8195eb5bc923f34a00fa2628ebeb4d3 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 12:45:25 -0400 Subject: [PATCH 13/26] Add server contact and refactor to use netcode to send stuff --- src/d_clisrv.c | 25 +++++++++++++++++++++++-- src/d_clisrv.h | 15 +++++++++++++-- src/d_main.cpp | 4 ---- src/d_netcmd.c | 29 ++++++++++++++++++++++++++--- src/d_netcmd.h | 1 + src/doomstat.h | 3 --- src/g_demo.c | 28 ++++++++++++++++++++-------- src/g_game.c | 1 - src/k_hud.c | 6 ++++-- src/m_menu.c | 2 -- src/mserv.c | 15 +++++++++++++++ src/p_saveg.c | 2 -- 12 files changed, 102 insertions(+), 29 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 94f4084f6..3e68dd626 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -160,7 +160,10 @@ static tic_t neededtic; SINT8 servernode = 0; // the number of the server node SINT8 joinnode = 0; // used for CL_VIEWSERVER -char connectedservername[MAXSERVERNAME+1]; +char connectedservername[MAXSERVERNAME]; +char connectedservercontact[MAXSERVERCONTACT]; +char connectedserverdescription[MAXSERVERDESCRIPTION]; + /// \brief do we accept new players? /// \todo WORK! boolean acceptnewnode = true; @@ -1140,6 +1143,10 @@ static boolean SV_SendServerConfig(INT32 node) memcpy(netbuffer->u.servercfg.server_context, server_context, 8); + strncpy(netbuffer->u.servercfg.server_name, cv_servername.string, MAXSERVERNAME); + strncpy(netbuffer->u.servercfg.server_contact, cv_server_contact.string, MAXSERVERCONTACT); + strncpy(netbuffer->u.servercfg.server_description, connectedserverdescription, MAXSERVERDESCRIPTION); + { const size_t len = sizeof (serverconfig_pak); @@ -3545,14 +3552,19 @@ void SV_ResetServer(void) // clear server_context memset(server_context, '-', 8); + memset(connectedservername, 0, MAXSERVERNAME); + memset(connectedservercontact, 0, MAXSERVERCONTACT); + memset(connectedserverdescription, 0, MAXSERVERDESCRIPTION); + CV_RevertNetVars(); DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); } -static inline void SV_GenContext(void) +static void SV_GenContext(void) { UINT8 i; + // generate server_context, as exactly 8 bytes of randomly mixed A-Z and a-z // (hopefully M_Random is initialized!! if not this will be awfully silly!) for (i = 0; i < 8; i++) @@ -3563,6 +3575,10 @@ static inline void SV_GenContext(void) else // lowercase server_context[i] = 'a'+(a-26); } + + strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); + strncpy(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); + strncpy(connectedserverdescription, DEFAULTDESCSTRING, MAXSERVERDESCRIPTION); } // @@ -4593,7 +4609,12 @@ static void HandlePacketFromAwayNode(SINT8 node) G_SetGametype(netbuffer->u.servercfg.gametype); modifiedgame = netbuffer->u.servercfg.modifiedgame; + memcpy(server_context, netbuffer->u.servercfg.server_context, 8); + + strncpy(connectedservername, netbuffer->u.servercfg.server_name, MAXSERVERNAME); + strncpy(connectedservercontact, netbuffer->u.servercfg.server_contact, MAXSERVERCONTACT); + strncpy(connectedserverdescription, netbuffer->u.servercfg.server_description, MAXSERVERDESCRIPTION); } #ifdef HAVE_DISCORDRPC diff --git a/src/d_clisrv.h b/src/d_clisrv.h index ae0e71a91..f375bf8ea 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -41,6 +41,12 @@ applications may follow different packet versions. // one that defines the actual packets to // be transmitted. +#define MAXSERVERNAME 32 +#define MAXSERVERCONTACT 1024 +#define MAXSERVERDESCRIPTION 320 +#define MAXSERVERDESCRIPTIONLINE 40 +#define DEFAULTDESCSTRING "Welcome to my SRB2Kart server!" + // Networking and tick handling related. #define BACKUPTICS 512 // more than enough for most timeouts.... #define CLIENTBACKUPTICS 32 @@ -211,6 +217,10 @@ struct serverconfig_pak UINT8 maxplayer; boolean allownewplayer; boolean discordinvites; + + char server_name[MAXSERVERNAME]; + char server_contact[MAXSERVERCONTACT]; + char server_description[MAXSERVERDESCRIPTION]; } ATTRPACK; struct filetx_pak @@ -259,7 +269,6 @@ struct clientconfig_pak #define SV_DEDICATED 0x40 // server is dedicated #define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil -#define MAXSERVERNAME 32 #define MAXFILENEEDED 915 #define MAX_MIRROR_LENGTH 256 // This packet is too large @@ -452,7 +461,9 @@ extern boolean dedicated; // For dedicated server extern UINT16 software_MAXPACKETLENGTH; extern boolean acceptnewnode; extern SINT8 servernode; -extern char connectedservername[MAXSERVERNAME+1]; +extern char connectedservername[MAXSERVERNAME]; +extern char connectedservercontact[MAXSERVERCONTACT]; +extern char connectedserverdescription[MAXSERVERDESCRIPTION]; void Command_Ping_f(void); extern tic_t connectiontimeout; diff --git a/src/d_main.cpp b/src/d_main.cpp index 53be62412..80b04a0f8 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1185,8 +1185,6 @@ void D_StartTitle(void) for (i = 0; i < MAXPLAYERS; i++) CL_ClearPlayer(i); - memset(&serverdescription, 0, sizeof(serverdescription)); - for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { players[g_localplayers[i]].availabilities = R_GetSkinAvailabilities(); @@ -1964,8 +1962,6 @@ void D_SRB2Main(void) COM_BufExecute(); // ensure the command buffer gets executed before the map starts (+skin) - strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); - if (M_CheckParm("-gametype") && M_IsNextParm()) { // from Command_Map_f diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7299e4ec1..e7517ddc4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -107,6 +107,7 @@ static void Got_ScoreboardAdd(UINT8 **cp, INT32 playernum); static void Got_ScoreboardClear(UINT8 **cp, INT32 playernum); static void Command_ScoreboardAdd(void); static void Command_ScoreboardClear(void); +static void Got_ServerInfoUpdate(UINT8 **cp, INT32 playernum); static void PointLimit_OnChange(void); static void TimeLimit_OnChange(void); @@ -766,6 +767,7 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "CHEAT", // XD_CHEAT "SCOREBOARDADD", // XD_SCOREBOARDADD "SCOREBOARDCLEAR", // XD_SCOREBOARDCLEAR + "SERVERINFOUPDATE", // XD_SERVERINFOUPDATE }; // ========================================================================= @@ -827,6 +829,7 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_SCOREBOARDCLEAR, Got_ScoreboardClear); COM_AddCommand("scoreboard_addline", Command_ScoreboardAdd); COM_AddCommand("scoreboard_clear", Command_ScoreboardClear); + RegisterNetXCmd(XD_SERVERINFOUPDATE, Got_ServerInfoUpdate); // Remote Administration COM_AddCommand("password", Command_Changepassword_f); @@ -3814,7 +3817,7 @@ static void Got_ScoreboardAdd(UINT8 **cp, INT32 playernum) return; } - serverdesclen = strlen(serverdescription); + serverdesclen = strlen(connectedserverdescription); tempbufflen = strlen(tempbuff); if ((serverdesclen + tempbufflen) > MAXSERVERDESCRIPTION) @@ -3824,7 +3827,7 @@ static void Got_ScoreboardAdd(UINT8 **cp, INT32 playernum) } else { - strncat(serverdescription, va("%s\n%c", tempbuff, '\0'), MAXSERVERDESCRIPTIONLINE); + strncat(connectedserverdescription, va("%s\n%c", tempbuff, '\0'), MAXSERVERDESCRIPTIONLINE); CONS_Printf(M_GetText("Scoreboard text line has been added.\n")); } } @@ -3848,10 +3851,30 @@ static void Got_ScoreboardClear(UINT8 **cp, INT32 playernum) return; } - memset(&serverdescription, 0, sizeof(serverdescription)); + memset(&connectedserverdescription, 0, sizeof(connectedserverdescription)); CONS_Printf(M_GetText("Scoreboard text have been reset by the server.\n")); } +static void Got_ServerInfoUpdate(UINT8 **cp, INT32 playernum) +{ + char tempname[MAXSERVERNAME]; + char tempcontact[MAXSERVERCONTACT]; + READSTRINGN(*cp, tempname, MAXSERVERNAME); + READSTRINGN(*cp, tempcontact, MAXSERVERCONTACT); + + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) // hacked client, or disasterous bug + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal Server Info Update command received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL); + return; + } + + strncpy(connectedservername, tempname, MAXSERVERNAME); + strncpy(connectedservercontact, tempcontact, MAXSERVERCONTACT); + CONS_Printf(M_GetText("Updated Server Info.\n")); +} + // Team changing functions static void HandleTeamChangeCommand(UINT8 localplayer) { diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 25d32033f..e1882b9ed 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -288,6 +288,7 @@ typedef enum XD_CHEAT, // 38 XD_SCOREBOARDADD, // 39 XD_SCOREBOARDCLEAR, // 40 + XD_SERVERINFOUPDATE, // 41 MAXNETXCMD } netxcmd_t; diff --git a/src/doomstat.h b/src/doomstat.h index 68ffff992..56dd8951b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -676,9 +676,6 @@ extern boolean thwompsactive; extern UINT8 lastLowestLap; extern SINT8 spbplace; extern boolean startedInFreePlay; -#define MAXSERVERDESCRIPTION 320 -#define MAXSERVERDESCRIPTIONLINE 40 -extern char serverdescription[MAXSERVERDESCRIPTION]; extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) extern boolean legitimateexit; diff --git a/src/g_demo.c b/src/g_demo.c index 9dff1bf93..c5d12d9e8 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -244,7 +244,9 @@ typedef struct UINT32 raflags; UINT8 gametype; UINT8 numlaps; - char serverdescription[MAXSERVERDESCRIPTIONLINE]; + char servername[MAXSERVERNAME]; + char servercontact[MAXSERVERCONTACT]; + char serverdescription[MAXSERVERDESCRIPTION]; UINT8 numfiles; demofile_t *files; @@ -654,7 +656,7 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) UINT8 attack; boolean kart = false, oldkart = false; boolean raflag = true; - boolean serverdesc = true; + boolean serverinfo = true; // these may not be present in old demo formats, so initialize them // also initialize them so the header can be free'd without issues @@ -664,7 +666,9 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) header->mapmusrng = 0; header->numlaps = 0; header->raflags = 0; - memset(header->serverdescription, 0, sizeof(header->serverdescription)); + memset(header->servername, 0, MAXSERVERNAME); + memset(header->servercontact, 0, MAXSERVERCONTACT); + memset(header->serverdescription, 0, MAXSERVERDESCRIPTION); header->empty = false; dp += 12; @@ -680,7 +684,7 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) break; case 0x0009: - serverdesc = false; + serverinfo = false; break; default: // too old, cannot support. @@ -690,7 +694,7 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) else if (!memcmp(startdp, "\xF0" "KartReplay" "\x0F", 12)) { raflag = false; - serverdesc = false; + serverinfo = false; switch (header->demoversion) { case 0x0001: // SRB2Kart 1.0.x (only staff ghosts supported) @@ -744,8 +748,10 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header) header->raflags = READUINT32(dp); } - if (serverdesc) + if (serverinfo) { + READSTRINGN(dp, header->servername, MAXSERVERNAME); + READSTRINGN(dp, header->servercontact, MAXSERVERCONTACT); READSTRINGN(dp, header->serverdescription, MAXSERVERDESCRIPTION); } @@ -2768,7 +2774,9 @@ void G_BeginRecording(void) WRITEUINT8(demobuf.p, demoflags); WRITEUINT32(demobuf.p, raflags); - WRITESTRINGN(demobuf.p, serverdescription, MAXSERVERDESCRIPTION); + WRITESTRINGN(demobuf.p, connectedservername, MAXSERVERNAME); + WRITESTRINGN(demobuf.p, connectedservercontact, MAXSERVERCONTACT); + WRITESTRINGN(demobuf.p, connectedserverdescription, MAXSERVERDESCRIPTION); WRITEUINT8(demobuf.p, gametype & 0xFF); WRITEUINT8(demobuf.p, numlaps); @@ -3528,7 +3536,6 @@ void G_DoPlayDemo(char *defdemoname) // demo title memcpy(demo.titlename, header.demotitle, 64); - strncpy(serverdescription, header.serverdescription, MAXSERVERDESCRIPTION); if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. ;//G_SkipDemoExtraFiles(&demobuf.p); @@ -3780,6 +3787,11 @@ void G_DoPlayDemo(char *defdemoname) P_SetRandSeed(header.randseed); G_InitNew(demoflags & DF_ENCORE, gamemap, true, true, false); // Doesn't matter whether you reset or not here, given changes to resetplayer. + // Setup server name, contact and description. + strncpy(connectedservername, header.servername, MAXSERVERNAME); + strncpy(connectedservercontact, header.servercontact, MAXSERVERCONTACT); + strncpy(connectedserverdescription, header.serverdescription, MAXSERVERDESCRIPTION); + for (pnum = 0; pnum < header.numplayers; pnum++) { // oldghost init doesn't work here, players aren't immediately spawned anymore diff --git a/src/g_game.c b/src/g_game.c index 102c5b97c..f7e6581f1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -303,7 +303,6 @@ boolean thwompsactive; // Thwomps activate on lap 2 UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors SINT8 spbplace; // SPB exists, give the person behind better items boolean startedInFreePlay; // Map was started in free play -char serverdescription[MAXSERVERDESCRIPTION]; // Server description for the scoreboard. // Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players) tic_t bombflashtimer = 0; // Cooldown before another FlashPal can be intialized by a bomb exploding near a displayplayer. Avoids seizures. diff --git a/src/k_hud.c b/src/k_hud.c index a1ecfc1a7..5690132da 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2210,8 +2210,10 @@ void K_DrawServerDescrption(INT32 x, INT32 y) if (connectedservername[0] != '\0') V_DrawThinString(x, y, V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedservername); - if (serverdescription[0] != '\0') - V_DrawSmallString(x, y+20, V_6WIDTHSPACE|V_ALLOWLOWERCASE, serverdescription); + V_DrawSmallString(x, y+10, V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_GRAYMAP, va("Contact: %s", (connectedservercontact[0] != '\0') ? connectedservercontact : "")); + + if (connectedserverdescription[0] != '\0') + V_DrawSmallString(x, y+20, V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedserverdescription); } diff --git a/src/m_menu.c b/src/m_menu.c index 1583a3ca8..9a4211920 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6413,8 +6413,6 @@ INT32 MR_StartServer(INT32 choice) multiplayer = true; - strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); - // Still need to reset devmode cht_debug = 0; diff --git a/src/mserv.c b/src/mserv.c index 50bf100c1..3c7d24142 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -22,6 +22,7 @@ #include "mserv.h" #include "m_menu.h" #include "z_zone.h" +#include "byteptr.h" #ifdef HAVE_DISCORDRPC #include "discord.h" @@ -503,6 +504,20 @@ Update_parameters (void) UpdateServer(); } #endif/*MASTERSERVER*/ + + // Lets update Clients on this info. + if (Playing() && server) + { + char buf[MAXSERVERNAME+MAXSERVERCONTACT]; + char *cp = buf; + + strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); + strncpy(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); + + WRITESTRINGN(cp, connectedservername, MAXSERVERNAME); + WRITESTRINGN(cp, connectedservercontact, MAXSERVERCONTACT); + SendNetXCmd(XD_SERVERINFOUPDATE, &buf, cp - buf); + } } static void MasterServer_OnChange(void) diff --git a/src/p_saveg.c b/src/p_saveg.c index 2caf50168..01c31f0f5 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5278,7 +5278,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT8(save->p, lastLowestLap); WRITESINT8(save->p, spbplace); WRITEUINT8(save->p, startedInFreePlay); - WRITESTRINGN(save->p, serverdescription, MAXSERVERDESCRIPTION); WRITEUINT32(save->p, introtime); WRITEUINT32(save->p, starttime); @@ -5465,7 +5464,6 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool lastLowestLap = READUINT8(save->p); spbplace = READSINT8(save->p); startedInFreePlay = READUINT8(save->p); - READSTRINGN(save->p, serverdescription, MAXSERVERDESCRIPTION); introtime = READUINT32(save->p); starttime = READUINT32(save->p); From 3f83c1056c434182710e5311e78bb3e7595ae026 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 12:51:28 -0400 Subject: [PATCH 14/26] Shrink Contact to not bloat netxcmd --- src/d_clisrv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index f375bf8ea..3563d7629 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -42,7 +42,7 @@ applications may follow different packet versions. // be transmitted. #define MAXSERVERNAME 32 -#define MAXSERVERCONTACT 1024 +#define MAXSERVERCONTACT 320 #define MAXSERVERDESCRIPTION 320 #define MAXSERVERDESCRIPTIONLINE 40 #define DEFAULTDESCSTRING "Welcome to my SRB2Kart server!" From 1183f2922eb4d7c0a82711d64f245a30fb982e77 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 14:02:32 -0400 Subject: [PATCH 15/26] Refactor this again to use new packet type instead of netxcmd This saves major netxcmd space --- src/d_clisrv.c | 39 ++++++++++++++++++- src/d_clisrv.h | 51 ++++++++++++++++--------- src/d_netcmd.c | 102 +++++++++++-------------------------------------- src/d_netcmd.h | 3 -- src/mserv.c | 9 ++--- src/typedef.h | 1 + 6 files changed, 98 insertions(+), 107 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3e68dd626..120ca4d45 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -870,7 +870,7 @@ static boolean CL_SendJoin(void) return HSendPacket(servernode, false, 0, sizeof (clientconfig_pak)); } -static void +void CopyCaretColors (char *p, const char *s, int n) { char *t; @@ -4381,6 +4381,40 @@ static void PT_LoginAuth(SINT8 node, INT32 netconsole) CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); } +void ServerInfoUpdateSend(void) +{ + UINT32 n; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + for (n = 1; n < MAXNETNODES; n++) + { + // Do Shit + if (nodeingame[n]) + { + CopyCaretColors(netbuffer->u.serverinfoupdate.servername, cv_servername.string, MAXSERVERNAME); + CopyCaretColors(netbuffer->u.serverinfoupdate.servercontact, cv_server_contact.string, MAXSERVERCONTACT); + strncpy(netbuffer->u.serverinfoupdate.serverdescription, connectedserverdescription, MAXSERVERDESCRIPTION); + + netbuffer->packettype = PT_SERVERINFOUPDATE; + HSendPacket(n, false, 0, MAXSERVERNAME+MAXSERVERCONTACT+MAXSERVERDESCRIPTION); + } + } +} + +static void PT_ServerInfoUpdate(SINT8 node) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + if (node != servernode) + return; + + if ((size_t)doomcom->datalength < sizeof(MAXSERVERNAME+MAXSERVERCONTACT+MAXSERVERDESCRIPTION))/* ignore partial sends */ + return; + + strncpy(connectedservername, netbuffer->u.serverinfoupdate.servername, MAXSERVERNAME); + strncpy(connectedservercontact, netbuffer->u.serverinfoupdate.servercontact, MAXSERVERCONTACT); + strncpy(connectedserverdescription, netbuffer->u.serverinfoupdate.serverdescription, MAXSERVERDESCRIPTION); +} /** Called when a PT_NODETIMEOUT packet is received * @@ -5157,6 +5191,9 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_LOGINCHALLENGE: PT_LoginChallenge(node); break; + case PT_SERVERINFOUPDATE: + PT_ServerInfoUpdate(node); + break; case PT_WILLRESENDGAMESTATE: PT_WillResendGamestate(); break; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 3563d7629..4360900f0 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -47,6 +47,9 @@ applications may follow different packet versions. #define MAXSERVERDESCRIPTIONLINE 40 #define DEFAULTDESCSTRING "Welcome to my SRB2Kart server!" +// Sends over info via packets to client players. +void ServerInfoUpdateSend(void); + // Networking and tick handling related. #define BACKUPTICS 512 // more than enough for most timeouts.... #define CLIENTBACKUPTICS 32 @@ -127,6 +130,8 @@ typedef enum PT_LOGINAUTH, // Challenge response from the client. PT_PING, // Packet sent to tell clients the other client's latency to server. + + PT_SERVERINFOUPDATE, // Update server info for clients. NUMPACKETTYPE } packettype_t; @@ -305,6 +310,13 @@ struct serverinfo_pak UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) } ATTRPACK; +struct serverinfoupdate_pak +{ + char servername[MAXSERVERNAME]; + char servercontact[MAXSERVERCONTACT]; + char serverdescription[MAXSERVERDESCRIPTION]; +}; + struct serverrefuse_pak { char reason[255]; @@ -374,28 +386,29 @@ struct doomdata_t UINT8 reserved; // Padding union { - clientcmd_pak clientpak; // 147 bytes - client2cmd_pak client2pak; // 206 bytes - client3cmd_pak client3pak; // 264 bytes(?) - client4cmd_pak client4pak; // 324 bytes(?) - servertics_pak serverpak; // 132495 bytes (more around 360, no?) - serverconfig_pak servercfg; // 773 bytes - UINT8 textcmd[MAXTEXTCMD+2]; // 66049 bytes (wut??? 64k??? More like 258 bytes...) - char filetxpak[sizeof (filetx_pak)];// 139 bytes + clientcmd_pak clientpak; + client2cmd_pak client2pak; + client3cmd_pak client3pak; + client4cmd_pak client4pak; + servertics_pak serverpak; + serverconfig_pak servercfg; + UINT8 textcmd[MAXTEXTCMD+2]; + char filetxpak[sizeof (filetx_pak)]; char fileack[sizeof (fileack_pak)]; UINT8 filereceived; - clientconfig_pak clientcfg; // 136 bytes + clientconfig_pak clientcfg; char salt[9]; UINT8 sha256sum[32]; - serverinfo_pak serverinfo; // 1024 bytes - serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) - askinfo_pak askinfo; // 61 bytes - msaskinfo_pak msaskinfo; // 22 bytes - plrinfo playerinfo[MSCOMPAT_MAXPLAYERS];// 576 bytes(?) - plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) - INT32 filesneedednum; // 4 bytes - filesneededconfig_pak filesneededcfg; // ??? bytes - netinfo_pak netinfo; // Don't believe their lies + serverinfo_pak serverinfo; + serverrefuse_pak serverrefuse; + serverinfoupdate_pak serverinfoupdate; + askinfo_pak askinfo; + msaskinfo_pak msaskinfo; + plrinfo playerinfo[MSCOMPAT_MAXPLAYERS]; + plrconfig playerconfig[MAXPLAYERS]; + INT32 filesneedednum; + filesneededconfig_pak filesneededcfg; + netinfo_pak netinfo; } u; // This is needed to pack diff packet types data together } ATTRPACK; @@ -559,6 +572,8 @@ void CL_UpdateServerList(void); // Is there a game running boolean Playing(void); +void CopyCaretColors (char *p, const char *s, int n); + // Broadcasts special packets to other players // to notify of game exit void D_QuitNetGame(void); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e7517ddc4..32aef5d70 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -103,11 +103,8 @@ static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum); static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum); static void Got_Automatecmd(UINT8 **cp, INT32 playernum); static void Got_Cheat(UINT8 **cp, INT32 playernum); -static void Got_ScoreboardAdd(UINT8 **cp, INT32 playernum); -static void Got_ScoreboardClear(UINT8 **cp, INT32 playernum); static void Command_ScoreboardAdd(void); static void Command_ScoreboardClear(void); -static void Got_ServerInfoUpdate(UINT8 **cp, INT32 playernum); static void PointLimit_OnChange(void); static void TimeLimit_OnChange(void); @@ -765,9 +762,6 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "SCHEDULECLEAR", // XD_SCHEDULECLEAR "AUTOMATE", // XD_AUTOMATE "CHEAT", // XD_CHEAT - "SCOREBOARDADD", // XD_SCOREBOARDADD - "SCOREBOARDCLEAR", // XD_SCOREBOARDCLEAR - "SERVERINFOUPDATE", // XD_SERVERINFOUPDATE }; // ========================================================================= @@ -825,11 +819,8 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd); RegisterNetXCmd(XD_CHEAT, Got_Cheat); - RegisterNetXCmd(XD_SCOREBOARDADD, Got_ScoreboardAdd); - RegisterNetXCmd(XD_SCOREBOARDCLEAR, Got_ScoreboardClear); COM_AddCommand("scoreboard_addline", Command_ScoreboardAdd); COM_AddCommand("scoreboard_clear", Command_ScoreboardClear); - RegisterNetXCmd(XD_SERVERINFOUPDATE, Got_ServerInfoUpdate); // Remote Administration COM_AddCommand("password", Command_Changepassword_f); @@ -3754,8 +3745,10 @@ static char *GetSpecialString(char *buf, char *input, size_t bufsize) static void Command_ScoreboardAdd(void) { - UINT8 buf[4]; - UINT8 *cp = buf; + if (!server) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + } if (COM_Argc() < 2) { @@ -3763,14 +3756,14 @@ static void Command_ScoreboardAdd(void) return; } - if (server || IsPlayerAdmin(consoleplayer)) { size_t i, j = COM_Argc(); char message[MAXSERVERDESCRIPTIONLINE+1]; char *finalstring; INT32 strlensize = 0; + INT32 serverdesclen = 0; - //Steal from the motd code so you don't have to put the reason in quotes. + // Steal from the motd code so you don't have to put the string in quotes. strlcpy(message, COM_Argv(1), sizeof message); for (i = 2; i < j; i++) { @@ -3787,6 +3780,7 @@ static void Command_ScoreboardAdd(void) GetSpecialString(finalstring, message, MAXSERVERDESCRIPTIONLINE); strlensize = strlen(finalstring); + serverdesclen = strlen(connectedserverdescription); if ((strlensize+1) > MAXSERVERDESCRIPTIONLINE) { @@ -3794,87 +3788,35 @@ static void Command_ScoreboardAdd(void) return; } - WRITESTRINGN(cp, finalstring, MAXSERVERDESCRIPTIONLINE+1); - SendNetXCmd(XD_SCOREBOARDADD, &buf, cp - buf); + if ((serverdesclen + strlensize) > MAXSERVERDESCRIPTION) + { + CONS_Alert(CONS_WARNING, M_GetText("Scoreboard text is full so no more text can be added.\n")); + return; + } + else + { + strncat(connectedserverdescription, finalstring, MAXSERVERDESCRIPTIONLINE); + CONS_Printf(M_GetText("Scoreboard text line has been added.\n")); + } + + ServerInfoUpdateSend(); Z_Free(finalstring); } - else - CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); -} - -static void Got_ScoreboardAdd(UINT8 **cp, INT32 playernum) -{ - char tempbuff[MAXSERVERDESCRIPTIONLINE]; - INT32 serverdesclen = 0; - INT32 tempbufflen = 0; - READSTRINGN(*cp, tempbuff, MAXSERVERDESCRIPTIONLINE+1); - - if (playernum != serverplayer && !IsPlayerAdmin(playernum)) // hacked client, or disasterous bug - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal Scoreboard Add command received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]); - if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); - return; - } - - serverdesclen = strlen(connectedserverdescription); - tempbufflen = strlen(tempbuff); - - if ((serverdesclen + tempbufflen) > MAXSERVERDESCRIPTION) - { - CONS_Alert(CONS_WARNING, M_GetText("Scoreboard text is full so no more text can be added.\n")); - return; - } - else - { - strncat(connectedserverdescription, va("%s\n%c", tempbuff, '\0'), MAXSERVERDESCRIPTIONLINE); - CONS_Printf(M_GetText("Scoreboard text line has been added.\n")); - } } static void Command_ScoreboardClear(void) { - if (!(server || (IsPlayerAdmin(consoleplayer)))) - return; - - SendNetXCmd(XD_SCOREBOARDCLEAR, NULL, 1); -} - -static void Got_ScoreboardClear(UINT8 **cp, INT32 playernum) -{ - (void)cp; - if (playernum != serverplayer && !IsPlayerAdmin(playernum)) + if (!server) { - CONS_Alert(CONS_WARNING, M_GetText("Illegal Scoreboard Clear command received from %s\n"), player_names[playernum]); - if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + CONS_Printf(M_GetText("Only the server can use this.\n")); return; } memset(&connectedserverdescription, 0, sizeof(connectedserverdescription)); + ServerInfoUpdateSend(); CONS_Printf(M_GetText("Scoreboard text have been reset by the server.\n")); } -static void Got_ServerInfoUpdate(UINT8 **cp, INT32 playernum) -{ - char tempname[MAXSERVERNAME]; - char tempcontact[MAXSERVERCONTACT]; - READSTRINGN(*cp, tempname, MAXSERVERNAME); - READSTRINGN(*cp, tempcontact, MAXSERVERCONTACT); - - if (playernum != serverplayer && !IsPlayerAdmin(playernum)) // hacked client, or disasterous bug - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal Server Info Update command received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]); - if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); - return; - } - - strncpy(connectedservername, tempname, MAXSERVERNAME); - strncpy(connectedservercontact, tempcontact, MAXSERVERCONTACT); - CONS_Printf(M_GetText("Updated Server Info.\n")); -} - // Team changing functions static void HandleTeamChangeCommand(UINT8 localplayer) { diff --git a/src/d_netcmd.h b/src/d_netcmd.h index e1882b9ed..375af51de 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -286,9 +286,6 @@ typedef enum XD_SCHEDULECLEAR, // 36 XD_AUTOMATE, // 37 XD_CHEAT, // 38 - XD_SCOREBOARDADD, // 39 - XD_SCOREBOARDCLEAR, // 40 - XD_SERVERINFOUPDATE, // 41 MAXNETXCMD } netxcmd_t; diff --git a/src/mserv.c b/src/mserv.c index 3c7d24142..0dbf9a126 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -23,6 +23,7 @@ #include "m_menu.h" #include "z_zone.h" #include "byteptr.h" +#include "i_net.h" #ifdef HAVE_DISCORDRPC #include "discord.h" @@ -508,15 +509,13 @@ Update_parameters (void) // Lets update Clients on this info. if (Playing() && server) { - char buf[MAXSERVERNAME+MAXSERVERCONTACT]; - char *cp = buf; + UINT32 n; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); strncpy(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); - WRITESTRINGN(cp, connectedservername, MAXSERVERNAME); - WRITESTRINGN(cp, connectedservercontact, MAXSERVERCONTACT); - SendNetXCmd(XD_SERVERINFOUPDATE, &buf, cp - buf); + ServerInfoUpdateSend(); } } diff --git a/src/typedef.h b/src/typedef.h index 72323f202..8548d8aad 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -62,6 +62,7 @@ TYPEDEF (fileack_pak); TYPEDEF (clientconfig_pak); TYPEDEF (serverinfo_pak); TYPEDEF (serverrefuse_pak); +TYPEDEF (serverinfoupdate_pak); TYPEDEF (askinfo_pak); TYPEDEF (msaskinfo_pak); TYPEDEF (plrinfo); From f362e5ce7573fefc6ceb5b4843774a628d29a5c6 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 14:05:02 -0400 Subject: [PATCH 16/26] Forogt the return :P --- src/d_netcmd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 32aef5d70..de565bc08 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3748,6 +3748,7 @@ static void Command_ScoreboardAdd(void) if (!server) { CONS_Printf(M_GetText("Only the server can use this.\n")); + return; } if (COM_Argc() < 2) From 6fec29499351af7b67c4e9f260e1814d8f00940c Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 14:06:16 -0400 Subject: [PATCH 17/26] Fix memory leak --- src/d_netcmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index de565bc08..b46c382cc 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3786,12 +3786,14 @@ static void Command_ScoreboardAdd(void) if ((strlensize+1) > MAXSERVERDESCRIPTIONLINE) { CONS_Alert(CONS_WARNING, M_GetText("Scoreboard line is too long to add.\n")); + Z_Free(finalstring); return; } if ((serverdesclen + strlensize) > MAXSERVERDESCRIPTION) { CONS_Alert(CONS_WARNING, M_GetText("Scoreboard text is full so no more text can be added.\n")); + Z_Free(finalstring); return; } else From 547f1b8e90cf917f34589c456cbc7af00eff97d6 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 14:20:11 -0400 Subject: [PATCH 18/26] Use sizeof and reliable mode --- src/d_clisrv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 120ca4d45..8af035d5c 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4396,7 +4396,7 @@ void ServerInfoUpdateSend(void) strncpy(netbuffer->u.serverinfoupdate.serverdescription, connectedserverdescription, MAXSERVERDESCRIPTION); netbuffer->packettype = PT_SERVERINFOUPDATE; - HSendPacket(n, false, 0, MAXSERVERNAME+MAXSERVERCONTACT+MAXSERVERDESCRIPTION); + HSendPacket(n, true, 0, sizeof(netbuffer->u.serverinfoupdate)); } } } @@ -4408,7 +4408,7 @@ static void PT_ServerInfoUpdate(SINT8 node) if (node != servernode) return; - if ((size_t)doomcom->datalength < sizeof(MAXSERVERNAME+MAXSERVERCONTACT+MAXSERVERDESCRIPTION))/* ignore partial sends */ + if ((size_t)doomcom->datalength < sizeof(netbuffer->u.serverinfoupdate))/* ignore partial sends */ return; strncpy(connectedservername, netbuffer->u.serverinfoupdate.servername, MAXSERVERNAME); From d0e1c46cc322fffdb74bdd7d6cc3062dc134ae3f Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 14:56:38 -0400 Subject: [PATCH 19/26] Clean up --- src/mserv.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mserv.c b/src/mserv.c index 0dbf9a126..2e1e45cbc 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -509,9 +509,6 @@ Update_parameters (void) // Lets update Clients on this info. if (Playing() && server) { - UINT32 n; - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); strncpy(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); From 96c9b029c571edcc87cd2d45b013da40d9e4365a Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 15:22:22 -0400 Subject: [PATCH 20/26] Use colorcode copy for init --- src/d_clisrv.c | 4 ++-- src/mserv.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8af035d5c..815461f62 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3576,8 +3576,8 @@ static void SV_GenContext(void) server_context[i] = 'a'+(a-26); } - strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); - strncpy(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); + CopyCaretColors(connectedservername, cv_servername.string, MAXSERVERNAME); + CopyCaretColors(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); strncpy(connectedserverdescription, DEFAULTDESCSTRING, MAXSERVERDESCRIPTION); } diff --git a/src/mserv.c b/src/mserv.c index 2e1e45cbc..ae1212891 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -509,8 +509,8 @@ Update_parameters (void) // Lets update Clients on this info. if (Playing() && server) { - strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); - strncpy(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); + CopyCaretColors(connectedservername, cv_servername.string, MAXSERVERNAME); + CopyCaretColors(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); ServerInfoUpdateSend(); } From 1a8958a34fc00444b268b0ca22ee8dd20769e7a7 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 1 Sep 2025 20:33:43 -0400 Subject: [PATCH 21/26] Start the basics mod the mod display system --- src/d_clisrv.c | 2 ++ src/d_clisrv.h | 13 ++++++++++ src/d_netcmd.c | 2 +- src/k_hud.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/typedef.h | 1 + 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 815461f62..54a5443c9 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -163,6 +163,8 @@ SINT8 joinnode = 0; // used for CL_VIEWSERVER char connectedservername[MAXSERVERNAME]; char connectedservercontact[MAXSERVERCONTACT]; char connectedserverdescription[MAXSERVERDESCRIPTION]; +servermods_t connectedservercustommods[MAXSERVERMODS]; +UINT8 numcustomservermods = 0; /// \brief do we accept new players? /// \todo WORK! diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 4360900f0..2c9d55af2 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -47,6 +47,17 @@ applications may follow different packet versions. #define MAXSERVERDESCRIPTIONLINE 40 #define DEFAULTDESCSTRING "Welcome to my SRB2Kart server!" +#define MAXSERVERMODS 255 +#define MAXSERVERMODNAME 13 + +struct servermods_t +{ + char modname[MAXSERVERMODNAME]; + consvar_t *cvar; + SINT8 active; // -1 is N/A, 0 is off, 1 is on. + boolean valid; +}; + // Sends over info via packets to client players. void ServerInfoUpdateSend(void); @@ -477,6 +488,8 @@ extern SINT8 servernode; extern char connectedservername[MAXSERVERNAME]; extern char connectedservercontact[MAXSERVERCONTACT]; extern char connectedserverdescription[MAXSERVERDESCRIPTION]; +extern servermods_t connectedservercustommods[MAXSERVERMODS]; +extern UINT8 numcustomservermods; void Command_Ping_f(void); extern tic_t connectiontimeout; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9f9d82933..e68d69521 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3799,7 +3799,7 @@ static void Command_ScoreboardAdd(void) } else { - strncat(connectedserverdescription, finalstring, MAXSERVERDESCRIPTIONLINE); + strncat(connectedserverdescription, va("%s\n", finalstring), MAXSERVERDESCRIPTIONLINE); CONS_Printf(M_GetText("Scoreboard text line has been added.\n")); } diff --git a/src/k_hud.c b/src/k_hud.c index 5690132da..b8b00b201 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2205,6 +2205,72 @@ INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines return x+rightoffset; } +#define BASEMODS 11 +void K_DrawServerMods(INT32 x, INT32 y) +{ + UINT8 i, j; + INT32 xoff = 0, yoff = 10; + UINT8 numdrawn = 0; + + servermods_t basemods[BASEMODS] = + { + {"Rings", NULL, K_RingsActive() > 0, true}, + {"4-Tier Drifts", NULL, K_PurpleDriftActive() > 0, true}, + {"Slipdash", NULL, K_SlipdashActive() > 0, true}, + {"Stacking", NULL, K_StackingActive() > 0, true}, + {"Chaining", NULL, K_ChainingActive() > 0, true}, + {"Chain Offroad", &cv_kartchainingoffroad, -1, true}, + {"Slope Boost", NULL, K_PurpleDriftActive() > 0, true}, + {"Drafting", NULL, K_PurpleDriftActive() > 0, true}, + {"Bump Spark", &cv_kartbumpspark, -1, true}, + {"Bump Spring", &cv_kartbumpspring, -1, true}, + {"Alt. Invin.", NULL, K_GetKartInvinType() == KARTINVIN_ALTERN, true} + }; + + V_DrawThinString(x, y, V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_GRAYMAP, "Gameplay / Balance Changes:"); + + for (j = 0; j < 2; j++) + { + UINT8 modcount = j == 0 ? BASEMODS : numcustomservermods; + servermods_t *modslist = j == 0 ? basemods : connectedservercustommods; + + // Draw the the modlist. + for (i = 0; i < modcount; i++) + { + boolean drawdis = false; + + if (modslist[i].valid) + { + if (modslist[i].cvar && modslist[i].cvar->value) + { + drawdis = true; + } + else if (modslist[i].active == 1) + { + drawdis = true; + } + + if (drawdis && modslist[i].modname[0] != '\0') + { + V_DrawSmallString(x+xoff, y+yoff, V_6WIDTHSPACE|V_ALLOWLOWERCASE, modslist[i].modname); + numdrawn++; + + if ((numdrawn % 2) == 0) + { + xoff -= 50; + yoff += 5; + } + else if ((numdrawn % 1) == 0) + { + xoff += 50; + } + } + } + } + } +} +#undef BASEMODS + void K_DrawServerDescrption(INT32 x, INT32 y) { if (connectedservername[0] != '\0') @@ -2215,6 +2281,7 @@ void K_DrawServerDescrption(INT32 x, INT32 y) if (connectedserverdescription[0] != '\0') V_DrawSmallString(x, y+20, V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedserverdescription); + K_DrawServerMods(x, y + 50); } static void K_drawKartLaps(void) diff --git a/src/typedef.h b/src/typedef.h index 8548d8aad..81b686f84 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -72,6 +72,7 @@ TYPEDEF (doomdata_t); TYPEDEF (serverelem_t); TYPEDEF (rewind_t); TYPEDEF (netinfo_pak); +TYPEDEF (servermods_t); // d_event.h TYPEDEF (event_t); From 7ed5c2de6daee812c178e1eaba1aab90200221e4 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 2 Sep 2025 15:40:01 -0400 Subject: [PATCH 22/26] Don't SHORT() stuff that doesn't need it for HUD code --- src/k_hud.c | 45 ++++++++++++++++++++------------------------- src/lua_hudlib.c | 6 +++--- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index b8b00b201..a3a78452e 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1168,8 +1168,8 @@ void K_getMinimapDrawinfo(drawinfo_t *out) { INT32 fx = MINI_X, fy = MINI_Y, fflags = (r_splitscreen < 2 ? V_SNAPTORIGHT : 0); // flags should only be 0 when it's centered (4p split) - fx -= SHORT(minimapinfo.minimap_pic->width)/2; - fy -= SHORT(minimapinfo.minimap_pic->height)/2; + fx -=minimapinfo.minimap_pic->width/2; + fy -=minimapinfo.minimap_pic->height/2; out->x = fx; out->y = fy; @@ -1689,7 +1689,7 @@ static void K_DrawKartPositionNum(INT32 num) boolean win = (stplyr->exiting && num == 1); //INT32 X = POSI_X; - INT32 W = SHORT(kp_positionnum[0][0]->width); + INT32 W = kp_positionnum[0][0]->width; fixed_t scale = FRACUNIT; patch_t *localpatch = kp_positionnum[0][0]; INT32 fx = 0, fy = 0, fflags = 0; @@ -1815,8 +1815,8 @@ static void K_DrawKartPositionNum(INT32 num) } V_DrawFixedPatch( - (fx<width)*scale/2) : 0), - (fy<height)*scale/2) : 0), + (fx<width)*scale/2 : 0), + (fy<height)*scale/2 : 0), scale, addOrSub|V_HUDTRANSHALF|fflags, localpatch, NULL ); // ^ if we overtake as p1 or p3 in splitscren, we shift it so that it doesn't go off screen. @@ -2850,7 +2850,7 @@ static void K_drawKartWanted(void) } else if (r_splitscreen == 3) // 4P splitscreen... { - basex = BASEVIDWIDTH/2 - (SHORT(kp_wantedsplit->width)/2); // center on screen + basex = BASEVIDWIDTH/2 - (kp_wantedsplit->width/2); // center on screen basey = BASEVIDHEIGHT - 55; //basey2 = 4; } @@ -3472,8 +3472,8 @@ static inline void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, if (encoremode) amnumxpos = -amnumxpos; - amxpos = amnumxpos + ((hudx + (SHORT(minimapinfo.minimap_pic->width)-SHORT(icon->width))/2)<height)-SHORT(icon->height))/2)<width-icon->width)/2)<height-icon->height)/2)<width)-48)/2)<height)-24)/2)<width-48)/2)<height-24)/2)<mo->skin)-skins; - amxpos = amnumxpos + ((hudx + (SHORT(minimapinfo.minimap_pic->width)-SHORT(faceprefix[skin][FACE_MINIMAP]->width))/2)<height)-SHORT(faceprefix[skin][FACE_MINIMAP]->height))/2)<width-faceprefix[skin][FACE_MINIMAP]->width)/2)<height-faceprefix[skin][FACE_MINIMAP]->height)/2)<width) / 2); - amypos = (amnumypos / FRACUNIT) + (SHORT(minimapinfo.minimap_pic->height) / 2); + amxpos = (amnumxpos / FRACUNIT) + (minimapinfo.minimap_pic->width / 2); + amypos = (amnumypos / FRACUNIT) + (minimapinfo.minimap_pic->height / 2); if (flags & V_NOSCALESTART) { @@ -3736,7 +3731,7 @@ static void K_drawKartMinimap(void) minimaptrans = ((10-minimaptrans)<width), y, splitflags|minimaptrans|V_FLIP, minimapinfo.minimap_pic); + V_DrawScaledPatch(x+minimapinfo.minimap_pic->width, y, splitflags|minimaptrans|V_FLIP, minimapinfo.minimap_pic); else V_DrawScaledPatch(x, y, splitflags|minimaptrans, minimapinfo.minimap_pic); @@ -4137,7 +4132,7 @@ static void K_drawKartStartCountdown(void) if (r_splitscreen) // splitscreen pnum += 10; - V_DrawScaledPatch(STCD_X - (SHORT(kp_startcountdown[pnum]->width)/2), STCD_Y - (SHORT(kp_startcountdown[pnum]->height)/2), V_SPLITSCREEN, kp_startcountdown[pnum]); + V_DrawScaledPatch(STCD_X - (kp_startcountdown[pnum]->width/2), STCD_Y - (kp_startcountdown[pnum]->height/2), V_SPLITSCREEN, kp_startcountdown[pnum]); } } @@ -4154,7 +4149,7 @@ static void K_drawKartFinish(void) if (r_splitscreen > 1) // 3/4p, stationary FIN { pnum += 2; - V_DrawScaledPatch(STCD_X - (SHORT(kp_racefinish[pnum]->width)/2), STCD_Y - (SHORT(kp_racefinish[pnum]->height)/2), splitflags, kp_racefinish[pnum]); + V_DrawScaledPatch(STCD_X - (kp_racefinish[pnum]->width/2), STCD_Y - (kp_racefinish[pnum]->height/2), splitflags, kp_racefinish[pnum]); return; } @@ -4166,7 +4161,7 @@ static void K_drawKartFinish(void) pnum += 4; x = ((vid.width<width)<width)<height)<<(FRACBITS-1)), + (STCD_Y<height<<(FRACBITS-1)), FRACUNIT, splitflags, kp_racefinish[pnum], NULL); } @@ -5320,7 +5315,7 @@ void K_drawKartHUD(void) return; if (gametype == GT_BATTLE && !r_splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM * - V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem); + V_DrawScaledPatch(BASEVIDWIDTH/2 - (kp_yougotem->width/2), 32, V_HUDTRANS, kp_yougotem); // Draw FREE PLAY. if (islonesome) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 485160d5b..50bd9b35d 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -762,10 +762,10 @@ static int libd_drawOnMinimap(lua_State *L) // let offsets transfer to the heads, too! if (encoremode) - mx += SHORT(minimapinfo.minimap_pic->leftoffset); + mx += minimapinfo.minimap_pic->leftoffset; else - mx -= SHORT(minimapinfo.minimap_pic->leftoffset); - my -= SHORT(minimapinfo.minimap_pic->topoffset); + mx -= minimapinfo.minimap_pic->leftoffset; + my -= minimapinfo.minimap_pic->topoffset; // now that we have replicated this behavior, we can draw an icon from our supplied x, y coordinates by replicating k_kart.c's totally understandable uncommented code!!! From d98928d74decdd7a88f25776a7cb65a4aeee4707 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 3 Sep 2025 09:41:02 -0400 Subject: [PATCH 23/26] Thanks debian --- src/sdl/i_video.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 55606aad1..0f323ebeb 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -255,7 +255,10 @@ static SDL_bool Impl_RenderContextReset(void) if (renderer) { SDL_DestroyRenderer(renderer); +// Thanks Debian.... +#if SDL_VERSION_ATLEAST(2,28,0) SDL_DestroyWindowSurface(window); // workaround for a bug in sdl +#endif texture = NULL; // Destroying a renderer also destroys all of its textures } renderer = NULL; From f66343134b4fb0de0cf236360358c2c3accd62e2 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 3 Sep 2025 11:59:24 -0400 Subject: [PATCH 24/26] Add back old tabrankings as toggle and other stuff --- src/d_clisrv.h | 4 +- src/hu_stuff.c | 13 ++++-- src/k_hud.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++-- src/k_hud.h | 3 ++ 4 files changed, 135 insertions(+), 9 deletions(-) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 2c9d55af2..2a0ae8c7c 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -45,7 +45,7 @@ applications may follow different packet versions. #define MAXSERVERCONTACT 320 #define MAXSERVERDESCRIPTION 320 #define MAXSERVERDESCRIPTIONLINE 40 -#define DEFAULTDESCSTRING "Welcome to my SRB2Kart server!" +#define DEFAULTDESCSTRING "Welcome to my SRB2Kart server!\n" #define MAXSERVERMODS 255 #define MAXSERVERMODNAME 13 @@ -54,7 +54,7 @@ struct servermods_t { char modname[MAXSERVERMODNAME]; consvar_t *cvar; - SINT8 active; // -1 is N/A, 0 is off, 1 is on. + SINT8 active; // -1 is N/A (example:if using cvar activation), 0 is off, 1 is on. boolean valid; }; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7f9819e5a..2d308f4d2 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2616,10 +2616,15 @@ static void HU_DrawRankings(void) #endif } - INT32 xoffset = K_DrawNeoTabRankings(0, 33, tab, scorelines, whiteplayer, hilicol, true); - - K_DrawServerDescrption(xoffset+10, 33); - //V_DrawThinString(xoffset+10, 33, V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + if (cv_newtabranking.value) + { + INT32 xoffset = K_DrawNeoTabRankings(0, 33, tab, scorelines, whiteplayer, hilicol, true); + K_DrawServerDescrption(xoffset+10, 33); + } + else + { + K_DrawTabRankings(((scorelines > 8) ? 32 : 40), 33, tab, scorelines, whiteplayer, hilicol); + } // draw spectators in a ticker across the bottom if (netgame && G_GametypeHasSpectators()) diff --git a/src/k_hud.c b/src/k_hud.c index b683106dc..002a36789 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -100,6 +100,8 @@ consvar_t cv_driftgaugeoffset = CVAR_INIT ("kartdriftgaugeoffset", "-10", CV_SAV static CV_PossibleValue_t HudColor_cons_t[MAXSKINCOLORS+1]; consvar_t cv_colorizedhudcolor = CVAR_INIT ("colorizedhudcolor", "Skin Color", CV_SAVE, HudColor_cons_t, NULL); +consvar_t cv_newtabranking = CVAR_INIT ("newtabranking", "On", CV_SAVE, CV_OnOff, NULL); + //{ Patch Definitions static patch_t *kp_nodraw; @@ -254,6 +256,7 @@ void K_RegisterKartHUDStuff(void) CV_RegisterVar(&cv_smoothposition); CV_RegisterVar(&cv_driftgauge); CV_RegisterVar(&cv_driftgaugeoffset); + CV_RegisterVar(&cv_newtabranking); } void K_LoadKartHUDGraphics(void) @@ -2227,8 +2230,6 @@ void K_DrawServerMods(INT32 x, INT32 y) {"Alt. Invin.", NULL, K_GetKartInvinType() == KARTINVIN_ALTERN, true} }; - V_DrawThinString(x, y, V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_GRAYMAP, "Gameplay / Balance Changes:"); - for (j = 0; j < 2; j++) { UINT8 modcount = j == 0 ? BASEMODS : numcustomservermods; @@ -2268,20 +2269,137 @@ void K_DrawServerMods(INT32 x, INT32 y) } } } + + if (numdrawn > 0) + V_DrawThinString(x, y, V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_GRAYMAP, "Gameplay / Balance Changes:"); + } #undef BASEMODS void K_DrawServerDescrption(INT32 x, INT32 y) { + UINT8 i, newlinecount = 0; if (connectedservername[0] != '\0') V_DrawThinString(x, y, V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedservername); V_DrawSmallString(x, y+10, V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_GRAYMAP, va("Contact: %s", (connectedservercontact[0] != '\0') ? connectedservercontact : "")); if (connectedserverdescription[0] != '\0') + { V_DrawSmallString(x, y+20, V_6WIDTHSPACE|V_ALLOWLOWERCASE, connectedserverdescription); - K_DrawServerMods(x, y + 50); + for (i = 0; connectedserverdescription[i]; i++) + newlinecount += (connectedserverdescription[i] == '\n'); + } + + K_DrawServerMods(x, y + 25 + newlinecount*6); +} + +// The old school one.... +void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol) +{ + INT32 i, rightoffset = 240; + UINT8 *colormap = NULL; + UINT16 hightlightcolor = 0; + INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2; + int basey = y, basex = x, y2; + + V_DrawFill(1-duptweak, 26, dupadjust-2, 1, 0); // Draw a horizontal line because it looks nice! + + scorelines--; + if (scorelines >= 8) + { + V_DrawFill(160, 26, 1, 147, 0); // Draw a vertical line to separate the two sides. + V_DrawFill(1-duptweak, 173, dupadjust-2, 1, 0); // And a horizontal line near the bottom. + rightoffset = (BASEVIDWIDTH/2) - 4 - x; + x = (BASEVIDWIDTH/2) + 4; + y += 18*(scorelines-8); + } + else + { + y += 18*scorelines; + } + + for (i = scorelines; i >= 0; i--) + { + char playername[MAXPLAYERNAME+1]; + + if (players[tab[i].num].spectator || !players[tab[i].num].mo) + continue; //ignore them. + + if (netgame) // don't draw ping offline + { + if (players[tab[i].num].bot) + { + V_DrawString(x + ((i < 8) ? -25 : rightoffset + 3), y-2, V_SNAPTOLEFT, "CPU"); + } + else if (tab[i].num != serverplayer || !server_lagless) + { + HU_drawPing(x + ((i < 8) ? -17 : rightoffset + 11), y-4, playerpingtable[tab[i].num], playerdelaytable[tab[i].num], playerpacketlosstable[tab[i].num], 0, true); + } + else if (tab[i].num == serverplayer) + { + V_DrawString(x + ((i < 8) ? -25 : rightoffset + 3), y-2, V_SNAPTOLEFT, "SRV"); + } + } + + STRBUFCPY(playername, tab[i].name); + + y2 = y; + + if (players[tab[i].num].mo->color) + { + colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); + if (players[tab[i].num].mo->colorized) + colormap = R_GetTranslationColormap(TC_RAINBOW, players[tab[i].num].mo->color, GTC_CACHE); + else + colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); + + hightlightcolor = skincolors[players[tab[i].num].mo->color].chatcolor; + } + + if (scorelines >= 8) + V_DrawThinString(x + 20, y2, ((tab[i].num == whiteplayer) ? hightlightcolor : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, playername); + else + V_DrawString(x + 20, y2, ((tab[i].num == whiteplayer) ? hightlightcolor : 0)|V_ALLOWLOWERCASE, playername); + + V_DrawMappedPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin][FACE_RANK], colormap); + + /*if (gametype == GT_BATTLE && players[tab[i].num].bumper > 0) -- not enough space for this + { + INT32 bumperx = x+19; + V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumper[0], colormap); + for (j = 1; j < players[tab[i].num].bumper; j++) + { + bumperx += 5; + V_DrawMappedPatch(bumperx, y-4, 0, kp_tinybumper[1], colormap); + } + }*/ + + if (tab[i].num == whiteplayer) + V_DrawScaledPatch(x, y-4, 0, kp_facehighlight[(leveltime / 4) % 8]); + + if (gametype == GT_BATTLE && players[tab[i].num].bumper <= 0) + V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers); + else + { + INT32 pos = players[tab[i].num].position; + if (pos < 0 || pos > MAXPLAYERS) + pos = 0; + // Draws the little number over the face + V_DrawScaledPatch(x-5, y+6, 0, kp_facenum[pos]); + } + + if (tab[i].string[0] != '\0') + V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, tab[i].string); + + y -= 18; + if (i == 8) + { + y = basey + 7*18; + x = basex; + } + } } static void K_drawKartLaps(void) diff --git a/src/k_hud.h b/src/k_hud.h index 5398ddd39..7052614d4 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -62,6 +62,8 @@ extern consvar_t cv_colorizeditembox; extern consvar_t cv_darkitembox; extern consvar_t cv_colorizedhudcolor; +extern consvar_t cv_newtabranking; + struct trackingResult_t { fixed_t x, y; @@ -98,6 +100,7 @@ void K_drawKartHUD(void); void K_drawKartFreePlay(void); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol, boolean split); +void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol); void K_DrawServerDescrption(INT32 x, INT32 y); From eef0d966a3851ee48a6fc1341b41e28710544b3d Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 3 Sep 2025 19:58:27 -0400 Subject: [PATCH 25/26] Allow Lua to add new scoreboard mods This is just how HostMod does it, so this doesn't need networking --- src/d_clisrv.c | 2 -- src/d_clisrv.h | 13 -------- src/d_main.cpp | 5 ++++ src/deh_tables.c | 6 ++++ src/k_hud.c | 76 +++++++++++++++++++++++++++++++++++++++-------- src/k_hud.h | 24 +++++++++++++++ src/lua_baselib.c | 27 +++++++++++++++++ src/typedef.h | 2 +- 8 files changed, 126 insertions(+), 29 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 54a5443c9..815461f62 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -163,8 +163,6 @@ SINT8 joinnode = 0; // used for CL_VIEWSERVER char connectedservername[MAXSERVERNAME]; char connectedservercontact[MAXSERVERCONTACT]; char connectedserverdescription[MAXSERVERDESCRIPTION]; -servermods_t connectedservercustommods[MAXSERVERMODS]; -UINT8 numcustomservermods = 0; /// \brief do we accept new players? /// \todo WORK! diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 2a0ae8c7c..0002cdb80 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -47,17 +47,6 @@ applications may follow different packet versions. #define MAXSERVERDESCRIPTIONLINE 40 #define DEFAULTDESCSTRING "Welcome to my SRB2Kart server!\n" -#define MAXSERVERMODS 255 -#define MAXSERVERMODNAME 13 - -struct servermods_t -{ - char modname[MAXSERVERMODNAME]; - consvar_t *cvar; - SINT8 active; // -1 is N/A (example:if using cvar activation), 0 is off, 1 is on. - boolean valid; -}; - // Sends over info via packets to client players. void ServerInfoUpdateSend(void); @@ -488,8 +477,6 @@ extern SINT8 servernode; extern char connectedservername[MAXSERVERNAME]; extern char connectedservercontact[MAXSERVERCONTACT]; extern char connectedserverdescription[MAXSERVERDESCRIPTION]; -extern servermods_t connectedservercustommods[MAXSERVERMODS]; -extern UINT8 numcustomservermods; void Command_Ping_f(void); extern tic_t connectiontimeout; diff --git a/src/d_main.cpp b/src/d_main.cpp index 6c682d9d9..52c714584 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -76,6 +76,7 @@ // SRB2Kart #include "k_grandprix.h" #include "k_boss.h" +#include "k_hud.h" #include "doomstat.h" #include "m_random.h" // P_ClearRandom #include "acs/interface.h" @@ -1213,6 +1214,10 @@ void D_StartTitle(void) // Reset GP memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); + // Reset Server mods + numcustomservermods = 0; + memset(customservermods, 0, sizeof(customservermods)); + // Reset boss info K_ResetBossInfo(); diff --git a/src/deh_tables.c b/src/deh_tables.c index 9b350cb81..e6037e5de 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -30,6 +30,7 @@ #include "k_bot.h" // bot constants (for lua) #include "g_input.h" // Game controls (for lua) #include "k_kart.h" // awardscaledrings_t +#include "k_hud.h" // scoreboardmod_e #include "k_waypoint.h" // waypoint values (for lua) #include "deh_tables.h" @@ -1636,5 +1637,10 @@ struct int_const_s const INT_CONST[] = { // k_waypoint.h values {"DEFAULT_WAYPOINT_RADIUS",DEFAULT_WAYPOINT_RADIUS}, + // scoreboardmod + {"SCOREBOARDMOD_NOTUSED", SCOREBOARDMOD_NOTUSED}, + {"SCOREBOARDMOD_INACTIVE", SCOREBOARDMOD_INACTIVE}, + {"SCOREBOARDMOD_ACTIVE", SCOREBOARDMOD_ACTIVE}, + {NULL,0} }; diff --git a/src/k_hud.c b/src/k_hud.c index 002a36789..0894b5b6c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2208,6 +2208,56 @@ INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines return x+rightoffset; } +servermods_t customservermods[MAXSERVERMODS]; +UINT8 numcustomservermods = 0; + +// Adds a new mod to the scoreboard display. +void K_AddNewScoreboardMod(const char *name, const consvar_t *cvar, SINT8 active) +{ + UINT32 hashcompare = HASH32(name, MAXSERVERMODNAME); + UINT8 i; + + for (i = 0; i < MAXSERVERMODS; i++) + { + if (customservermods[i].hash == hashcompare) + { + CONS_Alert(CONS_WARNING, "Scoreboard mod '%s' has already been added to the scoreboard.\n", name); + return; + } + } + + if (numcustomservermods+1 == MAXSERVERMODS) + { + CONS_Alert(CONS_ERROR, "Maximum Amount of scoreboard mods has been reached.\n"); + return; + } + + strncpy(customservermods[numcustomservermods].modname, name, MAXSERVERMODNAME); + customservermods[numcustomservermods].hash = hashcompare; + customservermods[numcustomservermods].cvar = cvar; + customservermods[numcustomservermods].active = CLAMP(active, SCOREBOARDMOD_NOTUSED, SCOREBOARDMOD_ACTIVE); + customservermods[numcustomservermods].valid = true; + numcustomservermods++; +} + +// Change the status of static scoreboard displays. +void K_SetScoreboardModStatus(const char *name, SINT8 active) +{ + UINT32 hashcompare = HASH32(name, MAXSERVERMODNAME); + UINT8 i; + + for (i = 0; i < MAXSERVERMODS; i++) + { + if (customservermods[i].hash == hashcompare) + { + customservermods[i].active = CLAMP(active, SCOREBOARDMOD_NOTUSED, SCOREBOARDMOD_ACTIVE); + return; + } + } + + CONS_Alert(CONS_WARNING, "Server mod '%s' does not exist so status cannot be changed.\n", name); +} + #define BASEMODS 11 void K_DrawServerMods(INT32 x, INT32 y) { @@ -2217,23 +2267,23 @@ void K_DrawServerMods(INT32 x, INT32 y) servermods_t basemods[BASEMODS] = { - {"Rings", NULL, K_RingsActive() > 0, true}, - {"4-Tier Drifts", NULL, K_PurpleDriftActive() > 0, true}, - {"Slipdash", NULL, K_SlipdashActive() > 0, true}, - {"Stacking", NULL, K_StackingActive() > 0, true}, - {"Chaining", NULL, K_ChainingActive() > 0, true}, - {"Chain Offroad", &cv_kartchainingoffroad, -1, true}, - {"Slope Boost", NULL, K_PurpleDriftActive() > 0, true}, - {"Drafting", NULL, K_PurpleDriftActive() > 0, true}, - {"Bump Spark", &cv_kartbumpspark, -1, true}, - {"Bump Spring", &cv_kartbumpspring, -1, true}, - {"Alt. Invin.", NULL, K_GetKartInvinType() == KARTINVIN_ALTERN, true} + {"Rings", 0, NULL, K_RingsActive() > 0, true}, + {"4-Tier Drifts", 0, NULL, K_PurpleDriftActive() > 0, true}, + {"Slipdash", 0, NULL, K_SlipdashActive() > 0, true}, + {"Stacking", 0, NULL, K_StackingActive() > 0, true}, + {"Chaining", 0, NULL, K_ChainingActive() > 0, true}, + {"Chain Offroad", 0, &cv_kartchainingoffroad, -1, true}, + {"Slope Boost", 0, NULL, K_PurpleDriftActive() > 0, true}, + {"Drafting", 0, NULL, K_PurpleDriftActive() > 0, true}, + {"Bump Spark", 0, &cv_kartbumpspark, -1, true}, + {"Bump Spring", 0, &cv_kartbumpspring, -1, true}, + {"Alt. Invin.", 0, NULL, K_GetKartInvinType() == KARTINVIN_ALTERN, true} }; for (j = 0; j < 2; j++) { UINT8 modcount = j == 0 ? BASEMODS : numcustomservermods; - servermods_t *modslist = j == 0 ? basemods : connectedservercustommods; + servermods_t *modslist = j == 0 ? basemods : customservermods; // Draw the the modlist. for (i = 0; i < modcount; i++) @@ -2246,7 +2296,7 @@ void K_DrawServerMods(INT32 x, INT32 y) { drawdis = true; } - else if (modslist[i].active == 1) + else if (modslist[i].active == SCOREBOARDMOD_ACTIVE) { drawdis = true; } diff --git a/src/k_hud.h b/src/k_hud.h index 7052614d4..5e4d4e6ab 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -102,6 +102,30 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol, boolean split); void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol); +#define MAXSERVERMODS 255 +#define MAXSERVERMODNAME 13 + +struct servermods_t +{ + char modname[MAXSERVERMODNAME]; + UINT32 hash; + const consvar_t *cvar; + SINT8 active; // -1 is N/A (example: if using cvar activation), 0 is off, 1 is on. + boolean valid; +}; + +typedef enum +{ + SCOREBOARDMOD_NOTUSED = -1, + SCOREBOARDMOD_INACTIVE, + SCOREBOARDMOD_ACTIVE, +} scoreboardmod_e; + +extern servermods_t customservermods[MAXSERVERMODS]; +extern UINT8 numcustomservermods; +void K_AddNewScoreboardMod(const char *name, const consvar_t *cvar, SINT8 active); +void K_SetScoreboardModStatus(const char *name, SINT8 active); + void K_DrawServerDescrption(INT32 x, INT32 y); void K_DrawDriftGauge(void); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9aeff1ce8..8d9b23125 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4349,6 +4349,29 @@ static int lib_kAwardScaledPlayerRings(lua_State *L) return 0; } +static int lib_kAddNewScoreboardMod(lua_State *L) +{ + const char *modname = luaL_checkstring(L, 1); + const char *cvarname = lua_isnil(L, 2) ? NULL : luaL_checkstring(L, 2); + const consvar_t *cvar = lua_isnil(L, 2) ? NULL : CV_FindVar(cvarname); + SINT8 active = SCOREBOARDMOD_NOTUSED; + + if (!cvarname || !cvar) + active = SCOREBOARDMOD_ACTIVE; + + K_AddNewScoreboardMod(modname, cvar, active); + return 0; +} + +static int lib_kSetScoreboardModStatus(lua_State *L) +{ + const char *modname = luaL_checkstring(L, 1); + SINT8 active = CLAMP(luaL_checkinteger(L, 2), SCOREBOARDMOD_NOTUSED, SCOREBOARDMOD_ACTIVE); + + K_SetScoreboardModStatus(modname, active); + return 0; +} + static int lib_kPlayerUsesBotMovement(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -5257,6 +5280,10 @@ static luaL_Reg lib[] = { {"K_AwardPlayerRings", lib_kAwardPlayerRings}, {"K_AwardScaledPlayerRings", lib_kAwardScaledPlayerRings}, + // k_hud + {"K_AddNewScoreboardMod", lib_kAddNewScoreboardMod}, + {"K_SetScoreboardModStatus", lib_kSetScoreboardModStatus}, + // k_waypoint {"K_NextRespawnWaypointIndex", lib_kNextRespawnWaypointIndex}, {"K_GetFinishLineWaypoint", lib_kGetFinishLineWaypoint}, diff --git a/src/typedef.h b/src/typedef.h index 81b686f84..b34af2b44 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -72,7 +72,6 @@ TYPEDEF (doomdata_t); TYPEDEF (serverelem_t); TYPEDEF (rewind_t); TYPEDEF (netinfo_pak); -TYPEDEF (servermods_t); // d_event.h TYPEDEF (event_t); @@ -178,6 +177,7 @@ TYPEDEF (followercategory_t); // k_hud.h TYPEDEF (trackingResult_t); +TYPEDEF (servermods_t); // k_menu.h TYPEDEF (menucolor_t); From 018ff0579d73e04d95310a9ec3dac72a256a51e3 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 3 Sep 2025 20:32:28 -0400 Subject: [PATCH 26/26] Just use CopyCaretColor --- src/d_netcmd.c | 75 +------------------------------------------------- 1 file changed, 1 insertion(+), 74 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 67e391f1a..95a143eea 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3671,79 +3671,6 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum) CONS_Printf(M_GetText("Scores have been reset by the server.\n")); } -ATTRINLINE static FUNCINLINE unsigned char GetColorChar(char *input, size_t *curpos) -{ - char c = input[*curpos++]; - if (c == '^') // oh, nevermind then. - return '^'; - - if (c >= '0' && c <= '9') - return 0x80+(c-'0'); - - c = tolower(c); - - if (c >= 'a' && c <= 'f') - return 0x80+10+(c-'a'); - - return 0x80; // Unhandled -- default to no color -} - -ATTRINLINE static FUNCINLINE char GetHexChar(char *input, size_t *curpos) -{ - char c = input[*curpos++]; - char endchr = 0; - if (c == '\\') // oh, nevermind then. - return '\\'; - - if (c >= '0' && c <= '9') - endchr += (c-'0') << 4; - else if (c >= 'A' && c <= 'F') - endchr += ((c-'A') + 10) << 4; - else if (c >= 'a' && c <= 'f') - endchr += ((c-'a') + 10) << 4; - else // invalid. stop and return a question mark. - return '?'; - - c = input[*curpos++]; - if (c >= '0' && c <= '9') - endchr += (c-'0'); - else if (c >= 'A' && c <= 'F') - endchr += ((c-'A') + 10); - else if (c >= 'a' && c <= 'f') - endchr += ((c-'a') + 10); - else // invalid. stop and return a question mark. - return '?'; - - return endchr; -} - -static char *GetSpecialString(char *buf, char *input, size_t bufsize) -{ - size_t i = 0; - size_t currentpos = 0; - strncpy(buf, input, bufsize); - - // we need one byte for a null terminated string - bufsize--; - while (i < bufsize) - { - char c = buf[currentpos++]; - if (c == '^') - { - buf[i++] = GetColorChar(buf, ¤tpos); - currentpos++; - } - /*else if (c == '\\') - { - buf[i++] = GetHexChar(buf, ¤tpos); - }*/ - else if (c != '\r') - buf[i++] = c; - } - - return buf; -} - static void Command_ScoreboardAdd(void) { if (!server) @@ -3779,7 +3706,7 @@ static void Command_ScoreboardAdd(void) finalstring = Z_Calloc(MAXSERVERDESCRIPTIONLINE*sizeof(char), PU_STATIC, NULL); - GetSpecialString(finalstring, message, MAXSERVERDESCRIPTIONLINE); + CopyCaretColors(finalstring, message, MAXSERVERDESCRIPTIONLINE); strlensize = strlen(finalstring); serverdesclen = strlen(connectedserverdescription);