diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 213f5dde0..c7e24e821 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2756,20 +2756,6 @@ void CL_Reset(void) } #ifndef NONET -static void Command_GetPlayerNum(void) -{ - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - if (serverplayer == i) - CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); - else - CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); - } -} - SINT8 nametonum(const char *name) { INT32 playernum, i; @@ -2799,41 +2785,145 @@ SINT8 nametonum(const char *name) return -1; } -/** Lists all players and their player numbers. +/** List all players along with a short status. * - * \sa Command_GetPlayerNum + * \sa Command_NodeTree */ -static void Command_Nodes(void) +/* +Formatted like so, with each element separated by space and written on lines: +Two digit player number, colon (:), colored player name, left-aligned. +Then a "status" which is delimited by a double dash (--). +If available, an IP address and port. +Admin status written as "(admin)". +Spectating status written as "(spectator)". +If admin and spectating status both apply and the player's address was not +available, the status is "crammed". If the status is not "crammed", it is +indented the width of " -- self". The intended effect is that the spectating +status aligns with other spectating statuses. +*/ +static void Command_ListPlayers(void) { - INT32 i; - size_t maxlen = 0; const char *address; + int width = 0; - for (i = 0; i < MAXPLAYERS; i++) + boolean admin; + boolean spectator; + + /* + Mode of player status for an individual player (admin, spectator). + 1 for admin + 2 for spectator + 4 for both + */ + int mode = 0; + + INT32 totalplayers = 0; + + const char *cc; + const char *pcc; + + INT32 i; + int n; + + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i]) { - const size_t plen = strlen(player_names[i]); - if (playeringame[i] && plen > maxlen) - maxlen = plen; + n = strlen(player_names[i]); + if (n > width) + width = n; + + if (mode != 7) + { + admin = IsPlayerAdmin(i); + spectator = players[i].spectator; + + if (admin) + mode |= 1; + if (spectator) + mode |= 2; + if (admin && spectator) + mode |= 4; + } } - for (i = 0; i < MAXPLAYERS; i++) - { + for (i = 0; i < MAXPLAYERS; ++i) if (playeringame[i]) - { - CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]); - CONS_Printf(" - %.2d", playernode[i]); - if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL) - CONS_Printf(" - %s", address); + { + admin = IsPlayerAdmin(i); + spectator = players[i].spectator; - if (IsPlayerAdmin(i)) - CONS_Printf(M_GetText(" (verified admin)")); + if (admin) + cc = "\x85";/* red */ + else if (spectator) + cc = "\x86";/* gray */ + else + cc = ""; - if (players[i].spectator) - CONS_Printf(M_GetText(" (spectator)")); + pcc = V_ApproximateSkinColorCode(players[i].skincolor); - CONS_Printf("\n"); + CONS_Printf("%.2d: ""%s""%-*s""\x80", i, pcc,width, player_names[i]); + + if (I_GetNodeAddress) + { + if (( address = I_GetNodeAddress(playernode[i]) )) + CONS_Printf(" -- %s", address); + else/* print spacer */ + { + /* ...but not if there's a crammed status and were admin */ + if (mode != 7 || !admin) + CONS_Printf(" -- ");/* -- self */ + } } + + if (admin) + CONS_Printf(M_GetText("%s"" (admin)"),cc); + if (spectator) + CONS_Printf(M_GetText("%s"" (spectator)"),cc); + + CONS_Printf("\n"); + + totalplayers++; } + + if (totalplayers == 1) + CONS_Printf("\nThere is 1 player in the game.\n"); + else + CONS_Printf("\nThere are %d players in the game.\n", totalplayers); +} + +/** Print a table listing all nodes, addresses and associated players. + * + * \sa Command_ListPlayers + */ +static void Command_NodeTree(void) +{ + const char *address; + + INT32 i; + INT32 totalnodes = 0; + + for (i = 0; i < MAXNETNODES; ++i) + if (nodeingame[i]) + { + CONS_Printf("* %d", i); + if (playerpernode[i] > 1) + CONS_Printf(" (%d players)", playerpernode[i]); + if (I_GetNodeAddress && ( address = I_GetNodeAddress(i) )) + CONS_Printf(" - %s", address); + CONS_Printf("\n"); +#define PRINTPLAYERNODE( prefix, array ) if ((array)[i] > -1) \ + CONS_Printf(prefix" (%d) %s\n", (array)[i], player_names[(array)[i]]); + PRINTPLAYERNODE ("|-", nodetoplayer4) + PRINTPLAYERNODE ("|-", nodetoplayer3) + PRINTPLAYERNODE ("|-", nodetoplayer2) + PRINTPLAYERNODE ("\\-", nodetoplayer) +#undef PRINTPLAYERNODE + CONS_Printf("\n"); + + totalnodes++; + } + + CONS_Printf("%d/%d nodes connected.\n", totalnodes, MAXNETNODES); } static void Command_Ban(void) @@ -3240,7 +3330,7 @@ void D_ClientServerInit(void) VERSION/100, VERSION%100, SUBVERSION)); #ifndef NONET - COM_AddCommand("getplayernum", Command_GetPlayerNum); + COM_AddCommand("listplayers", Command_ListPlayers); COM_AddCommand("kick", Command_Kick); COM_AddCommand("ban", Command_Ban); COM_AddCommand("banip", Command_BanIP); @@ -3248,7 +3338,7 @@ void D_ClientServerInit(void) COM_AddCommand("showbanlist", Command_ShowBan); COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("connect", Command_connect); - COM_AddCommand("nodes", Command_Nodes); + COM_AddCommand("nodetree", Command_NodeTree); #ifdef PACKETDROP COM_AddCommand("drop", Command_Drop); COM_AddCommand("droprate", Command_Droprate); @@ -3485,14 +3575,31 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (netgame) { - if (server && cv_showjoinaddress.value) + char *text; + if (server) { const char *address; - if (I_GetNodeAddress && (address = I_GetNodeAddress(node)) != NULL) - HU_AddChatText(va("\x82*Player %d has joined the game (node %d) (%s)", newplayernum+1, node, address), false); // merge join notification + IP to avoid clogging console/chat. + if (cv_showjoinaddress.value && + I_GetNodeAddress && ( address = I_GetNodeAddress(node) )) + { + text = va( + "\x82*Player %d (num %d) has joined the game (%s)", + newplayernum+1, newplayernum, address); + } + else + { + text = va( + "\x82Player %d (num %d) has joined the game", + newplayernum+1, newplayernum); + } } else - HU_AddChatText(va("\x82*Player %d has joined the game (node %d)", newplayernum+1, node), false); // if you don't wanna see the join address. + { + text = va( + "\x82Player %d has joined the game", + newplayernum+1); + } + HU_AddChatText(text, false); } if (server && multiplayer && motd[0] != '\0') @@ -4204,7 +4311,7 @@ static boolean CheckForSpeedHacks(UINT8 p) || netcmds[maketic%BACKUPTICS][p].driftturn > KART_FULLTURN || netcmds[maketic%BACKUPTICS][p].driftturn < -KART_FULLTURN) { XBOXSTATIC char buf[2]; - CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernode[p]); + CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from player %d\n"), p); //D_Clearticcmd(k); buf[0] = (char)p; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7dff12317..b91c6bdbf 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3858,7 +3858,7 @@ static void Command_Verify_f(void) if (COM_Argc() != 2) { - CONS_Printf(M_GetText("promote : give admin privileges to a node\n")); + CONS_Printf(M_GetText("promote : give admin privileges to a player\n")); return; } @@ -3914,7 +3914,7 @@ static void Command_RemoveAdmin_f(void) if (COM_Argc() != 2) { - CONS_Printf(M_GetText("demote : remove admin privileges from a node\n")); + CONS_Printf(M_GetText("demote : remove admin privileges from a player\n")); return; } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index f343f12b7..10e0f5fc6 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -499,23 +499,23 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm { - // what we're gonna do now is check if the node exists + // what we're gonna do now is check if the player exists // with that logic, characters 4 and 5 are our numbers: const char *newmsg; - INT32 spc = 1; // used if nodenum[1] is a space. - char *nodenum = (char*) malloc(3); - strncpy(nodenum, msg+3, 3); + INT32 spc = 1; // used if playernum[1] is a space. + char *playernum = (char*) malloc(3); + strncpy(playernum, msg+3, 3); // check for undesirable characters in our "number" - if (((nodenum[0] < '0') || (nodenum[0] > '9')) || ((nodenum[1] < '0') || (nodenum[1] > '9'))) + if (((playernum[0] < '0') || (playernum[0] > '9')) || ((playernum[1] < '0') || (playernum[1] > '9'))) { - // check if nodenum[1] is a space - if (nodenum[1] == ' ') + // check if playernum[1] is a space + if (playernum[1] == ' ') spc = 0; // let it slide else { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); - free(nodenum); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); + free(playernum); return; } } @@ -524,14 +524,14 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) { if (msg[5] != ' ') { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); - free(nodenum); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); + free(playernum); return; } } - target = atoi((const char*) nodenum); // turn that into a number - free(nodenum); + target = atoi((const char*) playernum); // turn that into a number + free(playernum); //CONS_Printf("%d\n", target); // check for target player, if it doesn't exist then we can't send the message! @@ -781,145 +781,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) { const UINT8 color = players[playernum].skincolor; - cstart = "\x83"; - - switch (color) - { - case SKINCOLOR_WHITE: - case SKINCOLOR_SILVER: - case SKINCOLOR_SLATE: - cstart = "\x80"; // White - break; - case SKINCOLOR_GREY: - case SKINCOLOR_NICKEL: - case SKINCOLOR_BLACK: - case SKINCOLOR_SKUNK: - case SKINCOLOR_JET: - cstart = "\x86"; // V_GRAYMAP - break; - case SKINCOLOR_SEPIA: - case SKINCOLOR_BEIGE: - case SKINCOLOR_WALNUT: - case SKINCOLOR_BROWN: - case SKINCOLOR_LEATHER: - case SKINCOLOR_RUST: - case SKINCOLOR_WRISTWATCH: - cstart = "\x8e"; // V_BROWNMAP - break; - case SKINCOLOR_FAIRY: - case SKINCOLOR_SALMON: - case SKINCOLOR_PINK: - case SKINCOLOR_ROSE: - case SKINCOLOR_BRICK: - case SKINCOLOR_LEMONADE: - case SKINCOLOR_BUBBLEGUM: - case SKINCOLOR_LILAC: - cstart = "\x8d"; // V_PINKMAP - break; - case SKINCOLOR_CINNAMON: - case SKINCOLOR_RUBY: - case SKINCOLOR_RASPBERRY: - case SKINCOLOR_CHERRY: - case SKINCOLOR_RED: - case SKINCOLOR_CRIMSON: - case SKINCOLOR_MAROON: - case SKINCOLOR_FLAME: - case SKINCOLOR_SCARLET: - case SKINCOLOR_KETCHUP: - cstart = "\x85"; // V_REDMAP - break; - case SKINCOLOR_DAWN: - case SKINCOLOR_SUNSET: - case SKINCOLOR_CREAMSICLE: - case SKINCOLOR_ORANGE: - case SKINCOLOR_PUMPKIN: - case SKINCOLOR_ROSEWOOD: - case SKINCOLOR_BURGUNDY: - case SKINCOLOR_TANGERINE: - cstart = "\x87"; // V_ORANGEMAP - break; - case SKINCOLOR_PEACH: - case SKINCOLOR_CARAMEL: - case SKINCOLOR_CREAM: - cstart = "\x8f"; // V_PEACHMAP - break; - case SKINCOLOR_GOLD: - case SKINCOLOR_ROYAL: - case SKINCOLOR_BRONZE: - case SKINCOLOR_COPPER: - case SKINCOLOR_THUNDER: - cstart = "\x8A"; // V_GOLDMAP - break; - case SKINCOLOR_POPCORN: - case SKINCOLOR_QUARRY: - case SKINCOLOR_YELLOW: - case SKINCOLOR_MUSTARD: - case SKINCOLOR_CROCODILE: - case SKINCOLOR_OLIVE: - cstart = "\x82"; // V_YELLOWMAP - break; - case SKINCOLOR_ARTICHOKE: - case SKINCOLOR_VOMIT: - case SKINCOLOR_GARDEN: - case SKINCOLOR_TEA: - case SKINCOLOR_PISTACHIO: - cstart = "\x8b"; // V_TEAMAP - break; - case SKINCOLOR_LIME: - case SKINCOLOR_HANDHELD: - case SKINCOLOR_MOSS: - case SKINCOLOR_CAMOUFLAGE: - case SKINCOLOR_ROBOHOOD: - case SKINCOLOR_MINT: - case SKINCOLOR_GREEN: - case SKINCOLOR_PINETREE: - case SKINCOLOR_EMERALD: - case SKINCOLOR_SWAMP: - case SKINCOLOR_DREAM: - case SKINCOLOR_PLAGUE: - case SKINCOLOR_ALGAE: - cstart = "\x83"; // V_GREENMAP - break; - case SKINCOLOR_CARIBBEAN: - case SKINCOLOR_AZURE: - case SKINCOLOR_AQUA: - case SKINCOLOR_TEAL: - case SKINCOLOR_CYAN: - case SKINCOLOR_JAWZ: - case SKINCOLOR_CERULEAN: - case SKINCOLOR_NAVY: - case SKINCOLOR_SAPPHIRE: - cstart = "\x88"; // V_SKYMAP - break; - case SKINCOLOR_PIGEON: - case SKINCOLOR_PLATINUM: - case SKINCOLOR_STEEL: - cstart = "\x8c"; // V_STEELMAP - break; - case SKINCOLOR_PERIWINKLE: - case SKINCOLOR_BLUE: - case SKINCOLOR_BLUEBERRY: - case SKINCOLOR_NOVA: - cstart = "\x84"; // V_BLUEMAP - break; - case SKINCOLOR_ULTRAVIOLET: - case SKINCOLOR_PURPLE: - case SKINCOLOR_FUCHSIA: - cstart = "\x81"; // V_PURPLEMAP - break; - case SKINCOLOR_PASTEL: - case SKINCOLOR_MOONSLAM: - case SKINCOLOR_DUSK: - case SKINCOLOR_TOXIC: - case SKINCOLOR_MAUVE: - case SKINCOLOR_LAVENDER: - case SKINCOLOR_BYZANTIUM: - case SKINCOLOR_POMEGRANATE: - cstart = "\x89"; // V_LAVENDERMAP - break; - default: - break; - } + cstart = V_ApproximateSkinColorCode(color); } prefix = cstart; diff --git a/src/v_video.c b/src/v_video.c index 9233eda42..3c8b4db92 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1380,6 +1380,151 @@ UINT8 *V_GetStringColormap(INT32 colorflags) #endif } +const char *V_ApproximateSkinColorCode(INT32 color) +{ + const char *cstart; + cstart = "\x83"; + + switch (color) + { + case SKINCOLOR_WHITE: + case SKINCOLOR_SILVER: + case SKINCOLOR_SLATE: + cstart = "\x80"; // White + break; + case SKINCOLOR_GREY: + case SKINCOLOR_NICKEL: + case SKINCOLOR_BLACK: + case SKINCOLOR_SKUNK: + case SKINCOLOR_JET: + cstart = "\x86"; // V_GRAYMAP + break; + case SKINCOLOR_SEPIA: + case SKINCOLOR_BEIGE: + case SKINCOLOR_WALNUT: + case SKINCOLOR_BROWN: + case SKINCOLOR_LEATHER: + case SKINCOLOR_RUST: + case SKINCOLOR_WRISTWATCH: + cstart = "\x8e"; // V_BROWNMAP + break; + case SKINCOLOR_FAIRY: + case SKINCOLOR_SALMON: + case SKINCOLOR_PINK: + case SKINCOLOR_ROSE: + case SKINCOLOR_BRICK: + case SKINCOLOR_LEMONADE: + case SKINCOLOR_BUBBLEGUM: + case SKINCOLOR_LILAC: + cstart = "\x8d"; // V_PINKMAP + break; + case SKINCOLOR_CINNAMON: + case SKINCOLOR_RUBY: + case SKINCOLOR_RASPBERRY: + case SKINCOLOR_CHERRY: + case SKINCOLOR_RED: + case SKINCOLOR_CRIMSON: + case SKINCOLOR_MAROON: + case SKINCOLOR_FLAME: + case SKINCOLOR_SCARLET: + case SKINCOLOR_KETCHUP: + cstart = "\x85"; // V_REDMAP + break; + case SKINCOLOR_DAWN: + case SKINCOLOR_SUNSET: + case SKINCOLOR_CREAMSICLE: + case SKINCOLOR_ORANGE: + case SKINCOLOR_PUMPKIN: + case SKINCOLOR_ROSEWOOD: + case SKINCOLOR_BURGUNDY: + case SKINCOLOR_TANGERINE: + cstart = "\x87"; // V_ORANGEMAP + break; + case SKINCOLOR_PEACH: + case SKINCOLOR_CARAMEL: + case SKINCOLOR_CREAM: + cstart = "\x8f"; // V_PEACHMAP + break; + case SKINCOLOR_GOLD: + case SKINCOLOR_ROYAL: + case SKINCOLOR_BRONZE: + case SKINCOLOR_COPPER: + case SKINCOLOR_THUNDER: + cstart = "\x8A"; // V_GOLDMAP + break; + case SKINCOLOR_POPCORN: + case SKINCOLOR_QUARRY: + case SKINCOLOR_YELLOW: + case SKINCOLOR_MUSTARD: + case SKINCOLOR_CROCODILE: + case SKINCOLOR_OLIVE: + cstart = "\x82"; // V_YELLOWMAP + break; + case SKINCOLOR_ARTICHOKE: + case SKINCOLOR_VOMIT: + case SKINCOLOR_GARDEN: + case SKINCOLOR_TEA: + case SKINCOLOR_PISTACHIO: + cstart = "\x8b"; // V_TEAMAP + break; + case SKINCOLOR_LIME: + case SKINCOLOR_HANDHELD: + case SKINCOLOR_MOSS: + case SKINCOLOR_CAMOUFLAGE: + case SKINCOLOR_ROBOHOOD: + case SKINCOLOR_MINT: + case SKINCOLOR_GREEN: + case SKINCOLOR_PINETREE: + case SKINCOLOR_EMERALD: + case SKINCOLOR_SWAMP: + case SKINCOLOR_DREAM: + case SKINCOLOR_PLAGUE: + case SKINCOLOR_ALGAE: + cstart = "\x83"; // V_GREENMAP + break; + case SKINCOLOR_CARIBBEAN: + case SKINCOLOR_AZURE: + case SKINCOLOR_AQUA: + case SKINCOLOR_TEAL: + case SKINCOLOR_CYAN: + case SKINCOLOR_JAWZ: + case SKINCOLOR_CERULEAN: + case SKINCOLOR_NAVY: + case SKINCOLOR_SAPPHIRE: + cstart = "\x88"; // V_SKYMAP + break; + case SKINCOLOR_PIGEON: + case SKINCOLOR_PLATINUM: + case SKINCOLOR_STEEL: + cstart = "\x8c"; // V_STEELMAP + break; + case SKINCOLOR_PERIWINKLE: + case SKINCOLOR_BLUE: + case SKINCOLOR_BLUEBERRY: + case SKINCOLOR_NOVA: + cstart = "\x84"; // V_BLUEMAP + break; + case SKINCOLOR_ULTRAVIOLET: + case SKINCOLOR_PURPLE: + case SKINCOLOR_FUCHSIA: + cstart = "\x81"; // V_PURPLEMAP + break; + case SKINCOLOR_PASTEL: + case SKINCOLOR_MOONSLAM: + case SKINCOLOR_DUSK: + case SKINCOLOR_TOXIC: + case SKINCOLOR_MAUVE: + case SKINCOLOR_LAVENDER: + case SKINCOLOR_BYZANTIUM: + case SKINCOLOR_POMEGRANATE: + cstart = "\x89"; // V_LAVENDERMAP + break; + default: + break; + } + return cstart; +} + // Writes a single character (draw WHITE if bit 7 set) // void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed) diff --git a/src/v_video.h b/src/v_video.h index c8485c179..d0dae2c7d 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -168,6 +168,8 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UI UINT8 *V_GetStringColormap(INT32 colorflags); +const char *V_ApproximateSkinColorCode(INT32 skincolor); + void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string); // wordwrap a string using the hu_font