//***************************************************************************** // ULONG medal_GetDesiredIcon( player_t *pPlayer, AInventory *&pTeamItem ) { ULONG ulDesiredSprite = NUM_SPRITES; // [BB] Invalid players certainly don't need any icon. if ( ( pPlayer == NULL ) || ( pPlayer->mo == NULL ) ) return NUM_SPRITES; // Draw an ally icon if this person is on our team. Would this be useful for co-op, too? // [BB] In free spectate mode, we don't have allies (and SCOREBOARD_GetViewPlayer doesn't return a useful value). if ( ( GAMEMODE_GetFlags( GAMEMODE_GetCurrentMode( )) & GMF_PLAYERSONTEAMS ) && ( CLIENTDEMO_IsInFreeSpectateMode() == false ) ) { // [BB] Dead spectators shall see the icon for their teammates. if ( pPlayer->mo->IsTeammate( players[SCOREBOARD_GetViewPlayer()].mo ) && !PLAYER_IsTrueSpectator ( &players[SCOREBOARD_GetViewPlayer()] ) ) ulDesiredSprite = SPRITE_ALLY; } // Draw a chat icon over the player if they're typing. if ( pPlayer->bChatting ) ulDesiredSprite = SPRITE_CHAT; // Draw a console icon over the player if they're in the console. if ( pPlayer->bInConsole ) ulDesiredSprite = SPRITE_INCONSOLE; // Draw a lag icon over their head if they're lagging. if ( pPlayer->bLagging ) ulDesiredSprite = SPRITE_LAG; // Draw a flag/skull above this player if he's carrying one. if ( GAMEMODE_GetFlags( GAMEMODE_GetCurrentMode( )) & GMF_USETEAMITEM ) { if ( pPlayer->bOnTeam ) { if ( oneflagctf ) { AInventory *pInventory = pPlayer->mo->FindInventory( PClass::FindClass( "WhiteFlag" )); if ( pInventory ) ulDesiredSprite = SPRITE_WHITEFLAG; } else { pTeamItem = TEAM_FindOpposingTeamsItemInPlayersInventory ( pPlayer ); if ( pTeamItem ) ulDesiredSprite = SPRITE_TEAMITEM; } } } // Draw the terminator artifact over the terminator. if ( terminator && ( pPlayer->cheats2 & CF2_TERMINATORARTIFACT )) ulDesiredSprite = SPRITE_TERMINATORARTIFACT; // Draw the possession artifact over the player. if (( possession || teampossession ) && ( pPlayer->cheats2 & CF2_POSSESSIONARTIFACT )) ulDesiredSprite = SPRITE_POSSESSIONARTIFACT; return ulDesiredSprite; }
//***************************************************************************** // void LASTMANSTANDING_Tick( void ) { // Not in LMS mode. if (( lastmanstanding == false ) && ( teamlms == false )) return; switch ( g_LMSState ) { case LMSS_WAITINGFORPLAYERS: if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { break; } if ( lastmanstanding ) { // Two players are here now, being the countdown! if ( GAME_CountActivePlayers( ) >= 2 ) { if ( sv_lmscountdowntime > 0 ) LASTMANSTANDING_StartCountdown(( sv_lmscountdowntime * TICRATE ) - 1 ); else LASTMANSTANDING_StartCountdown(( 10 * TICRATE ) - 1 ); } } if ( teamlms ) { if ( TEAM_TeamsWithPlayersOn( ) > 1 ) { if ( sv_lmscountdowntime > 0 ) LASTMANSTANDING_StartCountdown(( sv_lmscountdowntime * TICRATE ) - 1 ); else LASTMANSTANDING_StartCountdown(( 10 * TICRATE ) - 1 ); } } break; case LMSS_COUNTDOWN: if ( g_ulLMSCountdownTicks ) { g_ulLMSCountdownTicks--; // FIGHT! if (( g_ulLMSCountdownTicks == 0 ) && ( NETWORK_GetState( ) != NETSTATE_CLIENT ) && ( CLIENTDEMO_IsPlaying( ) == false )) { LASTMANSTANDING_DoFight( ); } // Play "3... 2... 1..." sounds. else if ( g_ulLMSCountdownTicks == ( 3 * TICRATE )) ANNOUNCER_PlayEntry( cl_announcer, "Three" ); else if ( g_ulLMSCountdownTicks == ( 2 * TICRATE )) ANNOUNCER_PlayEntry( cl_announcer, "Two" ); else if ( g_ulLMSCountdownTicks == ( 1 * TICRATE )) ANNOUNCER_PlayEntry( cl_announcer, "One" ); } break; case LMSS_INPROGRESS: if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { break; } // Check to see how many men are left standing. if ( lastmanstanding ) { // If only one man is left standing, somebody just won! if ( GAME_CountLivingAndRespawnablePlayers( ) == 1 ) { LONG lWinner; lWinner = LASTMANSTANDING_GetLastManStanding( ); if ( lWinner != -1 ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s \\c-wins!\n", players[lWinner].userinfo.netname ); else { Printf( "%s \\c-wins!\n", players[lWinner].userinfo.netname ); if ( lWinner == consoleplayer ) ANNOUNCER_PlayEntry( cl_announcer, "YouWin" ); } // Give the winner a win. PLAYER_SetWins( &players[lWinner], players[lWinner].ulWins + 1 ); // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( lWinner ); GAME_SetEndLevelDelay( 5 * TICRATE ); } } // If NOBODY is left standing, it's a draw game! else if ( GAME_CountLivingAndRespawnablePlayers( ) == 0 ) { ULONG ulIdx; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( PLAYER_IsTrueSpectator( &players[ulIdx] ) == false )) break; } if ( ulIdx != MAXPLAYERS ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "DRAW GAME!\n" ); else Printf( "DRAW GAME!\n" ); // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( MAXPLAYERS ); GAME_SetEndLevelDelay( 5 * TICRATE ); } } } // Check to see how many men are left standing on each team. if ( teamlms ) { if ( LASTMANSTANDING_TeamsWithAlivePlayersOn( ) <= 1) { LONG lWinner; lWinner = LASTMANSTANDING_TeamGetLastManStanding( ); if ( lWinner != -1 ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s \\c-wins!\n", TEAM_GetName( lWinner )); else { Printf( "%s \\c-wins!\n", TEAM_GetName( lWinner )); if ( players[consoleplayer].bOnTeam && ( lWinner == (LONG)players[consoleplayer].ulTeam )) ANNOUNCER_PlayEntry( cl_announcer, "YouWin" ); } // Give the team a win. TEAM_SetWinCount( lWinner, TEAM_GetWinCount( lWinner ) + 1, false ); // [BB] Every player who is still alive also gets a win. for ( ULONG ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if ( playeringame[ulIdx] && ( players[ulIdx].bOnTeam ) && ( players[ulIdx].bSpectating == false ) && PLAYER_IsAliveOrCanRespawn ( &players[ulIdx] ) ) PLAYER_SetWins( &players[ulIdx], players[ulIdx].ulWins + 1 ); } // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( lWinner ); GAME_SetEndLevelDelay( 5 * TICRATE ); } // If NOBODY is left standing, it's a draw game! else { ULONG ulIdx; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( PLAYER_IsTrueSpectator( &players[ulIdx] ) == false )) break; } if ( ulIdx != MAXPLAYERS ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "DRAW GAME!\n" ); else Printf( "DRAW GAME!\n" ); // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( teams.Size( ) ); GAME_SetEndLevelDelay( 5 * TICRATE ); } } } } break; default: break; } }
//***************************************************************************** // void SERVER_MASTER_SendServerInfo( netadr_t Address, ULONG ulFlags, ULONG ulTime ) { UCVarValue Val; char szAddress[4][4]; ULONG ulIdx; ULONG ulBits; ULONG ulNumPWADs; // Let's just use the master server buffer! It gets cleared again when we need it anyway! NETWORK_ClearBuffer( &g_MasterServerBuffer ); // First, check to see if we've been queried by this address recently. if ( g_lStoredQueryIPHead != g_lStoredQueryIPTail ) { ulIdx = g_lStoredQueryIPHead; while ( ulIdx != (ULONG)g_lStoredQueryIPTail ) { // Check to see if this IP exists in our stored query IP list. If it does, then // ignore it, since it queried us less than 10 seconds ago. if ( NETWORK_CompareAddress( Address, g_StoredQueryIPs[ulIdx].Address, true )) { // Write our header. NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_LAUNCHER_IGNORING ); // Send the time the launcher sent to us. NETWORK_WriteLong( &g_MasterServerBuffer, ulTime ); // Send the packet. // NETWORK_LaunchPacket( &g_MasterServerBuffer, Address, true ); NETWORK_LaunchPacket( &g_MasterServerBuffer, Address ); if ( sv_showlauncherqueries ) Printf( "Ignored IP launcher challenge.\n" ); // Nothing more to do here. return; } ulIdx++; ulIdx = ulIdx % MAX_STORED_QUERY_IPS; } } // Now, check to see if this IP has been banend from this server. itoa( Address.ip[0], szAddress[0], 10 ); itoa( Address.ip[1], szAddress[1], 10 ); itoa( Address.ip[2], szAddress[2], 10 ); itoa( Address.ip[3], szAddress[3], 10 ); if (( sv_enforcebans ) && ( SERVERBAN_IsIPBanned( szAddress[0], szAddress[1], szAddress[2], szAddress[3] ))) { // Write our header. NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_LAUNCHER_BANNED ); // Send the time the launcher sent to us. NETWORK_WriteLong( &g_MasterServerBuffer, ulTime ); // Send the packet. NETWORK_LaunchPacket( &g_MasterServerBuffer, Address ); if ( sv_showlauncherqueries ) Printf( "Denied BANNED IP launcher challenge.\n" ); // Nothing more to do here. return; } // This IP didn't exist in the list. and it wasn't banned. // So, add it, and keep it there for 10 seconds. g_StoredQueryIPs[g_lStoredQueryIPTail].Address = Address; g_StoredQueryIPs[g_lStoredQueryIPTail].lNextAllowedGametic = gametic + ( TICRATE * ( sv_queryignoretime )); g_lStoredQueryIPTail++; g_lStoredQueryIPTail = g_lStoredQueryIPTail % MAX_STORED_QUERY_IPS; if ( g_lStoredQueryIPTail == g_lStoredQueryIPHead ) Printf( "SERVER_MASTER_SendServerInfo: WARNING! g_lStoredQueryIPTail == g_lStoredQueryIPHead\n" ); // Write our header. NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_LAUNCHER_CHALLENGE ); // Send the time the launcher sent to us. NETWORK_WriteLong( &g_MasterServerBuffer, ulTime ); // Send our version. NETWORK_WriteString( &g_MasterServerBuffer, DOTVERSIONSTR ); // Send the information about the data that will be sent. ulBits = ulFlags; // If the launcher desires to know the team damage, but we're not in a game mode where // team damage applies, then don't send back team damage information. if (( teamplay || teamgame || teamlms || teampossession || teamcoop || (( deathmatch == false ) && ( teamgame == false ))) == false ) { if ( ulBits & SQF_TEAMDAMAGE ) ulBits &= ~SQF_TEAMDAMAGE; } // If the launcher desires to know the team score, but we're not in a game mode where // teams have scores, then don't send back team score information. if (( teamplay || teamgame || teamlms || teampossession || teamcoop ) == false ) { if ( ulBits & SQF_TEAMSCORES ) ulBits &= ~SQF_TEAMSCORES; } // If the launcher wants to know player data, then we have to tell them how many players // are in the server. if ( ulBits & SQF_PLAYERDATA ) ulBits |= SQF_NUMPLAYERS; NETWORK_WriteLong( &g_MasterServerBuffer, ulBits ); // Send the server name. if ( ulBits & SQF_NAME ) { Val = sv_hostname.GetGenericRep( CVAR_String ); NETWORK_WriteString( &g_MasterServerBuffer, Val.String ); } // Send the website URL. if ( ulBits & SQF_URL ) { Val = sv_website.GetGenericRep( CVAR_String ); NETWORK_WriteString( &g_MasterServerBuffer, Val.String ); } // Send the host's e-mail address. if ( ulBits & SQF_EMAIL ) { Val = sv_hostemail.GetGenericRep( CVAR_String ); NETWORK_WriteString( &g_MasterServerBuffer, Val.String ); } if ( ulBits & SQF_MAPNAME ) NETWORK_WriteString( &g_MasterServerBuffer, level.mapname ); if ( ulBits & SQF_MAXCLIENTS ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_maxclients ); if ( ulBits & SQF_MAXPLAYERS ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_maxplayers ); // Send out the PWAD information. if ( ulBits & SQF_PWADS ) { ulNumPWADs = 0; for ( ulIdx = 0; Wads.GetWadName( ulIdx ) != NULL; ulIdx++ ) { // Skip the IWAD file index, skulltag.wad/pk3, and files that were automatically // loaded from subdirectories (such as skin files). if (( ulIdx == FWadCollection::IWAD_FILENUM ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.wad" ) == 0 ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.pk3" ) == 0 ) || ( Wads.GetLoadedAutomatically( ulIdx ))) { continue; } ulNumPWADs++; } NETWORK_WriteByte( &g_MasterServerBuffer, ulNumPWADs ); for ( ulIdx = 0; Wads.GetWadName( ulIdx ) != NULL; ulIdx++ ) { // Skip the IWAD file index, skulltag.wad/pk3, and files that were automatically // loaded from subdirectories (such as skin files). if (( ulIdx == FWadCollection::IWAD_FILENUM ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.wad" ) == 0 ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.pk3" ) == 0 ) || ( Wads.GetLoadedAutomatically( ulIdx ))) { continue; } NETWORK_WriteString( &g_MasterServerBuffer, (char *)Wads.GetWadName( ulIdx )); } } if ( ulBits & SQF_GAMETYPE ) { NETWORK_WriteByte( &g_MasterServerBuffer, GAME_GetGameType( )); NETWORK_WriteByte( &g_MasterServerBuffer, instagib ); NETWORK_WriteByte( &g_MasterServerBuffer, buckshot ); } if ( ulBits & SQF_GAMENAME ) NETWORK_WriteString( &g_MasterServerBuffer, SERVER_MASTER_GetGameName( )); if ( ulBits & SQF_IWAD ) NETWORK_WriteString( &g_MasterServerBuffer, (char *)Wads.GetWadName( FWadCollection::IWAD_FILENUM )); if ( ulBits & SQF_FORCEPASSWORD ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_forcepassword ); if ( ulBits & SQF_FORCEJOINPASSWORD ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_forcejoinpassword ); if ( ulBits & SQF_GAMESKILL ) NETWORK_WriteByte( &g_MasterServerBuffer, gameskill ); if ( ulBits & SQF_BOTSKILL ) NETWORK_WriteByte( &g_MasterServerBuffer, botskill ); if ( ulBits & SQF_DMFLAGS ) { NETWORK_WriteLong( &g_MasterServerBuffer, dmflags ); NETWORK_WriteLong( &g_MasterServerBuffer, dmflags2 ); NETWORK_WriteLong( &g_MasterServerBuffer, compatflags ); } if ( ulBits & SQF_LIMITS ) { NETWORK_WriteShort( &g_MasterServerBuffer, fraglimit ); NETWORK_WriteShort( &g_MasterServerBuffer, (SHORT)timelimit ); if ( timelimit ) { LONG lTimeLeft; lTimeLeft = (LONG)( timelimit - ( level.totaltime / ( TICRATE * 60 ))); //ghk if ( lTimeLeft < 0 ) lTimeLeft = 0; NETWORK_WriteShort( &g_MasterServerBuffer, lTimeLeft ); } NETWORK_WriteShort( &g_MasterServerBuffer, duellimit ); NETWORK_WriteLong( &g_MasterServerBuffer, pointlimit ); //ghk writelong NETWORK_WriteShort( &g_MasterServerBuffer, winlimit ); } // Send the team damage scale. if ( teamplay || teamgame || teamlms || teampossession || teamcoop || (( deathmatch == false ) && ( teamgame == false ))) { if ( ulBits & SQF_TEAMDAMAGE ) NETWORK_WriteFloat( &g_MasterServerBuffer, teamdamage ); } // Send the team scores. if ( teamplay || teamgame || teamlms || teampossession || teamcoop ) { if ( ulBits & SQF_TEAMSCORES ) { for ( ulIdx = 0; ulIdx < NUM_TEAMS; ulIdx++ ) { if ( teamplay ) NETWORK_WriteShort( &g_MasterServerBuffer, TEAM_GetFragCount( ulIdx )); else if ( teamlms ) NETWORK_WriteShort( &g_MasterServerBuffer, TEAM_GetWinCount( ulIdx )); else NETWORK_WriteShort( &g_MasterServerBuffer, TEAM_GetScore( ulIdx )); //ghk writelong? } } } if ( ulBits & SQF_NUMPLAYERS ) NETWORK_WriteByte( &g_MasterServerBuffer, SERVER_CalcNumPlayers( )); if ( ulBits & SQF_PLAYERDATA ) { for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if ( playeringame[ulIdx] == false ) continue; NETWORK_WriteString( &g_MasterServerBuffer, players[ulIdx].userinfo.netname ); if ( teamgame || possession || teampossession || cooperative || teamcoop ) NETWORK_WriteLong( &g_MasterServerBuffer, players[ulIdx].lPointCount );//ghk writelong else if ( deathmatch ) NETWORK_WriteLong( &g_MasterServerBuffer, players[ulIdx].fragcount ); //ghk writelong else NETWORK_WriteLong( &g_MasterServerBuffer, players[ulIdx].killcount ); //ghk writelong NETWORK_WriteShort( &g_MasterServerBuffer, players[ulIdx].ulPing ); NETWORK_WriteByte( &g_MasterServerBuffer, PLAYER_IsTrueSpectator( &players[ulIdx] )); NETWORK_WriteByte( &g_MasterServerBuffer, players[ulIdx].bIsBot ); if ( teamplay || teamgame || teamlms || teampossession || teamcoop ) { if ( players[ulIdx].bOnTeam == false ) NETWORK_WriteByte( &g_MasterServerBuffer, 255 ); else NETWORK_WriteByte( &g_MasterServerBuffer, players[ulIdx].ulTeam ); } NETWORK_WriteByte( &g_MasterServerBuffer, players[ulIdx].ulTime / ( TICRATE * 60 )); } } // NETWORK_LaunchPacket( &g_MasterServerBuffer, Address, true ); NETWORK_LaunchPacket( &g_MasterServerBuffer, Address ); }
//***************************************************************************** // void DUEL_DoFight( void ) { ULONG ulIdx; DHUDMessageFadeOut *pMsg; // No longer waiting to duel. if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) DUEL_SetState( DS_INDUEL ); // Make sure this is 0. Can be non-zero in network games if they're slightly out of sync. g_ulDuelCountdownTicks = 0; // Reset level time to 0. level.time = 0; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { // Since the level time is being reset, also reset the last frag/excellent time for // each player. players[ulIdx].ulLastExcellentTick = 0; players[ulIdx].ulLastFragTick = 0; players[ulIdx].ulLastBFGFragTick = 0; players[ulIdx].ulDeathsWithoutFrag = 0; players[ulIdx].ulFragsWithoutDeath = 0; players[ulIdx].ulRailgunShots = 0; } // Tell clients to "fight!". if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_DoGameModeFight( 0 ); if ( NETWORK_GetState( ) != NETSTATE_SERVER ) { // Play fight sound. ANNOUNCER_PlayEntry( cl_announcer, "Fight" ); screen->SetFont( BigFont ); // Display "FIGHT!" HUD message. pMsg = new DHUDMessageFadeOut( "FIGHT!", 160.4f, 75.0f, 320, 200, CR_RED, 2.0f, 1.0f ); StatusBar->AttachMessage( pMsg, 'CNTR' ); screen->SetFont( SmallFont ); } // Display a little thing in the server window so servers can know when matches begin. else Printf( "FIGHT!\n" ); // Reset the map. if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) GAME_ResetMap( ); if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) { // Respawn the players. for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( PLAYER_IsTrueSpectator( &players[ulIdx] ) == false )) { if ( players[ulIdx].mo ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_DestroyThing( players[ulIdx].mo ); players[ulIdx].mo->Destroy( ); players[ulIdx].mo = NULL; } // Set the player's state to PST_REBORNNOINVENTORY so they everything is cleared (weapons, etc.) players[ulIdx].playerstate = PST_REBORNNOINVENTORY; G_DeathMatchSpawnPlayer( ulIdx, true ); if ( players[ulIdx].pSkullBot ) players[ulIdx].pSkullBot->PostEvent( BOTEVENT_DUEL_FIGHT ); } } } SCOREBOARD_RefreshHUD( ); }
//***************************************************************************** // void CHAT_PrintChatString( ULONG ulPlayer, ULONG ulMode, const char *pszString ) { ULONG ulChatLevel = 0; FString OutString; FString ChatString; // [RC] Are we ignoring this player? if (( ulPlayer != MAXPLAYERS ) && players[ulPlayer].bIgnoreChat ) return; // If ulPlayer == MAXPLAYERS, it is the server talking. if ( ulPlayer == MAXPLAYERS ) { // Special support for "/me" commands. ulChatLevel = PRINT_HIGH; if ( strnicmp( "/me", pszString, 3 ) == 0 ) { pszString += 3; OutString = "* <server>"; } else OutString = "<server>: "; } else if ( ulMode == CHATMODE_GLOBAL ) { ulChatLevel = PRINT_CHAT; // Special support for "/me" commands. if ( strnicmp( "/me", pszString, 3 ) == 0 ) { ulChatLevel = PRINT_HIGH; pszString += 3; OutString.AppendFormat( "* %s\\cc", players[ulPlayer].userinfo.netname ); } else { OutString.AppendFormat( "%s" TEXTCOLOR_CHAT ": ", players[ulPlayer].userinfo.netname ); } } else if ( ulMode == CHATMODE_TEAM ) { ulChatLevel = PRINT_TEAMCHAT; if ( PLAYER_IsTrueSpectator ( &players[consoleplayer] ) ) OutString += "<SPEC> "; else { OutString = "\\c"; OutString += V_GetColorChar( TEAM_GetTextColor( players[consoleplayer].ulTeam )); OutString += "<TEAM> "; } // Special support for "/me" commands. if ( strnicmp( "/me", pszString, 3 ) == 0 ) { ulChatLevel = PRINT_HIGH; pszString += 3; OutString.AppendFormat( "\\cc* %s\\cc", players[ulPlayer].userinfo.netname ); } else { OutString.AppendFormat( "\\cd%s" TEXTCOLOR_TEAMCHAT ": ", players[ulPlayer].userinfo.netname ); } } ChatString = pszString; // [RC] Remove linebreaks and other escape codes from chat. ChatString.Substitute("\\", "\\\\"); // [RC] ...but allow chat colors. ChatString.Substitute("\\\\c", "\\c"); // [BB] Remove invalid color codes, those can confuse the printing and create new lines. V_RemoveInvalidColorCodes( ChatString ); // [RC] ...if the user wants them. if ( con_colorinmessages == 2) V_RemoveColorCodes( ChatString ); // [BB] Remove any kind of trailing crap. V_RemoveTrailingCrapFromFString ( ChatString ); // [BB] If the chat string is empty now, it only contained crap and is ignored. if ( ChatString.IsEmpty() ) return; OutString += ChatString; Printf( ulChatLevel, "%s\n", OutString.GetChars() ); // [BB] If the user doesn't want to see the messages, they shouldn't make a sound. if ( show_messages ) { // [RC] User can choose the chat sound. if ( chat_sound == 1 ) // Default S_Sound( CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE ); else if ( chat_sound == 2 ) // Doom 1 S_Sound( CHAN_VOICE | CHAN_UI, "misc/chat2", 1, ATTN_NONE ); else if ( chat_sound == 3 ) // Doom 2 S_Sound( CHAN_VOICE | CHAN_UI, "misc/chat", 1, ATTN_NONE ); } BOTCMD_SetLastChatString( pszString ); BOTCMD_SetLastChatPlayer( players[ulPlayer].userinfo.netname ); { ULONG ulIdx; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if ( playeringame[ulIdx] == false ) continue; // Don't tell the bot someone talked if it was it who talked. if ( ulIdx == ulPlayer ) continue; // If this is a bot, tell it a player said something. if ( players[ulIdx].pSkullBot ) players[ulIdx].pSkullBot->PostEvent( BOTEVENT_PLAYER_SAY ); } } }
//***************************************************************************** // void medal_SelectIcon( ULONG ulPlayer ) { AInventory *pInventory; player_t *pPlayer; ULONG ulActualSprite = NUM_SPRITES; // [BB] If ulPlayer carries a TeamItem, e.g. flag or skull, we store a pointer // to it in pTeamItem and set the floaty icon to the carry (or spawn) state of // the TeamItem. We also need to copy the Translation of the TeamItem to the // FloatyIcon. AInventory *pTeamItem = NULL; if ( ulPlayer >= MAXPLAYERS ) return; pPlayer = &players[ulPlayer]; if ( pPlayer->mo == NULL ) return; // Allow the user to disable icons. if (( cl_icons == false ) || ( NETWORK_GetState( ) == NETSTATE_SERVER ) || pPlayer->bSpectating ) { if ( pPlayer->pIcon ) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } return; } // Verify that our current icon is valid. (i.e. We may have had a chat bubble, then // stopped talking, so we need to delete it). if ( pPlayer->pIcon && pPlayer->pIcon->bTeamItemFloatyIcon == false ) { switch ( (ULONG)( pPlayer->pIcon->state - pPlayer->pIcon->SpawnState )) { // Chat icon. Delete it if the player is no longer talking. case S_CHAT: if ( pPlayer->bChatting == false ) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else ulActualSprite = SPRITE_CHAT; break; // In console icon. Delete it if the player is no longer in the console. case S_INCONSOLE: case ( S_INCONSOLE + 1): if ( pPlayer->bInConsole == false ) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else ulActualSprite = SPRITE_INCONSOLE; break; // Ally icon. Delete it if the player is now our enemy or if we're spectating. // [BB] Dead spectators shall keep the icon for their teammates. case S_ALLY: if ( PLAYER_IsTrueSpectator ( &players[ SCOREBOARD_GetViewPlayer() ] ) || ( !pPlayer->mo->IsTeammate( players[ SCOREBOARD_GetViewPlayer() ].mo ) ) ) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else ulActualSprite = SPRITE_ALLY; break; // Flag/skull icon. Delete it if the player no longer has it. case S_WHITEFLAG: case ( S_WHITEFLAG + 1 ): case ( S_WHITEFLAG + 2 ): case ( S_WHITEFLAG + 3 ): case ( S_WHITEFLAG + 4 ): case ( S_WHITEFLAG + 5 ): { bool bDelete = false; // Delete the icon if teamgame has been turned off, or if the player // is not on a team. if (( teamgame == false ) || ( pPlayer->bOnTeam == false )) { bDelete = true; } // Delete the white flag if the player no longer has it. pInventory = pPlayer->mo->FindInventory( PClass::FindClass( "WhiteFlag" )); if (( oneflagctf ) && ( pInventory == NULL )) bDelete = true; // We wish to delete the icon, so do that now. if ( bDelete ) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else ulActualSprite = SPRITE_WHITEFLAG; } break; // Terminator artifact icon. Delete it if the player no longer has it. case S_TERMINATORARTIFACT: case ( S_TERMINATORARTIFACT + 1 ): case ( S_TERMINATORARTIFACT + 2 ): case ( S_TERMINATORARTIFACT + 3 ): if (( terminator == false ) || (( pPlayer->cheats2 & CF2_TERMINATORARTIFACT ) == false )) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else ulActualSprite = SPRITE_TERMINATORARTIFACT; break; // Lag icon. Delete it if the player is no longer lagging. case S_LAG: if ((( NETWORK_GetState( ) != NETSTATE_CLIENT ) && ( CLIENTDEMO_IsPlaying( ) == false )) || ( pPlayer->bLagging == false )) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else ulActualSprite = SPRITE_LAG; break; // Possession artifact icon. Delete it if the player no longer has it. case S_POSSESSIONARTIFACT: case ( S_POSSESSIONARTIFACT + 1 ): case ( S_POSSESSIONARTIFACT + 2 ): case ( S_POSSESSIONARTIFACT + 3 ): if ((( possession == false ) && ( teampossession == false )) || (( pPlayer->cheats2 & CF2_POSSESSIONARTIFACT ) == false )) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else ulActualSprite = SPRITE_POSSESSIONARTIFACT; break; } } // Check if we need to have an icon above us, or change the current icon. { if ( pPlayer->pIcon && pPlayer->pIcon->bTeamItemFloatyIcon ) { if ( !( GAMEMODE_GetFlags( GAMEMODE_GetCurrentMode( )) & GMF_USETEAMITEM ) || ( pPlayer->bOnTeam == false ) || ( TEAM_FindOpposingTeamsItemInPlayersInventory ( pPlayer ) == NULL ) ) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } else { ulActualSprite = SPRITE_TEAMITEM; } } ULONG ulFrame = 65535; const ULONG ulDesiredSprite = medal_GetDesiredIcon ( pPlayer, pTeamItem ); // [BB] Determine the frame based on the desired sprite. switch ( ulDesiredSprite ) { case SPRITE_ALLY: ulFrame = S_ALLY; break; case SPRITE_CHAT: ulFrame = S_CHAT; break; case SPRITE_INCONSOLE: ulFrame = S_INCONSOLE; break; case SPRITE_LAG: ulFrame = S_LAG; break; case SPRITE_WHITEFLAG: ulFrame = S_WHITEFLAG; break; case SPRITE_TEAMITEM: ulFrame = 0; break; case SPRITE_TERMINATORARTIFACT: ulFrame = S_TERMINATORARTIFACT; break; case SPRITE_POSSESSIONARTIFACT: ulFrame = S_POSSESSIONARTIFACT; break; default: break; } // We have an icon that needs to be spawned. if ((( ulFrame != 65535 ) && ( ulDesiredSprite != NUM_SPRITES ))) { // [BB] If a TeamItem icon replaces an existing non-team icon, we have to delete the old icon first. if ( pPlayer->pIcon && ( pPlayer->pIcon->bTeamItemFloatyIcon == false ) && pTeamItem ) { pPlayer->pIcon->Destroy( ); pPlayer->pIcon = NULL; } if (( pPlayer->pIcon == NULL ) || ( ulDesiredSprite != ulActualSprite )) { if ( pPlayer->pIcon == NULL ) { pPlayer->pIcon = Spawn<AFloatyIcon>( pPlayer->mo->x, pPlayer->mo->y, pPlayer->mo->z + pPlayer->mo->height + ( 4 * FRACUNIT ), NO_REPLACE ); if ( pTeamItem ) { pPlayer->pIcon->bTeamItemFloatyIcon = true; FName Name = "Carry"; FState *CarryState = pTeamItem->FindState( Name ); // [BB] If the TeamItem has a Carry state (like the built in flags), use it. // Otherwise use the spawn state (the built in skulls don't have a carry state). if ( CarryState ) pPlayer->pIcon->SetState( CarryState ); else pPlayer->pIcon->SetState( pTeamItem->SpawnState ); pPlayer->pIcon->Translation = pTeamItem->Translation; } else { pPlayer->pIcon->bTeamItemFloatyIcon = false; } } if ( pPlayer->pIcon ) { // [BB] Potentially the new icon overrides an existing medal, so make sure that it doesn't fade out. pPlayer->pIcon->lTick = 0; pPlayer->pIcon->SetTracer( pPlayer->mo ); if ( pPlayer->pIcon->bTeamItemFloatyIcon == false ) pPlayer->pIcon->SetState( pPlayer->pIcon->SpawnState + ulFrame ); } } } } }