int CHudScoreboard :: DrawScoreboard( float fTime ) { GetAllPlayersInfo(); // Packetloss removed on Kelly 'shipping nazi' Bailey's orders // if ( cl_showpacketloss && cl_showpacketloss->value && ( ScreenWidth >= 400 ) ) // { // can_show_packetloss = 1; // } // just sort the list on the fly // list is sorted first by frags, then by deaths float list_slot = 0; // print the heading line DrawUtils::DrawRectangle(xstart, ystart, xend - xstart, yend - ystart, m_colors.r, m_colors.g, m_colors.b, m_colors.a, m_bDrawStroke); int ypos = ystart + (list_slot * ROW_GAP) + 5; DrawUtils::DrawHudString( NAME_POS_START(), ypos, NAME_POS_END(), (char*)(gHUD.m_Teamplay ? "TEAMS" : "PLAYERS"), 255, 140, 0 ); DrawUtils::DrawHudStringReverse( KILLS_POS_END(), ypos, 0, "KILLS", 255, 140, 0 ); DrawUtils::DrawHudString( DEATHS_POS_START(), ypos, DEATHS_POS_END(), "DEATHS", 255, 140, 0 ); DrawUtils::DrawHudStringReverse( PING_POS_END(), ypos, PING_POS_START(), "PING", 255, 140, 0 ); list_slot += 2; ypos = ystart + (list_slot * ROW_GAP); FillRGBA( xstart, ypos, xend - xstart, 1, 255, 140, 0, 255); // draw the separator line list_slot += 0.8; if ( gHUD.m_Teamplay ) { DrawTeams( list_slot ); } else { // it's not teamplay, so just draw a simple player list DrawPlayers( list_slot ); } return 1; }
// Message handler for TeamInfo message // accepts two values: // byte: client number // string: client team name int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) { BufferReader reader( pszName, pbuf, iSize ); short cl = reader.ReadByte(); int teamNumber = 0; if ( cl > 0 && cl <= MAX_PLAYERS ) { // set the players team char teamName[MAX_TEAM_NAME]; strncpy( teamName, reader.ReadString(), MAX_TEAM_NAME ); if( !stricmp( teamName, "TERRORIST") ) teamNumber = TEAM_TERRORIST; else if( !stricmp( teamName, "CT") ) teamNumber = TEAM_CT; else if( !stricmp( teamName, "SPECTATOR" ) || !stricmp( teamName, "UNASSIGNED" ) ) { teamNumber = TEAM_SPECTATOR; strncpy( teamName, "SPECTATOR", MAX_TEAM_NAME ); } // just in case else teamNumber = TEAM_UNASSIGNED; strncpy( g_PlayerExtraInfo[cl].teamname, teamName, MAX_TEAM_NAME ); g_PlayerExtraInfo[cl].teamnumber = teamNumber; } // rebuild the list of teams // clear out player counts from teams for ( int i = 1; i <= m_iNumTeams; i++ ) { g_TeamInfo[i].players = 0; } // rebuild the team list GetAllPlayersInfo(); m_iNumTeams = 0; for ( int i = 1; i < MAX_PLAYERS; i++ ) { int j; //if ( g_PlayerInfoList[i].name == NULL ) // continue; if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) continue; // skip over players who are not in a team // is this player in an existing team? for ( j = 1; j <= m_iNumTeams; j++ ) { if ( g_TeamInfo[j].name[0] == '\0' ) break; if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) break; } if ( j > m_iNumTeams ) { // they aren't in a listed team, so make a new one for ( j = 1; j <= m_iNumTeams; j++ ) { if ( g_TeamInfo[j].name[0] == '\0' ) break; } m_iNumTeams = max( j, m_iNumTeams ); strncpy( g_TeamInfo[j].name, g_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); g_TeamInfo[j].teamnumber = g_PlayerExtraInfo[i].teamnumber; g_TeamInfo[j].players = 0; } g_TeamInfo[j].players++; } // clear out any empty teams for ( int i = 1; i <= m_iNumTeams; i++ ) { if ( g_TeamInfo[i].players < 1 ) memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); } return 1; }
int CHudScoreboard :: Draw( float fTime ) { if ( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission ) return 1; GetAllPlayersInfo(); // just sort the list on the fly // list is sorted first by frags, then by deaths float list_slot = 0; int xpos_rel = (ScreenWidth - SCOREBOARD_WIDTH) / 2; // print the heading line int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); int xpos = NAME_RANGE_MIN + xpos_rel; if ( !gHUD.m_Teamplay ) gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); else gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 ); gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, "kills", 255, 140, 0 ); gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", 255, 140, 0 ); gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 ); gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "latency", 255, 140, 0 ); list_slot += 1.2; ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); xpos = NAME_RANGE_MIN + xpos_rel; FillRGBA( xpos - 5, ypos, PING_RANGE_MAX - 5, 1, 255, 140, 0, 255); // draw the seperator line list_slot += 0.8; if ( !gHUD.m_Teamplay ) { // it's not teamplay, so just draw a simple player list DrawPlayers( xpos_rel, list_slot ); return 1; } // clear out team scores for ( int i = 1; i <= m_iNumTeams; i++ ) { if ( !m_TeamInfo[i].scores_overriden ) m_TeamInfo[i].frags = m_TeamInfo[i].deaths = 0; m_TeamInfo[i].ping = m_TeamInfo[i].packetloss = 0; } // recalc the team scores, then draw them for ( i = 1; i < MAX_PLAYERS; i++ ) { if ( m_PlayerInfoList[i].name == NULL ) continue; // empty player slot, skip if ( m_PlayerExtraInfo[i].teamname[0] == 0 ) continue; // skip over players who are not in a team // find what team this player is in for ( int j = 1; j <= m_iNumTeams; j++ ) { if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) ) break; } if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy continue; if ( !m_TeamInfo[j].scores_overriden ) { m_TeamInfo[j].frags += m_PlayerExtraInfo[i].frags; m_TeamInfo[j].deaths += m_PlayerExtraInfo[i].deaths; } m_TeamInfo[j].ping += m_PlayerInfoList[i].ping; m_TeamInfo[j].packetloss += m_PlayerInfoList[i].packetloss; if ( m_PlayerInfoList[i].thisplayer ) m_TeamInfo[j].ownteam = TRUE; else m_TeamInfo[j].ownteam = FALSE; } // find team ping/packetloss averages for ( i = 1; i <= m_iNumTeams; i++ ) { m_TeamInfo[i].already_drawn = FALSE; if ( m_TeamInfo[i].players > 0 ) { m_TeamInfo[i].ping /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping m_TeamInfo[i].packetloss /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping } } // Draw the teams while ( 1 ) { int highest_frags = -99999; int lowest_deaths = 99999; int best_team = 0; for ( i = 1; i <= m_iNumTeams; i++ ) { if ( m_TeamInfo[i].players < 0 ) continue; if ( !m_TeamInfo[i].already_drawn && m_TeamInfo[i].frags >= highest_frags ) { if ( m_TeamInfo[i].frags > highest_frags || m_TeamInfo[i].deaths < lowest_deaths ) { best_team = i; lowest_deaths = m_TeamInfo[i].deaths; highest_frags = m_TeamInfo[i].frags; } } } // draw the best team on the scoreboard if ( !best_team ) break; // draw out the best team team_info_t *team_info = &m_TeamInfo[best_team]; ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); // check we haven't drawn too far down if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border break; xpos = NAME_RANGE_MIN + xpos_rel; int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish if ( team_info->ownteam ) // if it is their team, draw the background different color { // overlay the background in blue, then draw the score text over it FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 ); } // draw their name (left to right) gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b ); // draw kills (right to left) xpos = KILLS_RANGE_MAX + xpos_rel; gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, team_info->frags, r, g, b ); // draw divider xpos = DIVIDER_POS + xpos_rel; gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); // draw deaths xpos = DEATHS_RANGE_MAX + xpos_rel; gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, team_info->deaths, r, g, b ); // draw ping // draw ping & packetloss static char buf[64]; sprintf( buf, "%d", team_info->ping ); xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; UnpackRGB( r, g, b, RGB_YELLOWISH ); gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); /* Packetloss removed on Kelly 'shipping nazi' Bailey's orders sprintf( buf, " %d", team_info->packetloss ); gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); */ team_info->already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get drawn again list_slot++; // draw all the players that belong to this team, indented slightly list_slot = DrawPlayers( xpos_rel, list_slot, 10, team_info->name ); } // draw all the players who are not in a team list_slot += 0.5; DrawPlayers( xpos_rel, list_slot, 0, "" ); return 1; }
// Message handler for TeamInfo message // accepts two values: // byte: client number // string: client team name int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); short cl = READ_BYTE(); if ( cl > 0 && cl <= MAX_PLAYERS ) { // set the players team strncpy( m_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME ); } // rebuild the list of teams // clear out player counts from teams for ( int i = 1; i <= m_iNumTeams; i++ ) { m_TeamInfo[i].players = 0; } // rebuild the team list GetAllPlayersInfo(); m_iNumTeams = 0; for ( i = 1; i < MAX_PLAYERS; i++ ) { if ( m_PlayerInfoList[i].name == NULL ) continue; if ( m_PlayerExtraInfo[i].teamname[0] == 0 ) continue; // skip over players who are not in a team // is this player in an existing team? for ( int j = 1; j <= m_iNumTeams; j++ ) { if ( m_TeamInfo[j].name[0] == '\0' ) break; if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) ) break; } if ( j > m_iNumTeams ) { // they aren't in a listed team, so make a new one // search through for an empty team slot for ( int j = 1; j <= m_iNumTeams; j++ ) { if ( m_TeamInfo[j].name[0] == '\0' ) break; } m_iNumTeams = max( j, m_iNumTeams ); strncpy( m_TeamInfo[j].name, m_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); m_TeamInfo[j].players = 0; } m_TeamInfo[j].players++; } // clear out any empty teams for ( i = 1; i <= m_iNumTeams; i++ ) { if ( m_TeamInfo[i].players < 1 ) memset( &m_TeamInfo[i], 0, sizeof(team_info_t) ); } return 1; }