summaryrefslogtreecommitdiff
path: root/src/game/g_team.c
diff options
context:
space:
mode:
authorIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
committerIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
commit425decdf7e9284d15aa726e3ae96b9942fb0e3ea (patch)
tree6c0dd7edfefff1be7b9e75fe0b3a0a85fe1595f3 /src/game/g_team.c
parentccb0b2e4d6674a7a00c9bf491f08fc73b6898c54 (diff)
create tremded branch
Diffstat (limited to 'src/game/g_team.c')
-rw-r--r--src/game/g_team.c457
1 files changed, 324 insertions, 133 deletions
diff --git a/src/game/g_team.c b/src/game/g_team.c
index 1d8d102..4af6235 100644
--- a/src/game/g_team.c
+++ b/src/game/g_team.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
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,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,35 +17,54 @@ 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
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
#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 );
+/*
+================
+G_TeamFromString
- if( vsprintf( msg, fmt, argptr ) > sizeof( msg ) )
- G_Error ( "PrintMsg overrun" );
+Return the team referenced by a string
+================
+*/
+team_t G_TeamFromString( char *str )
+{
+ switch( tolower( *str ) )
+ {
+ case '0': case 's': return TEAM_NONE;
+ case '1': case 'a': return TEAM_ALIENS;
+ case '2': case 'h': return TEAM_HUMANS;
+ default: return NUM_TEAMS;
+ }
+}
- va_end( argptr );
+/*
+================
+G_TeamCommand
- // double quotes are bad
- while( ( p = strchr( msg, '"' ) ) != NULL )
- *p = '\'';
+Broadcasts a command to only a specific team
+================
+*/
+void G_TeamCommand( team_t team, const char *cmd )
+{
+ int i;
- trap_SendServerCommand( ( ( ent == NULL ) ? -1 : ent-g_entities ), va( "print \"%s\"", msg ) );
+ for( i = 0 ; i < level.maxclients ; i++ )
+ {
+ if( level.clients[ i ].pers.connected == CON_CONNECTED )
+ {
+ if( level.clients[ i ].pers.teamSelection == team ||
+ ( level.clients[ i ].pers.teamSelection == TEAM_NONE &&
+ G_admin_permission( &g_entities[ i ], ADMF_SPEC_ALLCHAT ) ) )
+ trap_SendServerCommand( i, cmd );
+ }
+ }
}
-
/*
==============
OnSameTeam
@@ -62,156 +82,312 @@ qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 )
}
/*
-===========
-Team_GetLocation
+==================
+G_ClientListForTeam
+==================
+*/
+static clientList_t G_ClientListForTeam( team_t team )
+{
+ int i;
+ clientList_t clientList;
-Report a location for the player. Uses placed nearby target_location entities
-============
+ Com_Memset( &clientList, 0, sizeof( clientList_t ) );
+
+ for( i = 0; i < g_maxclients.integer; i++ )
+ {
+ gentity_t *ent = g_entities + i;
+ if( ent->client->pers.connected != CON_CONNECTED )
+ continue;
+
+ if( ent->inuse && ( ent->client->ps.stats[ STAT_TEAM ] == team ) )
+ Com_ClientListAdd( &clientList, ent->client->ps.clientNum );
+ }
+
+ return clientList;
+}
+
+/*
+==================
+G_UpdateTeamConfigStrings
+==================
*/
-gentity_t *Team_GetLocation( gentity_t *ent )
+void G_UpdateTeamConfigStrings( void )
{
- gentity_t *eloc, *best;
- float bestlen, len;
- vec3_t origin;
+ clientList_t alienTeam = G_ClientListForTeam( TEAM_ALIENS );
+ clientList_t humanTeam = G_ClientListForTeam( TEAM_HUMANS );
- best = NULL;
- bestlen = 3.0f * 8192.0f * 8192.0f;
+ if( level.intermissiontime )
+ {
+ // No restrictions once the game has ended
+ Com_Memset( &alienTeam, 0, sizeof( clientList_t ) );
+ Com_Memset( &humanTeam, 0, sizeof( clientList_t ) );
+ }
- VectorCopy( ent->r.currentOrigin, origin );
+ trap_SetConfigstringRestrictions( CS_VOTE_TIME + TEAM_ALIENS, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_STRING + TEAM_ALIENS, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_YES + TEAM_ALIENS, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_NO + TEAM_ALIENS, &humanTeam );
- for( eloc = level.locationHead; eloc; eloc = eloc->nextTrain )
+ trap_SetConfigstringRestrictions( CS_VOTE_TIME + TEAM_HUMANS, &alienTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_STRING + TEAM_HUMANS, &alienTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_YES + TEAM_HUMANS, &alienTeam );
+ trap_SetConfigstringRestrictions( CS_VOTE_NO + TEAM_HUMANS, &alienTeam );
+
+ trap_SetConfigstringRestrictions( CS_ALIEN_STAGES, &humanTeam );
+ trap_SetConfigstringRestrictions( CS_HUMAN_STAGES, &alienTeam );
+}
+
+/*
+==================
+G_LeaveTeam
+==================
+*/
+void G_LeaveTeam( gentity_t *self )
+{
+ team_t team = self->client->pers.teamSelection;
+ gentity_t *ent;
+ int i;
+
+ if( team == TEAM_ALIENS )
+ G_RemoveFromSpawnQueue( &level.alienSpawnQueue, self->client->ps.clientNum );
+ else if( team == TEAM_HUMANS )
+ G_RemoveFromSpawnQueue( &level.humanSpawnQueue, self->client->ps.clientNum );
+ else
{
- 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( self->client->sess.spectatorState == SPECTATOR_FOLLOW )
+ G_StopFollowing( self );
+ return;
+ }
- if( len > bestlen )
- continue;
+ // stop any following clients
+ G_StopFromFollowing( self );
- if( !trap_InPVS( origin, eloc->r.currentOrigin ) )
+ G_Vote( self, team, qfalse );
+ self->suicideTime = 0;
+
+ for( i = 0; i < level.num_entities; i++ )
+ {
+ ent = &g_entities[ i ];
+ if( !ent->inuse )
continue;
- bestlen = len;
- best = eloc;
+ if( ent->client && ent->client->pers.connected == CON_CONNECTED )
+ {
+ // cure poison
+ if( ent->client->ps.stats[ STAT_STATE ] & SS_POISONED &&
+ ent->client->lastPoisonClient == self )
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
+ }
+ else if( ent->s.eType == ET_MISSILE && ent->r.ownerNum == self->s.number )
+ G_FreeEntity( ent );
}
- return best;
+ // cut all relevant zap beams
+ G_ClearPlayerZapEffects( self );
+
+ G_namelog_update_score( self->client );
}
+/*
+=================
+G_ChangeTeam
+=================
+*/
+void G_ChangeTeam( gentity_t *ent, team_t newTeam )
+{
+ team_t oldTeam = ent->client->pers.teamSelection;
+
+ if( oldTeam == newTeam )
+ return;
+
+ G_LeaveTeam( ent );
+ ent->client->pers.teamChangeTime = level.time;
+ ent->client->pers.teamSelection = newTeam;
+ ent->client->pers.classSelection = PCL_NONE;
+ ClientSpawn( ent, NULL, NULL, NULL );
+
+ if( oldTeam == TEAM_HUMANS && newTeam == TEAM_ALIENS )
+ {
+ // Convert from human to alien credits
+ ent->client->pers.credit =
+ (int)( ent->client->pers.credit *
+ ALIEN_MAX_CREDITS / HUMAN_MAX_CREDITS + 0.5f );
+ }
+ else if( oldTeam == TEAM_ALIENS && newTeam == TEAM_HUMANS )
+ {
+ // Convert from alien to human credits
+ ent->client->pers.credit =
+ (int)( ent->client->pers.credit *
+ HUMAN_MAX_CREDITS / ALIEN_MAX_CREDITS + 0.5f );
+ }
+
+ if( !g_cheats.integer )
+ {
+ if( ent->client->noclip )
+ {
+ ent->client->noclip = qfalse;
+ ent->r.contents = ent->client->cliprcontents;
+ }
+ ent->flags &= ~( FL_GODMODE | FL_NOTARGET );
+ }
+
+ // Copy credits to ps for the client
+ ent->client->ps.persistant[ PERS_CREDIT ] = ent->client->pers.credit;
+
+ ClientUserinfoChanged( ent->client->ps.clientNum, qfalse );
+
+ G_UpdateTeamConfigStrings( );
+
+ G_LogPrintf( "ChangeTeam: %d %s: %s" S_COLOR_WHITE " switched teams\n",
+ (int)( ent - g_entities ), BG_TeamName( newTeam ), ent->client->pers.netname );
+
+ G_namelog_update_score( ent->client );
+ TeamplayInfoMessage( ent );
+}
/*
===========
-Team_GetLocationMsg
+Team_GetLocation
-Report a location message for the player. Uses placed nearby target_location entities
+Report a location for the player. Uses placed nearby target_location entities
============
*/
-qboolean Team_GetLocationMsg( gentity_t *ent, char *loc, int loclen )
+gentity_t *Team_GetLocation( gentity_t *ent )
{
- gentity_t *best;
-
- best = Team_GetLocation( ent );
+ gentity_t *eloc, *best;
+ float bestlen, len;
- if( !best )
- return qfalse;
+ best = NULL;
+ bestlen = 3.0f * 8192.0f * 8192.0f;
- if( best->count )
+ for( eloc = level.locationHead; eloc; eloc = eloc->nextTrain )
{
- if( best->count < 0 )
- best->count = 0;
+ len = DistanceSquared( ent->r.currentOrigin, eloc->r.currentOrigin );
+
+ if( len > bestlen )
+ continue;
- if( best->count > 7 )
- best->count = 7;
+ if( !trap_InPVS( ent->r.currentOrigin, eloc->r.currentOrigin ) )
+ continue;
- Com_sprintf( loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message );
+ bestlen = len;
+ best = eloc;
}
- else
- Com_sprintf( loc, loclen, "%s", best->message );
- return qtrue;
+ return best;
}
/*---------------------------------------------------------------------------*/
-static int QDECL SortClients( const void *a, const void *b )
-{
- return *(int *)a - *(int *)b;
-}
-
-
/*
==================
-TeamplayLocationsMessage
+TeamplayInfoMessage
Format:
- clientNum location health armor weapon powerups
+ clientNum location health weapon upgrade
==================
*/
void TeamplayInfoMessage( gentity_t *ent )
{
- char entry[ 1024 ];
- char string[ 8192 ];
- int stringlength;
- int i, j;
+ char entry[ 17 ],
+ string[ ( MAX_CLIENTS - 1 ) * ( sizeof( entry ) - 1 ) + 1 ];
+ int i, j;
+ int team, stringlength;
gentity_t *player;
- int cnt;
- int h, a = 0;
- int clients[ TEAM_MAXOVERLAY ];
+ gclient_t *cl;
+ upgrade_t upgrade = UP_NONE;
+ int curWeaponClass = WP_NONE ; // sends weapon for humans, class for aliens
+ char *format;
- if( ! ent->client->pers.teamInfo )
- return;
+ if( !g_allowTeamOverlay.integer )
+ 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( !ent->client->pers.teamInfo )
+ return;
- if( player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam )
- clients[ cnt++ ] = level.sortedClients[ i ];
+ if( ent->client->pers.teamSelection == TEAM_NONE )
+ {
+ if( ent->client->sess.spectatorState == SPECTATOR_FREE ||
+ ent->client->sess.spectatorClient < 0 )
+ return;
+ team = g_entities[ ent->client->sess.spectatorClient ].client->
+ pers.teamSelection;
}
+ else
+ team = ent->client->pers.teamSelection;
- // We have the top eight players, sort them by clientNum
- qsort( clients, cnt, sizeof( clients[ 0 ] ), SortClients );
+ if( team == TEAM_ALIENS )
+ format = " %i %i %i %i"; // aliens don't have upgrades
+ else
+ format = " %i %i %i %i %i";
- // send the latest information on all clients
- string[ 0 ] = 0;
+ string[ 0 ] = '\0';
stringlength = 0;
- for( i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++)
+ for( i = 0; i < level.maxclients; i++)
{
- player = g_entities + i;
+ player = g_entities + i ;
+ cl = player->client;
- if( player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam )
- {
- h = player->client->ps.stats[ STAT_HEALTH ];
+ if( ent == player || !cl || team != cl->pers.teamSelection ||
+ !player->inuse )
+ continue;
- if( h < 0 )
- h = 0;
+ // only update if changed since last time
+ if( cl->pers.infoChangeTime <= ent->client->pers.teamInfo )
+ continue;
- 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 );
+ if( cl->sess.spectatorState != SPECTATOR_NOT )
+ {
+ curWeaponClass = WP_NONE;
+ upgrade = UP_NONE;
+ }
+ else if ( cl->pers.teamSelection == TEAM_HUMANS )
+ {
+ curWeaponClass = cl->ps.weapon;
+
+ if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, cl->ps.stats ) )
+ upgrade = UP_BATTLESUIT;
+ else if( BG_InventoryContainsUpgrade( UP_JETPACK, cl->ps.stats ) )
+ upgrade = UP_JETPACK;
+ else if( BG_InventoryContainsUpgrade( UP_BATTPACK, cl->ps.stats ) )
+ upgrade = UP_BATTPACK;
+ else if( BG_InventoryContainsUpgrade( UP_HELMET, cl->ps.stats ) )
+ upgrade = UP_HELMET;
+ else if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, cl->ps.stats ) )
+ upgrade = UP_LIGHTARMOUR;
+ else
+ upgrade = UP_NONE;
+ }
+ else if( cl->pers.teamSelection == TEAM_ALIENS )
+ {
+ curWeaponClass = cl->ps.stats[ STAT_CLASS ];
+ upgrade = UP_NONE;
+ }
- j = strlen( entry );
+ Com_sprintf( entry, sizeof( entry ), format, i,
+ cl->pers.location,
+ cl->ps.stats[ STAT_HEALTH ] < 1 ? 0 : cl->ps.stats[ STAT_HEALTH ],
+ curWeaponClass,
+ upgrade );
- if( stringlength + j > sizeof( string ) )
- break;
+ j = strlen( entry );
- strcpy( string + stringlength, entry );
- stringlength += j;
- cnt++;
- }
+ // this should not happen if entry and string sizes are correct
+ if( stringlength + j >= sizeof( string ) )
+ break;
+
+ strcpy( string + stringlength, entry );
+ stringlength += j;
}
- trap_SendServerCommand( ent - g_entities, va( "tinfo %i %s", cnt, string ) );
+ if( string[ 0 ] )
+ {
+ trap_SendServerCommand( ent - g_entities, va( "tinfo%s", string ) );
+ ent->client->pers.teamInfo = level.time;
+ }
}
void CheckTeamStatus( void )
@@ -229,16 +405,25 @@ void CheckTeamStatus( void )
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 ) )
+ if( ent->inuse && ( ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ||
+ ent->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) )
{
loc = Team_GetLocation( ent );
if( loc )
- ent->client->pers.teamState.location = loc->health;
- else
- ent->client->pers.teamState.location = 0;
+ {
+ if( ent->client->pers.location != loc->s.generic1 )
+ {
+ ent->client->pers.infoChangeTime = level.time;
+ ent->client->pers.location = loc->s.generic1;
+ }
+ }
+ else if( ent->client->pers.location != 0 )
+ {
+ ent->client->pers.infoChangeTime = level.time;
+ ent->client->pers.location = 0;
+ }
}
}
@@ -248,29 +433,35 @@ void CheckTeamStatus( void )
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 ) )
+ if( ent->inuse )
TeamplayInfoMessage( ent );
}
}
- //Warn on unbalanced teams
- if ( g_teamImbalanceWarnings.integer && !level.intermissiontime && level.time - level.lastTeamUnbalancedTime > ( g_teamImbalanceWarnings.integer * 1000 ) && level.numTeamWarnings<3 )
+ // Warn on imbalanced teams
+ if( g_teamImbalanceWarnings.integer && !level.intermissiontime &&
+ ( level.time - level.lastTeamImbalancedTime >
+ ( g_teamImbalanceWarnings.integer * 1000 ) ) &&
+ level.numTeamImbalanceWarnings < 3 && !level.restarted )
{
- 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;
- }
+ level.lastTeamImbalancedTime = level.time;
+ if( level.numAlienSpawns > 0 &&
+ level.numHumanClients - level.numAlienClients > 2 )
+ {
+ trap_SendServerCommand( -1, "print \"Teams are imbalanced. "
+ "Humans have more players.\n\"");
+ level.numTeamImbalanceWarnings++;
+ }
+ else if( level.numHumanSpawns > 0 &&
+ level.numAlienClients - level.numHumanClients > 2 )
+ {
+ trap_SendServerCommand ( -1, "print \"Teams are imbalanced. "
+ "Aliens have more players.\n\"");
+ level.numTeamImbalanceWarnings++;
+ }
+ else
+ {
+ level.numTeamImbalanceWarnings = 0;
+ }
}
}