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