/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 2000-2006 Tim Angus This file is part of Tremulous. Tremulous is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Tremulous is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Tremulous; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "g_local.h" // NULL for everyone void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) { char msg[ 1024 ]; va_list argptr; char *p; va_start( argptr,fmt ); if( vsprintf( msg, fmt, argptr ) > sizeof( msg ) ) G_Error ( "PrintMsg overrun" ); va_end( argptr ); // double quotes are bad while( ( p = strchr( msg, '"' ) ) != NULL ) *p = '\''; trap_SendServerCommand( ( ( ent == NULL ) ? -1 : ent-g_entities ), va( "print \"%s\"", msg ) ); } /* ============== OnSameTeam ============== */ qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) { if( !ent1->client || !ent2->client ) return qfalse; if( ent1->client->pers.teamSelection == ent2->client->pers.teamSelection ) return qtrue; return qfalse; } /* =========== Team_GetLocation Report a location for the player. Uses placed nearby target_location entities ============ */ gentity_t *Team_GetLocation( gentity_t *ent ) { gentity_t *eloc, *best; float bestlen, len; vec3_t origin; best = NULL; bestlen = 3.0f * 8192.0f * 8192.0f; VectorCopy( ent->r.currentOrigin, origin ); for( eloc = level.locationHead; eloc; eloc = eloc->nextTrain ) { len = ( origin[ 0 ] - eloc->r.currentOrigin[ 0 ] ) * ( origin[ 0 ] - eloc->r.currentOrigin[ 0 ] ) + ( origin[ 1 ] - eloc->r.currentOrigin[ 1 ] ) * ( origin[ 1 ] - eloc->r.currentOrigin[ 1 ] ) + ( origin[ 2 ] - eloc->r.currentOrigin[ 2 ] ) * ( origin[ 2 ] - eloc->r.currentOrigin[ 2 ] ); if( len > bestlen ) continue; if( !trap_InPVS( origin, eloc->r.currentOrigin ) ) continue; bestlen = len; best = eloc; } return best; } /* =========== Team_GetLocationMsg Report a location message for the player. Uses placed nearby target_location entities ============ */ qboolean Team_GetLocationMsg( gentity_t *ent, char *loc, int loclen ) { gentity_t *best; best = Team_GetLocation( ent ); if( !best ) return qfalse; if( best->count ) { if( best->count < 0 ) best->count = 0; if( best->count > 7 ) best->count = 7; Com_sprintf( loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message ); } else Com_sprintf( loc, loclen, "%s", best->message ); return qtrue; } /*---------------------------------------------------------------------------*/ static int QDECL SortClients( const void *a, const void *b ) { return *(int *)a - *(int *)b; } /* ================== TeamplayLocationsMessage Format: clientNum location health armor weapon powerups ================== */ void TeamplayInfoMessage( gentity_t *ent ) { char entry[ 1024 ]; char string[ 8192 ]; int stringlength; int i, j; gentity_t *player; int cnt; int h, a = 0; int clients[ TEAM_MAXOVERLAY ]; if( ! ent->client->pers.teamInfo ) return; // figure out what client should be on the display // we are limited to 8, but we want to use the top eight players // but in client order (so they don't keep changing position on the overlay) for( i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++ ) { player = g_entities + level.sortedClients[ i ]; if( player->inuse && player->client->sess.sessionTeam == ent->client->sess.sessionTeam ) clients[ cnt++ ] = level.sortedClients[ i ]; } // We have the top eight players, sort them by clientNum qsort( clients, cnt, sizeof( clients[ 0 ] ), SortClients ); // send the latest information on all clients string[ 0 ] = 0; stringlength = 0; for( i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) { player = g_entities + i; if( player->inuse && player->client->sess.sessionTeam == ent->client->sess.sessionTeam ) { h = player->client->ps.stats[ STAT_HEALTH ]; if( h < 0 ) h = 0; Com_sprintf( entry, sizeof( entry ), " %i %i %i %i %i %i", // level.sortedClients[i], player->client->pers.teamState.location, h, a, i, player->client->pers.teamState.location, h, a, player->client->ps.weapon, player->s.misc ); j = strlen( entry ); if( stringlength + j > sizeof( string ) ) break; strcpy( string + stringlength, entry ); stringlength += j; cnt++; } } trap_SendServerCommand( ent - g_entities, va( "tinfo %i %s", cnt, string ) ); } void CheckTeamStatus( void ) { int i; gentity_t *loc, *ent; if( level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME ) { level.lastTeamLocationTime = level.time; for( i = 0; i < g_maxclients.integer; i++ ) { ent = g_entities + i; if( ent->client->pers.connected != CON_CONNECTED ) continue; if( ent->inuse && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) ) { loc = Team_GetLocation( ent ); if( loc ) ent->client->pers.teamState.location = loc->health; else ent->client->pers.teamState.location = 0; } } for( i = 0; i < g_maxclients.integer; i++ ) { ent = g_entities + i; if( ent->client->pers.connected != CON_CONNECTED ) continue; if( ent->inuse && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) ) TeamplayInfoMessage( ent ); } } //Warn on unbalanced teams if ( g_teamImbalanceWarnings.integer && !level.intermissiontime && level.time - level.lastTeamUnbalancedTime > ( g_teamImbalanceWarnings.integer * 1000 ) && level.numTeamWarnings<3 ) { level.lastTeamUnbalancedTime = level.time; if (level.numAlienSpawns > 0 && level.numHumanClients - level.numAlienClients > 2) { trap_SendServerCommand (-1, "print \"Teams are unbalanced. Humans have more players.\n Humans will keep their points when switching teams.\n\""); level.numTeamWarnings++; } else if (level.numHumanSpawns > 0 && level.numAlienClients - level.numHumanClients > 2) { trap_SendServerCommand (-1, "print \"Teams are unbalanced. Aliens have more players.\n Aliens will keep their points when switching teams.\n\""); level.numTeamWarnings++; } else { level.numTeamWarnings = 0; } } }