diff options
author | Mikko Tiusanen <ams@daug.net> | 2014-05-04 01:18:52 +0300 |
---|---|---|
committer | Mikko Tiusanen <ams@daug.net> | 2014-05-04 01:18:52 +0300 |
commit | 01beb9919b95479d8be040bec74abc5cc67a5e43 (patch) | |
tree | 65f0b79e793848491832756a4c3a32b23668fab3 /src/game/g_team.c | |
parent | 191d731da136b7ee959a17e63111c9146219a768 (diff) |
Initial import.
Diffstat (limited to 'src/game/g_team.c')
-rw-r--r-- | src/game/g_team.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/src/game/g_team.c b/src/game/g_team.c new file mode 100644 index 0000000..45a2370 --- /dev/null +++ b/src/game/g_team.c @@ -0,0 +1,558 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2000-2009 Darklegion Development + +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 +=========================================================================== +*/ +/* +=========================================================================== +TREMULOUS EDGE MOD SRC FILE +=========================================================================== +*/ +#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( Q_vsnprintf( msg, sizeof( 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 ) ); +} + +/* +================ +G_TeamFromString + +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; + } +} + +/* +================ +G_TeamCommand + +Broadcasts a command to only a specific team +================ +*/ +void G_TeamCommand( team_t team, char *cmd ) +{ + int i; + + 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 +============== +*/ +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; +} + +/* +================== +G_ClientListForTeam +================== +*/ +static clientList_t G_ClientListForTeam( team_t team ) +{ + int i; + clientList_t clientList; + + 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 +================== +*/ +void G_UpdateTeamConfigStrings( void ) +{ + clientList_t alienTeam = G_ClientListForTeam( TEAM_ALIENS ); + clientList_t humanTeam = G_ClientListForTeam( TEAM_HUMANS ); + + if( level.intermissiontime ) + { + // No restrictions once the game has ended + Com_Memset( &alienTeam, 0, sizeof( clientList_t ) ); + Com_Memset( &humanTeam, 0, sizeof( clientList_t ) ); + } + + 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 ); + + 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 + { + if( self->client->sess.spectatorState == SPECTATOR_FOLLOW ) + G_StopFollowing( self ); + return; + } + + // stop any following clients + G_StopFromFollowing( self ); + + G_Vote( self, team, qfalse ); + self->suicideTime = 0; + + + + + + for( i = 0; i < level.num_entities; i++ ) + { + ent = &g_entities[ i ]; + if( !ent->inuse ) + continue; + + 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 ); + } + + // cut all relevant zap beams + G_ClearPlayerZapEffects( self ); + + // cure infection + if( ent->client->ps.stats[ STAT_STATE ] & SS_INFECTED && + ent->client->lastInfectionClient == self ) + ent->client->ps.stats[ STAT_STATE ] &= ~SS_INFECTED; + + else if( ent->s.eType == ET_MISSILE && ent->r.ownerNum == self->s.number ) + G_FreeEntity( ent ); + + + + + + + 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 ); + } + + // 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", + ent - g_entities, BG_TeamName( newTeam ), ent->client->pers.netname ); + + G_namelog_update_score( ent->client ); + TeamplayInfoMessage( ent ); + +} + + + /* + Call this method to balance teams + */ +void G_BalanceTeams() +{ + team_t sourceTeam; + gentity_t *ent; + int clientId,lastTime,i; + if( level.numAlienSpawns > 0 && level.numHumanClients - level.numAlienClients >= 2 ) { + sourceTeam = TEAM_HUMANS; + } else if( level.numHumanSpawns > 0 && level.numAlienClients - level.numHumanClients >= 2 ) { + sourceTeam = TEAM_ALIENS; + } else return; + clientId = -1; + lastTime = 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->pers.teamSelection == sourceTeam && ent->client->pers.teamChangeTime > lastTime) { + clientId = i; + lastTime = ent->client->pers.teamChangeTime; + } + } + if (clientId != -1) { + ent = g_entities + clientId; + + switch(sourceTeam) { + case TEAM_HUMANS: + // Refund all weapons and equipment before team change + for( i = WP_NONE+1; i < WP_NUM_WEAPONS; ++i ) + { + if ( i == WP_HBUILD && ent->client->ps.stats[ STAT_MISC ] > 0 ) + continue; + if (BG_InventoryContainsWeapon( i, ent->client->ps.stats ) && BG_Weapon( i )->purchasable ) + { + G_AddCreditToClient( ent->client, (short)BG_Weapon( i )->price, qfalse ); + } + } + for( i = UP_NONE+1; i < UP_NUM_UPGRADES; ++i ) + { + if (BG_InventoryContainsUpgrade( i, ent->client->ps.stats ) && BG_Upgrade( i )->purchasable ) + { + G_AddCreditToClient( ent->client, (short)BG_Upgrade( i )->price, qfalse ); + } + } + trap_SendServerCommand( -1, "print \"Humans have more players. Moving last joining player to alien team...\n\""); + break; + case TEAM_ALIENS: + // Refund evo-points to aliens + G_AddCreditToClient( ent->client, (short)(BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->cost * ALIEN_CREDITS_PER_KILL), qfalse ); + + trap_SendServerCommand( -1, "print \"Aliens have more players. Moving last joining player to human team...\n\""); + break; + default: + break; + } + G_ChangeTeam(ent,(sourceTeam == TEAM_HUMANS) ? TEAM_ALIENS : TEAM_HUMANS); + } +} + + +/* +=========== +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; + + best = NULL; + bestlen = 3.0f * 8192.0f * 8192.0f; + + for( eloc = level.locationHead; eloc; eloc = eloc->nextTrain ) + { + len = DistanceSquared( ent->r.currentOrigin, eloc->r.currentOrigin ); + + if( len > bestlen ) + continue; + + if( !trap_InPVS( ent->r.currentOrigin, eloc->r.currentOrigin ) ) + continue; + + bestlen = len; + best = eloc; + } + + return best; +} + + +/*---------------------------------------------------------------------------*/ + +/* +================== +TeamplayInfoMessage + +Format: + clientNum location health weapon upgrade + +================== +*/ +void TeamplayInfoMessage( gentity_t *ent ) +{ + char entry[ 19 ], string[ 1143 ]; + int i, j; + int team, stringlength; + int sent = 0; + gentity_t *player; + gclient_t *cl; + upgrade_t upgrade = UP_NONE; + int curWeaponClass = WP_NONE ; // sends weapon for humans, class for aliens + char *tmp; + + if( !g_allowTeamOverlay.integer ) + return; + + if( !ent->client->pers.teamInfo ) + return; + + 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; + + string[ 0 ] = '\0'; + stringlength = 0; + + for( i = 0; i < MAX_CLIENTS; i++) + { + player = g_entities + i ; + cl = player->client; + + if( ent == player || !cl || team != cl->pers.teamSelection || + !player->inuse ) + continue; + + 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; + } + + tmp = va( "%i %i %i %i", + player->client->pers.location, + player->client->ps.stats[ STAT_HEALTH ] < 1 ? 0 : + player->client->ps.stats[ STAT_HEALTH ], + curWeaponClass, + upgrade ); + + if( !strcmp( ent->client->pers.cinfo[ i ], tmp ) ) + continue; + + Q_strncpyz( ent->client->pers.cinfo[ i ], tmp, + sizeof( ent->client->pers.cinfo[ i ] ) ); + + Com_sprintf( entry, sizeof( entry ), " %i %s", i, tmp ); + + j = strlen( entry ); + + if( stringlength + j > sizeof( string ) ) + break; + + strcpy( string + stringlength, entry ); + stringlength += j; + sent++; + } + + if( !sent ) + return; + + trap_SendServerCommand( ent - g_entities, va( "tinfo%s", 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_TEAM ] == TEAM_HUMANS || + ent->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) ) + { + + loc = Team_GetLocation( ent ); + + if( loc ) + ent->client->pers.location = loc->s.generic1; + else + ent->client->pers.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 ) + TeamplayInfoMessage( ent ); + } + } + + // Warn on imbalanced teams + if( g_teamImbalanceWarnings.integer && !level.intermissiontime && + ( level.time - level.lastTeamImbalancedTime > + ( g_teamImbalanceWarnings.integer * 1000 ) ) && + level.numTeamImbalanceWarnings < 3 && !level.restarted ) + { + level.lastTeamImbalancedTime = level.time; + if( level.numAlienSpawns > 0 && + level.numHumanClients - level.numAlienClients >= 2 ) + { + trap_SendServerCommand( -1, "print \"^5Teams are imbalanced. " + "^5Humans have more players.\n\""); + level.numTeamImbalanceWarnings++; + G_BalanceTeams(); + } + else if( level.numHumanSpawns > 0 && + level.numAlienClients - level.numHumanClients >= 2 ) + { + trap_SendServerCommand ( -1, "print \"^5Teams are imbalanced. " + "^5Aliens have more players.\n\""); + level.numTeamImbalanceWarnings++; + G_BalanceTeams(); + } + else + { + level.numTeamImbalanceWarnings = 0; + } + } +} |