Example #1
0
/*
===============
SV_SetConfigstringRestrictions
===============
*/
void SV_SetConfigstringRestrictions (int index, const clientList_t* clientList) {
	int i;
	clientList_t oldClientList = sv.configstrings[index].clientList;

	sv.configstrings[index].clientList = *clientList;
	sv.configstrings[index].restricted = qtrue;

	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
		if ( svs.clients[i].state >= CS_CONNECTED ) {
			if ( Com_ClientListContains( &oldClientList, i ) !=
				Com_ClientListContains( clientList, i ) ) {
				// A client has left or joined the restricted list, so update
				SV_SendConfigstring(&svs.clients[i], index);
			}
		}
	}
}
Example #2
0
/*
===============
SV_SendConfigstring

Creates and sends the server command necessary to update the CS index for the
given client
===============
*/
static void SV_SendConfigstring(client_t *client, int index)
{
	int maxChunkSize = MAX_STRING_CHARS - 24;
	int len;

	if( sv.configstrings[index].restricted && Com_ClientListContains(
		&sv.configstrings[index].clientList, client - svs.clients ) ) {
		// Send a blank config string for this client if it's listed
		SV_SendServerCommand( client, -1, "cs %i \"\"\n", index );
		return;
	}

	len = strlen(sv.configstrings[index].s);

	if( len >= maxChunkSize ) {
		int		sent = 0;
		int		remaining = len;
		char	*cmd;
		char	buf[MAX_STRING_CHARS];

		while (remaining > 0 ) {
			if ( sent == 0 ) {
				cmd = "bcs0";
			}
			else if( remaining < maxChunkSize ) {
				cmd = "bcs2";
			}
			else {
				cmd = "bcs1";
			}
			Q_strncpyz( buf, &sv.configstrings[index].s[sent],
				maxChunkSize );

			SV_SendServerCommand( client, -1, "%s %i \"%s\"\n", cmd,
				index, buf );

			sent += (maxChunkSize - 1);
			remaining -= (maxChunkSize - 1);
		}
	} else {
		// standard cs, just send it
		SV_SendServerCommand( client, -1, "cs %i \"%s\"\n", index,
			sv.configstrings[index].s );
	}
}
							 /*
=================
CG_DrawPlayerScore
=================
*/
static void CG_DrawPlayerScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
	char	string[1024];
	vec3_t	headAngles;
	playerInfo_t	*pi;
	int iconx, headx;
	playerState_t *ps;

	if ( score->playerNum < 0 || score->playerNum >= cgs.maxplayers ) {
		Com_Printf( "Bad score->playerNum: %i\n", score->playerNum );
		return;
	}
	
	pi = &cgs.playerinfo[score->playerNum];

	iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);
	headx = SB_HEAD_X + (SB_RATING_WIDTH / 2);

	// draw the handicap or bot skill marker (unless player has flag)
	if ( pi->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
		if( largeFormat ) {
			CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );
		}
		else {
			CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );
		}
	} else if ( pi->powerups & ( 1 << PW_REDFLAG ) ) {
		if( largeFormat ) {
			CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );
		}
		else {
			CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );
		}
	} else if ( pi->powerups & ( 1 << PW_BLUEFLAG ) ) {
		if( largeFormat ) {
			CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );
		}
		else {
			CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );
		}
	} else {
		if ( pi->botSkill > 0 && pi->botSkill <= 5 ) {
			if ( cg_drawIcons.integer ) {
				if( largeFormat ) {
					CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ pi->botSkill - 1 ] );
				}
				else {
					CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ pi->botSkill - 1 ] );
				}
			}
		} else if ( pi->handicap < 100 ) {
			Com_sprintf( string, sizeof( string ), "%i", pi->handicap );
			if ( cgs.gametype == GT_TOURNAMENT ) {
				CG_DrawString( iconx, y - SMALLCHAR_HEIGHT/2, string, UI_SMALLFONT|UI_NOSCALE, color );
			}
			else {
				CG_DrawString( iconx, y, string, UI_SMALLFONT|UI_NOSCALE, color );
			}
		}

		// draw the wins / losses
		if ( cgs.gametype == GT_TOURNAMENT ) {
			Com_sprintf( string, sizeof( string ), "%i/%i", pi->wins, pi->losses );
			if( pi->handicap < 100 && !pi->botSkill ) {
				CG_DrawString( iconx, y + SMALLCHAR_HEIGHT/2, string, UI_SMALLFONT|UI_NOSCALE, color );
			}
			else {
				CG_DrawString( iconx, y, string, UI_SMALLFONT|UI_NOSCALE, color );
			}
		}
	}

	// draw the face
	VectorClear( headAngles );
	headAngles[YAW] = 180;
	if( largeFormat ) {
		CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE, 
			score->playerNum, headAngles );
	}
	else {
		CG_DrawHead( headx, y, 16, 16, score->playerNum, headAngles );
	}

