# HG changeset patch # User Adam Kaminski # Date 1607734392 18000 # Fri Dec 11 19:53:12 2020 -0500 # Node ID 94f481ed5fa1c48f8f5e68e2efc7782f688dcc4f # Parent 7893580a86b95f54838cee05174bcc6e0a51f3d0 Added a new chat mode that lets players send private messages to each other. The sender can either pass the player's name with "sayto" or a player's number with "sayto_idx". Alternatively, players can send private messages to the server by passing "server" as a name. diff -r 7893580a86b9 -r 94f481ed5fa1 docs/zandronum-history.txt --- a/docs/zandronum-history.txt Thu Nov 27 10:58:34 2014 +0200 +++ b/docs/zandronum-history.txt Fri Dec 11 19:53:12 2020 -0500 @@ -16,6 +16,7 @@ --- *+ - Added a new server administration menu, from which server settings can be changed without needing to use the console. The menu will ask for the RCON password if necessary. Gameplay and compatibility settings are now grayed out unless the user has RCON access and work online properly. Added various Zandronum-specific gameplay settings to the menu. [Dusk] +*+ - Added a new chat mode that lets players send private messages to each other. The sender can either pass the player's name with "sayto" or a player's number with "sayto_idx". Alternatively, players can send private messages to the server by passing "server" as a name. [Kaminsky] + - "stat nettraffic" now also shows information on the number of many missing packets the client requests from the servers. [Torr Samaho] + - The server can now broadcast the MD5 hashes of loaded PWADs to launchers. [Sean] + - Added new console commands "demo_ticsplayed" to show the current position in demo playback and "demo_skipto" to skip to such a position. diff -r 7893580a86b9 -r 94f481ed5fa1 src/c_console.cpp --- a/src/c_console.cpp Thu Nov 27 10:58:34 2014 +0200 +++ b/src/c_console.cpp Fri Dec 11 19:53:12 2020 -0500 @@ -242,8 +242,9 @@ static ULONG g_ulRCONPlayer = MAXPLAYERS; // [BC] Add a new print level for OpenGL messages. -#define PRINTLEVELS 6 -int PrintColors[PRINTLEVELS+2] = { CR_RED, CR_GOLD, CR_GRAY, CR_GREEN, CR_BRICK, CR_GOLD, CR_ORANGE }; +// [AK] Added a new print level for private chat messages. +#define PRINTLEVELS 7 +int PrintColors[PRINTLEVELS+2] = { CR_RED, CR_GOLD, CR_GRAY, CR_GREEN, CR_BRICK, CR_CYAN, CR_GOLD, CR_ORANGE }; static void setmsgcolor (int index, int color); @@ -285,6 +286,12 @@ setmsgcolor (4, self); } +CUSTOM_CVAR (Int, msg5color, 21, CVAR_ARCHIVE) +{ + // [AK] Private chat message color. + setmsgcolor (5, self); +} + CUSTOM_CVAR (Int, msgmidcolor, 5, CVAR_ARCHIVE) { setmsgcolor (PRINTLEVELS, self); diff -r 7893580a86b9 -r 94f481ed5fa1 src/chat.cpp --- a/src/chat.cpp Thu Nov 27 10:58:34 2014 +0200 +++ b/src/chat.cpp Fri Dec 11 19:53:12 2020 -0500 @@ -128,6 +128,9 @@ static ChatBuffer g_ChatBuffer; static ULONG g_ulChatMode; +// [AK] The index of the player we're sending a private chat message to. +static ULONG g_ulChatPlayer = 0; + //***************************************************************************** // CONSOLE VARIABLES @@ -148,6 +151,8 @@ EXTERN_CVAR( Int, con_colorinmessages ); // [RC] Played when a chat message arrives. Values: off, default, Doom 1 (dstink), Doom 2 (dsradio). CVAR (Int, chat_sound, 1, CVAR_ARCHIVE) +// [AK] Played when a private chat message arrives. +CVAR (Int, privatechat_sound, 2, CVAR_ARCHIVE) //***************************************************************************** FStringCVar *g_ChatMacros[10] = @@ -508,6 +513,14 @@ players[i].lIgnoreChatTicks = -1; } } + + // [AK] If we're typing a chat message to another player, we must constantly check if + // they're in the game. If not, cancel the message entirely. + if ( g_ulChatMode == CHATMODE_PRIVATE_SEND ) + { + if (( g_ulChatPlayer != MAXPLAYERS ) && ( PLAYER_IsValidPlayer( g_ulChatPlayer ) == false )) + chat_SetChatMode( CHATMODE_NONE ); + } } //***************************************************************************** @@ -594,7 +607,24 @@ } else if ( pEvent->data1 == '\t' ) { - g_ChatBuffer.TabComplete(); + if (( g_ulChatMode == CHATMODE_PRIVATE_SEND ) && ( g_ulChatPlayer != MAXPLAYERS )) + { + ULONG oldPlayer = g_ulChatPlayer; + + do + { + if ( ++g_ulChatPlayer >= MAXPLAYERS ) + g_ulChatPlayer = 0; + + if ( g_ulChatPlayer == oldPlayer ) + break; + } + while (( PLAYER_IsValidPlayer( g_ulChatPlayer ) == false ) || ( g_ulChatPlayer == consoleplayer )); + } + else + { + g_ChatBuffer.TabComplete(); + } return ( true ); } } @@ -626,7 +656,7 @@ // void CHAT_Render( void ) { - static const char *prompt = "SAY: "; + FString prompt = "Say: "; static const char *cursor = gameinfo.gametype == GAME_Doom ? "_" : "["; bool scale = ( con_scaletext ) && ( con_virtualwidth > 0 ) && ( con_virtualheight > 0 ); float scaleX = 1.0f; @@ -635,6 +665,8 @@ if ( g_ulChatMode == CHATMODE_NONE ) return; + else if ( g_ulChatMode == CHATMODE_PRIVATE_SEND ) + prompt.Format( "Say : ", g_ulChatPlayer != MAXPLAYERS ? players[g_ulChatPlayer].userinfo.GetName() : "Server" ); if ( scale ) { @@ -664,6 +696,11 @@ promptColor = CR_GREY; messageColor = static_cast( TEAM_GetTextColor( players[consoleplayer].ulTeam )); } + // [AK] Use a different color when sending a private message to the server. + else if (( g_ulChatMode == CHATMODE_PRIVATE_SEND ) && ( g_ulChatPlayer == MAXPLAYERS )) + { + promptColor = CR_GREY; + } // [TP] If we're currently viewing the archive, use a different color if ( g_ChatBuffer.IsInArchive() ) @@ -695,19 +732,36 @@ // [RC] Tell chatters about the iron curtain of LMS chat. if ( GAMEMODE_AreSpectatorsFordiddenToChatToPlayers() ) { - FString note; + FString note = "\\cdNOTE: \\cc"; + bool bDrawNote = true; // Is this the spectator talking? if ( players[consoleplayer].bSpectating ) - note = "\\cdNOTE: \\ccPlayers cannot hear you chat"; - else - note = "\\cdNOTE: \\ccSpectators cannot talk to you"; + { + if ( g_ulChatMode != CHATMODE_PRIVATE_SEND ) + note += "\\ccPlayers cannot hear you chat"; + else if (( g_ulChatPlayer != MAXPLAYERS ) && ( players[g_ulChatPlayer].bSpectating == false )) + note.AppendFormat( "%s \\cccannot hear you chat", players[g_ulChatPlayer].userinfo.GetName()); + else bDrawNote = false; + } - V_ColorizeString( note ); - HUD_DrawText( SmallFont, CR_UNTRANSLATED, - (LONG)(( ( scale ? *con_virtualwidth : SCREENWIDTH )/ 2 ) - ( SmallFont->StringWidth( note ) / 2 )), - (LONG)(( positionY * scaleY ) - ( SmallFont->GetHeight( ) * 2 ) + 1 ), - note ); + else + { + if ( g_ulChatMode != CHATMODE_PRIVATE_SEND ) + note += "\\ccSpectators cannot talk to you"; + else if (( g_ulChatPlayer != MAXPLAYERS ) && ( players[g_ulChatPlayer].bSpectating )) + note.AppendFormat( "%s \\cccannot talk to you", players[g_ulChatPlayer].userinfo.GetName() ); + else bDrawNote = false; + } + + if ( bDrawNote ) + { + V_ColorizeString( note ); + HUD_DrawText( SmallFont, CR_UNTRANSLATED, + (LONG)(( ( scale ? *con_virtualwidth : SCREENWIDTH )/ 2 ) - ( SmallFont->StringWidth( note ) / 2 )), + (LONG)(( positionY * scaleY ) - ( SmallFont->GetHeight( ) * 2 ) + 1 ), + note ); + } } BorderTopRefresh = screen->GetPageCount( ); @@ -735,15 +789,27 @@ // If ulPlayer == MAXPLAYERS, it is the server talking. if ( ulPlayer == MAXPLAYERS ) { + if (( ulMode == CHATMODE_PRIVATE_SEND ) || ( ulMode == CHATMODE_PRIVATE_RECEIVE )) + ulChatLevel = PRINT_PRIVATECHAT; + else + ulChatLevel = PRINT_HIGH; + // Special support for "/me" commands. - ulChatLevel = PRINT_HIGH; if ( strnicmp( "/me", pszString, 3 ) == 0 ) { pszString += 3; - OutString = "* "; + if ( ulChatLevel == PRINT_PRIVATECHAT ) + OutString.Format( TEXTCOLOR_GREY "<%s Server> ", ulMode == CHATMODE_PRIVATE_SEND ? "To" : "From" ); + + OutString.AppendFormat( "* %s" TEXTCOLOR_GREY, ulMode == CHATMODE_PRIVATE_SEND ? players[consoleplayer].userinfo.GetName() : "" ); } else - OutString = ": "; + { + if ( ulChatLevel == PRINT_PRIVATECHAT ) + OutString.Format( TEXTCOLOR_GREY "<%s Server> ", ulMode == CHATMODE_PRIVATE_SEND ? "To" : "From" ); + else + OutString = ": "; + } } else if ( ulMode == CHATMODE_GLOBAL ) { @@ -785,6 +851,24 @@ OutString.AppendFormat( TEXTCOLOR_GREEN "%s" TEXTCOLOR_TEAMCHAT ": ", players[ulPlayer].userinfo.GetName() ); } } + else if (( ulMode == CHATMODE_PRIVATE_SEND ) || ( ulMode == CHATMODE_PRIVATE_RECEIVE )) + { + ulChatLevel = PRINT_PRIVATECHAT; + + OutString.AppendFormat( TEXTCOLOR_GREEN "<%s ", ulMode == CHATMODE_PRIVATE_SEND ? "To" : "From" ); + OutString.AppendFormat( "%s" TEXTCOLOR_GREEN ">", players[ulPlayer].userinfo.GetName() ); + + // Special support for "/me" commands. + if ( strnicmp( "/me", pszString, 3 ) == 0 ) + { + pszString += 3; + OutString.AppendFormat( TEXTCOLOR_GREY " * %s" TEXTCOLOR_GREY, players[ulMode == CHATMODE_PRIVATE_SEND ? consoleplayer : ulPlayer].userinfo.GetName() ); + } + else + { + OutString.AppendFormat( TEXTCOLOR_PRIVATECHAT ": " ); + } + } ChatString = pszString; @@ -810,11 +894,13 @@ if ( show_messages ) { // [RC] User can choose the chat sound. - if ( chat_sound == 1 ) // Default + int sound = ( ulMode > CHATMODE_TEAM ) ? privatechat_sound : chat_sound; + + if ( sound == 1 ) // Default S_Sound( CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE ); - else if ( chat_sound == 2 ) // Doom 1 + else if ( sound == 2 ) // Doom 1 S_Sound( CHAN_VOICE | CHAN_UI, "misc/chat2", 1, ATTN_NONE ); - else if ( chat_sound == 3 ) // Doom 2 + else if ( sound == 3 ) // Doom 2 S_Sound( CHAN_VOICE | CHAN_UI, "misc/chat", 1, ATTN_NONE ); } @@ -886,7 +972,10 @@ // If we're the client, let the server handle formatting/sending the msg to other players. if ( NETWORK_GetState( ) == NETSTATE_CLIENT ) { - CLIENTCOMMANDS_Say( ulMode, ChatMessage.GetChars( )); + if ( ulMode == CHATMODE_PRIVATE_SEND ) + CLIENTCOMMANDS_PrivateSay( g_ulChatPlayer, ChatMessage.GetChars( )); + else + CLIENTCOMMANDS_Say( ulMode, ChatMessage.GetChars( )); } else if ( demorecording ) { @@ -896,7 +985,8 @@ } else { - CHAT_PrintChatString( consoleplayer, ulMode, ChatMessage.GetChars( )); + ULONG ulPlayer = ulMode == CHATMODE_PRIVATE_SEND ? g_ulChatPlayer : (ULONG)consoleplayer; + CHAT_PrintChatString( ulPlayer, ulMode, ChatMessage.GetChars( )); } // [TP] The message has been sent. Start creating a new one. @@ -1137,6 +1227,152 @@ //***************************************************************************** // +// [AK] Allows players (or the server) to send private messages to other players. +// +bool chat_CanSendPrivateMessage( ULONG ulPlayer ) +{ + if ( ulPlayer == MAXPLAYERS ) + return true; + + if ( g_ulChatPlayer == MAXPLAYERS ) + g_ulChatPlayer = 0; + + // [AK] If we're still trying to send a message to an invalid player, find another player. + if (( PLAYER_IsValidPlayer( g_ulChatPlayer ) == false ) || ( g_ulChatPlayer == (ULONG)consoleplayer )) + { + ULONG oldPlayer = g_ulChatPlayer; + + do + { + // [AK] Keep looping until we find another player who we can send a message to. + if ( ++g_ulChatPlayer >= MAXPLAYERS ) + g_ulChatPlayer = 0; + + // [AK] If we're back to the old value, then there's nobody else to send a message to. + if ( g_ulChatPlayer == oldPlayer ) + { + Printf( "There's no other player to send a private message to.\n" ); + return false; + } + } + while (( PLAYER_IsValidPlayer( g_ulChatPlayer ) == false ) || ( g_ulChatPlayer == (ULONG)consoleplayer )); + } + + return true; +} + +void chat_PrivateMessage( FCommandLine &argv, const ULONG ulPlayer ) +{ + ULONG ulIdx; + FString ChatString; + + // [AK] Mods are not allowed to say anything in the player's name. + if ( ACS_IsCalledFromConsoleCommand( ) ) + return; + + // [AK] No chatting while playing a demo. + if ( CLIENTDEMO_IsPlaying( ) == true ) + { + Printf( "You can't send private messages during demo playback.\n" ); + return; + } + + if ( argv.argc( ) >= 2 ) + { + // [AK] Don't send private messages to invalid players. + if ( ulPlayer == MAXPLAYERS + 1 ) + { + Printf( "There isn't a player named %s" TEXTCOLOR_NORMAL ".\n", argv[1] ); + return; + } + + // [AK] Don't send private messages to ourselves. + if (( ulPlayer == (ULONG)consoleplayer ) && ( NETWORK_GetState( ) != NETSTATE_SERVER )) + { + Printf( "You can't send a private message to yourself.\n" ); + return; + } + + g_ulChatPlayer = ulPlayer; + + if ( argv.argc( ) > 2 ) + { + for ( ulIdx = 2; ulIdx < static_cast( argv.argc( ) ); ulIdx++ ) + ChatString.AppendFormat( "%s ", argv[ulIdx] ); + + // Send the server's chat string out to clients, and print it in the console. + if ( NETWORK_GetState( ) == NETSTATE_SERVER ) + SERVER_SendChatMessage( MAXPLAYERS, CHATMODE_PRIVATE_SEND, ChatString.GetChars( ), g_ulChatPlayer ); + else + // We typed out our message in the console or with a macro. Go ahead and send the message now. + chat_SendMessage( CHATMODE_PRIVATE_SEND, ChatString.GetChars( ) ); + + return; + } + } + + if (( NETWORK_GetState( ) != NETSTATE_SERVER ) && ( chat_CanSendPrivateMessage( ulPlayer ) )) + { + // The message we send will only be for the player who we wish to chat with. + chat_SetChatMode( CHATMODE_PRIVATE_SEND ); + + // Hide the console. + C_HideConsole( ); + + // Clear out the chat buffer. + g_ChatBuffer.Clear( ); + } +} + +CCMD( sayto ) +{ + ULONG ulPlayer = 0; + + if ( argv.argc() >= 2 ) + { + if ( stricmp( argv[1], "Server" ) == 0 ) + { + if ( NETWORK_GetState( ) == NETSTATE_SERVER ) + { + Printf( "You can't send a private message to yourself.\n" ); + return; + } + else if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) + { + Printf( "You can't send a private message to the server in an offline game.\n" ); + return; + } + + ulPlayer = MAXPLAYERS; + } + else + { + ulPlayer = SERVER_GetPlayerIndexFromName( argv[1], true, true ); + if ( ulPlayer == MAXPLAYERS ) ulPlayer++; + } + } + + chat_PrivateMessage( argv, ulPlayer ); +} + +CCMD( sayto_idx ) +{ + int playerIndex = 0; + + if ( argv.argc() >= 2 ) + { + if ( argv.SafeGetNumber( 1, playerIndex ) == false ) + return; + + if ( PLAYER_IsValidPlayer( playerIndex ) == false ) + return; + } + + chat_PrivateMessage( argv, playerIndex ); +} + +//***************************************************************************** +// // [RC] Lets clients ignore an annoying player's chat messages. // void chat_IgnorePlayer( FCommandLine &argv, const ULONG ulPlayer ) @@ -1284,3 +1520,24 @@ } } +// [AK] +CCMD( messagemode3 ) +{ + // [AK] Mods are not allowed to say anything in the player's name. + if ( ACS_IsCalledFromConsoleCommand( )) + return; + + // [AK] No chatting while playing a demo. + if ( CLIENTDEMO_IsPlaying( ) == true ) + { + Printf( "You can't send private messages during demo playback.\n" ); + return; + } + + if (( NETWORK_GetState( ) != NETSTATE_SERVER ) && ( chat_CanSendPrivateMessage( 0 ) )) + { + chat_SetChatMode( CHATMODE_PRIVATE_SEND ); + C_HideConsole( ); + g_ChatBuffer.Clear(); + } +} \ No newline at end of file diff -r 7893580a86b9 -r 94f481ed5fa1 src/chat.h --- a/src/chat.h Thu Nov 27 10:58:34 2014 +0200 +++ b/src/chat.h Fri Dec 11 19:53:12 2020 -0500 @@ -65,6 +65,8 @@ CHATMODE_NONE, CHATMODE_GLOBAL, CHATMODE_TEAM, + CHATMODE_PRIVATE_SEND, // [AK] We're send a private message. + CHATMODE_PRIVATE_RECEIVE, // [AK] We're receiving a private message. NUM_CHATMODES diff -r 7893580a86b9 -r 94f481ed5fa1 src/cl_commands.cpp --- a/src/cl_commands.cpp Thu Nov 27 10:58:34 2014 +0200 +++ b/src/cl_commands.cpp Fri Dec 11 19:53:12 2020 -0500 @@ -284,6 +284,22 @@ //***************************************************************************** // +void CLIENTCOMMANDS_PrivateSay( ULONG ulPlayer, const char *pszString ) +{ + // [AK] Limit messages to certain length. + FString chatstring ( pszString ); + + if ( chatstring.Len() > MAX_CHATBUFFER_LENGTH ) + chatstring = chatstring.Left( MAX_CHATBUFFER_LENGTH ); + + CLIENT_GetLocalBuffer()->ByteStream.WriteByte( CLC_SAY ); + CLIENT_GetLocalBuffer()->ByteStream.WriteByte( CHATMODE_PRIVATE_SEND ); + CLIENT_GetLocalBuffer()->ByteStream.WriteByte( ulPlayer ); + CLIENT_GetLocalBuffer()->ByteStream.WriteString( chatstring ); +} + +//***************************************************************************** +// void CLIENTCOMMANDS_Ignore( ULONG ulPlayer, bool bIgnore, LONG lTicks ) { CLIENT_GetLocalBuffer( )->ByteStream.WriteByte( CLC_IGNORE ); diff -r 7893580a86b9 -r 94f481ed5fa1 src/cl_commands.h --- a/src/cl_commands.h Thu Nov 27 10:58:34 2014 +0200 +++ b/src/cl_commands.h Fri Dec 11 19:53:12 2020 -0500 @@ -78,6 +78,7 @@ void CLIENTCOMMANDS_StartChat( void ); void CLIENTCOMMANDS_EndChat( void ); void CLIENTCOMMANDS_Say( ULONG ulMode, const char *pszString ); +void CLIENTCOMMANDS_PrivateSay( ULONG ulPlayer, const char *pszString ); void CLIENTCOMMANDS_Ignore( ULONG ulPlayer, bool bIgnore, LONG lTicks = -1 ); void CLIENTCOMMANDS_ClientMove( void ); void CLIENTCOMMANDS_MissingPacket( void ); diff -r 7893580a86b9 -r 94f481ed5fa1 src/doomtype.h --- a/src/doomtype.h Thu Nov 27 10:58:34 2014 +0200 +++ b/src/doomtype.h Fri Dec 11 19:53:12 2020 -0500 @@ -142,7 +142,9 @@ PRINT_HIGH, // critical messages PRINT_CHAT, // chat messages PRINT_TEAMCHAT, // chat messages from a teammate - + + // [AK] Private chat messages from another player. + PRINT_PRIVATECHAT, // [BC] Output for OpenGL messages. PRINT_OPENGL, }; @@ -151,7 +153,8 @@ #define PRINT_HIGH 2 // critical messages #define PRINT_CHAT 3 // chat messages #define PRINT_TEAMCHAT 4 // chat messages from a teammate -#define PRINT_LOG 5 // only to logfile +#define PRINT_PRIVATECHAT 5 // private chat messages from another player +#define PRINT_LOG 6 // only to logfile #define PRINT_BOLD 200 // What Printf_Bold used // [BC] heh, why did I define this here? diff -r 7893580a86b9 -r 94f481ed5fa1 src/sv_commands.cpp --- a/src/sv_commands.cpp Thu Nov 27 10:58:34 2014 +0200 +++ b/src/sv_commands.cpp Fri Dec 11 19:53:12 2020 -0500 @@ -1063,6 +1063,33 @@ //***************************************************************************** // +void SERVERCOMMANDS_PrivateSay( ULONG ulSender, ULONG ulReceiver, const char *pszString, bool bForbidChatToPlayers, ULONG ulPlayerExtra, ServerCommandFlags flags ) +{ + if ( ulSender != MAXPLAYERS && PLAYER_IsValidPlayer( ulSender ) == false ) + return; + + ServerCommands::PlayerSay command; + command.SetMessage( pszString ); + + // [AK] First send the command to the player receiving the message. + if (( ulReceiver != MAXPLAYERS ) && ( !bForbidChatToPlayers || players[ulReceiver].bSpectating )) + { + command.SetPlayerNumber( ulSender ); + command.SetMode( CHATMODE_PRIVATE_RECEIVE ); + command.sendCommandToClients( ulReceiver, SVCF_ONLYTHISCLIENT ); + } + + // [AK] Next, send the command back to the player who sent the message. + if ( ulSender != MAXPLAYERS ) + { + command.SetPlayerNumber( ulReceiver ); + command.SetMode( CHATMODE_PRIVATE_SEND ); + command.sendCommandToClients( ulSender, SVCF_ONLYTHISCLIENT ); + } +} + +//***************************************************************************** +// void SERVERCOMMANDS_PlayerTaunt( ULONG ulPlayer, ULONG ulPlayerExtra, ServerCommandFlags flags ) { if ( PLAYER_IsValidPlayer( ulPlayer ) == false ) diff -r 7893580a86b9 -r 94f481ed5fa1 src/sv_commands.h --- a/src/sv_commands.h Thu Nov 27 10:58:34 2014 +0200 +++ b/src/sv_commands.h Fri Dec 11 19:53:12 2020 -0500 @@ -154,6 +154,7 @@ void SERVERCOMMANDS_ResetAllPlayersFragcount( ULONG ulPlayerExtra = MAXPLAYERS, ServerCommandFlags flags = 0 ); void SERVERCOMMANDS_PlayerIsSpectator( ULONG ulPlayer, ULONG ulPlayerExtra = MAXPLAYERS, ServerCommandFlags flags = 0 ); void SERVERCOMMANDS_PlayerSay( ULONG ulPlayer, const char *pszString, ULONG ulMode, bool bForbidChatToPlayers, ULONG ulPlayerExtra = MAXPLAYERS, ServerCommandFlags flags = 0 ); +void SERVERCOMMANDS_PrivateSay( ULONG ulSender, ULONG ulReceiver, const char *pszString, bool bForbidChatToPlayers, ULONG ulPlayerExtra = MAXPLAYERS, ServerCommandFlags flags = 0 ); void SERVERCOMMANDS_PlayerTaunt( ULONG ulPlayer, ULONG ulPlayerExtra = MAXPLAYERS, ServerCommandFlags flags = 0 ); void SERVERCOMMANDS_PlayerRespawnInvulnerability( ULONG ulPlayer, ULONG ulPlayerExtra = MAXPLAYERS, ServerCommandFlags flags = 0 ); void SERVERCOMMANDS_PlayerUseInventory( ULONG ulPlayer, AInventory *pItem, ULONG ulPlayerExtra = MAXPLAYERS, ServerCommandFlags flags = 0 ); diff -r 7893580a86b9 -r 94f481ed5fa1 src/sv_main.cpp --- a/src/sv_main.cpp Thu Nov 27 10:58:34 2014 +0200 +++ b/src/sv_main.cpp Fri Dec 11 19:53:12 2020 -0500 @@ -1088,7 +1088,7 @@ //***************************************************************************** // -void SERVER_SendChatMessage( ULONG ulPlayer, ULONG ulMode, const char *pszString ) +void SERVER_SendChatMessage( ULONG ulPlayer, ULONG ulMode, const char *pszString, ULONG ulReceiver ) { // [BB] Ignore any chat messages with invalid chat mode. This is crucial because // the rest of the code assumes that only valid chat modes are used. @@ -1116,7 +1116,15 @@ // This way the code below doesn't need to be altered. pszString = cleanedChatString.GetChars(); - SERVERCOMMANDS_PlayerSay( ulPlayer, pszString, ulMode, bFordidChatToPlayers ); + // [AK] Check if we're sending a private message. + if( ulMode == CHATMODE_PRIVATE_SEND ) + SERVERCOMMANDS_PrivateSay( ulPlayer, ulReceiver, pszString, bFordidChatToPlayers ); + else + SERVERCOMMANDS_PlayerSay( ulPlayer, pszString, ulMode, bFordidChatToPlayers ); + + // [AK] Don't log private messages that aren't sent to/from the server. + if (( ulMode == CHATMODE_PRIVATE_SEND ) && ( ulPlayer != MAXPLAYERS ) && ( ulReceiver != MAXPLAYERS )) + return; // [BB] This is to make the lines readily identifiable, necessary // for MiX-MaN's IRC server control tool for example. @@ -1126,17 +1134,29 @@ if ( strnicmp( "/me", pszString, 3 ) == 0 ) { pszString += 3; - if ( ulPlayer == MAXPLAYERS ) - Printf( "* %s\n", pszString ); - else - Printf( "* %s%s\n", players[ulPlayer].userinfo.GetName(), pszString ); + if ( ulMode == CHATMODE_PRIVATE_SEND ) + { + if ( ulPlayer == MAXPLAYERS ) + Printf( " ", players[ulReceiver].userinfo.GetName() ); + else + Printf( " ", players[ulPlayer].userinfo.GetName() ); + } + + Printf( "* %s%s\n", ulPlayer != MAXPLAYERS ? players[ulPlayer].userinfo.GetName() : "", pszString ); } else { - if ( ulPlayer == MAXPLAYERS ) - Printf( ": %s\n", pszString ); + if ( ulMode == CHATMODE_PRIVATE_SEND ) + { + if ( ulPlayer == MAXPLAYERS ) + Printf( ": %s\n", players[ulReceiver].userinfo.GetName(), pszString ); + else + Printf( ": %s\n", players[ulPlayer].userinfo.GetName(), pszString ); + } else - Printf( "%s: %s\n", players[ulPlayer].userinfo.GetName(), pszString ); + { + Printf( "%s: %s\n", ulPlayer != MAXPLAYERS ? players[ulPlayer].userinfo.GetName() : "", pszString ); + } } } @@ -4982,10 +5002,15 @@ static bool server_Say( BYTESTREAM_s *pByteStream ) { ULONG ulPlayer = g_lCurrentClient; + ULONG ulReceiver = MAXPLAYERS; // Read in the chat mode (normal, team, etc.) ULONG ulChatMode = pByteStream->ReadByte(); + // [AK] If we're sending a private message to a player, get their index number. + if ( ulChatMode == CHATMODE_PRIVATE_SEND ) + ulReceiver = pByteStream->ReadByte(); + // Read in the chat string. const char *pszChatString = pByteStream->ReadString(); @@ -5064,7 +5089,7 @@ return ( true ); } - SERVER_SendChatMessage( ulPlayer, ulChatMode, pszChatString ); + SERVER_SendChatMessage( ulPlayer, ulChatMode, pszChatString, ulReceiver ); return ( false ); } } diff -r 7893580a86b9 -r 94f481ed5fa1 src/sv_main.h --- a/src/sv_main.h Thu Nov 27 10:58:34 2014 +0200 +++ b/src/sv_main.h Fri Dec 11 19:53:12 2020 -0500 @@ -448,7 +448,7 @@ ULONG SERVER_CalcNumNonSpectatingPlayers( ULONG ulExcludePlayer ); void SERVER_CheckTimeouts( void ); void SERVER_GetPackets( void ); -void SERVER_SendChatMessage( ULONG ulPlayer, ULONG ulMode, const char *pszString ); +void SERVER_SendChatMessage( ULONG ulPlayer, ULONG ulMode, const char *pszString, ULONG ulReceiver = MAXPLAYERS ); void SERVER_DetermineConnectionType( BYTESTREAM_s *pByteStream ); void SERVER_SetupNewConnection( BYTESTREAM_s *pByteStream, bool bNewPlayer ); void SERVER_RequestClientToAuthenticate( ULONG ulClient ); diff -r 7893580a86b9 -r 94f481ed5fa1 src/v_font.cpp --- a/src/v_font.cpp Thu Nov 27 10:58:34 2014 +0200 +++ b/src/v_font.cpp Fri Dec 11 19:53:12 2020 -0500 @@ -2568,6 +2568,10 @@ { newcolor = boldcolor; } + else if (newcolor == '?') // [AK] Private chat + { + newcolor = PrintColors[PRINT_PRIVATECHAT]; + } else if (newcolor == '!') // Team chat { newcolor = PrintColors[PRINT_TEAMCHAT]; diff -r 7893580a86b9 -r 94f481ed5fa1 src/v_text.h --- a/src/v_text.h Thu Nov 27 10:58:34 2014 +0200 +++ b/src/v_text.h Fri Dec 11 19:53:12 2020 -0500 @@ -75,6 +75,9 @@ #define TEXTCOLOR_CHAT "\034*" #define TEXTCOLOR_TEAMCHAT "\034!" +// [AK] New text color for private chat messages. +#define TEXTCOLOR_PRIVATECHAT "\034?" + // [BC] New text functions. void V_ApplyCharArrayFunctionToFString ( FString &String, void (*CharArrayFunction) ( char *pszString ) ); void V_ColorizeString( char *pszString ); diff -r 7893580a86b9 -r 94f481ed5fa1 wadsrc/static/menudef.txt --- a/wadsrc/static/menudef.txt Thu Nov 27 10:58:34 2014 +0200 +++ b/wadsrc/static/menudef.txt Fri Dec 11 19:53:12 2020 -0500 @@ -482,6 +482,7 @@ StaticText "Chat", 1 Control "Say", "messagemode" Control "Team say", "messagemode2" + Control "Private say", "messagemode3" // [AK] StaticText "" StaticText "Weapons", 1 Control "Next weapon", "weapnext" @@ -1137,6 +1138,10 @@ 0.0, "Item Pickup" 1.0, "Obituaries" 2.0, "Critical Messages" + // [AK] Added chat levels. + 3.0, "Chat Messages" + 4.0, "Team Messages" + 5.0, "Private Messages" } // [TP] @@ -1163,6 +1168,7 @@ Option "Show messages", "show_messages", "OnOff" Option "Show obituaries", "show_obituaries", "OnOff" Option "Chat sound", "chat_sound", "ZA_ChatSound" // [TP] + Option "Private chat sound", "privatechat_sound", "ZA_ChatSound" // [AK] // [EP] con_scaletext is moved to the "Text scaling" submenu // Option "Scale text in high res", "con_scaletext", "ScaleValues" Option "Minimum message level", "msg", "MessageLevels" @@ -1176,6 +1182,7 @@ Option "Critical Messages", "msg2color", "TextColors" Option "Chat Messages", "msg3color", "TextColors" Option "Team Messages", "msg4color", "TextColors" + Option "Private Messages", "msg5color", "TextColors" // [AK] Option "Centered Messages", "msgmidcolor", "TextColors" StaticText " " Option "Screenshot messages", "screenshot_quiet", "OffOn"