Пример #1
0
//==========================================
// BOT_DMclass_CheckShot
// Checks if shot is blocked (doesn't verify it would hit)
//==========================================
static bool BOT_DMclass_CheckShot( edict_t *ent, vec3_t point )
{
	trace_t tr;
	vec3_t start, forward, right, offset;

	if( random() > ent->ai->pers.cha.firerate )
		return false;

	AngleVectors( ent->r.client->ps.viewangles, forward, right, NULL );

	VectorSet( offset, 0, 0, ent->viewheight );
	G_ProjectSource( ent->s.origin, offset, forward, right, start );

	// blocked, don't shoot
	G_Trace( &tr, start, vec3_origin, vec3_origin, point, ent, MASK_AISOLID );
	if( tr.fraction < 0.8f )
	{
		if( tr.ent < 1 || !game.edicts[tr.ent].takedamage || game.edicts[tr.ent].movetype == MOVETYPE_PUSH )
			return false;

		// check if the player we found is at our team
		if( game.edicts[tr.ent].s.team == ent->s.team && GS_TeamBasedGametype() )
			return false;
	}

	return true;
}
Пример #2
0
/*
* G_Match_ScorelimitHit
*/
bool G_Match_ScorelimitHit( void )
{
	edict_t	*e;

	if( GS_MatchState() != MATCH_STATE_PLAYTIME )
		return false;

	if( g_scorelimit->integer )
	{
		if( !GS_TeamBasedGametype() )
		{
			for( e = game.edicts+1; PLAYERNUM( e ) < gs.maxclients; e++ )
			{
				if( !e->r.inuse )
					continue;

				if( e->r.client->level.stats.score >= g_scorelimit->integer )
					return true;
			}
		}
		else
		{
			int team;

			for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
			{
				if( teamlist[team].stats.score >= g_scorelimit->integer )
					return true;
			}
		}
	}

	return false;
}
Пример #3
0
void G_Gametype_GENERIC_SetUpWarmup( void )
{
	level.gametype.readyAnnouncementEnabled = true;
	level.gametype.scoreAnnouncementEnabled = false;
	level.gametype.countdownEnabled = false;
	level.gametype.pickableItemsMask = ( level.gametype.spawnableItemsMask|level.gametype.dropableItemsMask );
	if( GS_Instagib() )
		level.gametype.pickableItemsMask &= ~G_INSTAGIB_NEGATE_ITEMMASK;

	if( GS_TeamBasedGametype() )
	{
		bool any = false;
		int team;
		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			if( G_Teams_TeamIsLocked( team ) )
			{
				G_Teams_UnLockTeam( team );
				any = true;
			}
		}
		if( any )
			G_PrintMsg( NULL, "Teams unlocked.\n" );
	}
	else
	{
		if( G_Teams_TeamIsLocked( TEAM_PLAYERS ) )
		{
			G_Teams_UnLockTeam( TEAM_PLAYERS );
			G_PrintMsg( NULL, "Teams unlocked.\n" );
		}
	}
	G_Teams_RemoveInvites();
}
Пример #4
0
/*
* G_RunGametype
*/
void G_RunGametype( void )
{
	G_Teams_ExecuteChallengersQueue();
	G_Teams_UpdateMembersList();
	G_Match_CheckStateAbort();

	G_UpdateScoreBoardMessages();

	//check gametype specific rules
	if( game.asEngine != NULL )
		GT_asCallThinkRules();
	else
		G_Gametype_GENERIC_ThinkRules();

	if( G_EachNewSecond() )
	{
		G_CheckNumBots();
		G_TickOutPowerUps();
	}

	if( G_EachNewMinute() )
		G_CheckEvenTeam();

	G_Match_ScoreAnnouncement();
	G_Match_ReadyAnnouncement();

	if( GS_TeamBasedGametype() )
		G_Teams_UpdateTeamInfoMessages();

	G_asGarbageCollect( false );
}
Пример #5
0
void G_Gametype_GENERIC_SetUpCountdown( void )
{
	bool any = false;
	int team;

	G_Match_RemoveAllProjectiles();
	G_Items_RespawnByType( 0, 0, 0 ); // respawn all items

	level.gametype.readyAnnouncementEnabled = false;
	level.gametype.scoreAnnouncementEnabled = false;
	level.gametype.countdownEnabled = true;
	level.gametype.pickableItemsMask = 0; // disallow item pickup

	if( GS_TeamBasedGametype() )
	{
		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
			if( G_Teams_LockTeam( team ) )
				any = true;
	}
	else
	{
		if( G_Teams_LockTeam( TEAM_PLAYERS ) )
			any = true;
	}

	if( any )
		G_PrintMsg( NULL, "Teams locked.\n" );

	G_AnnouncerSound( NULL, trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_GET_READY_TO_FIGHT_1_to_2, ( rand()&1 )+1 ) ),
		GS_MAX_TEAMS, true, NULL );
}
Пример #6
0
float BOT_DMclass_PlayerWeight( edict_t *self, edict_t *enemy )
{
	bool rage_mode = false;

	if( !enemy || enemy == self )
		return 0;

	if( G_ISGHOSTING( enemy ) || enemy->flags & (FL_NOTARGET|FL_BUSY) )
		return 0;

	if( self->r.client->ps.inventory[POWERUP_QUAD] || self->r.client->ps.inventory[POWERUP_SHELL] )
		rage_mode = true;

	// don't fight against powerups.
	if( enemy->r.client && ( enemy->r.client->ps.inventory[POWERUP_QUAD] || enemy->r.client->ps.inventory[POWERUP_SHELL] ) )
		return 0.2;

	//if not team based give some weight to every one
	if( GS_TeamBasedGametype() && ( enemy->s.team == self->s.team ) )
		return 0;

	// if having EF_CARRIER we can assume it's someone important
	if( enemy->s.effects & EF_CARRIER )
		return 2.0f;

	if( enemy == self->ai->last_attacker )
		return rage_mode ? 4.0f : 1.0f;

	return rage_mode ? 4.0f : 0.3f;
}
Пример #7
0
//==============
// CG_ForceTeam
//==============
static int CG_ForceTeam( int entNum, int team )
{
	if( !GS_TeamBasedGametype() )
	{
		if( ISVIEWERENTITY( entNum ) )
		{
			if( cg_forceMyTeamAlpha->integer )
				return TEAM_ALPHA;
		}
		else
		{
			if( cg_forceTeamPlayersTeamBeta->integer )
				return TEAM_BETA;
		}

		return team;
	}
	else
	{
		int myteam = cg.predictedPlayerState.stats[STAT_TEAM];

		if( cg_forceMyTeamAlpha->integer && myteam != TEAM_SPECTATOR )
		{
			if( team == myteam )
				return TEAM_ALPHA;
			if( team == TEAM_ALPHA )
				return myteam;
		}

		return team;
	}
}
Пример #8
0
/*
* Cmd_ChaseCam_f
*/
void Cmd_ChaseCam_f( edict_t *ent ) {
	bool team_only;
	const char *arg1;

	if( ent->s.team != TEAM_SPECTATOR && !ent->r.client->teamstate.is_coach ) {
		G_Teams_JoinTeam( ent, TEAM_SPECTATOR );
		if( !CheckFlood( ent, false ) ) { // prevent 'joined spectators' spam
			G_PrintMsg( NULL, "%s%s joined the %s%s team.\n", ent->r.client->netname,
						S_COLOR_WHITE, GS_TeamName( ent->s.team ), S_COLOR_WHITE );
		}
	}

	// & 1 = scorelead
	// & 2 = powerups
	// & 4 = objectives
	// & 8 = fragger

	if( ent->r.client->teamstate.is_coach && GS_TeamBasedGametype() ) {
		team_only = true;
	} else {
		team_only = false;
	}

	arg1 = trap_Cmd_Argv( 1 );

	if( trap_Cmd_Argc() < 2 ) {
		G_ChasePlayer( ent, NULL, team_only, 0 );
	} else if( !Q_stricmp( arg1, "auto" ) ) {
		G_PrintMsg( ent, "Chasecam mode is 'auto'. It will follow the score leader when no powerup nor flag is carried.\n" );
		G_ChasePlayer( ent, NULL, team_only, 7 );
	} else if( !Q_stricmp( arg1, "carriers" ) ) {
		G_PrintMsg( ent, "Chasecam mode is 'carriers'. It will switch to flag or powerup carriers when any of these items is picked up.\n" );
		G_ChasePlayer( ent, NULL, team_only, 6 );
	} else if( !Q_stricmp( arg1, "powerups" ) ) {
		G_PrintMsg( ent, "Chasecam mode is 'powerups'. It will switch to powerup carriers when any of these items is picked up.\n" );
		G_ChasePlayer( ent, NULL, team_only, 2 );
	} else if( !Q_stricmp( arg1, "objectives" ) ) {
		G_PrintMsg( ent, "Chasecam mode is 'objectives'. It will switch to objectives carriers when any of these items is picked up.\n" );
		G_ChasePlayer( ent, NULL, team_only, 4 );
	} else if( !Q_stricmp( arg1, "score" ) ) {
		G_PrintMsg( ent, "Chasecam mode is 'score'. It will always follow the player with the best score.\n" );
		G_ChasePlayer( ent, NULL, team_only, 1 );
	} else if( !Q_stricmp( arg1, "fragger" ) ) {
		G_PrintMsg( ent, "Chasecam mode is 'fragger'. The last fragging player will be followed.\n" );
		G_ChasePlayer( ent, NULL, team_only, 8 );
	} else if( !Q_stricmp( arg1, "help" ) ) {
		G_PrintMsg( ent, "Chasecam modes:\n" );
		G_PrintMsg( ent, "- 'auto': Chase the score leader unless there's an objective carrier or a powerup carrier.\n" );
		G_PrintMsg( ent, "- 'carriers': User has pov control unless there's an objective carrier or a powerup carrier.\n" );
		G_PrintMsg( ent, "- 'objectives': User has pov control unless there's an objective carrier.\n" );
		G_PrintMsg( ent, "- 'powerups': User has pov control unless there's a flag carrier.\n" );
		G_PrintMsg( ent, "- 'score': Always follow the score leader. User has no pov control.\n" );
		G_PrintMsg( ent, "- 'none': Disable chasecam.\n" );
		return;
	} else {
		G_ChasePlayer( ent, arg1, team_only, 0 );
	}

	G_Teams_LeaveChallengersQueue( ent );
}
Пример #9
0
static qboolean GS_CheckBladeAutoAttack( player_state_t *playerState, int timeDelta )
{
	vec3_t origin, dir, end;
	trace_t trace;
	entity_state_t *targ, *player;
	gs_weapon_definition_t *weapondef = GS_GetWeaponDef( WEAP_GUNBLADE );

	if( playerState->POVnum <= 0 || (int)playerState->POVnum > gs.maxclients )
		return qfalse;

	if( !( playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_GUNBLADEAUTOATTACK ) )
		return qfalse;

	VectorCopy( playerState->pmove.origin, origin );
	origin[2] += playerState->viewheight;
	AngleVectors( playerState->viewangles, dir, NULL, NULL );
	VectorMA( origin, weapondef->firedef_weak.timeout, dir, end );

	// check for a player to touch
	module_Trace( &trace, origin, vec3_origin, vec3_origin, end, playerState->POVnum, CONTENTS_BODY, timeDelta );
	if( trace.ent <= 0 || trace.ent > gs.maxclients )
		return qfalse;

	player = module_GetEntityState( playerState->POVnum, 0 );
	targ = module_GetEntityState( trace.ent, 0 );
	if( !( targ->effects & EF_TAKEDAMAGE ) || targ->type != ET_PLAYER )
		return qfalse;

	if( GS_TeamBasedGametype() && ( targ->team == player->team ) )
		return qfalse;

	return qtrue;
}
Пример #10
0
/*
* G_GameTypes_DenyJoinTeam
*/
static int G_GameTypes_DenyJoinTeam( edict_t *ent, int team )
{
	if( team < 0 || team >= GS_MAX_TEAMS )
	{
		G_Printf( "WARNING: 'G_GameTypes_CanJoinTeam' parsing a unrecognized team value\n" );
		return ER_TEAM_INVALID;
	}

	if( team == TEAM_SPECTATOR )
		return ER_TEAM_OK;

	if( GS_MatchState() > MATCH_STATE_PLAYTIME )
		return ER_TEAM_MATCHSTATE;

	// waiting for chanllengers queue to be executed
	if( GS_HasChallengers() &&
		game.realtime < level.spawnedTimeStamp + (unsigned)( G_CHALLENGERS_MIN_JOINTEAM_MAPTIME + game.snapFrameTime ) )
		return ER_TEAM_CHALLENGERS;

	// force eveyone to go through queue so things work on map change
	if( GS_HasChallengers() && !ent->r.client->queueTimeStamp )
		return ER_TEAM_CHALLENGERS;

	//see if team is locked
	if( G_Teams_TeamIsLocked( team ) && !G_Teams_PlayerIsInvited( team, ent ) )
		return ER_TEAM_LOCKED;

	if( GS_TeamBasedGametype() )
	{
		if( team >= TEAM_ALPHA && team < GS_MAX_TEAMS )
		{
			// see if team is full
			int count = teamlist[team].numplayers;

			if( ( count + 1 > level.gametype.maxPlayersPerTeam &&
				level.gametype.maxPlayersPerTeam > 0 ) ||
				( count + 1 > g_teams_maxplayers->integer &&
				g_teams_maxplayers->integer > 0 ) )
				return ER_TEAM_FULL;

			if( !g_teams_allow_uneven->integer && !G_Teams_CanKeepEvenTeam( ent->s.team, team ) )
				return ER_TEAM_UNEVEN;

			return ER_TEAM_OK;
		}
		else
		{
			return ER_TEAM_INVALID;
		}
	}
	else if( team == TEAM_PLAYERS )
	{
		return ER_TEAM_OK;
	}

	return ER_TEAM_INVALID;
}
Пример #11
0
AiBaseTeamBrain *AiBaseTeamBrain::InstantiateTeamBrain( int team, const char *gametype ) {
	// Delegate construction to AiSquadBasedTeamBrain
	if( GS_TeamBasedGametype() && !GS_InvidualGameType() ) {
		return AiSquadBasedTeamBrain::InstantiateTeamBrain( team, gametype );
	}

	void *mem = G_Malloc( sizeof( AiBaseTeamBrain ) );
	return new(mem)AiBaseTeamBrain( team );
}
Пример #12
0
/*
* G_Gametype_CanTeamDamage
*/
bool G_Gametype_CanTeamDamage( int damageflags )
{
	if( damageflags & DAMAGE_NO_PROTECTION )
		return true;

	if( !GS_TeamBasedGametype() )
		return true;

	return g_allow_teamdamage->integer ? true : false;
}
Пример #13
0
/*
* G_Teams_AdvanceChallengersQueue
*/
void G_Teams_AdvanceChallengersQueue( void )
{
	int i, team, loserscount, winnerscount, playerscount = 0;
	int maxscore = 999999;
	edict_t *won, *e;
	int START_TEAM = TEAM_PLAYERS, END_TEAM = TEAM_PLAYERS+1;

	if( !GS_HasChallengers() )
		return;

	G_Teams_UpdateMembersList();

	if( GS_TeamBasedGametype() )
	{
		START_TEAM = TEAM_ALPHA;
		END_TEAM = GS_MAX_TEAMS;
	}

	// assign new timestamps to all the players inside teams
	for( team = START_TEAM; team < END_TEAM; team++ )
	{
		playerscount += teamlist[team].numplayers;
	}

	if( !playerscount )
		return;

	loserscount = 0;
	if( playerscount > 1 )
	{
		loserscount = (int)( playerscount / 2 );
	}
	winnerscount = playerscount - loserscount;

	// put everyone who just played out of the challengers queue
	for( team = START_TEAM; team < END_TEAM; team++ )
	{
		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			e = game.edicts + teamlist[team].playerIndices[i];
			e->r.client->queueTimeStamp = 0;
		}
	}

	// put (back) the best scoring players in first positions of challengers queue
	for( i = 0; i < winnerscount; i++ )
	{
		won = G_Teams_BestScoreBelow( maxscore );
		if( won )
		{
			maxscore = won->r.client->level.stats.score;
			won->r.client->queueTimeStamp = 1 + ( winnerscount-i ); // never have 2 players with the same timestamp
		}
	}
}
Пример #14
0
/*
* Cmd_Timeout_f
*/
static void Cmd_Timeout_f( edict_t *ent )
{
	int num;

	if( ent->s.team == TEAM_SPECTATOR || GS_MatchState() != MATCH_STATE_PLAYTIME )
		return;

	if( GS_TeamBasedGametype() )
		num = ent->s.team;
	else
		num = ENTNUM( ent )-1;

	if( GS_MatchPaused() && ( level.timeout.endtime - level.timeout.time ) >= 2*TIMEIN_TIME )
	{
		G_PrintMsg( ent, "Timeout already in progress\n" );
		return;
	}

	if( g_maxtimeouts->integer != -1 && level.timeout.used[num] >= g_maxtimeouts->integer )
	{
		if( g_maxtimeouts->integer == 0 )
			G_PrintMsg( ent, "Timeouts are not allowed on this server\n" );
		else if( GS_TeamBasedGametype() )
			G_PrintMsg( ent, "Your team doesn't have any timeouts left\n" );
		else
			G_PrintMsg( ent, "You don't have any timeouts left\n" );
		return;
	}

	G_PrintMsg( NULL, "%s%s called a timeout\n", ent->r.client->netname, S_COLOR_WHITE );

	if( !GS_MatchPaused() )
		G_AnnouncerSound( NULL, trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_TIMEOUT_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL );

	level.timeout.used[num]++;
	GS_GamestatSetFlag( GAMESTAT_FLAG_PAUSED, true );
	level.timeout.caller = num;
	level.timeout.endtime = level.timeout.time + TIMEOUT_TIME + FRAMETIME;
}
Пример #15
0
/*
* Cmd_Timeout_f
*/
static void Cmd_Timein_f( edict_t *ent )
{
	int num;

	if( ent->s.team == TEAM_SPECTATOR )
		return;

	if( !GS_MatchPaused() )
	{
		G_PrintMsg( ent, "No timeout in progress.\n" );
		return;
	}

	if( level.timeout.endtime - level.timeout.time <= 2 * TIMEIN_TIME )
	{
		G_PrintMsg( ent, "The timeout is about to end already.\n" );
		return;
	}

	if( GS_TeamBasedGametype() )
		num = ent->s.team;
	else
		num = ENTNUM( ent )-1;

	if( level.timeout.caller != num )
	{
		if( GS_TeamBasedGametype() )
			G_PrintMsg( ent, "Your team didn't call this timeout.\n" );
		else
			G_PrintMsg( ent, "You didn't call this timeout.\n" );
		return;
	}

	level.timeout.endtime = level.timeout.time + TIMEIN_TIME + FRAMETIME;

	G_AnnouncerSound( NULL, trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_TIMEIN_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL );

	G_PrintMsg( NULL, "%s%s called a timein\n", ent->r.client->netname, S_COLOR_WHITE );
}
Пример #16
0
void AiBaseTeamBrain::OnGametypeChanged( const char *gametype ) {
	// First, unregister all current brains (if any)
	for( int team = TEAM_PLAYERS; team < GS_MAX_TEAMS; ++team )
		UnregisterTeamBrain( team );

	if( GS_TeamBasedGametype() ) {
		for( int team = TEAM_ALPHA; team < GS_MAX_TEAMS; ++team ) {
			RegisterTeamBrain( team, InstantiateTeamBrain( team, gametype ) );
		}
	} else {
		RegisterTeamBrain( TEAM_PLAYERS, InstantiateTeamBrain( TEAM_PLAYERS, gametype ) );
	}
}
Пример #17
0
/*
* GS_IsTeamDamage
*/
qboolean GS_IsTeamDamage( entity_state_t *targ, entity_state_t *attacker )
{
	if( !GS_TeamBasedGametype() )
		return qfalse;

	assert( targ && attacker );

	if( targ->team && attacker->team &&
		targ->team == attacker->team &&
		targ->number != attacker->number )
		return qtrue;

	return qfalse;
}
Пример #18
0
/*
* G_WasLeading
*/
static bool G_WasLeading( edict_t *ent )
{
	int num, i;

	if( GS_TeamBasedGametype() )
		num = ent->s.team;
	else
		num = PLAYERNUM( ent ) + 1;

	for( i = 0; i < MAX_CLIENTS && last_leaders[i] != 0; i++ )
	{
		if( last_leaders[i] == num )
			return true;
	}

	return false;
}
Пример #19
0
void G_Teams_Coach( edict_t *ent )
{
	if( GS_TeamBasedGametype() && !GS_InvidualGameType() && ent->s.team != TEAM_SPECTATOR )
	{
		if( !teamlist[ent->s.team].has_coach )
		{
			if( GS_MatchState() > MATCH_STATE_WARMUP && !GS_MatchPaused() )
			{
				G_PrintMsg( ent, "Can't set coach mode with the match in progress\n" );
			}
			else
			{
				// move to coach mode
				ent->r.client->teamstate.is_coach = true;
				G_GhostClient( ent );
				ent->health = ent->max_health;
				ent->deadflag = DEAD_NO;

				G_ChasePlayer( ent, NULL, true, 0 );

				//clear up his scores
				G_Match_Ready( ent ); // set ready and check readys
				memset( &ent->r.client->level.stats, 0, sizeof( ent->r.client->level.stats ) );

				teamlist[ent->s.team].has_coach = true;
				G_PrintMsg( NULL, "%s%s is now team %s coach \n", ent->r.client->netname,
					S_COLOR_WHITE, GS_TeamName( ent->s.team ) );
			}
		}
		else if( ent->r.client->teamstate.is_coach )
		{                            // if you are this team coach, resign
			ent->r.client->teamstate.is_coach = false;
			G_PrintMsg( NULL, "%s%s is no longer team %s coach \n", ent->r.client->netname,
				S_COLOR_WHITE, GS_TeamName( ent->s.team ) );

			G_Teams_SetTeam( ent, ent->s.team );
		}
		else
			G_PrintMsg( ent, "Your team already has a coach.\n" );
	}
	else
		G_PrintMsg( ent, "Coaching only valid while on a team in Team based Gametypes.\n" );
}
Пример #20
0
void AiBaseTeamBrain::AcquireBotFrameAffinity( int entNum ) {
	// Always specify offset as zero for affinity module that = 1 (any % 1 == 0)
	if( AffinityModulo() == 1 ) {
		SetBotFrameAffinity( entNum, AffinityModulo(), 0 );
		return;
	}

	if( GS_TeamBasedGametype() ) {
		unsigned modulo = AffinityModulo(); // Precompute
		static_assert( MAX_AFFINITY_OFFSET == 4, "Only two teams are supported" );
		switch( modulo ) {
			case 4:
				// If the think cycle consist of 4 frames:
				// the Alpha team brain thinks on frame 0, bots of team Alpha think on frame 1,
				// the Beta team brain thinks on frame 2, bots of team Beta think on frame 3
				SetBotFrameAffinity( entNum, modulo, 2 * ( (unsigned)team - TEAM_ALPHA ) + 1 );
				break;
			case 3:
				// If the think cycle consist of 3 frames:
				// team brains think on frame 0, bots of team Alpha think on frame 1, bots of team Beta think on frame 2
				SetBotFrameAffinity( entNum, modulo, 1 + (unsigned)team - TEAM_ALPHA );
				break;
			case 2:
				// If the think cycle consist of 2 frames:
				// the Alpha team brain and team Alpha bot brains think on frame 0,
				// the Beta team brain an team Beta bot brains think on frame 1
				SetBotFrameAffinity( entNum, modulo, (unsigned)team - TEAM_ALPHA );
				break;
		}
	} else {
		// Select less used offset (thus, less loaded frames)
		unsigned chosenOffset = 0;
		for( unsigned i = 1; i < MAX_AFFINITY_OFFSET; ++i ) {
			if( affinityOffsetsInUse[chosenOffset] > affinityOffsetsInUse[i] ) {
				chosenOffset = i;
			}
		}
		affinityOffsetsInUse[chosenOffset]++;
		SetBotFrameAffinity( entNum, AffinityModulo(), chosenOffset );
	}
}
Пример #21
0
/*
* G_CheckEvenTeam
*/
static void G_CheckEvenTeam( void )
{
	int max = 0;
	int min = gs.maxclients + 1;
	int uneven_team = TEAM_SPECTATOR;
	int i;

	if( GS_MatchState() >= MATCH_STATE_POSTMATCH )
		return;

	if( !GS_TeamBasedGametype() )
		return;

	if( g_teams_allow_uneven->integer )
		return;

	for( i = TEAM_ALPHA; i < GS_MAX_TEAMS; i++ )
	{
		if( max < teamlist[i].numplayers )
		{
			max = teamlist[i].numplayers;
			uneven_team = i;
		}
		if( min > teamlist[i].numplayers )
			min = teamlist[i].numplayers;
	}

	if( max - min > 1 )
	{
		for( i = 0; i < teamlist[uneven_team].numplayers; i++ )
		{
			edict_t	*e = game.edicts + teamlist[uneven_team].playerIndices[i];
			if( !e->r.inuse )
				continue;
			G_CenterPrintMsg( e, "Teams are uneven. Please switch into another team." ); // FIXME: need more suitable message :P
			G_PrintMsg( e, "%sTeams are uneven. Please switch into another team.\n", S_COLOR_CYAN ); // FIXME: need more suitable message :P
		}
		// FIXME: switch team forcibly?
	}
}
Пример #22
0
/*
* 
* G_Teams_BestScoreBelow
*/
static edict_t *G_Teams_BestScoreBelow( int maxscore )
{
	int team, i;
	edict_t *e, *best = NULL;
	int bestScore = -9999999;

	if( GS_TeamBasedGametype() )
	{
		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			for( i = 0; i < teamlist[team].numplayers; i++ )
			{
				e = game.edicts + teamlist[team].playerIndices[i];
				if( e->r.client->level.stats.score > bestScore &&
					e->r.client->level.stats.score <= maxscore
					&& !e->r.client->queueTimeStamp )
				{
					bestScore = e->r.client->level.stats.score;
					best = e;
				}
			}
		}
	}
	else
	{
		for( i = 0; i < teamlist[TEAM_PLAYERS].numplayers; i++ )
		{
			e = game.edicts + teamlist[TEAM_PLAYERS].playerIndices[i];
			if( e->r.client->level.stats.score > bestScore &&
				e->r.client->level.stats.score <= maxscore
				&& !e->r.client->queueTimeStamp )
			{
				bestScore = e->r.client->level.stats.score;
				best = e;
			}
		}
	}

	return best;
}
Пример #23
0
/*
* CG_FlashGameWindow
*
* Flashes game window in case of important events (match state changes, etc) for user to notice
*/
static void CG_FlashGameWindow( void )
{
	static int oldState = -1;
	int newState;
	bool flash = false;
	static int oldAlphaScore, oldBetaScore;
	static bool scoresSet = false;

	// notify player of important match states
	newState = GS_MatchState();
	if( oldState != newState )
	{
		switch( newState )
		{
		case MATCH_STATE_COUNTDOWN:
		case MATCH_STATE_PLAYTIME:
		case MATCH_STATE_POSTMATCH:
			flash = true;
			break;
		default:
			break;
		}

		oldState = newState;
	}

	// notify player of teams scoring in team-based gametypes
	if( !scoresSet || 
		( oldAlphaScore != cg.predictedPlayerState.stats[STAT_TEAM_ALPHA_SCORE] || oldBetaScore != cg.predictedPlayerState.stats[STAT_TEAM_BETA_SCORE] ) )  {
		oldAlphaScore = cg.predictedPlayerState.stats[STAT_TEAM_ALPHA_SCORE];
		oldBetaScore = cg.predictedPlayerState.stats[STAT_TEAM_BETA_SCORE];

		flash = scoresSet && GS_TeamBasedGametype() && !GS_InvidualGameType();
		scoresSet = true;
	}

	if( flash )
		trap_VID_FlashWindow( cg_flashWindowCount->integer );
}
Пример #24
0
/*
* G_Match_CheckExtendPlayTime
*/
bool G_Match_CheckExtendPlayTime( void )
{
	// check for extended time/sudden death
	if( GS_MatchState() != MATCH_STATE_PLAYTIME )
		return false;

	if( GS_TeamBasedGametype() && !level.forceExit )
	{
		if( G_Match_Tied() )
		{
			GS_GamestatSetFlag( GAMESTAT_FLAG_MATCHEXTENDED, true );
			gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_PLAYTIME;
			gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime;

			if( g_match_extendedtime->value )
			{
				if( !GS_MatchExtended() )  // first one
					G_AnnouncerSound( NULL, trap_SoundIndex( S_ANNOUNCER_OVERTIME_GOING_TO_OVERTIME ), GS_MAX_TEAMS, true, NULL );
				else
					G_AnnouncerSound( NULL, trap_SoundIndex( S_ANNOUNCER_OVERTIME_OVERTIME ), GS_MAX_TEAMS, true, NULL );

				G_PrintMsg( NULL, "Match tied. Timelimit extended by %i minutes!\n", g_match_extendedtime->integer );
				G_CenterPrintFormatMsg( NULL, "%s MINUTE OVERTIME\n", va( "%i", g_match_extendedtime->integer ), NULL );
				gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)( ( fabs( g_match_extendedtime->value ) * 60 ) * 1000 );
			}
			else
			{
				G_AnnouncerSound( NULL, trap_SoundIndex( va( S_ANNOUNCER_OVERTIME_SUDDENDEATH_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL );
				G_PrintMsg( NULL, "Match tied. Sudden death!\n" );
				G_CenterPrintMsg( NULL, "SUDDEN DEATH" );
				gs.gameState.longstats[GAMELONG_MATCHDURATION] = 0;
			}

			return true;
		}
	}

	return false;
}
Пример #25
0
/*
* Spawn_ItemTimer
*/
static edict_t *Spawn_ItemTimer( edict_t *ent )
{
	edict_t *timer;
	int locationTag;

	// location tag
	locationTag = G_MapLocationTAGForOrigin( ent->s.origin );

	// item timer is a special entity type, carrying information about its parent item entity
	// which is only visible to spectators
	timer = G_Spawn();
	timer->s.type = ET_ITEM_TIMER;
	timer->s.itemNum = ent->s.itemNum;
	timer->s.team = TEAM_SPECTATOR;
	timer->r.svflags = SVF_ONLYTEAM | SVF_BROADCAST;
	timer->r.owner = ent;
	timer->s.modelindex = 0;
	timer->s.modelindex2 = locationTag;
	timer->nextThink = level.time + 250;
	timer->think = item_timer_think;
	VectorCopy( ent->s.origin, timer->s.origin ); // for z-sorting

	if( /*( ( item->type != IT_POWERUP ) && */GS_TeamBasedGametype() )
	{
		edict_t *base;

		// what follows is basically a hack that allows timers to be assigned
		// to different teams in CTF. Powerups remain unassigned though
		base = G_ClosestFlagBase( ent );
		if( base )
			timer->s.modelindex = base->s.team;
	}

	timer->s.modelindex++; // add + 1 so we're guaranteed to have modelindex > 0

	return timer;
}
Пример #26
0
/*
* G_Match_ScoreAnnouncement
*/
static void G_Match_ScoreAnnouncement( void )
{
	int i;
	edict_t *e, *chased;
	int num_leaders, team;

	if( !level.gametype.scoreAnnouncementEnabled )
		return;

	num_leaders = 0;
	memset( leaders, 0, sizeof( leaders ) );

	if( GS_TeamBasedGametype() )
	{
		int score_max = -999999999;

		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			if( !teamlist[team].numplayers )
				continue;

			if( teamlist[team].stats.score > score_max )
			{
				score_max = teamlist[team].stats.score;
				leaders[0] = team;
				num_leaders = 1;
			}
			else if( teamlist[team].stats.score == score_max )
			{
				leaders[num_leaders++] = team;
			}
		}
		leaders[num_leaders] = 0;
	}
	else
	{
		int score_max = -999999999;

		for( i = 0; i < MAX_CLIENTS && i < teamlist[TEAM_PLAYERS].numplayers; i++ )
		{
			if( game.clients[teamlist[TEAM_PLAYERS].playerIndices[i]-1].level.stats.score > score_max )
			{
				score_max = game.clients[teamlist[TEAM_PLAYERS].playerIndices[i]-1].level.stats.score;
				leaders[0] = teamlist[TEAM_PLAYERS].playerIndices[i];
				num_leaders = 1;
			}
			else if( game.clients[teamlist[TEAM_PLAYERS].playerIndices[i]-1].level.stats.score == score_max )
			{
				leaders[num_leaders++] = teamlist[TEAM_PLAYERS].playerIndices[i];
			}
		}
		leaders[num_leaders] = 0;
	}

	if( !score_announcement_init )
	{
		// copy over to last_leaders
		memcpy( last_leaders, leaders, sizeof( leaders ) );
		score_announcement_init = true;
		return;
	}

	for( e = game.edicts + 1; PLAYERNUM( e ) < gs.maxclients; e++ )
	{
		if( !e->r.client || trap_GetClientState( PLAYERNUM( e ) ) < CS_SPAWNED )
			continue;

		if( e->r.client->resp.chase.active )
			chased = &game.edicts[e->r.client->resp.chase.target];
		else
			chased = e;

		// floating spectator
		if( chased->s.team == TEAM_SPECTATOR )
		{
			if( !GS_TeamBasedGametype() )
				continue;

			if( last_leaders[1] == 0 && leaders[1] != 0 )
			{
				G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, ( rand()&1 )+1 ) ),
					GS_MAX_TEAMS, true, NULL );
			}
			else if( leaders[1] == 0 && ( last_leaders[0] != leaders[0] || last_leaders[1] != 0 ) )
			{
				//G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_1_to_4_TAKEN_LEAD_1_to_2,
				//	leaders[0]-1, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL );
			}
			continue;
		}

		// in the game or chasing someone who is
		if( G_WasLeading( chased ) && !G_IsLeading( chased ) )
		{
			if( GS_TeamBasedGametype() && !GS_InvidualGameType() )
				G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_LOST_LEAD_1_to_2, ( rand()&1 )+1 ) ),
				GS_MAX_TEAMS, true, NULL );
			else
				G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_LOST_LEAD_1_to_2, ( rand()&1 )+1 ) ),
				GS_MAX_TEAMS, true, NULL );
		}
		else if( ( !G_WasLeading( chased ) || ( last_leaders[1] != 0 ) ) && G_IsLeading( chased ) && ( leaders[1] == 0 ) )
		{
			if( GS_TeamBasedGametype() && !GS_InvidualGameType() )
				G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TAKEN_LEAD_1_to_2, ( rand()&1 )+1 ) ),
				GS_MAX_TEAMS, true, NULL );
			else
				G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TAKEN_LEAD_1_to_2, ( rand()&1 )+1 ) ),
				GS_MAX_TEAMS, true, NULL );
		}
		else if( ( !G_WasLeading( chased ) || ( last_leaders[1] == 0 ) ) && G_IsLeading( chased ) && ( leaders[1] != 0 ) )
		{
			if( GS_TeamBasedGametype() && !GS_InvidualGameType() )
				G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, ( rand()&1 )+1 ) ),
				GS_MAX_TEAMS, true, NULL );
			else
				G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TIED_LEAD_1_to_2, ( rand()&1 )+1 ) ),
				GS_MAX_TEAMS, true, NULL );
		}
	}

	// copy over to last_leaders
	memcpy( last_leaders, leaders, sizeof( leaders ) );
}
Пример #27
0
/*
* SCR_DrawPlayerTab
*/
static int SCR_DrawPlayerTab( const char **ptrptr, int team, int x, int y, int panelWidth, struct qfontface_s *font, int pass )
{
	int dir, align, i, columncount;
	char type, string[MAX_STRING_CHARS];
	const char *token, *layout;
	int height, width, xoffset, yoffset;
	vec4_t teamcolor = { 0.0f, 0.0f, 0.0f, 1.0f }, color;
	int iconnum;
	struct shader_s *icon;
	bool highlight = false, trans = false;

	if( GS_TeamBasedGametype() )
	{
		dir = ( team == TEAM_ALPHA ) ? -1 : 1;
		align = ( team == TEAM_ALPHA ) ? ALIGN_RIGHT_TOP : ALIGN_LEFT_TOP;
	}
	else
	{
		dir = 0;
		align = ALIGN_CENTER_TOP;
	}

	xoffset = 0;
	yoffset = 0;

	height = trap_SCR_FontHeight( font );

	// start from the center again
	xoffset = CG_HorizontalAlignForWidth( 0, align, panelWidth );
	xoffset += ( SCB_CENTERMARGIN * dir );

	// draw the background
	columncount = 0;
	if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) )
		CG_TeamColor( team, teamcolor );

	// draw the player tab column titles
	layout = cgs.configStrings[CS_SCB_PLAYERTAB_LAYOUT];

	while( SCR_GetNextColumnLayout( &layout, NULL, &type, &width, font ) != NULL )
	{
		// grab the actual scoreboard data
		if( !SCR_ParseToken( ptrptr, &token ) )
			break;

		if( SCR_SkipColumn( type ) )
			continue;

		Vector4Copy( colorWhite, color ); // reset to white after each column
		icon = NULL;
		string[0] = 0;

		// interpret the data based on the type defined in the layout
		switch( type )
		{
		default:
			CG_Error( "SCR_DrawPlayerTab: Invalid player tab layout\n" );
			break;

		case 's': // is a string
			{
				char l10n[MAX_STRING_CHARS];
				Q_strncpyz( string, CG_TranslateColoredString( token, l10n, sizeof( l10n ) ), sizeof( string ) );
			}
			break;

		case 'n': // is a player name indicated by player number
			i = atoi( token );

			if( i < 0 ) // negative numbers toggle transparency on
			{
				trans = true;
				i = -1 - i;
			}

			if( i < 0 || i >= gs.maxclients )
				Q_strncpyz( string, "invalid", sizeof( string ) );
			else
				Q_strncpyz( string, cgs.clientInfo[i].name, sizeof( string ) );

			if( ISVIEWERENTITY( i + 1 ) ) // highlight if it's our own player
				highlight = true;

			break;
		case 'i': // is a integer (negatives are colored in red)
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%i", i );
			VectorCopy( i >= 0 ? colorWhite : colorRed, color );
			break;

		case 'f': // is a float
			Q_snprintfz( string, sizeof( string ), "%.2f", atof( token ) );
			break;

		case 'l': // p is an integer colored in latency style
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%i", i );
			CG_PingColor( i, color );
			break;

		case 'b': // is a Y/N boolean
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%s", CG_TranslateString( ( i != 0 ) ? "Yes" : "No" ) );
			VectorCopy( i ? colorGreen : colorRed, color );
			break;

		case 'p': // is a picture. It uses height for width to get a square
			iconnum = atoi( token );
			if( ( iconnum > 0 ) && ( iconnum < MAX_IMAGES ) )
				icon = cgs.imagePrecache[iconnum];
			break;

		case 't': // is a race time. Convert time into MM:SS:mm
			{
				unsigned int milli, min, sec;

				milli = (unsigned int)( atoi( token ) );
				if( !milli )
					Q_snprintfz( string, sizeof( string ), CG_TranslateString( "no time" ) );
				else
				{
					min = milli / 60000;
					milli -= min * 60000;
					sec = milli / 1000;
					milli -= sec * 1000;
					Q_snprintfz( string, sizeof( string ), va( "%02i:%02i.%03i", min, sec, milli ) );
				}
			}
			break;

		case 'r': // is a ready state tick that is hidden when not in warmup
			if( atoi( token ) )
				icon = CG_MediaShader( cgs.media.shaderVSayIcon[VSAY_YES] );
			break;
		}

		if( !width )
			continue;

		// draw the column background
		teamcolor[3] = SCB_BACKGROUND_ALPHA;
		if( columncount & 1 )
			teamcolor[3] -= 0.15;

		if( highlight )
			teamcolor[3] += 0.3;

		if( trans )
			color[3] = 0.3;

		if( !pass ) {
			trap_R_DrawStretchPic( x + xoffset, y + yoffset, width, height, 0, 0, 1, 1, teamcolor, cgs.shaderWhite );

			if( icon )
				SCR_AddPlayerIcon( icon, x + xoffset, y + yoffset, color[3], font );
		}

		// draw the column value
		if( pass && string[0] )
		{
			trap_SCR_DrawClampString( x + xoffset, y + yoffset, string,
				x + xoffset, y + yoffset,
				x + xoffset + width, y + yoffset + height, font, color );
		}

		columncount++;

		xoffset += width;
	}

	yoffset += height;
	return yoffset;
}
Пример #28
0
/*
* G_Match_CheckStateAbort
*/
static void G_Match_CheckStateAbort( void )
{
	bool any = false;
	bool enough;

	if( GS_MatchState() <= MATCH_STATE_NONE || GS_MatchState() >= MATCH_STATE_POSTMATCH
		|| level.gametype.mathAbortDisabled )
	{
		GS_GamestatSetFlag( GAMESTAT_FLAG_WAITING, false );
		return;
	}

	if( GS_TeamBasedGametype() )
	{
		int team, emptyteams = 0;

		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			if( !teamlist[team].numplayers )
				emptyteams++;
			else
				any = true;
		}

		enough = ( emptyteams == 0 );
	}
	else
	{
		enough = ( teamlist[TEAM_PLAYERS].numplayers > 1 );
		any = ( teamlist[TEAM_PLAYERS].numplayers > 0 );
	}

	// if waiting, turn on match states when enough players joined
	if( GS_MatchWaiting() && enough )
	{
		GS_GamestatSetFlag( GAMESTAT_FLAG_WAITING, false );
		G_UpdatePlayersMatchMsgs();
	}
	// turn off active match states if not enough players left
	else if( GS_MatchState() == MATCH_STATE_WARMUP && !enough && GS_MatchDuration() )
	{
		GS_GamestatSetFlag( GAMESTAT_FLAG_WAITING, true );
		G_UpdatePlayersMatchMsgs();
	}
	else if( GS_MatchState() == MATCH_STATE_COUNTDOWN && !enough )
	{
		if( any ) {
			G_PrintMsg( NULL, "Not enough players left. Countdown aborted.\n" );
			G_CenterPrintMsg( NULL, "COUNTDOWN ABORTED" );
		}
		G_Match_Autorecord_Cancel();
		G_Match_LaunchState( MATCH_STATE_WARMUP );
		GS_GamestatSetFlag( GAMESTAT_FLAG_WAITING, true );
		G_UpdatePlayersMatchMsgs();
	}
	// match running, but not enough players left
	else if( GS_MatchState() == MATCH_STATE_PLAYTIME && !enough )
	{
		if( any ) {
			G_PrintMsg( NULL, "Not enough players left. Match aborted.\n" );
			G_CenterPrintMsg( NULL, "MATCH ABORTED" );
		}
		G_EndMatch();
	}
}
Пример #29
0
/*
* G_Match_ReadyAnnouncement
*/
static void G_Match_ReadyAnnouncement( void )
{
	int i;
	edict_t *e;
	int team;
	bool readyupwarnings = false;
	int START_TEAM, END_TEAM;

	if( !level.gametype.readyAnnouncementEnabled )
		return;

	// ready up announcements

	if( GS_TeamBasedGametype() )
	{
		START_TEAM = TEAM_ALPHA;
		END_TEAM = GS_MAX_TEAMS;
	}
	else
	{
		START_TEAM = TEAM_PLAYERS;
		END_TEAM = TEAM_PLAYERS+1;
	}

	for( team = START_TEAM; team < END_TEAM; team++ )
	{
		if( !teamlist[team].numplayers )
			continue;

		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			e = game.edicts + teamlist[team].playerIndices[i];
			if( e->r.svflags & SVF_FAKECLIENT )
				continue;

			if( level.ready[teamlist[team].playerIndices[i]-1] )
			{
				readyupwarnings = true;
				break;
			}
		}
	}

	if( !readyupwarnings )
		return;

	// now let's repeat and warn
	for( team = START_TEAM; team < END_TEAM; team++ )
	{
		if( !teamlist[team].numplayers )
			continue;
		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			if( !level.ready[teamlist[team].playerIndices[i]-1] )
			{
				e = game.edicts + teamlist[team].playerIndices[i];
				if( !e->r.client || trap_GetClientState( PLAYERNUM( e ) ) != CS_SPAWNED )
					continue;

				if( e->r.client->teamstate.readyUpWarningNext < game.realtime )
				{
					e->r.client->teamstate.readyUpWarningNext = game.realtime + G_ANNOUNCER_READYUP_DELAY;
					e->r.client->teamstate.readyUpWarningCount++;
					if( e->r.client->teamstate.readyUpWarningCount > 3 )
					{
						G_AnnouncerSound( e, trap_SoundIndex( S_ANNOUNCER_READY_UP_PISSEDOFF ), GS_MAX_TEAMS, true, NULL );
						e->r.client->teamstate.readyUpWarningCount = 0;
					}
					else
					{
						G_AnnouncerSound( e, trap_SoundIndex( S_ANNOUNCER_READY_UP_POLITE ), GS_MAX_TEAMS, true, NULL );
					}
				}
			}
		}
	}
}
Пример #30
0
/*
* G_Match_CheckReadys
*/
void G_Match_CheckReadys( void )
{
	edict_t *e;
	bool allready;
	int readys, notreadys, teamsready;
	int team, i;

	if( GS_MatchState() != MATCH_STATE_WARMUP && GS_MatchState() != MATCH_STATE_COUNTDOWN )
		return;

	if( GS_MatchState() == MATCH_STATE_COUNTDOWN && level.forceStart )
		return; // never stop countdown if we have run out of warmup_timelimit

	teamsready = 0;
	for( team = TEAM_PLAYERS; team < GS_MAX_TEAMS; team++ )
	{
		readys = notreadys = 0;
		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			e = game.edicts + teamlist[team].playerIndices[i];

			if( !e->r.inuse )
				continue;
			if( e->s.team == TEAM_SPECTATOR )  //ignore spectators
				continue;

			if( level.ready[PLAYERNUM( e )] )
				readys++;
			else
				notreadys++;
		}
		if( !notreadys && readys )
			teamsready++;
	}

	// everyone has commited
	if( GS_TeamBasedGametype() )
	{
		if( teamsready == GS_MAX_TEAMS - TEAM_ALPHA )
			allready = true;
		else
			allready = false;
	}
	else
	{       //ffa
		if( teamsready && teamlist[TEAM_PLAYERS].numplayers > 1 )
			allready = true;
		else
			allready = false;
	}

	if( allready == true && GS_MatchState() != MATCH_STATE_COUNTDOWN )
	{
		G_PrintMsg( NULL, "All players are ready.  Match starting!\n" );
		G_Match_LaunchState( MATCH_STATE_COUNTDOWN );
	}
	else if( allready == false && GS_MatchState() == MATCH_STATE_COUNTDOWN )
	{
		G_PrintMsg( NULL, "Countdown aborted.\n" );
		G_CenterPrintMsg( NULL, "COUNTDOWN ABORTED" );
		G_Match_Autorecord_Cancel();
		G_Match_LaunchState( MATCH_STATE_WARMUP );
	}
}