#ifdef MISSIONPACK
	// draw the team task
	switch ( pi->teamTask ) {
		case TEAMTASK_OFFENSE:
			CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader );
			break;
		case TEAMTASK_DEFENSE:
			CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader );
			break;
		case TEAMTASK_PATROL:
			CG_DrawPic( headx + 48, y, 16, 16, cgs.media.patrolShader );
			break;
		case TEAMTASK_FOLLOW:
			CG_DrawPic( headx + 48, y, 16, 16, cgs.media.followShader );
			break;
		case TEAMTASK_CAMP:
			CG_DrawPic( headx + 48, y, 16, 16, cgs.media.campShader );
			break;
		case TEAMTASK_RETRIEVE:
			CG_DrawPic( headx + 48, y, 16, 16, cgs.media.retrieveShader );
			break;
		case TEAMTASK_ESCORT:
			CG_DrawPic( headx + 48, y, 16, 16, cgs.media.escortShader );
			break;
		default:
			break;
	}
#endif

	if (cg.cur_ps) {
		if (score->playerNum == cg.cur_ps->playerNum) {
			ps = cg.cur_ps;
		} else {
			ps = NULL;
		}
	} else {
		ps = CG_LocalPlayerState(score->playerNum);
	}

	// highlight your position
	if ( ps ) {
		float	hcolor[4];
		int		rank;

		localPlayer = qtrue;

		if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR || cgs.gametype >= GT_TEAM ) {
			rank = -1;
		} else {
			rank = ps->persistant[PERS_RANK] & ~RANK_TIED_FLAG;
		}
		if ( rank == 0 ) {
			hcolor[0] = 0;
			hcolor[1] = 0;
			hcolor[2] = 0.7f;
		} else if ( rank == 1 ) {
			hcolor[0] = 0.7f;
			hcolor[1] = 0;
			hcolor[2] = 0;
		} else if ( rank == 2 ) {
			hcolor[0] = 0.7f;
			hcolor[1] = 0.7f;
			hcolor[2] = 0;
		} else {
			hcolor[0] = 0.7f;
			hcolor[1] = 0.7f;
			hcolor[2] = 0.7f;
		}

		hcolor[3] = fade * 0.7;
		CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y, 
			640 - SB_SCORELINE_X - BIGCHAR_WIDTH - (SB_RATING_WIDTH / 2), BIGCHAR_HEIGHT+1, hcolor );
	}

	// draw the score line
	if ( score->ping == -1 ) {
		Com_sprintf(string, sizeof(string), "connecting");
	} else if ( pi->team == TEAM_SPECTATOR ) {
		Com_sprintf(string, sizeof(string), "SPECT");
	} else {
		Com_sprintf(string, sizeof(string), "%5i", score->score);
	}
	CG_DrawString( SB_SCORE_X + (SB_RATING_WIDTH / 2) + 4*BIGCHAR_WIDTH, y, string, UI_RIGHT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color );

	if ( score->ping != -1 ) {
		Com_sprintf(string, sizeof(string), "%4i", score->ping);
		CG_DrawString( SB_PING_X - (SB_RATING_WIDTH / 2) + 4*BIGCHAR_WIDTH, y, string, UI_RIGHT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color );

		Com_sprintf(string, sizeof(string), "%4i", score->time);
		CG_DrawString( SB_TIME_X - (SB_RATING_WIDTH / 2) + 4*BIGCHAR_WIDTH, y, string, UI_RIGHT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color );
	}

	CG_DrawString( SB_NAME_X - (SB_RATING_WIDTH / 2), y, pi->name, UI_LEFT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color );

	// add the "ready" marker for intermission exiting
	if ( Com_ClientListContains( &cg.readyPlayers, score->playerNum ) ) {
		CG_DrawString( iconx, y, "READY", UI_LEFT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color );
	}
}
Example #4
0
/*
===============
SV_AddEntitiesVisibleFromPoint
===============
*/
static void SV_AddEntitiesVisibleFromPoint( int psIndex, int clientNum, vec3_t origin, clientSnapshot_t *frame, 
									snapshotEntityNumbers_t *eNums, qboolean portal ) {
	int		e, i;
	sharedEntity_t *ent;
	svEntity_t	*svEnt;
	int		l;
	int		clientarea, clientcluster;
	int		leafnum;
	byte	*clientpvs;
	byte	*bitvector;

	// during an error shutdown message we may need to transmit
	// the shutdown message after the server has shutdown, so
	// specfically check for it
	if ( !sv.state ) {
		return;
	}

	leafnum = CM_PointLeafnum (origin);
	clientarea = CM_LeafArea (leafnum);
	clientcluster = CM_LeafCluster (leafnum);

	// calculate the visible areas
	frame->areabytes[psIndex] = CM_WriteAreaBits( frame->areabits[psIndex], clientarea );

	clientpvs = CM_ClusterPVS (clientcluster);

	for ( e = 0 ; e < sv.num_entities ; e++ ) {
		ent = SV_GentityNum(e);

		// never send entities that aren't linked in
		if ( !ent->r.linked ) {
			continue;
		}

		if (ent->s.number != e) {
			Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
			ent->s.number = e;
		}

		// entities can be flagged to explicitly not be sent to the client
		if ( ent->r.svFlags & SVF_NOCLIENT ) {
			continue;
		}

		// entities can be flagged to be sent to a given mask of clients
		if ( ent->r.svFlags & SVF_CLIENTMASK ) {
			if ( !Com_ClientListContains( &ent->r.sendClients, clientNum ) )
				continue;
		}

		svEnt = SV_SvEntityForGentity( ent );

		// don't double add an entity through portals
		if ( svEnt->snapshotCounter == sv.snapshotCounter ) {
			continue;
		}

		// limit based on distance
		if ( ent->r.cullDistance ) {
			vec3_t dir;
			VectorSubtract(ent->s.origin, origin, dir);
			if ( VectorLengthSquared(dir) > (float) ent->r.cullDistance * ent->r.cullDistance ) {
				continue;
			}
		}

		// broadcast entities are always sent
		if ( ent->r.svFlags & SVF_BROADCAST ) {
			SV_AddEntToSnapshot( frame, svEnt, ent, eNums );
			continue;
		}

		// ignore if not touching a PV leaf
		// check area
		if ( !CM_AreasConnected( clientarea, svEnt->areanum ) ) {
			// doors can legally straddle two areas, so
			// we may need to check another one
			if ( !CM_AreasConnected( clientarea, svEnt->areanum2 ) ) {
				continue;		// blocked by a door
			}
		}

		bitvector = clientpvs;

		// check individual leafs
		if ( !svEnt->numClusters ) {
			continue;
		}
		l = 0;
		for ( i=0 ; i < svEnt->numClusters ; i++ ) {
			l = svEnt->clusternums[i];
			if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
				break;
			}
		}

		// if we haven't found it to be visible,
		// check overflow clusters that coudln't be stored
		if ( i == svEnt->numClusters ) {
			if ( svEnt->lastCluster ) {
				for ( ; l <= svEnt->lastCluster ; l++ ) {
					if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
						break;
					}
				}
				if ( l == svEnt->lastCluster ) {
					continue;	// not visible
				}
			} else {
				continue;
			}
		}

		// visibility dummies
		if ( ent->r.svFlags & SVF_VISDUMMY ) {
			sharedEntity_t *ment = NULL;

			// find master
			ment = SV_GentityNum( ent->r.visDummyNum );

			if ( ment ) {
				svEntity_t *master = NULL;
				master = SV_SvEntityForGentity( ment );

				if ( master->snapshotCounter == sv.snapshotCounter || !ment->r.linked ) {
					continue;
				}

				SV_AddEntToSnapshot( frame, master, ment, eNums );
			}

			// master needs to be added, but not this dummy ent
			continue;
		} else if ( ent->r.svFlags & SVF_VISDUMMY_MULTIPLE ) {
			int h;
			sharedEntity_t *ment = NULL;
			svEntity_t *master = NULL;

			for ( h = 0; h < sv.num_entities; h++ ) {
				ment = SV_GentityNum( h );

				if ( ment == ent ) {
					continue;
				}

				if ( ment ) {
					master = SV_SvEntityForGentity( ment );
				} else {
					continue;
				}

				if ( !ment->r.linked ) {
					continue;
				}

				if ( ment->s.number != h ) {
					Com_DPrintf( "FIXING vis dummy multiple ment->S.NUMBER!!!\n" );
					ment->s.number = h;
				}

				if ( ment->r.svFlags & SVF_NOCLIENT ) {
					continue;
				}

				if ( master->snapshotCounter == sv.snapshotCounter ) {
					continue;
				}

				if ( ment->r.visDummyNum == ent->s.number ) {
					SV_AddEntToSnapshot( frame, master, ment, eNums );
				}
			}

			// masters need to be added, but not this dummy ent
			continue;
		}

		// add it
		SV_AddEntToSnapshot( frame, svEnt, ent, eNums );

		// if it's a portal entity, add everything visible from its camera position
		if ( ent->r.svFlags & SVF_PORTAL ) {
			if ( ent->r.portalCullDistance ) {
				vec3_t dir;
				VectorSubtract(ent->s.origin, origin, dir);
				if ( VectorLengthSquared(dir) > (float) ent->r.portalCullDistance * ent->r.portalCullDistance ) {
					continue;
				}
			}
			SV_AddEntitiesVisibleFromPoint( psIndex, clientNum, ent->s.origin2, frame, eNums, qtrue );
		}

	}
