summaryrefslogtreecommitdiff
path: root/src/game/g_team.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_team.c')
-rw-r--r--src/game/g_team.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/src/game/g_team.c b/src/game/g_team.c
new file mode 100644
index 0000000..1d8d102
--- /dev/null
+++ b/src/game/g_team.c
@@ -0,0 +1,276 @@
+/*
+===========================================================================
+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;
+ }
+ }
+}