Example #5
0
/*
=================
CG_Say
=================
*/
static void CG_Say( const char *name, int clientNum, saymode_t mode, const char *text )
{
	char prefix[ 21 ] = "";
	char *ignore = "";
	char *location = "";
	char color;
	char *maybeColon;

	if ( clientNum >= 0 && clientNum < MAX_CLIENTS )
	{
		clientInfo_t *ci = &cgs.clientinfo[ clientNum ];
		char         *tcolor = S_COLOR_WHITE;

		name = ci->name;

		if ( ci->team == TEAM_ALIENS )
		{
			tcolor = S_COLOR_RED;
		}
		else if ( ci->team == TEAM_HUMANS )
		{
			tcolor = S_COLOR_CYAN;
		}

		if ( cg_chatTeamPrefix.integer )
		{
			Com_sprintf( prefix, sizeof( prefix ), "[%s%c" S_COLOR_WHITE "] ",
			             tcolor, toupper( * ( BG_TeamName( ci->team ) ) ) );
		}

		if ( Com_ClientListContains( &cgs.ignoreList, clientNum ) )
		{
			ignore = "[skipnotify]";
		}

		if ( ( mode == SAY_TEAM || mode == SAY_AREA ) &&
		     cg.snap->ps.pm_type != PM_INTERMISSION )
		{
			int locationNum;

			if ( clientNum == cg.snap->ps.clientNum )
			{
				centity_t *locent;

				locent = CG_GetPlayerLocation();

				if ( locent )
				{
					locationNum = locent->currentState.generic1;
				}
				else
				{
					locationNum = 0;
				}
			}
			else
			{
				locationNum = ci->location;
			}

			if ( locationNum > 0 && locationNum < MAX_LOCATIONS )
			{
				const char *s = CG_ConfigString( CS_LOCATIONS + locationNum );

				if ( *s )
				{
					location = va( " (%s" S_COLOR_WHITE ")", s );
				}
			}
		}
	}
	else if ( name )
	{
		Q_strcat( prefix, sizeof( prefix ), "[ADMIN]" );
	}
	else
	{
		name = "console";
	}

	// IRC-like /me parsing
	if ( mode != SAY_RAW && Q_stricmpn( text, "/me ", 4 ) == 0 )
	{
		text += 4;
		Q_strcat( prefix, sizeof( prefix ), "* " );
		maybeColon = "";
	}
	else
	{
		maybeColon = ":";
	}

	color = '0' + UI_GetChatColour( mode, cgs.clientinfo[ clientNum ].team );

	switch ( mode )
	{
		case SAY_ALL:
			// might already be ignored but in that case no harm is done
			if ( cg_teamChatsOnly.integer )
			{
				ignore = "[skipnotify]";
			}

		case SAY_ALL_ADMIN:
			CG_Printf(  "%s%s%s^7%s ^%c%s\n",
			           ignore, prefix, name, maybeColon, color, text );
			break;

		case SAY_TEAM:
			CG_Printf( "%s%s(%s^7)%s%s ^%c%s\n",
			           ignore, prefix, name, location, maybeColon, color, text );
			break;

		case SAY_ADMINS:
		case SAY_ADMINS_PUBLIC:
			CG_Printf( "%s%s%s%s^7%s ^%c%s\n",
			           ignore, prefix,
			           ( mode == SAY_ADMINS ) ? "[ADMIN]" : "[PLAYER]",
			           name, maybeColon, color, text );
			break;

		case SAY_AREA:
		case SAY_AREA_TEAM:
			CG_Printf( "%s%s<%s^7>%s%s ^%c%s\n",
			           ignore, prefix, name, location, maybeColon, color, text );
			break;

		case SAY_PRIVMSG:
		case SAY_TPRIVMSG:
			CG_Printf( "%s%s[%s^7 -> %s^7]%s ^%c%s\n",
			           ignore, prefix, name, cgs.clientinfo[ cg.clientNum ].name,
			           maybeColon, color, text );

			if ( !ignore[ 0 ] )
			{
				CG_CenterPrint( va( "^%cPrivate message from: " S_COLOR_WHITE "%s",
				                    color, name ), 200, GIANTCHAR_WIDTH * 4 );

				if ( clientNum < 0 || clientNum >= MAX_CLIENTS )
				{
					clientNum = cg.clientNum;
				}

				CG_Printf(_( ">> to reply, say: /m %d [your message] <<\n"), clientNum );
			}

			break;

		case SAY_RAW:
			CG_Printf( "%s\n", text );
			break;

		case SAY_DEFAULT:
		default:
			break;
	}

	switch ( mode )
	{
		case SAY_TEAM:
		case SAY_AREA:
		case SAY_TPRIVMSG:
			if ( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
			{
				trap_S_StartLocalSound( cgs.media.alienTalkSound, CHAN_LOCAL_SOUND );
				break;
			}
			else if ( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
			{
				trap_S_StartLocalSound( cgs.media.humanTalkSound, CHAN_LOCAL_SOUND );
				break;
			}

		default:
			trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
	}
}
Example #6
0
/*
=================
CG_ParseVoice

voice clientNum vChan cmdNum trackNum [sayText]
=================
*/
static void CG_ParseVoice( void )
{
	int            clientNum;
	voiceChannel_t vChan;
	char           sayText[ MAX_SAY_TEXT ] = { "" };
	voiceTrack_t   *track;
	clientInfo_t   *ci;

	if ( trap_Argc() < 5 || trap_Argc() > 6 )
	{
		return;
	}

	if ( trap_Argc() == 6 )
	{
		Q_strncpyz( sayText, CG_Argv( 5 ), sizeof( sayText ) );
	}

	clientNum = atoi( CG_Argv( 1 ) );

	if ( clientNum < 0 || clientNum >= MAX_CLIENTS )
	{
		return;
	}

	vChan = atoi( CG_Argv( 2 ) );

	if ( ( unsigned ) vChan >= VOICE_CHAN_NUM_CHANS )
	{
		return;
	}

	if ( cg_teamChatsOnly.integer && vChan != VOICE_CHAN_TEAM )
	{
		return;
	}

	ci = &cgs.clientinfo[ clientNum ];

	// this joker is still talking
	if ( ci->voiceTime > cg.time )
	{
		return;
	}

	track = CG_VoiceTrack( ci->voice, atoi( CG_Argv( 3 ) ), atoi( CG_Argv( 4 ) ) );

	// keep track of how long the player will be speaking
	// assume it takes 3s to say "*unintelligible gibberish*"
	if ( track )
	{
		ci->voiceTime = cg.time + track->duration;
	}
	else
	{
		ci->voiceTime = cg.time + 3000;
	}

	if ( !sayText[ 0 ] )
	{
		if ( track )
		{
			Q_strncpyz( sayText, track->text, sizeof( sayText ) );
		}
		else
		{
			Q_strncpyz( sayText, "*unintelligible gibberish*", sizeof( sayText ) );
		}
	}

	if ( !cg_noVoiceText.integer )
	{
		switch ( vChan )
		{
			case VOICE_CHAN_ALL:
				CG_Say( NULL, clientNum, SAY_ALL, sayText );
				break;

			case VOICE_CHAN_TEAM:
				CG_Say( NULL, clientNum, SAY_TEAM, sayText );
				break;

			case VOICE_CHAN_LOCAL:
				CG_Say( NULL, clientNum, SAY_AREA_TEAM, sayText );
				break;

			default:
				break;
		}
	}

	// playing voice audio tracks disabled
	if ( cg_noVoiceChats.integer )
	{
		return;
	}

	// no audio track to play
	if ( !track )
	{
		return;
	}

	// don't play audio track for lamers
	if ( Com_ClientListContains( &cgs.ignoreList, clientNum ) )
	{
		return;
	}

	switch ( vChan )
	{
		case VOICE_CHAN_ALL:
			trap_S_StartLocalSound( track->track, CHAN_VOICE );
			break;

		case VOICE_CHAN_TEAM:
			trap_S_StartLocalSound( track->track, CHAN_VOICE );
			break;

		case VOICE_CHAN_LOCAL:
			trap_S_StartSound( NULL, clientNum, CHAN_VOICE, track->track );
			break;

		default:
			break;
	}
}