Example #1
0
/*
===============
GLimp_EndFrame

Responsible for doing a swapbuffers
===============
*/
void GLimp_EndFrame( void )
{
	// don't flip if drawing to front buffer
	if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
	{
		SDL_GL_SwapWindow( window );
	}

	/*if( r_minimize && r_minimize->integer )
	{
		extern qboolean fullscreen_minimized;
		extern void IN_DeactivateMouse( void );
		SDL_Surface *s = SDL_GetWindowSurface( window );//SDL_GetVideoSurface( );
		qboolean    fullscreen = qfalse;
		qboolean    minimized = qfalse;

		fullscreen = ( s && ( s->flags & SDL_WINDOW_FULLSCREEN ) );

#ifdef MACOS_X
		// this is a bit crap, but the mac SDL_WM_IconifyWindow does not work
		// on fullscreen windows, nor does the SDL_WM_ToggleFullscreen work
		if( !fullscreen )
		{
			if( SDL_WM_IconifyWindow( ) )
				IN_DeactivateMouse();
			Cvar_Set( "r_minimize", "0" ); 
		}
		else if( r_fullscreen->integer ) 
		{
			Cvar_Set( "r_fullscreen", "0" );
			fullscreen_minimized = qtrue;
		}
#else
		minimized = ( SDL_WM_IconifyWindow( ) != 0 );
		if( fullscreen && minimized )
			fullscreen_minimized = qtrue;

		// this shouldn't be necessary, but seems to prevent X11 mouse problems
		if( minimized )
			IN_DeactivateMouse();

		Cvar_Set( "r_minimize", "0" ); 
#endif // MACOS_X
	}*/
	/*
	if( r_fullscreen->modified )
	{
		qboolean    fullscreen;
		qboolean    needToToggle = qtrue;
		qboolean    sdlToggled = qfalse;
		SDL_Surface *s = SDL_GetWindowSurface( window );

		if( s )
		{
			// Find out the current state
			fullscreen = !!( s->flags & SDL_WINDOW_FULLSCREEN );
				
			if( r_fullscreen->integer && Cvar_VariableIntegerValue( "in_nograb" ) )
			{
				ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
				ri.Cvar_Set( "r_fullscreen", "0" );
				r_fullscreen->modified = qfalse;
			}

			// Is the state we want different from the current state?
			needToToggle = !!r_fullscreen->integer != fullscreen;

			if( needToToggle ) {
				if( r_fullscreen->integer ) {
					sdlToggled = SDL_SetWindowFullscreen( window, SDL_WINDOW_FULLSCREEN );
				}
				else {
					sdlToggled = SDL_SetWindowFullscreen( window, 0 );
				}
				if( sdlToggled == 0 ) {
					sdlToggled = 1;
				}
			}
		}

		if( needToToggle )
		{
			// SDL_WM_ToggleFullScreen didn't work, so do it the slow way
			if( !sdlToggled )
				Cbuf_AddText( "vid_restart" );

			IN_Restart( );
		}

		r_fullscreen->modified = qfalse;
	}*/
}
Example #2
0
static void WP_FireConcussionAlt( gentity_t *ent )
{//a rail-gun-like beam
	int			damage = weaponData[WP_CONCUSSION].altDamage, skip, traces = DISRUPTOR_ALT_TRACES;
	//int			velocity = weaponData[WP_CONCUSSION].altVelocity;
	qboolean	render_impact = qtrue;
	vec3_t		start, end;
	vec3_t		muzzle2, spot, dir;
	trace_t		tr;
	gentity_t	*traceEnt, *tent;
	float		dist, shotDist, shotRange = 8192;
	qboolean	hitDodged = qfalse;

	if (ent->s.number >= MAX_CLIENTS)
	{
		vec3_t angles;
		vectoangles(forwardVec, angles);
		angles[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f
		angles[YAW]	  += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f
		AngleVectors(angles, forwardVec, vrightVec, up);
	}

	//Shove us backwards for half a second
	VectorMA( ent->client->ps.velocity, -200, forwardVec, ent->client->ps.velocity );
	ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
	if ( (ent->client->ps.pm_flags&PMF_DUCKED) )
	{//hunkered down
		ent->client->ps.pm_time = 100;
	}
	else
	{
		ent->client->ps.pm_time = 250;
	}
	ent->client->ps.pm_flags |= PMF_TIME_KNOCKBACK|PMF_TIME_NOFRICTION;
	//FIXME: only if on ground?  So no "rocket jump"?  Or: (see next FIXME)
	//FIXME: instead, set a forced ucmd backmove instead of this sliding

	VectorCopy( muzzle, muzzle2 ); // making a backup copy

	// The trace start will originate at the eye so we can ensure that it hits the crosshair.
	if ( ent->NPC )
	{
		switch ( g_spskill->integer )
		{
		case 0:
			damage = CONC_ALT_NPC_DAMAGE_EASY;
			break;
		case 1:
			damage = CONC_ALT_NPC_DAMAGE_MEDIUM;
			break;
		case 2:
		default:
			damage = CONC_ALT_NPC_DAMAGE_HARD;
			break;
		}

		damage *= weaponData[WP_CONCUSSION].npcAltDmgMult;
	}
	VectorCopy( muzzle, start );
	WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );

	skip = ent->s.number;

//	if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time )
//	{
//		// in overcharge mode, so doing double damage
//		damage *= 2;
//	}

	//Make it a little easier to hit guys at long range
	vec3_t shot_mins, shot_maxs;
	VectorSet( shot_mins, -1, -1, -1 );
	VectorSet( shot_maxs, 1, 1, 1 );

	for ( int i = 0; i < traces; i++ )
	{
		VectorMA( start, shotRange, forwardVec, end );

		//NOTE: if you want to be able to hit guys in emplaced guns, use "G2_COLLIDE, 10" instead of "G2_RETURNONHIT, 0"
		//alternately, if you end up hitting an emplaced_gun that has a sitter, just redo this one trace with the "G2_COLLIDE, 10" to see if we it the sitter
		//gi.trace( &tr, start, NULL, NULL, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 );
		gi.trace( &tr, start, shot_mins, shot_maxs, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 );

		if ( tr.surfaceFlags & SURF_NOIMPACT )
		{
			render_impact = qfalse;
		}

		if ( tr.entityNum == ent->s.number )
		{
			// should never happen, but basically we don't want to consider a hit to ourselves?
			// Get ready for an attempt to trace through another person
			VectorCopy( tr.endpos, muzzle2 );
			VectorCopy( tr.endpos, start );
			skip = tr.entityNum;
#ifdef _DEBUG
			gi.Printf( "BAD! Concussion gun shot somehow traced back and hit the owner!\n" );
#endif
			continue;
		}

		// always render a shot beam, doing this the old way because I don't much feel like overriding the effect.
		//NOTE: let's just draw one beam at the end
		//tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT );
		//tent->svFlags |= SVF_BROADCAST;

		//VectorCopy( muzzle2, tent->s.origin2 );

		if ( tr.fraction >= 1.0f )
		{
			// draw the beam but don't do anything else
			break;
		}

		traceEnt = &g_entities[tr.entityNum];

		if ( traceEnt //&& traceEnt->NPC
			&& (traceEnt->s.weapon == WP_SABER || (traceEnt->client && (traceEnt->client->NPC_class == CLASS_BOBAFETT || traceEnt->client->NPC_class == CLASS_MANDA || traceEnt->client->NPC_class == CLASS_COMMANDO||traceEnt->client->NPC_class == CLASS_REBORN))))
		{//FIXME: need a more reliable way to know we hit a jedi?
			hitDodged = Jedi_DodgeEvasion( traceEnt, ent, &tr, HL_NONE );
			//acts like we didn't even hit him
		}
		if ( !hitDodged )
		{
			if ( render_impact )
			{
				if (( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage )
					|| !Q_stricmp( traceEnt->classname, "misc_model_breakable" )
					|| traceEnt->s.eType == ET_MOVER )
				{
					// Create a simple impact type mark that doesn't last long in the world
					G_PlayEffect( G_EffectIndex( "concussion/alt_hit" ), tr.endpos, tr.plane.normal );

					if ( traceEnt->client && LogAccuracyHit( traceEnt, ent ))
					{//NOTE: hitting multiple ents can still get you over 100% accuracy
						ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
					}

					int hitLoc = G_GetHitLocFromTrace( &tr, MOD_CONC_ALT );
					qboolean noKnockBack = (qboolean)((traceEnt->flags&FL_NO_KNOCKBACK) != 0);//will be set if they die, I want to know if it was on *before* they died
					if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH )
					{//hehe
						G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, 10, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc );
						break;
					}
					G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, damage, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc );

					//do knockback and knockdown manually
					if ( traceEnt->client )
					{//only if we hit a client
						vec3_t pushDir;
						VectorCopy( forwardVec, pushDir );
						if ( pushDir[2] < 0.2f )
						{
							pushDir[2] = 0.2f;
						}//hmm, re-normalize?  nah...
						//if ( traceEnt->NPC || Q_irand(0,g_spskill->integer+1) )
						{
							if ( !noKnockBack )
							{//knock-backable
								G_Throw( traceEnt, pushDir, 200 );
								if ( traceEnt->client->NPC_class == CLASS_ROCKETTROOPER )
								{
									traceEnt->client->ps.pm_time = Q_irand( 1500, 3000 );
								}
							}
							if ( traceEnt->health > 0 )
							{//alive
								if ( G_HasKnockdownAnims( traceEnt ) )
								{//knock-downable
									G_Knockdown( traceEnt, ent, pushDir, 400, qtrue );
								}
							}
						}
					}

					if ( traceEnt->s.eType == ET_MOVER )
					{//stop the traces on any mover
						break;
					}
				}
				else
				{
					 // we only make this mark on things that can't break or move
					tent = G_TempEntity( tr.endpos, EV_CONC_ALT_MISS );
					tent->svFlags |= SVF_BROADCAST;
					VectorCopy( tr.plane.normal, tent->pos1 );
					break; // hit solid, but doesn't take damage, so stop the shot...we _could_ allow it to shoot through walls, might be cool?
				}
			}
			else // not rendering impact, must be a skybox or other similar thing?
			{
				break; // don't try anymore traces
			}
		}
		// Get ready for an attempt to trace through another person
		VectorCopy( tr.endpos, muzzle2 );
		VectorCopy( tr.endpos, start );
		skip = tr.entityNum;
		hitDodged = qfalse;
	}
	//just draw one beam all the way to the end
	tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT );
	tent->svFlags |= SVF_BROADCAST;
	VectorCopy( muzzle, tent->s.origin2 );

	// now go along the trail and make sight events
	VectorSubtract( tr.endpos, muzzle, dir );

	shotDist = VectorNormalize( dir );

	//FIXME: if shoot *really* close to someone, the alert could be way out of their FOV
	for ( dist = 0; dist < shotDist; dist += 64 )
	{
		//FIXME: on a really long shot, this could make a LOT of alerts in one frame...
		VectorMA( muzzle, dist, dir, spot );
		AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 );
		//FIXME: creates *way* too many effects, make it one effect somehow?
		G_PlayEffect( G_EffectIndex( "concussion/alt_ring" ), spot, forwardVec );
	}
	//FIXME: spawn a temp ent that continuously spawns sight alerts here?  And 1 sound alert to draw their attention?
	VectorMA( start, shotDist-4, forwardVec, spot );
	AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 );

	G_PlayEffect( G_EffectIndex( "concussion/altmuzzle_flash" ), muzzle, forwardVec );
}
static race_t TranslateRaceName( const char *name ) 
{
	if ( !Q_stricmp( name, "human" ) ) 
	{
		return RACE_HUMAN;
	}
	
	if ( !Q_stricmp( name, "borg" ) ) 
	{
		return RACE_BORG;
	}
	
	if ( !Q_stricmp( name, "parasite" ) ) 
	{
		return RACE_PARASITE;
	}
	
	if ( !Q_stricmp( name, "klingon" ) ) 
	{
		return RACE_KLINGON;
	}
	
	if ( !Q_stricmp( name, "malon" ) ) 
	{
		return RACE_MALON;
	}
	
	if ( !Q_stricmp( name, "hirogen" ) ) 
	{
		return RACE_HIROGEN;
	}
	
	if ( !Q_stricmp( name, "stasis" ) ) 
	{
		return RACE_STASIS;
	}
	
	if ( !Q_stricmp( name, "species8472" ) ) 
	{
		return RACE_8472;
	}
	
	if ( !Q_stricmp( name, "dreadnought" ) ) 
	{
		return RACE_BOT;
	}
	
	if ( !Q_stricmp( name, "harvester" ) || !Q_stricmp( name, "biohulk" ) ) 
	{
		return RACE_HARVESTER;
	}
	
	if ( !Q_stricmp( name, "reaver" ) ) 
	{
		return RACE_REAVER;
	}

	if ( !Q_stricmp( name, "avatar" ) ) 
	{
		return RACE_AVATAR;
	}

	if ( !Q_stricmp( name, "vulcan" ) ) 
	{
		return RACE_VULCAN;
	}

	if ( !Q_stricmp( name, "betazoid" ) ) 
	{
		return RACE_BETAZOID;
	}

	if ( !Q_stricmp( name, "bolian" ) ) 
	{
		return RACE_BOLIAN;
	}

	if ( !Q_stricmp( name, "talaxian" ) ) 
	{
		return RACE_TALAXIAN;
	}

	if ( !Q_stricmp( name, "bajoran" ) ) 
	{
		return RACE_BAJORAN;
	}

	if ( !Q_stricmp( name, "hologram" ) ) 
	{
		return RACE_HOLOGRAM;
	}

	return RACE_NONE;
}
Example #4
0
/*
==================
SV_Map_f

Restart the server on a different map
==================
*/
static void SV_Map_f( void ) {
	char		*cmd;
	char		*map;
	qboolean	killBots, cheat;
	char		expanded[MAX_QPATH];
	char		mapname[MAX_QPATH];

	map = Cmd_Argv(1);
	if ( !map ) {
		return;
	}

	// make sure the level exists before trying to change, so that
	// a typo at the server console won't end the game
	Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
	if ( FS_ReadFile (expanded, NULL) == -1 ) {
		Com_Printf ("Can't find map %s\n", expanded);
		return;
	}

	// force latched values to get set
	Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH );

	cmd = Cmd_Argv(0);
	if ( Q_stricmpn( cmd, "sp", 2 ) == 0 ) {
		Cvar_SetValue( "g_gametype", GT_SINGLE_PLAYER );
		Cvar_SetValue( "g_doWarmup", 0 );
		// may not set sv_maxclients directly, always set latched
		Cvar_SetLatched( "sv_maxclients", "8" );
		cmd += 2;
		cheat = qfalse;
		killBots = qtrue;
	}
	else {
		if ( !Q_stricmp( cmd, "devmap" ) || !Q_stricmp( cmd, "spdevmap" ) ) {
			cheat = qtrue;
			killBots = qtrue;
		} else {
			cheat = qfalse;
			killBots = qfalse;
		}
		if( sv_gametype->integer == GT_SINGLE_PLAYER ) {
			Cvar_SetValue( "g_gametype", GT_FFA );
		}
	}

	// save the map name here cause on a map restart we reload the q3config.cfg
	// and thus nuke the arguments of the map command
	Q_strncpyz(mapname, map, sizeof(mapname));

	// start up the map
	SV_SpawnServer( mapname, killBots );

	// set the cheat value
	// if the level was started with "map <levelname>", then
	// cheats will not be allowed.  If started with "devmap <levelname>"
	// then cheats will be allowed
	if ( cheat ) {
		Cvar_Set( "sv_cheats", "1" );
	} else {
		Cvar_Set( "sv_cheats", "0" );
	}
}
Example #5
0
//G_MissileImpact now returns qfalse if and only if the player physically dodged the damage.
//this allows G_RunMissile to properly handle he
qboolean G_MissileImpact( gentity_t *ent, trace_t *trace ) {
//void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
//[/DodgeSys]
    gentity_t		*other;
    qboolean		isKnockedSaber = qfalse;
    //[DodgeSys]
    int missileDmg;
    //[/DodgeSys]

    other = &g_entities[trace->entityNum];

    // check for bounce
    //[WeaponSys]
    //allow thermals to bounce off players and such.
    if ( (!other->takedamage || ent->s.weapon == WP_THERMAL) &&
            //if ( !other->takedamage &&
            //[/WeaponSys]
            (ent->bounceCount > 0 || ent->bounceCount == -5) &&
            ( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) {
        G_BounceMissile( ent, trace );
        G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
    }
    else if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {   //this is a knocked-away saber
        if (ent->bounceCount > 0 || ent->bounceCount == -5)
        {
            G_BounceMissile( ent, trace );
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }

        isKnockedSaber = qtrue;
    }

    // I would glom onto the FL_BOUNCE code section above, but don't feel like risking breaking something else
    if (/* (!other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags&(FL_BOUNCE_SHRAPNEL) ) ) ||*/ ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius&&(ent->bounceCount > 0 || ent->bounceCount == -5)) )
    {
        G_BounceMissile( ent, trace );

        if ( ent->bounceCount < 1 )
        {
            ent->flags &= ~FL_BOUNCE_SHRAPNEL;
        }
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
    }

    if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
    {   //hit this person's saber, so..
        gentity_t *otherOwner = &g_entities[other->r.ownerNum];

        if (otherOwner->takedamage && otherOwner->client && otherOwner->client->ps.duelInProgress &&
                otherOwner->client->ps.duelIndex != ent->r.ownerNum)
        {
            goto killProj;
        }
    }
    else if (!isKnockedSaber)
    {
        if (other->takedamage && other->client && other->client->ps.duelInProgress &&
                other->client->ps.duelIndex != ent->r.ownerNum)
        {
            goto killProj;
        }
    }

    if (other->flags & FL_DMG_BY_HEAVY_WEAP_ONLY)
    {
        if (ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_ROCKET &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_ROCKET_HOMING &&
                ent->methodOfDeath != MOD_THERMAL &&
                ent->methodOfDeath != MOD_THERMAL_SPLASH &&
                ent->methodOfDeath != MOD_TRIP_MINE_SPLASH &&
                ent->methodOfDeath != MOD_TIMED_MINE_SPLASH &&
                ent->methodOfDeath != MOD_DET_PACK_SPLASH &&
                ent->methodOfDeath != MOD_VEHICLE &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT &&
                ent->methodOfDeath != MOD_SABER &&
                //[Asteroids]
                ent->methodOfDeath != MOD_TURBLAST &&
                ent->methodOfDeath != MOD_TARGET_LASER)
            //[/Asteroids]
        {
            vec3_t fwd;

            if (trace)
            {
                VectorCopy(trace->plane.normal, fwd);
            }
            else
            {   //oh well
                AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
            }

            G_DeflectMissile(other, ent, fwd);
            G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }
    }

    //ROP VEHICLE_IMP START
    if((other->s.NPC_class == CLASS_VEHICLE && other->m_pVehicle
            && !other->m_pVehicle->m_pVehicleInfo->AllWeaponsDoDamageToShields
            && other->client->ps.stats[STAT_ARMOR] > 0) || other->flags & FL_SHIELDED)
    {
        if (ent->s.weapon != WP_ROCKET_LAUNCHER &&
                ent->s.weapon != WP_THERMAL &&
                ent->s.weapon != WP_GRENADE &&
                ent->s.weapon != WP_DET_PACK &&
                ent->s.weapon != WP_DEMP2 &&
                ent->s.weapon != WP_EMPLACED_GUN &&
                ent->s.weapon != WP_TURRET &&
                ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_TURBLAST &&
                ent->methodOfDeath != MOD_VEHICLE &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT &&
                !(ent->dflags&DAMAGE_HEAVY_WEAP_CLASS) )
        {
            vec3_t fwd;

            if (other->client)
            {
                AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
            }
            else
            {
                AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
            }

            G_DeflectMissile(other, ent, fwd);
            G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }
    }
    //ROP VEHICLE_IMP END

    //[BoltBlockSys]
    if (OJP_SaberCanBlock(other, ent, qfalse, trace->endpos, -1, -1))
        //[/BoltBlockSys]
    {   //only block one projectile per 200ms (to prevent giant swarms of projectiles being blocked)
        //[BoltBlockSys]
        //racc - missile hit the actual player and it's a type of missile that you can deflect/ref with the saber.

        //racc - play projectile block animation
        other->client->ps.weaponTime = 0;
        WP_SaberBlockNonRandom(other, ent->r.currentOrigin, qtrue);

        OJP_HandleBoltBlock(ent, other, trace);
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
        //[/BoltBlockSys]
    }
    else if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
    {   //hit this person's saber, so..
        gentity_t *otherOwner = &g_entities[other->r.ownerNum];

        if (otherOwner->takedamage && otherOwner->client &&
                ent->s.weapon != WP_TUSKEN_RIFLE &&
                ent->s.weapon != WP_ROCKET_LAUNCHER &&
                ent->s.weapon != WP_THERMAL &&
                ent->s.weapon != WP_GRENADE &&
                ent->s.weapon != WP_DET_PACK &&
                //[BoltBlockSys]
                //ent->s.weapon != WP_DEMP2 &&
                //[BoltBlockSys]
                ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT /*&&
			otherOwner->client->ps.saberBlockTime < level.time*/)
        {   //for now still deflect even if saberBlockTime >= level.time because it hit the actual saber

            //in this case, deflect it even if we can't actually block it because it hit our saber
            //WP_SaberCanBlock(otherOwner, ent->r.currentOrigin, 0, 0, qtrue, 0);
            if ((otherOwner->client && !BG_SaberInAttack(otherOwner->client->ps.saberMove))
                    || (otherOwner->client && (pm->cmd.buttons & BUTTON_FORCEPOWER || pm->cmd.buttons & BUTTON_FORCEGRIP
                                               || pm->cmd.buttons & BUTTON_FORCE_LIGHTNING) ))
            {   //racc - play projectile block animation even in .
                otherOwner->client->ps.weaponTime = 0;
                WP_SaberBlockNonRandom(otherOwner, ent->r.currentOrigin, qtrue);
            }

            //[BoltBlockSys]
            OJP_HandleBoltBlock(ent, otherOwner, trace);
            //[/BoltBlockSys]
            //[DodgeSys]
            return qtrue;
            //return;
            //[/DodgeSys]
        }
    }

    // check for sticking
    //[SaberThrowSys]
    if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK )
            && ent->s.weapon != WP_SABER)
        //if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) )
        //[/SaberThrowSys]
    {
        laserTrapStick( ent, trace->endpos, trace->plane.normal );
        G_AddEvent( ent, EV_MISSILE_STICK, 0 );
        //[DodgeSys]
        return qtrue;
        //return;
        //[/DodgeSys]
    }

    // impact damage
    if (other->takedamage && !isKnockedSaber) {
        //[DodgeSys]
        //make players be able to dodge projectiles.
        missileDmg = ent->damage;
        if(G_DoDodge(other, &g_entities[ent->r.ownerNum], trace->endpos, -1, &missileDmg, ent->methodOfDeath))
        {   //player dodged the damage, have missile continue moving.
            if(ent->s.weapon == WP_ROCKET_LAUNCHER)
                ent->genericValue1 = 0;
            return qfalse;
        }
        //[/DodgeSys]

        // FIXME: wrong damage direction?
        //[DodgeSys]
        if ( missileDmg ) {
            //if ( ent->damage ) {
            //[/DodgeSys]
            vec3_t	velocity;
            qboolean didDmg = qfalse;

            BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
            if ( VectorLength( velocity ) == 0 ) {
                velocity[2] = 1;	// stepped on a grenade
            }

            if (ent->s.weapon == WP_BOWCASTER || ent->s.weapon == WP_FLECHETTE ||
                    ent->s.weapon == WP_ROCKET_LAUNCHER)
            {
                if (ent->s.weapon == WP_FLECHETTE && (ent->s.eFlags & EF_ALT_FIRING))
                {
                    ent->think(ent);
                }
                else
                {
                    G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg,
                              //[/DodgeSys]
                              DAMAGE_HALF_ABSORB, ent->methodOfDeath);
                    didDmg = qtrue;
                }
            }
            else {
                gentity_t *owner = &g_entities[ent->r.ownerNum];
                float distance = VectorDistance(owner->r.currentOrigin,other->r.currentOrigin);

                if(distance <= 100.0f)
                {
                    G_Damage (other, ent, owner, velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg * 2,
                              //[/DodgeSys]
                              0, ent->methodOfDeath);
                }
                else if (distance <= 300.0f)
                {
                    G_Damage (other, ent, owner, velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg * 1.5,
                              //[/DodgeSys]
                              0, ent->methodOfDeath);
                }
                else
                {
                    G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
                              //[DodgeSys]
                              ent->r.currentOrigin, missileDmg,
                              //[/DodgeSys]
                              0, ent->methodOfDeath);
                }
                didDmg = qtrue;
            }


            if (didDmg && other && other->client)
            {   //What I'm wondering is why this isn't in the NPC pain funcs. But this is what SP does, so whatever.
                class_t	npc_class = other->client->NPC_class;

                // If we are a robot and we aren't currently doing the full body electricity...
                if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
                        npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE ||
                        npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd
                        npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
                {
                    // special droid only behaviors
                    if ( other->client->ps.electrifyTime < level.time + 100 )
                    {
                        // ... do the effect for a split second for some more feedback
                        other->client->ps.electrifyTime = level.time + 450;
                    }
                    //FIXME: throw some sparks off droids,too
                }
            }
        }

        if ( ent->s.weapon == WP_DEMP2 )
        {   //a hit with demp2 decloaks people, disables ships
            if ( other && other->client && other->client->NPC_class == CLASS_VEHICLE )
            {   //hit a vehicle
                if ( other->m_pVehicle //valid vehicle ent
                        && other->m_pVehicle->m_pVehicleInfo//valid stats
                        && (other->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER//always affect speeders
                            ||(other->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER && ent->classname && Q_stricmp("vehicle_proj", ent->classname ) == 0) )//only vehicle ion weapons affect a fighter in this manner
                        && !FighterIsLanded( other->m_pVehicle , &other->client->ps )//not landed
                        && !(other->spawnflags&2) )//and not suspended
                {   //vehicles hit by "ion cannons" lose control
                    if ( other->client->ps.electrifyTime > level.time )
                    {   //add onto it
                        //FIXME: extern the length of the "out of control" time?
                        other->client->ps.electrifyTime += Q_irand(200,500);
                        if ( other->client->ps.electrifyTime > level.time + 4000 )
                        {   //cap it
                            other->client->ps.electrifyTime = level.time + 4000;
                        }
                    }
                    else
                    {   //start it
                        //FIXME: extern the length of the "out of control" time?
                        other->client->ps.electrifyTime = level.time + Q_irand(200,500);
                    }
                }
            }
            else if ( other && other->client && other->client->ps.powerups[PW_CLOAKED] )
            {
                Jedi_Decloak( other );
                if ( ent->methodOfDeath == MOD_DEMP2_ALT )
                {   //direct hit with alt disables cloak forever
                    //permanently disable the saboteur's cloak
                    other->client->cloakToggleTime = Q3_INFINITE;
                }
                else
                {   //temp disable
                    other->client->cloakToggleTime = level.time + Q_irand( 3000, 10000 );
                }
            }
        }
    }
killProj:
    // is it cheaper in bandwidth to just remove this ent and create a new
    // one, rather than changing the missile into the explosion?

    if ( other->takedamage && other->client && !isKnockedSaber ) {
        G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
        ent->s.otherEntityNum = other->s.number;
    } else if( trace->surfaceFlags & SURF_METALSTEPS ) {
        G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
    } else if (ent->s.weapon != G2_MODEL_PART && !isKnockedSaber) {
        G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
    }

    if (!isKnockedSaber)
    {
        ent->freeAfterEvent = qtrue;

        // change over to a normal entity right at the point of impact
        ent->s.eType = ET_GENERAL;
    }

    SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth

    G_SetOrigin( ent, trace->endpos );

    ent->takedamage = qfalse;
    // splash damage (doesn't apply to person directly hit)
    if ( ent->splashDamage ) {
        G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
                        other, ent, ent->splashMethodOfDeath );
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        ent->freeAfterEvent = qfalse; //it will free itself
    }

    trap_LinkEntity( ent );

    //[DodgeSys]
    return qtrue;
    //[/DodgeSys]
}
Example #6
0
/*
============
Cmd_CompleteArgument
============
*/
void Cmd_CompleteArgument( const char *command, char *args, int argNum ) {
	for ( cmd_function_t *cmd=cmd_functions; cmd; cmd=cmd->next ) {
		if ( !Q_stricmp( command, cmd->name ) && cmd->complete )
			cmd->complete( args, argNum );
	}
}
Example #7
0
static void Svcmd_Kick_f( void ) {
	gclient_t	*cl;
	int			i;
	int			timeout = -1;
	char		sTimeout[MAX_TOKEN_CHARS];
	char		name[MAX_TOKEN_CHARS];

	// make sure server is running
	if ( !G_Is_SV_Running() ) {
		G_Printf( "Server is not running.\n" );
		return;
	}

	if ( trap_Argc() < 2 || trap_Argc() > 3 ) {
		G_Printf ("Usage: kick <player name> [timeout]\n");
		return;
	}

	if( trap_Argc() == 3 ) {
		trap_Argv( 2, sTimeout, sizeof( sTimeout ) );
		timeout = atoi( sTimeout );
	} else {
		timeout = 300;
	}

	trap_Argv(1, name, sizeof(name));
	cl = G_GetPlayerByName( name );//ClientForString( name );

	if ( !cl ) {
		if ( !Q_stricmp(name, "all") ) {
			for (i = 0, cl = level.clients; i < level.numConnectedClients; i++, cl++) {
		
				// dont kick localclients ...
				if ( cl->pers.localClient ) {
					continue;
				}

				if ( timeout != -1 ) {
					char *ip;
					char userinfo[MAX_INFO_STRING];
					
					trap_GetUserinfo( cl - level.clients, userinfo, sizeof( userinfo ) );
					ip = Info_ValueForKey (userinfo, "ip");
					
					// use engine banning system, mods may choose to use their own banlist
					if (USE_ENGINE_BANLIST) { 
						
						// kick but dont ban bots, they arent that lame
						if ( (g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) {
							timeout = 0;
						}

						trap_DropClient(cl - level.clients, "player kicked", timeout);
					} else {
						trap_DropClient(cl - level.clients, "player kicked", 0);
						
						// kick but dont ban bots, they arent that lame
						if ( !(g_entities[cl - level.clients].r.svFlags & SVF_BOT) )
							AddIPBan( ip );
					}

				} else {
					trap_DropClient(cl - level.clients, "player kicked", 0);				
				}
			}
		} else if ( !Q_stricmp(name, "allbots") ) {
			for (i = 0, cl = level.clients; i < level.numConnectedClients; i++, cl++) {
				if ( !(g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) {
					continue;
				}
				// kick but dont ban bots, they arent that lame
				trap_DropClient(cl - level.clients, "player kicked", 0);
			}
		}
		return;
	} else {
		// dont kick localclients ...
		if ( cl->pers.localClient ) {
			G_Printf("Cannot kick host player\n");
			return;
		}

		if ( timeout != -1 ) {
			char *ip;
			char userinfo[MAX_INFO_STRING];
			
			trap_GetUserinfo( cl - level.clients, userinfo, sizeof( userinfo ) );
			ip = Info_ValueForKey (userinfo, "ip");
			
			// use engine banning system, mods may choose to use their own banlist
			if (USE_ENGINE_BANLIST) { 
				
				// kick but dont ban bots, they arent that lame
				if ( (g_entities[cl - level.clients].r.svFlags & SVF_BOT) ) {
					timeout = 0;
				}
				trap_DropClient(cl - level.clients, "player kicked", timeout);
			} else {
				trap_DropClient(cl - level.clients, "player kicked", 0);
				
				// kick but dont ban bots, they arent that lame
				if ( !(g_entities[cl - level.clients].r.svFlags & SVF_BOT) )
					AddIPBan( ip );
			}

		} else {
			trap_DropClient(cl - level.clients, "player kicked", 0);				
		}
	}
}
Example #8
0
/*
 * Give items to a client
 */
void
Cmd_Give_f(edict_t *ent)
{
	char *name;
	gitem_t *it;
	int index;
	int i;
	qboolean give_all;
	edict_t *it_ent;

	if (!ent)
	{
		return;
	}

	if ((deathmatch->value || coop->value) && !sv_cheats->value)
	{
		gi.cprintf( ent, PRINT_HIGH,
				"You must run the server with '+set cheats 1' to enable this command.\n");
		return;
	}

	name = gi.args();

	if (Q_stricmp(name, "all") == 0)
	{
		give_all = true;
	}
	else
	{
		give_all = false;
	}

	if (give_all || (Q_stricmp(gi.argv(1), "health") == 0))
	{
		if (gi.argc() == 3)
		{
			ent->health = (int)strtol(gi.argv(2), (char **)NULL, 10);
		}
		else
		{
			ent->health = ent->max_health;
		}

		if (!give_all)
		{
			return;
		}
	}

	if (give_all || (Q_stricmp(name, "weapons") == 0))
	{
		for (i = 0; i < game.num_items; i++)
		{
			it = itemlist + i;

			if (!it->pickup)
			{
				continue;
			}

			if (!(it->flags & IT_WEAPON))
			{
				continue;
			}

			ent->client->pers.inventory[i] += 1;
		}

		if (!give_all)
		{
			return;
		}
	}

	if (give_all || (Q_stricmp(name, "ammo") == 0))
	{
		for (i = 0; i < game.num_items; i++)
		{
			it = itemlist + i;

			if (!it->pickup)
			{
				continue;
			}

			if (!(it->flags & IT_AMMO))
			{
				continue;
			}

			Add_Ammo(ent, it, 1000);
		}

		if (!give_all)
		{
			return;
		}
	}

	if (give_all || (Q_stricmp(name, "armor") == 0))
	{
		gitem_armor_t *info;

		it = FindItem("Jacket Armor");
		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;

		it = FindItem("Combat Armor");
		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;

		it = FindItem("Body Armor");
		info = (gitem_armor_t *)it->info;
		ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count;

		if (!give_all)
		{
			return;
		}
	}

	if (give_all || (Q_stricmp(name, "Power Shield") == 0))
	{
		it = FindItem("Power Shield");
		it_ent = G_Spawn();
		it_ent->classname = it->classname;
		SpawnItem(it_ent, it);
		Touch_Item(it_ent, ent, NULL, NULL);

		if (it_ent->inuse)
		{
			G_FreeEdict(it_ent);
		}

		if (!give_all)
		{
			return;
		}
	}

	if (give_all)
	{
		for (i = 0; i < game.num_items; i++)
		{
			it = itemlist + i;

			if (!it->pickup)
			{
				continue;
			}

			if (it->flags & (IT_ARMOR | IT_WEAPON | IT_AMMO))
			{
				continue;
			}

			ent->client->pers.inventory[i] = 1;
		}

		return;
	}

	it = FindItem(name);

	if (!it)
	{
		name = gi.argv(1);
		it = FindItem(name);

		if (!it)
		{
			gi.cprintf(ent, PRINT_HIGH, "unknown item\n");
			return;
		}
	}

	if (!it->pickup)
	{
		gi.cprintf(ent, PRINT_HIGH, "non-pickup item\n");
		return;
	}

	index = ITEM_INDEX(it);

	if (it->flags & IT_AMMO)
	{
		if (gi.argc() == 3)
		{
			ent->client->pers.inventory[index] = (int)strtol(gi.argv(2), (char **)NULL, 10);
		}
		else
		{
			ent->client->pers.inventory[index] += it->quantity;
		}
	}
	else
	{
		it_ent = G_Spawn();
		it_ent->classname = it->classname;
		SpawnItem(it_ent, it);
		Touch_Item(it_ent, ent, NULL, NULL);

		if (it_ent->inuse)
		{
			G_FreeEdict(it_ent);
		}
	}
}
Example #9
0
// finds all trigger_multiples linked to asw_objective_escape entities
void CASW_Spawn_Manager::FindEscapeTriggers()
{
	m_EscapeTriggers.Purge();

	// go through all escape objectives
	CBaseEntity* pEntity = NULL;
	while ( (pEntity = gEntList.FindEntityByClassname( pEntity, "asw_objective_escape" )) != NULL )
	{
		CASW_Objective_Escape* pObjective = dynamic_cast<CASW_Objective_Escape*>(pEntity);
		if ( !pObjective )
			continue;

		const char *pszEscapeTargetName = STRING( pObjective->GetEntityName() );

		CBaseEntity* pOtherEntity = NULL;
		while ( (pOtherEntity = gEntList.FindEntityByClassname( pOtherEntity, "trigger_multiple" )) != NULL )
		{
			CTriggerMultiple *pTrigger = dynamic_cast<CTriggerMultiple*>( pOtherEntity );
			if ( !pTrigger )
				continue;

			bool bAdded = false;
			CBaseEntityOutput *pOutput = pTrigger->FindNamedOutput( "OnTrigger" );
			if ( pOutput )
			{
				CEventAction *pAction = pOutput->GetFirstAction();
				while ( pAction )
				{
					if ( !Q_stricmp( STRING( pAction->m_iTarget ), pszEscapeTargetName ) )
					{
						bAdded = true;
						m_EscapeTriggers.AddToTail( pTrigger );
						break;
					}
					pAction = pAction->m_pNext;
				}
			}

			if ( !bAdded )
			{
				pOutput = pTrigger->FindNamedOutput( "OnStartTouch" );
				if ( pOutput )
				{
					CEventAction *pAction = pOutput->GetFirstAction();
					while ( pAction )
					{
						if ( !Q_stricmp( STRING( pAction->m_iTarget ), pszEscapeTargetName ) )
						{
							bAdded = true;
							m_EscapeTriggers.AddToTail( pTrigger );
							break;
						}
						pAction = pAction->m_pNext;
					}
				}
			}
			
		}
	}
	Msg("Spawn manager found %d escape triggers\n", m_EscapeTriggers.Count() );
}
Example #10
0
/*
=================
ConsoleCommand

=================
*/
qboolean	ConsoleCommand( void ) {
	char	cmd[MAX_TOKEN_CHARS];

	trap_Argv( 0, cmd, sizeof( cmd ) );

#ifdef SAVEGAME_SUPPORT
	if (Q_stricmp (cmd, "savegame") == 0) {

		if( g_gametype.integer != GT_SINGLE_PLAYER )
			return qtrue;

		// don't allow a manual savegame command while we are waiting for the game to start/exit
		if (g_reloading.integer)
			return qtrue;
		if (saveGamePending)
			return qtrue;

		trap_Argv( 1, cmd, sizeof( cmd ) );
		if (strlen(cmd) > 0) {
			// strip the extension if provided
			if (strrchr(cmd, '.')) {
				cmd[strrchr(cmd,'.')-cmd] = '\0';
			}
			if ( !Q_stricmp( cmd, "current") ) {		// beginning of map
				Com_Printf("sorry, '%s' is a reserved savegame name.  please use another name.\n", cmd);
				return qtrue;
			}

			if (G_SaveGame( cmd ))
				trap_SendServerCommand(-1, "cp \"Game Saved\n\"");	// deletedgame
			else
				G_Printf( "Unable to save game.\n" );

		} else {	// need a name
			G_Printf( "syntax: savegame <name>\n" );
		}

		return qtrue;
	}
#endif // SAVEGAME_SUPPORT

	if ( Q_stricmp (cmd, "entitylist") == 0 ) {
		Svcmd_EntityList_f();
		return qtrue;
	}

	if ( Q_stricmp (cmd, "forceteam") == 0 ) {
		Svcmd_ForceTeam_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "game_memory") == 0) {
		Svcmd_GameMem_f();
		return qtrue;
	}

	/*if (Q_stricmp (cmd, "addbot") == 0) {
		Svcmd_AddBot_f();
		return qtrue;
	}
	if (Q_stricmp (cmd, "removebot") == 0) {
		Svcmd_AddBot_f();
		return qtrue;
	}*/
	if (Q_stricmp (cmd, "addip") == 0) {
		Svcmd_AddIP_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "removeip") == 0) {
		Svcmd_RemoveIP_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "listip") == 0) {
		trap_SendConsoleCommand( EXEC_INSERT, "g_banIPs\n" );
		return qtrue;
	}

	if (Q_stricmp (cmd, "listmaxlivesip") == 0) {
		PrintMaxLivesGUID();
		return qtrue;
	}

	if (Q_stricmp (cmd, "reset_match") == 0) {
		Svcmd_ResetMatch_f(qtrue, qtrue);
		return qtrue;
	}

	if (Q_stricmp (cmd, "swap_teams") == 0) {
		Svcmd_SwapTeams_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "shuffle_teams") == 0) {
		Svcmd_ShuffleTeams_f();
		return qtrue;
	}

	// -NERVE - SMF

	if (Q_stricmp (cmd, "makeReferee") == 0) {
		G_MakeReferee();
		return qtrue;
	}

	if (Q_stricmp (cmd, "removeReferee") == 0) {
		G_RemoveReferee();
		return qtrue;
	}

	/*if (Q_stricmp (cmd, "mute") == 0) {
		G_MuteClient();
		return qtrue;
	}

	if (Q_stricmp (cmd, "unmute") == 0) {
		G_UnMuteClient();
		return qtrue;
	}*/

	if (Q_stricmp (cmd, "ban") == 0) {
		G_PlayerBan();
		return qtrue;
	}

	if( Q_stricmp( cmd, "campaign" ) == 0 ) {
		Svcmd_Campaign_f();
		return qtrue;
	}

	if( Q_stricmp( cmd, "listcampaigns" ) == 0 ) {
		Svcmd_ListCampaigns_f();
		return qtrue;
	}

	// fretn - moved from engine
	if (!Q_stricmp(cmd, "kick")) {
		Svcmd_Kick_f();
		return qtrue;
	}
	
	if (!Q_stricmp(cmd, "clientkick")) {
		Svcmd_KickNum_f();
		return qtrue;
	}
	
	if (!Q_stricmp(cmd, "noVoteLimit")) {
		Svcmd_noVoteLimit();
		return qtrue;
	}

	if (!Q_stricmp(cmd, "cp")) {
		AP(va("cp \"%s\n\"", ConcatArgs(1)));
		return qtrue;
	}
	if (!Q_stricmp(cmd, "qsay")) {
		AP(va("chat \"%s\"", ConcatArgs(1)));
		G_LogPrintf("qsay: \"%s\n\"", ConcatArgs(1));
		return qtrue;
	}
	if (!Q_stricmp(cmd, "bp")) {
		AP(va("bp \"%s\"", ConcatArgs(1)));
		G_LogPrintf("banner: \"%s\n\"", ConcatArgs(1));
		return qtrue;
	}
	if (!Q_stricmp(cmd, "cpm")) {
		AP(va("cpm \"%s\n\"", ConcatArgs(1)));
		return qtrue;
	}


	if (!Q_stricmp(cmd, "freespec"))
	{
		gclient_t	*cl;
		char num[MAX_TOKEN_CHARS];
		int clientnum;

		trap_Argv(1, num, sizeof(num));
		clientnum = atoi(num);

		cl = G_GetPlayerByNum( clientnum );

		if ( !cl ) {
			return;
		}

		cl->sess.freeSpec = qtrue;
		return qtrue;
	}

	if (!Q_stricmp(cmd, "pcmd")) {
		gclient_t	*cl;
		char	name[MAX_TOKEN_CHARS];
		int		clientNum;

		trap_Argv(1, name, sizeof(name));
		clientNum = atoi(name);

		cl = G_GetPlayerByNum( clientNum );
	
		if ( !cl ) {
			return;
		}

		trap_SendServerCommand(cl - level.clients, va("pcmd %s", ConcatArgs(2)));
		return qtrue;
	}


	if (!Q_stricmp(cmd, "blockmap")) {
		char map[MAX_STRING_TOKENS];
		char blocklist[MAX_CVAR_VALUE_STRING];

		trap_Argv(1, map, sizeof(map));

		if (strlen(tjg_blockedMaps.string) + strlen(map) > sizeof(tjg_blockedMaps.string))
		{
			AP("print \"tjg_blockedMaps is full.\n\"");
		}
		else
		{
			Com_sprintf(blocklist, sizeof(blocklist), "%s %s", tjg_blockedMaps.string, map);
			trap_Cvar_Set("tjg_blockedMaps", va("%s", blocklist));
		}


		return qtrue;
	}

	
	if (!tjg_recordMode.integer)
	{
		if (!Q_stricmp(cmd, "forcecvar")) 
		{
			char cvar_name[MAX_TOKEN_CHARS]; 
			char cvar_val[MAX_TOKEN_CHARS];
			trap_Argv(1, cvar_name, sizeof(cvar_name)); 
			trap_Argv(2, cvar_val, sizeof(cvar_val)); 
			trap_Cvar_Set(cvar_name, va("%d", atoi(cvar_val))); 
			AP(va("print \"Forced %s to %s.\n\"", cvar_name, va("%d", atoi(cvar_val)) ) ); 
			return qtrue;
		}
	}

	if( g_dedicated.integer ) {
		if( !Q_stricmp (cmd, "say")) {
			trap_SendServerCommand( -1, va("cpm \"server: %s\n\"", ConcatArgs(1) ) );
			return qtrue;
		}

		// OSP - console also gets ref commands
		if(!level.fLocalHost && Q_stricmp(cmd, "ref") == 0) {
			// CHRUKER: b005 - G_refCommandCheck expects the next argument (warn, pause, lock etc).
			trap_Argv(1, cmd, sizeof(cmd)); 
			if(!G_refCommandCheck(NULL, cmd)) {
				G_refHelp_cmd(NULL);
			}
			return(qtrue);
		}

		// everything else will also be printed as a say command
//		trap_SendServerCommand( -1, va("cpm \"server: %s\n\"", ConcatArgs(0) ) );

		// prints to the console instead now
		return qfalse;
	}


	return qfalse;
}
qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) 
{
	char	*token;
	char	*value;
	char	*p;
	int		n;
	float	f;
	char	*patch;
	char	sound[MAX_QPATH];
	clientInfo_t	*ci = &NPC->client->clientInfo;
	renderInfo_t	*ri = &NPC->client->renderInfo;
	gNPCstats_t		*stats = &NPC->NPC->stats;

	if ( !NPCName || !NPCName[0]) 
	{
		NPCName = "Player";
	}

	Q_strncpyz( ci->name, NPCName, sizeof( ci->name ) );
	
	// fill in defaults
	stats->aggression	= 3;
	stats->aim			= 3;
	stats->earshot		= 1024;
	stats->evasion		= 3;
	stats->hfov			= 75;
	stats->intelligence	= 3;
	stats->move			= 3;
	stats->reactions	= 3;
	stats->vfov			= 45;
	stats->vigilance	= 0.1f;
	stats->visrange		= 1024;

	stats->moveType		= MT_RUNJUMP;
	stats->yawSpeed		= 90;
	stats->walkSpeed	= 90;
	stats->runSpeed		= 300;
	stats->acceleration	= 15;//Increase/descrease speed this much per frame (20fps)

	ri->scaleXYZ[0] = ri->scaleXYZ[1] = ri->scaleXYZ[2] = 100;
	
	//Set defaults
	//FIXME: should probably put default torso and head models, but what about enemies
	//that don't have any- like Stasis?
	Q_strncpyz( ri->headModelName,	DEFAULT_HEADMODEL,  sizeof(ri->headModelName),	qtrue);
	Q_strncpyz( ri->torsoModelName, DEFAULT_TORSOMODEL, sizeof(ri->torsoModelName),	qtrue);
	Q_strncpyz( ri->legsModelName,	DEFAULT_LEGSMODEL,  sizeof(ri->legsModelName),	qtrue);

	//FIXME: should we have one for weapon too?
	
	/*
	ri->headYawRangeLeft = 50;
	ri->headYawRangeRight = 50;
	ri->headPitchRangeUp = 40;
	ri->headPitchRangeDown = 50;
	ri->torsoYawRangeLeft = 60;
	ri->torsoYawRangeRight = 60;
	ri->torsoPitchRangeUp = 30;
	ri->torsoPitchRangeDown = 70;
	*/

	ri->headYawRangeLeft = 80;
	ri->headYawRangeRight = 80;
	ri->headPitchRangeUp = 45;
	ri->headPitchRangeDown = 45;
	ri->torsoYawRangeLeft = 90;
	ri->torsoYawRangeRight = 90;
	ri->torsoPitchRangeUp = 30;
	ri->torsoPitchRangeDown = 50;

/*
	NPC->NPC->allWeaponOrder[0]	= WP_COMPRESSION_RIFLE;
	NPC->NPC->allWeaponOrder[1]	= WP_PHASER;
	NPC->NPC->allWeaponOrder[2]	= WP_IMOD;
	NPC->NPC->allWeaponOrder[3]	= WP_SCAVENGER_RIFLE;
	NPC->NPC->allWeaponOrder[4]	= WP_TRICORDER;
	NPC->NPC->allWeaponOrder[6]	= WP_NONE;
	NPC->NPC->allWeaponOrder[6]	= WP_NONE;
	NPC->NPC->allWeaponOrder[7]	= WP_NONE;
*/

	VectorCopy(playerMins, NPC->mins);
	VectorCopy(playerMaxs, NPC->maxs);
	NPC->client->crouchheight = CROUCH_MAXS_2;
	NPC->client->standheight = DEFAULT_MAXS_2;

	//ci->customBasicSoundDir = "munro";

	if ( !Q_stricmp( "random", NPCName ) )
	{//Randomly assemble a starfleet guy
		NPC_BuildRandom( NPC );
	}
	else
	{
		p = NPCParms;
		COM_BeginParseSession();

		// look for the right NPC
		while ( p ) 
		{
			token = COM_ParseExt( &p, qtrue );
			if ( token[0] == 0 )
			{
				return qfalse;
			}

			if ( !Q_stricmp( token, NPCName ) ) 
			{
				break;
			}

			SkipBracedSection( &p );
		}
		if ( !p ) 
		{
			return qfalse;
		}

		if ( G_ParseLiteral( &p, "{" ) ) 
		{
			return qfalse;
		}
			
		// parse the NPC info block
		while ( 1 ) 
		{
			token = COM_ParseExt( &p, qtrue );
			if ( !token[0] ) 
			{
				gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPCName );
				return qfalse;
			}

			if ( !Q_stricmp( token, "}" ) ) 
			{
				break;
			}
	//===MODEL PROPERTIES===========================================================
			// headmodel
			if ( !Q_stricmp( token, "headmodel" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}

				if(!Q_stricmp("none", value))
				{
					ri->headModelName[0] = NULL;
					//Zero the head clamp range so the torso & legs don't lag behind
					ri->headYawRangeLeft = 
					ri->headYawRangeRight = 
					ri->headPitchRangeUp = 
					ri->headPitchRangeDown = 0;
				}
				else
				{
					Q_strncpyz( ri->headModelName, value, sizeof(ri->headModelName), qtrue);
				}
				continue;
			}
			
			// torsomodel
			if ( !Q_stricmp( token, "torsomodel" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}

				if(!Q_stricmp("none", value))
				{
					ri->torsoModelName[0] = NULL;
					//Zero the torso clamp range so the legs don't lag behind
					ri->torsoYawRangeLeft = 
					ri->torsoYawRangeRight = 
					ri->torsoPitchRangeUp = 
					ri->torsoPitchRangeDown = 0;
				}
				else
				{
					Q_strncpyz( ri->torsoModelName, value, sizeof(ri->torsoModelName), qtrue);
				}
				continue;
			}

			// legsmodel
			if ( !Q_stricmp( token, "legsmodel" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}
				Q_strncpyz( ri->legsModelName, value, sizeof(ri->legsModelName), qtrue);			
				//Need to do this here to get the right index
				G_ParseAnimFileSet( value, &ci->animFileIndex, qfalse );
				continue;
			}
			
			//headYawRangeLeft
			if ( !Q_stricmp( token, "headYawRangeLeft" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->headYawRangeLeft = n;
				continue;
			}

			//headYawRangeRight
			if ( !Q_stricmp( token, "headYawRangeRight" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->headYawRangeRight = n;
				continue;
			}

			//headPitchRangeUp
			if ( !Q_stricmp( token, "headPitchRangeUp" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->headPitchRangeUp = n;
				continue;
			}
			
			//headPitchRangeDown
			if ( !Q_stricmp( token, "headPitchRangeDown" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->headPitchRangeDown = n;
				continue;
			}

			//torsoYawRangeLeft
			if ( !Q_stricmp( token, "torsoYawRangeLeft" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->torsoYawRangeLeft = n;
				continue;
			}

			//torsoYawRangeRight
			if ( !Q_stricmp( token, "torsoYawRangeRight" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->torsoYawRangeRight = n;
				continue;
			}

			//torsoPitchRangeUp
			if ( !Q_stricmp( token, "torsoPitchRangeUp" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->torsoPitchRangeUp = n;
				continue;
			}

			//torsoPitchRangeDown
			if ( !Q_stricmp( token, "torsoPitchRangeDown" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->torsoPitchRangeDown = n;
				continue;
			}

			// Uniform XYZ scale
			if ( !Q_stricmp( token, "scale" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->scaleXYZ[0] = ri->scaleXYZ[1] = ri->scaleXYZ[2] = n;
				continue;
			}

			//X scale
			if ( !Q_stricmp( token, "scaleX" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->scaleXYZ[0] = n;
				continue;
			}

			//Y scale
			if ( !Q_stricmp( token, "scaleY" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->scaleXYZ[1] = n;
				continue;
			}

			//Z scale
			if ( !Q_stricmp( token, "scaleZ" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				ri->scaleXYZ[2] = n;
				continue;
			}

			if ( !Q_stricmp( token, "boltOn" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}

				G_AddBoltOn( NPC, value );
				continue;
			}
	//===AI STATS=====================================================================
			// aggression
			if ( !Q_stricmp( token, "aggression" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 1 || n > 5 ) {
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->aggression = n;
				continue;
			}

			// aim
			if ( !Q_stricmp( token, "aim" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 1 || n > 5 ) {
					gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->aim = n;
				continue;
			}

			// earshot
			if ( !Q_stricmp( token, "earshot" ) ) {
				if ( G_ParseFloat( &p, &f ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( f < 0.0f ) 
				{
					gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->earshot = f;
				continue;
			}

			// evasion
			if ( !Q_stricmp( token, "evasion" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 1 || n > 5 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->evasion = n;
				continue;
			}

			// hfov
			if ( !Q_stricmp( token, "hfov" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 30 || n > 180 ) {
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->hfov = n;// / 2;	//FIXME: Why was this being done?!
				continue;
			}

			// intelligence
			if ( !Q_stricmp( token, "intelligence" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 1 || n > 5 ) {
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->intelligence = n;
				continue;
			}
			
			// move
			if ( !Q_stricmp( token, "move" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 1 || n > 5 ) {
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->move = n;
				continue;
			}

			// reactions
			if ( !Q_stricmp( token, "reactions" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 1 || n > 5 ) {
					gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->reactions = n;
				continue;
			}

			// shootDistance
			if ( !Q_stricmp( token, "shootDistance" ) ) {
				if ( G_ParseFloat( &p, &f ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( f < 0.0f ) 
				{
					gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->shootDistance = f;
				continue;
			}

			// vfov
			if ( !Q_stricmp( token, "vfov" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 30 || n > 180 ) {
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->vfov = n / 2;
				continue;
			}

			// vigilance
			if ( !Q_stricmp( token, "vigilance" ) ) {
				if ( G_ParseFloat( &p, &f ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( f < 0.0f ) 
				{
					gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->vigilance = f;
				continue;
			}

			// visrange
			if ( !Q_stricmp( token, "visrange" ) ) {
				if ( G_ParseFloat( &p, &f ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( f < 0.0f ) 
				{
					gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->visrange = f;
				continue;
			}

			// race
			if ( !Q_stricmp( token, "race" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}
				NPC->client->race = TranslateRaceName(value);
				continue;
			}

			// rank
			if ( !Q_stricmp( token, "rank" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}
				NPC->NPC->rank = TranslateRankName(value);
				continue;
			}

			// fullName
			if ( !Q_stricmp( token, "fullName" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}
				NPC->fullName = G_NewString(value);
				continue;
			}

			// playerTeam
			if ( !Q_stricmp( token, "playerTeam" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}
				NPC->client->playerTeam = TranslateTeamName(value);
				continue;
			}

			// enemyTeam
			if ( !Q_stricmp( token, "enemyTeam" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}
				NPC->client->enemyTeam = TranslateTeamName(value);
				continue;
			}

	//===MOVEMENT STATS============================================================
			
			if ( !Q_stricmp( token, "width" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					continue;
				}

				NPC->mins[0] = NPC->mins[1] = -n;
				NPC->maxs[0] = NPC->maxs[1] = n;
				continue;
			}

			if ( !Q_stricmp( token, "height" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					continue;
				}

				NPC->mins[2] = DEFAULT_MINS_2;//Cannot change
				NPC->maxs[2] = NPC->client->standheight = n + DEFAULT_MINS_2;
				continue;
			}

			if ( !Q_stricmp( token, "crouchheight" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					continue;
				}

				NPC->client->crouchheight = n + DEFAULT_MINS_2;
				continue;
			}

			if ( !Q_stricmp( token, "movetype" ) ) 
			{
				if ( G_ParseString( &p, &value ) ) 
				{
					continue;
				}

				stats->moveType = (movetype_t)MoveTypeNameToEnum(value);
				continue;
			}
				
			// yawSpeed
			if ( !Q_stricmp( token, "yawSpeed" ) ) {
				if ( G_ParseInt( &p, &n ) ) {
					SkipRestOfLine( &p );
					continue;
				}
				if ( n <= 0) {
					gi.Printf(  "bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->yawSpeed = ((float)(n));
				continue;
			}

			// walkSpeed
			if ( !Q_stricmp( token, "walkSpeed" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->walkSpeed = n;
				continue;
			}
			
			//runSpeed
			if ( !Q_stricmp( token, "runSpeed" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->runSpeed = n;
				continue;
			}

			//acceleration
			if ( !Q_stricmp( token, "acceleration" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < 0 ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				stats->acceleration = n;
				continue;
			}
	//===MISC===============================================================================
			// default behavior
			if ( !Q_stricmp( token, "behavior" ) ) 
			{
				if ( G_ParseInt( &p, &n ) ) 
				{
					SkipRestOfLine( &p );
					continue;
				}
				if ( n < BS_DEFAULT || n >= NUM_BSTATES ) 
				{
					gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
					continue;
				}
				NPC->NPC->defaultBehavior = (bState_t)(n);
				continue;
			}

			// snd
			if ( !Q_stricmp( token, "snd" ) ) {
				if ( G_ParseString( &p, &value ) ) {
					continue;
				}
				if ( !(NPC->svFlags&SVF_NO_BASIC_SOUNDS) )
				{
					//FIXME: store this in some sound field or parse in the soundTable like the animTable...
					Q_strncpyz( sound, value, sizeof( sound ) );
					patch = strstr( sound, "/" );
					if ( patch ) 
					{
						*patch = 0;
					}
					ci->customBasicSoundDir = G_NewString( sound );
				}
				continue;
			}

			// sndcombat
			if ( !Q_stricmp( token, "sndcombat" ) ) {
				if ( G_ParseString( &p, &value ) ) {
					continue;
				}
				if ( !(NPC->svFlags&SVF_NO_COMBAT_SOUNDS) )
				{
					//FIXME: store this in some sound field or parse in the soundTable like the animTable...
					Q_strncpyz( sound, value, sizeof( sound ) );
					patch = strstr( sound, "/" );
					if ( patch ) 
					{
						*patch = 0;
					}
					ci->customCombatSoundDir = G_NewString( sound );
				}
				continue;
			}
			
			// sndextra
			if ( !Q_stricmp( token, "sndextra" ) ) {
				if ( G_ParseString( &p, &value ) ) {
					continue;
				}
				if ( !(NPC->svFlags&SVF_NO_EXTRA_SOUNDS) )
				{
					//FIXME: store this in some sound field or parse in the soundTable like the animTable...
					Q_strncpyz( sound, value, sizeof( sound ) );
					patch = strstr( sound, "/" );
					if ( patch ) 
					{
						*patch = 0;
					}
					ci->customExtraSoundDir = G_NewString( sound );
				}
				continue;
			}

			// sndscav
			if ( !Q_stricmp( token, "sndscav" ) ) {
				if ( G_ParseString( &p, &value ) ) {
					continue;
				}
				if ( !(NPC->svFlags&SVF_NO_SCAV_SOUNDS) )
				{
					//FIXME: store this in some sound field or parse in the soundTable like the animTable...
					Q_strncpyz( sound, value, sizeof( sound ) );
					patch = strstr( sound, "/" );
					if ( patch ) 
					{
						*patch = 0;
					}
					ci->customScavSoundDir = G_NewString( sound );
				}
				continue;
			}

			gi.Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, NPCName );
			SkipRestOfLine( &p );
		}
	}

	ci->infoValid = qfalse;

	if(	NPCsPrecached )
	{//Spawning in after initial precache, our models are precached, we just need to set our clientInfo
		CG_RegisterClientModels( NPC->s.number );
		CG_RegisterNPCCustomSounds( ci );
		CG_RegisterNPCEffects( NPC->client->playerTeam );
	}

	return qtrue;
}
/*
void NPC_Precache ( char *NPCName )

Precaches NPC skins, tgas and md3s.

*/
void NPC_Precache ( gentity_t *spawner )
{
	clientInfo_t	ci={0};
	renderInfo_t	ri={0};
	team_t			playerTeam = TEAM_FREE;
	char	*token;
	char	*value;
	char	*p;
	char	*patch;
	char	sound[MAX_QPATH];

	if ( !Q_stricmp( "random", spawner->NPC_type ) )
	{//sorry, can't precache a random just yet
		return;
	}

	p = NPCParms;
	COM_BeginParseSession();

	// look for the right NPC
	while ( p ) 
	{
		token = COM_ParseExt( &p, qtrue );
		if ( token[0] == 0 )
			return;

		if ( !Q_stricmp( token, spawner->NPC_type ) ) 
		{
			break;
		}

		SkipBracedSection( &p );
	}

	if ( !p ) 
	{
		return;
	}

	if ( G_ParseLiteral( &p, "{" ) ) 
	{
		return;
	}

	// parse the NPC info block
	while ( 1 ) 
	{
		token = COM_ParseExt( &p, qtrue );
		if ( !token[0] ) 
		{
			gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", spawner->NPC_type );
			return;
		}

		if ( !Q_stricmp( token, "}" ) ) 
		{
			break;
		}

		// headmodel
		if ( !Q_stricmp( token, "headmodel" ) ) 
		{
			if ( G_ParseString( &p, &value ) ) 
			{
				continue;
			}

			if(!Q_stricmp("none", value))
			{
			}
			else
			{
				Q_strncpyz( ri.headModelName, value, sizeof(ri.headModelName), qtrue);
			}
			continue;
		}
		
		// torsomodel
		if ( !Q_stricmp( token, "torsomodel" ) ) 
		{
			if ( G_ParseString( &p, &value ) ) 
			{
				continue;
			}

			if(!Q_stricmp("none", value))
			{
			}
			else
			{
				Q_strncpyz( ri.torsoModelName, value, sizeof(ri.torsoModelName), qtrue);
			}
			continue;
		}

		// legsmodel
		if ( !Q_stricmp( token, "legsmodel" ) ) 
		{
			if ( G_ParseString( &p, &value ) ) 
			{
				continue;
			}
			Q_strncpyz( ri.legsModelName, value, sizeof(ri.legsModelName), qtrue);			
			continue;
		}

		// playerTeam
		if ( !Q_stricmp( token, "playerTeam" ) ) 
		{
			if ( G_ParseString( &p, &value ) ) 
			{
				continue;
			}
			playerTeam = TranslateTeamName(value);
			continue;
		}

		// snd
		if ( !Q_stricmp( token, "snd" ) ) {
			if ( G_ParseString( &p, &value ) ) {
				continue;
			}
			if ( !(spawner->svFlags&SVF_NO_BASIC_SOUNDS) )
			{
				//FIXME: store this in some sound field or parse in the soundTable like the animTable...
				Q_strncpyz( sound, value, sizeof( sound ) );
				patch = strstr( sound, "/" );
				if ( patch ) 
				{
					*patch = 0;
				}
				ci.customBasicSoundDir = G_NewString( sound );
			}
			continue;
		}

		// sndcombat
		if ( !Q_stricmp( token, "sndcombat" ) ) {
			if ( G_ParseString( &p, &value ) ) {
				continue;
			}
			if ( !(spawner->svFlags&SVF_NO_COMBAT_SOUNDS) )
			{
				//FIXME: store this in some sound field or parse in the soundTable like the animTable...
				Q_strncpyz( sound, value, sizeof( sound ) );
				patch = strstr( sound, "/" );
				if ( patch ) 
				{
					*patch = 0;
				}
				ci.customCombatSoundDir = G_NewString( sound );
			}
			continue;
		}
		
		// sndextra
		if ( !Q_stricmp( token, "sndextra" ) ) {
			if ( G_ParseString( &p, &value ) ) {
				continue;
			}
			if ( !(spawner->svFlags&SVF_NO_EXTRA_SOUNDS) )
			{
				//FIXME: store this in some sound field or parse in the soundTable like the animTable...
				Q_strncpyz( sound, value, sizeof( sound ) );
				patch = strstr( sound, "/" );
				if ( patch ) 
				{
					*patch = 0;
				}
				ci.customExtraSoundDir = G_NewString( sound );
			}
			continue;
		}

		// sndscav
		if ( !Q_stricmp( token, "sndscav" ) ) {
			if ( G_ParseString( &p, &value ) ) {
				continue;
			}
			if ( !(spawner->svFlags&SVF_NO_SCAV_SOUNDS) )
			{
				//FIXME: store this in some sound field or parse in the soundTable like the animTable...
				Q_strncpyz( sound, value, sizeof( sound ) );
				patch = strstr( sound, "/" );
				if ( patch ) 
				{
					*patch = 0;
				}
				ci.customScavSoundDir = G_NewString( sound );
			}
			continue;
		}
	}

	CG_RegisterClientRenderInfo( &ci, &ri );
	CG_RegisterNPCCustomSounds( &ci );
	CG_RegisterNPCEffects( playerTeam );
	//FIXME: precache the beam-in/exit sound and effect if not silentspawn
	//FIXME: Look for a "sounds" directory and precache death, pain, alert sounds
}
void NPC_PrecacheAnimationCFG( const char *NPC_type )
{
	char	*token;
	char	*value;
	char	*p;
	int		junk;

	if ( !Q_stricmp( "random", NPC_type ) )
	{//sorry, can't precache a random just yet
		return;
	}

	p = NPCParms;
	COM_BeginParseSession();

	// look for the right NPC
	while ( p ) 
	{
		token = COM_ParseExt( &p, qtrue );
		if ( token[0] == 0 )
			return;

		if ( !Q_stricmp( token, NPC_type ) ) 
		{
			break;
		}

		SkipBracedSection( &p );
	}

	if ( !p ) 
	{
		return;
	}

	if ( G_ParseLiteral( &p, "{" ) ) 
	{
		return;
	}

	// parse the NPC info block
	while ( 1 ) 
	{
		token = COM_ParseExt( &p, qtrue );
		if ( !token[0] ) 
		{
			gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPC_type );
			return;
		}

		if ( !Q_stricmp( token, "}" ) ) 
		{
			break;
		}

		// legsmodel
		if ( !Q_stricmp( token, "legsmodel" ) ) 
		{
			if ( G_ParseString( &p, &value ) ) 
			{
				continue;
			}
			G_ParseAnimFileSet( value, &junk, qfalse );
			return;
		}
	}
}
Example #14
0
int
NET_Socket ( char *net_interface, int port, netsrc_t type, int family )
{
	char Buf[BUFSIZ], *Host, *Service;
	int newsocket, Error;
	struct sockaddr_storage ss;
	struct addrinfo hints, *res, *ai;
	qboolean _true = true;
	int i = 1;

	struct ipv6_mreq mreq;
	cvar_t *mcast;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = family;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;
	hints.ai_flags = AI_PASSIVE;

	if (!net_interface || !net_interface[0] ||
		!Q_stricmp(net_interface, "localhost"))
	{
		Host = (family == AF_INET6) ? "::" : "0.0.0.0";
	}
	else
	{
		Host = net_interface;
	}

	if (port == PORT_ANY)
	{
		Service = NULL;
	}
	else
	{
		sprintf(Buf, "%5d", port);
		Service = Buf;
	}

	if ((Error = getaddrinfo(Host, Service, &hints, &res)))
	{
		return 0;
	}

	for (ai = res; ai != NULL; ai = ai->ai_next)
	{
		if ((newsocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1)
		{
			Com_Printf("NET_Socket: socket: %s\n", strerror(errno));
			continue;
		}

		/* make it non-blocking */
		if (ioctl(newsocket, FIONBIO, (char *)&_true) == -1)
		{
			Com_Printf("NET_Socket: ioctl FIONBIO: %s\n", strerror(errno));
			continue;
		}

		if (family == AF_INET)
		{
			/* make it broadcast capable */
			if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
			{
				Com_Printf("ERROR: NET_Socket: setsockopt SO_BROADCAST:%s\n",
						NET_ErrorString());
				return 0;
			}
		}

		/* make it reusable */
		if (setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)) == -1)
		{
			Com_Printf("ERROR: NET_Socket: setsockopt SO_REUSEADDR:%s\n",
						NET_ErrorString());
				return 0;
		}

		if (bind(newsocket, ai->ai_addr, ai->ai_addrlen) < 0)
		{
			Com_Printf("NET_Socket: bind: %s\n", strerror(errno));
		}
		else
		{
			memcpy(&ss, ai->ai_addr, ai->ai_addrlen);
			break;
		}
	}

	if (res != NULL)
	{
		freeaddrinfo(res);
	}

	if (ai == NULL)
	{
		return 0;
	}

	switch (ss.ss_family)
	{
		case AF_INET:
			break;

		case AF_INET6:
			/* Multicast outgoing interface is specified for
			   client and server (+set multicast <ifname>) */
			mcast = Cvar_Get("multicast", "NULL", CVAR_NOSET);
			multicast_interface = (strcmp(mcast->string, "NULL") ? mcast->string : NULL);

			if (multicast_interface != NULL)
			{
				/* multicast_interface is a global variable.
				   Also used in NET_SendPacket() */
				if ((mreq.ipv6mr_interface = if_nametoindex(multicast_interface)) == 0)
				{
					Com_Printf("NET_Socket: invalid interface: %s\n", multicast_interface);
				}

				if (setsockopt(newsocket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
							&mreq.ipv6mr_interface, sizeof(mreq.ipv6mr_interface)) < 0)
				{
					Com_Printf("NET_Socket: IPV6_MULTICAST_IF: %s\n", strerror(errno));
				}

				/* Join multicast group ONLY if server */
				if (type == NS_SERVER)
				{
					if (inet_pton(AF_INET6, QUAKE2MCAST, &mreq.ipv6mr_multiaddr.s6_addr) != 1)
					{
						Com_Printf("NET_Socket: inet_pton: %s\n", strerror(errno));
					}

					if (setsockopt(newsocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)
					{
						Com_Printf("NET_Socket: IPV6_JOIN_GROUP: %s\n", strerror(errno));
					}
				}
			}

			break;
	}

	return newsocket;
}
Example #15
0
/*
================
SV_SpawnServer

Change the server to a new map, taking all connected
clients along with it.
================
*/
void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve )
{
	int			i;
	int			checksum;

// The following fixes for potential issues only work on Xbox
#ifdef _XBOX
	extern qboolean stop_icarus;
	stop_icarus = qfalse;

	//Broken scripts may leave the player locked.  I think that's always bad.
	extern qboolean player_locked;
	player_locked = qfalse;

	//If you quit while in Matrix Mode, this never gets cleared!
	extern qboolean MatrixMode;
	MatrixMode = qfalse;

	// Temporary code to turn on HDR effect for specific maps only
	if (!Q_stricmp(server, "t3_rift"))
	{
		Cvar_Set( "r_hdreffect", "1" );
	}
	else
	{
		Cvar_Set( "r_hdreffect", "0" );
	}
#endif

	RE_RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve );


	Cvar_SetValue( "cl_paused", 0 );
	Cvar_Set( "timescale", "1" );//jic we were skipping

	// shut down the existing game if it is running
	SV_ShutdownGameProgs(qtrue);

	Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string);
	Com_Printf ("Server: %s\n",server);	

#ifdef _XBOX
	// disable vsync during load for speed
	qglDisable(GL_VSYNC);
#endif

	// don't let sound stutter and dump all stuff on the hunk
	CL_MapLoading();

	if (!CM_SameMap(server))
	{ //rww - only clear if not loading the same map
		CM_ClearMap();
	}
#ifndef _XBOX
	else if (CM_HasTerrain())
	{ //always clear when going between maps with terrain
		CM_ClearMap();
	}
#endif

	// Miniheap never changes sizes, so I just put it really early in mem.
	G2VertSpaceServer->ResetHeap();

#ifdef _XBOX
	// Deletes all textures
	R_DeleteTextures();
#endif
	Hunk_Clear();

	// Moved up from below to help reduce fragmentation
	if (svs.snapshotEntities)
	{
		Z_Free(svs.snapshotEntities);
		svs.snapshotEntities = NULL;
	}

	// wipe the entire per-level structure
	// Also moved up, trying to do all freeing before new allocs
	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
		if ( sv.configstrings[i] ) {
			Z_Free( sv.configstrings[i] );
			sv.configstrings[i] = NULL;
		}
	}

#ifdef _XBOX
	SV_ClearLastLevel();
#endif

	// Collect all the small allocations done by the cvar system
	// This frees, then allocates. Make it the last thing before other
	// allocations begin!
	Cvar_Defrag();

/*
		This is useful for debugging memory fragmentation.  Please don't
	   remove it.
*/
#ifdef _XBOX
	// We've over-freed the info array above, this puts it back into a working state
	Ghoul2InfoArray_Reset();

	extern void Z_DumpMemMap_f(void);
	extern void Z_Details_f(void);
	extern void Z_TagPointers(memtag_t);
	Z_DumpMemMap_f();
//	Z_TagPointers(TAG_ALL);
	Z_Details_f();
#endif

	// init client structures and svs.numSnapshotEntities
	// This is moved down quite a bit, but should be safe. And keeps
	// svs.clients right at the beginning of memory
	if ( !Cvar_VariableIntegerValue("sv_running") ) {
		SV_Startup();
	}

 	// clear out those shaders, images and Models
	R_InitImages();
	R_InitShaders();
	R_ModelInit();

	// allocate the snapshot entities 
	svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue );

	Music_SetLevelName(server);

	// toggle the server bit so clients can detect that a
	// server has changed
//!@	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// set nextmap to the same map, but it may be overriden
	// by the game startup or another console command
	Cvar_Set( "nextmap", va("map %s", server) );


	memset (&sv, 0, sizeof(sv));


	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
		sv.configstrings[i] = CopyString("");
	}

	sv.time = 1000;
	G2API_SetTime(sv.time,G2T_SV_TIME);

#ifdef _XBOX
	CL_StartHunkUsers();
	CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum );
	RE_LoadWorldMap(va("maps/%s.bsp", server));
#else
	CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum, qfalse );
#endif

	// set serverinfo visible name
	Cvar_Set( "mapname", server );

	Cvar_Set( "sv_mapChecksum", va("%i",checksum) );

	// serverid should be different each time
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );

	// clear physics interaction links
	SV_ClearWorld ();
	
	// media configstring setting should be done during
	// the loading stage, so connected clients don't have
	// to load during actual gameplay
	sv.state = SS_LOADING;

	// load and spawn all other entities
	SV_InitGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0 ;i < 3 ; i++ ) {
		ge->RunFrame( sv.time );
		sv.time += 100;
		G2API_SetTime(sv.time,G2T_SV_TIME);
	}
	ge->ConnectNavs(sv_mapname->string, sv_mapChecksum->integer);

	// create a baseline for more efficient communications
	SV_CreateBaseline ();

	for (i=0 ; i<1 ; i++) {
		// clear all time counters, because we have reset sv.time
		svs.clients[i].lastPacketTime = 0;
		svs.clients[i].lastConnectTime = 0;
		svs.clients[i].nextSnapshotTime = 0;

		// send the new gamestate to all connected clients
		if (svs.clients[i].state >= CS_CONNECTED) {
			char	*denied;

			// connect the client again
			denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ );	// firstTime = qfalse, qbFromSavedGame
			if ( denied ) {
				// this generally shouldn't happen, because the client
				// was connected before the level change
				SV_DropClient( &svs.clients[i], denied );
			} else {
				svs.clients[i].state = CS_CONNECTED;
				// when we get the next packet from a connected client,
				// the new gamestate will be sent
			}
		}
	}	

	// run another frame to allow things to look at all connected clients
	ge->RunFrame( sv.time );
	sv.time += 100;
	G2API_SetTime(sv.time,G2T_SV_TIME);


	// save systeminfo and serverinfo strings
	SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) );
	cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;

	SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
	cvar_modifiedFlags &= ~CVAR_SERVERINFO;

	// any media configstring setting now should issue a warning
	// and any configstring changes should be reliably transmitted
	// to all clients
	sv.state = SS_GAME;
	
	// send a heartbeat now so the master will get up to date info
	svs.nextHeartbeatTime = -9999999;

	Hunk_SetMark();
	Z_Validate();
	Z_Validate();
	Z_Validate();
	
	Com_Printf ("-----------------------------------\n");
}
Example #16
0
void
ClientCommand(edict_t *ent)
{
	char *cmd;

	if (!ent)
	{
		return;
	}

	if (!ent->client)
	{
		return; /* not fully in game yet */
	}

	cmd = gi.argv(0);

	if (Q_stricmp(cmd, "players") == 0)
	{
		Cmd_Players_f(ent);
		return;
	}

	if (Q_stricmp(cmd, "say") == 0)
	{
		Cmd_Say_f(ent, false, false);
		return;
	}

	if (Q_stricmp(cmd, "say_team") == 0)
	{
		Cmd_Say_f(ent, true, false);
		return;
	}

	if (Q_stricmp(cmd, "score") == 0)
	{
		Cmd_Score_f(ent);
		return;
	}

	if (Q_stricmp(cmd, "help") == 0)
	{
		Cmd_Help_f(ent);
		return;
	}

	if (level.intermissiontime)
	{
		return;
	}

	if (Q_stricmp(cmd, "use") == 0)
	{
		Cmd_Use_f(ent);
	}
	else if (Q_stricmp(cmd, "drop") == 0)
	{
		Cmd_Drop_f(ent);
	}
	else if (Q_stricmp(cmd, "give") == 0)
	{
		Cmd_Give_f(ent);
	}
	else if (Q_stricmp(cmd, "god") == 0)
	{
		Cmd_God_f(ent);
	}
	else if (Q_stricmp(cmd, "notarget") == 0)
	{
		Cmd_Notarget_f(ent);
	}
	else if (Q_stricmp(cmd, "noclip") == 0)
	{
		Cmd_Noclip_f(ent);
	}
	else if (Q_stricmp(cmd, "inven") == 0)
	{
		Cmd_Inven_f(ent);
	}
	else if (Q_stricmp(cmd, "invnext") == 0)
	{
		SelectNextItem(ent, -1);
	}
	else if (Q_stricmp(cmd, "invprev") == 0)
	{
		SelectPrevItem(ent, -1);
	}
	else if (Q_stricmp(cmd, "invnextw") == 0)
	{
		SelectNextItem(ent, IT_WEAPON);
	}
	else if (Q_stricmp(cmd, "invprevw") == 0)
	{
		SelectPrevItem(ent, IT_WEAPON);
	}
	else if (Q_stricmp(cmd, "invnextp") == 0)
	{
		SelectNextItem(ent, IT_POWERUP);
	}
	else if (Q_stricmp(cmd, "invprevp") == 0)
	{
		SelectPrevItem(ent, IT_POWERUP);
	}
	else if (Q_stricmp(cmd, "invuse") == 0)
	{
		Cmd_InvUse_f(ent);
	}
	else if (Q_stricmp(cmd, "invdrop") == 0)
	{
		Cmd_InvDrop_f(ent);
	}
	else if (Q_stricmp(cmd, "weapprev") == 0)
	{
		Cmd_WeapPrev_f(ent);
	}
	else if (Q_stricmp(cmd, "weapnext") == 0)
	{
		Cmd_WeapNext_f(ent);
	}
	else if (Q_stricmp(cmd, "weaplast") == 0)
	{
		Cmd_WeapLast_f(ent);
	}
	else if (Q_stricmp(cmd, "kill") == 0)
	{
		Cmd_Kill_f(ent);
	}
	else if (Q_stricmp(cmd, "putaway") == 0)
	{
		Cmd_PutAway_f(ent);
	}
	else if (Q_stricmp(cmd, "wave") == 0)
	{
		Cmd_Wave_f(ent);
	}
	else if (Q_stricmp(cmd, "playerlist") == 0)
	{
		Cmd_PlayerList_f(ent);
	}
	else /* anything that doesn't match a command will be a chat */
	{
		Cmd_Say_f(ent, false, true);
	}
}
Example #17
0
//-----------------------------------------------------
static qboolean VEH_TurretFindEnemies( Vehicle_t *pVeh, 
						 gentity_t *parent, 
						 turretStats_t *turretStats, 
						 int turretNum, int curMuzzle )
//-----------------------------------------------------
{
	qboolean	found = qfalse;
	int			i, count;
	float		bestDist = turretStats->fAIRange * turretStats->fAIRange;
	float		enemyDist;
	vec3_t		enemyDir, org, org2;
	qboolean	foundClient = qfalse;
	gentity_t	*entity_list[MAX_GENTITIES], *target, *bestTarget = NULL;

	WP_CalcVehMuzzle( parent, curMuzzle );
	VectorCopy( pVeh->m_vMuzzlePos[curMuzzle], org2 );

	count = G_RadiusList( org2, turretStats->fAIRange, parent, qtrue, entity_list );

	for ( i = 0; i < count; i++ )
	{
		trace_t	tr;
		target = entity_list[i];

		if ( target == parent 
			|| !target->takedamage 
			|| target->health <= 0 
			|| ( target->flags & FL_NOTARGET ))
		{
			continue;
		}
		if ( !target->client )
		{// only attack clients
			if ( !(target->flags&FL_BBRUSH)//not a breakable brush
				|| !target->takedamage//is a bbrush, but invincible
				|| (target->NPC_targetname&&parent->targetname&&Q_stricmp(target->NPC_targetname,parent->targetname)!=0) )//not in invicible bbrush, but can only be broken by an NPC that is not me
			{
				if ( target->s.weapon == WP_TURRET
					&& target->classname
					&& Q_strncmp( "misc_turret", target->classname, 11 ) == 0 )
				{//these guys we want to shoot at
				}
				else
				{
					continue;
				}
			}
			//else: we will shoot at bbrushes!
		}
		else if ( target->client->sess.sessionTeam == TEAM_SPECTATOR )
		{
			continue;
		}
		if ( target == ((gentity_t*)pVeh->m_pPilot)
			|| target->r.ownerNum == parent->s.number )
		{//don't get angry at my pilot or passengers?
			continue;
		}
		if ( parent->client
			&& parent->client->sess.sessionTeam )
		{
			if ( target->client )
			{
				if ( target->client->sess.sessionTeam == parent->client->sess.sessionTeam )
				{ 
					// A bot/client/NPC we don't want to shoot
					continue;
				}
			}
			else if ( target->teamnodmg == parent->client->sess.sessionTeam )
			{//some other entity that's allied with us
				continue;
			}
		}
		if ( !trap_InPVS( org2, target->r.currentOrigin ))
		{
			continue;
		}

		VectorCopy( target->r.currentOrigin, org );

		trap_Trace( &tr, org2, NULL, NULL, org, parent->s.number, MASK_SHOT );

		if ( tr.entityNum == target->s.number
			|| (!tr.allsolid && !tr.startsolid && tr.fraction == 1.0 ) )
		{
			// Only acquire if have a clear shot, Is it in range and closer than our best?
			VectorSubtract( target->r.currentOrigin, org2, enemyDir );
			enemyDist = VectorLengthSquared( enemyDir );

			if ( enemyDist < bestDist || (target->client && !foundClient))// all things equal, keep current
			{
				bestTarget = target;
				bestDist = enemyDist;
				found = qtrue;
				if ( target->client )
				{//prefer clients over non-clients
					foundClient = qtrue;
				}
			}
		}
	}

	if ( found )
	{
		pVeh->turretStatus[turretNum].enemyEntNum = bestTarget->s.number;
	}

	return found;
}
Example #18
0
void _MapExitLevel (char *NextMap)
{
	votelist_t *votemap = NULL;
	//Igor[Rock] BEGIN
	FILE *votefile;
	char buf[MAX_STR_LEN];
	//Igor[Rock] END

	if (_iCheckMapVotes ())
	{
		votemap = MapWithMostVotes (NULL);
		Q_strncpyz (NextMap, votemap->mapname, MAX_QPATH);
		gi.bprintf (PRINT_HIGH, "Next map was voted on and is %s.\n", NextMap);
	}

	//clear stats
	for (votemap = map_votes; votemap != NULL; votemap = votemap->next)
	{
		//Igor[Rock] BEGIN
		if (votemap->num_votes)
		{
			votemap->num_allvotes += votemap->num_votes;
			num_allvotes += votemap->num_votes;
		}
		if (Q_stricmp (level.mapname, votemap->mapname) == 0)
		{
			if (map_num_clients > 1)
			{
				if (votemap->num_allvotes < (map_num_clients / 2))
				{
					num_allvotes -= votemap->num_allvotes;
					votemap->num_allvotes = 0;
				}
				else
				{
					num_allvotes -= (map_num_clients / 2);
					votemap->num_allvotes -= (map_num_clients / 2);
				}
			}
			else
			{
				if (votemap->num_allvotes)
				{
					num_allvotes--;
					votemap->num_allvotes--;
				}
			}
		}
		//Igor[Rock] END
		votemap->num_votes = 0;
	}

	//Igor[Rock] BEGIN
	// Save the actual votes to a file
	votefile = fopen (maplistpath, "w");
	if (votefile != NULL)
	{
		sprintf (buf, "%d\n", num_allvotes);
		fputs (buf, votefile);

		for (votemap = map_votes; votemap != NULL; votemap = votemap->next)
		{
			sprintf (buf, "%s,%d\n", votemap->mapname, votemap->num_allvotes);
			fputs (buf, votefile);
		}

		fclose (votefile);
	}
	//Igor[Rock] END
	map_num_votes = 0;
	map_num_clients = 0;
	map_need_to_check_votes = true;
}
Example #19
0
/*
==================
SV_WriteDownloadToClient

Check to see if the client wants a file, open it if needed and start pumping the client
Fill up msg with data
==================
*/
void SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
{
	int curindex;
	int rate;
	int blockspersnap;
	int unreferenced = 1;
	char errorMessage[1024];
	char pakbuf[MAX_QPATH], *pakptr;
	int numRefPaks;

	if (!*cl->downloadName)
		return;	// Nothing being downloaded

	if(!cl->download)
	{
		qboolean idPack = qfalse;
		qboolean missionPack = qfalse;

 		// Chop off filename extension.
		Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName);
		pakptr = strrchr(pakbuf, '.');

		if(pakptr)
		{
			*pakptr = '\0';

			// Check for pk3 filename extension
			if(!Q_stricmp(pakptr + 1, "pk3"))
			{
				const char *referencedPaks = FS_ReferencedPakNames();

				// Check whether the file appears in the list of referenced
				// paks to prevent downloading of arbitrary files.
				Cmd_TokenizeStringIgnoreQuotes(referencedPaks);
				numRefPaks = Cmd_Argc();

				for(curindex = 0; curindex < numRefPaks; curindex++)
				{
					if(!FS_FilenameCompare(Cmd_Argv(curindex), pakbuf))
					{
						unreferenced = 0;

						// now that we know the file is referenced,
						// check whether it's legal to download it.
						missionPack = FS_idPak(pakbuf, "missionpack");
						idPack = missionPack;
						idPack = (qboolean)(idPack || FS_idPak(pakbuf, BASEGAME));

						break;
					}
				}
			}
		}

		cl->download = 0;

		// We open the file here
		if ( !sv_allowDownload->integer ||
			idPack || unreferenced ||
			( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) {
			// cannot auto-download file
			if(unreferenced)
			{
				Com_Printf("clientDownload: %d : \"%s\" is not referenced and cannot be downloaded.\n", (int) (cl - svs.clients), cl->downloadName);
				Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName);
			}
			else if (idPack) {
				Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", (int) (cl - svs.clients), cl->downloadName);
				if(missionPack)
				{
					Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n"
									"The Team Arena mission pack can be found in your local game store.", cl->downloadName);
				}
				else
				{
					Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName);
				}
			}
			else if ( !sv_allowDownload->integer ) {
				Com_Printf("clientDownload: %d : \"%s\" download disabled\n", (int) (cl - svs.clients), cl->downloadName);
				if (sv_pure->integer) {
					Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"
										"You will need to get this file elsewhere before you "
										"can connect to this pure server.\n", cl->downloadName);
				} else {
					Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"
                    "The server you are connecting to is not a pure server, "
                    "set autodownload to No in your settings and you might be "
                    "able to join the game anyway.\n", cl->downloadName);
				}
			} else {
        // NOTE TTimo this is NOT supposed to happen unless bug in our filesystem scheme?
        //   if the pk3 is referenced, it must have been found somewhere in the filesystem
				Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", (int) (cl - svs.clients), cl->downloadName);
				Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName);
			}
			MSG_WriteByte( msg, svc_download );
			MSG_WriteShort( msg, 0 ); // client is expecting block zero
			MSG_WriteLong( msg, -1 ); // illegal file size
			MSG_WriteString( msg, errorMessage );

			*cl->downloadName = 0;

			if(cl->download)
				FS_FCloseFile(cl->download);

			return;
		}

		Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName );

		// Init
		cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0;
		cl->downloadCount = 0;
		cl->downloadEOF = qfalse;
	}

	// Perform any reads that we need to
	while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW &&
		cl->downloadSize != cl->downloadCount) {

		curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW);

		if (!cl->downloadBlocks[curindex])
			cl->downloadBlocks[curindex] = (unsigned char *)Z_Malloc( MAX_DOWNLOAD_BLKSIZE, TAG_DOWNLOAD, qtrue );

		cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download );

		if (cl->downloadBlockSize[curindex] < 0) {
			// EOF right now
			cl->downloadCount = cl->downloadSize;
			break;
		}

		cl->downloadCount += cl->downloadBlockSize[curindex];

		// Load in next block
		cl->downloadCurrentBlock++;
	}

	// Check to see if we have eof condition and add the EOF block
	if (cl->downloadCount == cl->downloadSize &&
		!cl->downloadEOF &&
		cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) {

		cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0;
		cl->downloadCurrentBlock++;

		cl->downloadEOF = qtrue;  // We have added the EOF block
	}

	// Loop up to window size times based on how many blocks we can fit in the
	// client snapMsec and rate

	// based on the rate, how many bytes can we fit in the snapMsec time of the client
	// normal rate / snapshotMsec calculation
	rate = cl->rate;
	if ( sv_maxRate->integer ) {
		if ( sv_maxRate->integer < 1000 ) {
			Cvar_Set( "sv_MaxRate", "1000" );
		}
		if ( sv_maxRate->integer < rate ) {
			rate = sv_maxRate->integer;
		}
	}

	if (!rate) {
		blockspersnap = 1;
	} else {
		blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) /
			MAX_DOWNLOAD_BLKSIZE;
	}

	if (blockspersnap < 0)
		blockspersnap = 1;

	while (blockspersnap--) {

		// Write out the next section of the file, if we have already reached our window,
		// automatically start retransmitting

		if (cl->downloadClientBlock == cl->downloadCurrentBlock)
			return; // Nothing to transmit

		if (cl->downloadXmitBlock == cl->downloadCurrentBlock) {
			// We have transmitted the complete window, should we start resending?
			if (svs.time - cl->downloadSendTime > MAX_DOWNLOAD_BLKSIZE * 1000 / rate)
				cl->downloadXmitBlock = cl->downloadClientBlock;
			else
				return;
		}

		// Send current block
		curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW);

		MSG_WriteByte( msg, svc_download );
		MSG_WriteShort( msg, cl->downloadXmitBlock );

		// block zero is special, contains file size
		if ( cl->downloadXmitBlock == 0 )
			MSG_WriteLong( msg, cl->downloadSize );

		MSG_WriteShort( msg, cl->downloadBlockSize[curindex] );

		// Write the block
		if ( cl->downloadBlockSize[curindex] ) {
			MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] );
		}

		Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock );

		// Move on to the next block
		// It will get sent with next snap shot.  The rate will keep us in line.
		cl->downloadXmitBlock++;

		cl->downloadSendTime = svs.time;
	}
}
Example #20
0
static void Z_TagDebug_f(void)
{
	TagBlockLabels_t AllTagBlockLabels_Local;
	qboolean bSnapShotTestActive = qfalse;

	memtag_t eTag = TAG_ALL;

	const char *psTAGName = Cmd_Argv(1);
	if (psTAGName[0])
	{
		// check optional arg...
		//
		if (!Q_stricmp(psTAGName,"#snap"))
		{
			bSnapShotTestActive = qtrue;

			AllTagBlockLabels_Local = AllTagBlockLabels;	// horrible great STL copy

			psTAGName = Cmd_Argv(2);			
		}

		if (psTAGName[0])
		{
			// skip over "tag_" if user supplied it...
			//
			if (!Q_stricmpn(psTAGName,"TAG_",4))
			{
				psTAGName += 4;
			}

			// see if the user specified a valid tag...
			//
			for (int i=0; i<TAG_COUNT; i++)
			{
				if (!Q_stricmp(psTAGName,psTagStrings[i]))
				{
					eTag = (memtag_t) i;
					break;
				}
			}
		}
	}
	else
	{
		Com_Printf("Usage: 'zone_tagdebug [#snap] <tag>', e.g. TAG_GHOUL2, TAG_ALL (careful!)\n");
		return;
	}

	Com_Printf("Dumping debug data for tag \"%s\"...%s\n\n",psTagStrings[eTag], bSnapShotTestActive?"( since snapshot only )":"");

	Com_Printf("%8s"," ");	// to compensate for code further down:   Com_Printf("(%5d) ",iBlocksListed);
	if (eTag == TAG_ALL)
	{
		Com_Printf("%20s ","Zone Tag");
	}
	Com_Printf("%9s\n","Bytes");
	Com_Printf("%8s"," ");
	if (eTag == TAG_ALL)
	{
		Com_Printf("%20s ","--------");
	}
	Com_Printf("%9s\n","-----");


	if (bSnapShotTestActive)
	{
		// dec ref counts in last snapshot for all current blocks (which will make new stuff go negative)
		//
		zoneHeader_t *pMemory = TheZone.Header.pNext;
		while (pMemory)
		{
			if (pMemory->eTag == eTag || eTag == TAG_ALL)
			{
				AllTagBlockLabels_Local[psTagStrings[pMemory->eTag]][pMemory->sOptionalLabel]--;
			}
			pMemory = pMemory->pNext;		
		}
	}

	// now dump them out...
	//
	int iBlocksListed = 0;
	int iTotalSize = 0;
	zoneHeader_t *pMemory = TheZone.Header.pNext;
	while (pMemory)
	{
		if (	(pMemory->eTag == eTag	|| eTag == TAG_ALL)
			&&  (!bSnapShotTestActive	|| (pMemory->iSnapshotNumber == giZoneSnaphotNum && AllTagBlockLabels_Local[psTagStrings[pMemory->eTag]][pMemory->sOptionalLabel] <0) )
			)
		{
			float	fSize		= (float)(pMemory->iSize) / 1024.0f / 1024.0f;
			int		iSize		= fSize;
			int		iRemainder 	= 100.0f * (fSize - floor(fSize));

			Com_Printf("(%5d) ",iBlocksListed);

			if (eTag == TAG_ALL)
			{
				Com_Printf("%20s",psTagStrings[pMemory->eTag]);
			}

			Com_Printf(" %9d (%2d.%02dMB) File: \"%s\", Line: %d\n",
						  pMemory->iSize,
 							  iSize,iRemainder,
												pMemory->sSrcFileBaseName,
															pMemory->iSrcFileLineNum
					   );
			if (pMemory->sOptionalLabel[0])
			{
				Com_Printf("( Label: \"%s\" )\n",pMemory->sOptionalLabel);
			}
			iBlocksListed++;
			iTotalSize += pMemory->iSize;
			
			if (bSnapShotTestActive)
			{
				// bump ref count so we only 1 warning per new string, not for every one sharing that label...
				//
				AllTagBlockLabels_Local[psTagStrings[pMemory->eTag]][pMemory->sOptionalLabel]++;
			}
		}
		pMemory = pMemory->pNext;		
	}

	Com_Printf("( %d blocks listed, %d bytes (%.2fMB) total )\n",iBlocksListed, iTotalSize, (float)iTotalSize / 1024.0f / 1024.0f);
}
Example #21
0
void SP_info_player_coop(edict_t *self){
	if(!coop->value){
		G_FreeEdict(self);
		return;
	}
	
	if((Q_stricmp(level.mapname, "jail2") == 0) ||
			(Q_stricmp(level.mapname, "jail4") == 0) ||
			(Q_stricmp(level.mapname, "mine1") == 0) ||
			(Q_stricmp(level.mapname, "mine2") == 0) ||
			(Q_stricmp(level.mapname, "mine3") == 0) ||
			(Q_stricmp(level.mapname, "mine4") == 0) ||
			(Q_stricmp(level.mapname, "lab") == 0) ||
			(Q_stricmp(level.mapname, "boss1") == 0) ||
			(Q_stricmp(level.mapname, "fact3") == 0) ||
			(Q_stricmp(level.mapname, "biggun") == 0) ||
			(Q_stricmp(level.mapname, "space") == 0) ||
			(Q_stricmp(level.mapname, "command") == 0) ||
			(Q_stricmp(level.mapname, "power2") == 0) ||
			(Q_stricmp(level.mapname, "strike") == 0)){
		// invoke one of our gross, ugly, disgusting hacks
		self->think = SP_FixCoopSpots;
		self->nextthink = level.time + FRAMETIME;
	}
}
Example #22
0
/*
============
Cmd_SetCommandCompletionFunc
============
*/
void Cmd_SetCommandCompletionFunc( const char *command, completionFunc_t complete ) {
	for ( cmd_function_t *cmd=cmd_functions; cmd; cmd=cmd->next ) {
		if ( !Q_stricmp( command, cmd->name ) )
			cmd->complete = complete;
	}
}
void CG_DrawFireTeamOverlay( rectDef_t* rect ) {
	int x = rect->x;
	int y = rect->y + 1;	// +1, jitter it into place in 1024 :)
	int boxWidth = 204;
	int bestWidth = -1;
	char *locStr[MAX_FIRETEAM_MEMBERS];
	vec2_t loc;
	float h;
	clientInfo_t* ci = NULL;
	char buffer[64];
	fireteamData_t* f = NULL;
	int i;
	vec4_t clr1 =	{ .16f,		.2f,	.17f,	.8f };
	vec4_t clr2 =	{ 0.f,		0.f,		0.f,		.2f };
	vec4_t clr3 =	{ 0.25f,		0.f,		0.f,		153/255.f };
	vec4_t tclr =	{ 0.6f,		0.6f,		0.6f,		1.0f };
	vec4_t bgColor		= { 0.0f, 0.0f, 0.0f, 0.6f };		// window
	vec4_t borderColor	= { 0.5f, 0.5f, 0.5f, 0.5f };	// window
	centity_t*	cent;

	bgColor[3] = cg_fireteamAlpha.value;

	if(cg.hudEditor.showHudEditor) {
		//draw a fake fireteam box...
		CG_DrawFakeFireTeamOverlay(rect);
		return;
	} else 	if(!(f = CG_IsOnFireteam( cg.clientNum ))) {
		return;
	}

	h = 12 + 2 + 2;
	for(i = 0; i < MAX_FIRETEAM_MEMBERS; i++) {
		int		locwidth;
		vec3_t	origin;

		ci = CG_SortedFireTeamPlayerForPosition( i );
		if(!ci) {
			break;
		}

		h += FT_BAR_HEIGHT + FT_BAR_YSPACING;

		loc[0] = ci->location[0];
		loc[1] = ci->location[1];

		if(cg_locations.integer > 0) {
			qboolean locValid = qtrue;
			cent = &cg_entities[ci->clientNum];

			// Dens: use lerpOrigin for now
			origin[0] = cent->lerpOrigin[0];
			origin[1] = cent->lerpOrigin[1];
			origin[2] = cent->lerpOrigin[2];
	
			locStr[i] = va( "^3%s", CG_GetLocationMsg(origin));

			if (!Q_stricmp( locStr[i], "^3Unknown")){
				locStr[i] = va( "^3(%s)", BG_GetLocationString( loc ));
				locValid = qfalse;
			}

			if(cg_locations.integer > 1 && locValid)
				Q_strcat( locStr[i], 64, va(" ^3(%s)", BG_GetLocationString( loc )) );

		} else {
			locStr[i] = va( "^3(%s)", BG_GetLocationString( loc ));
		}

		if( !locStr[i][1] || !*locStr[i] )
			locStr[i] = " ";
	
		locwidth = CG_Text_Width_Ext( locStr[i], 0.2f, 0, &cgs.media.font3 );
	
		if(locwidth > bestWidth)
			bestWidth = locwidth;
	}

	boxWidth += bestWidth;

	CG_DrawRect( x, y, boxWidth, h, 1, borderColor);
	CG_FillRect( x + 1, y + 1, boxWidth - 2, h - 2, bgColor);

	x += 2;
	y += 2;

	CG_FillRect( x, y, boxWidth - 4, 12, clr1 );

	Com_sprintf( buffer, 64, "Fireteam: %s", bg_fireteamNames[f->ident] );
	//sprintf( buffer, "Fireteam: %s", bg_fireteamNames[f->ident] );
	Q_strupr( buffer );
	CG_Text_Paint_Ext( x + 3, y + FT_BAR_HEIGHT, .19f, .19f, tclr, buffer, 0, 0, 0, &cgs.media.font1 );

	x += 2;
	//y += 2;

	for(i = 0; i < MAX_FIRETEAM_MEMBERS; i++) {
		y += FT_BAR_HEIGHT + FT_BAR_YSPACING;
		x = rect->x + 2;

		ci = CG_SortedFireTeamPlayerForPosition( i );
		if(!ci) {
			break;;
		}
		
		if( ci->selected ) {
			CG_FillRect( x, y + FT_BAR_YSPACING, boxWidth - 4, FT_BAR_HEIGHT, clr3 );
		} else {
			CG_FillRect( x, y + FT_BAR_YSPACING, boxWidth - 4, FT_BAR_HEIGHT, clr2 );
		}

		x += 4;
				
		//draw class
		if(cg_drawClassIcons.integer & CLASSICON_FIRETEAM){
			trap_R_SetColor( colorWhite );
			CG_DrawPic(x-2, y+2, FT_BAR_HEIGHT, FT_BAR_HEIGHT,
				cgs.media.skillPics[BG_ClassSkillForClass( ci->cls )]);
			trap_R_SetColor( NULL );
		}else{
			CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorWhite, BG_ClassLetterForNumber( ci->cls ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );	
		}
		x += 10;
		
		// quad: draw latched class
		// pheno: not with an old server, that doesn't send the latched class
		if( ci->cls != ci->latchClass && cgs.etpub > ETPUB_VERSION( 0, 8, 1 ) ) {
			//draw separator
			CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorYellow, ">", 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
			x += 10;
			
			//draw class
			if(cg_drawClassIcons.integer & CLASSICON_FIRETEAM) {
				trap_R_SetColor( colorYellow );
				CG_DrawPic(x - 2, y + 2, FT_BAR_HEIGHT, FT_BAR_HEIGHT,
					cgs.media.skillPics[BG_ClassSkillForClass(ci->latchClass)]);
				trap_R_SetColor(NULL);
			} else {
				CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorYellow, BG_ClassLetterForNumber( ci->latchClass ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
			}
			x += 10;
		}
		else
			x += 20;
		
		CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, ci->team == TEAM_AXIS ? miniRankNames_Axis[ci->rank] : miniRankNames_Allies[ci->rank], 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );	
		x += 22;
		
		CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, ci->name, 0, 17, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
		x += 90;

/*		CG_DrawPic(x + 2, y + 2, FT_BAR_HEIGHT - 4, FT_BAR_HEIGHT - 4, cgs.media.movementAutonomyIcons[0]);
		x += FT_BAR_HEIGHT;

		CG_DrawPic(x + 2, y + 2, FT_BAR_HEIGHT - 4, FT_BAR_HEIGHT - 4, cgs.media.weaponAutonomyIcons[0]);
		x += FT_BAR_HEIGHT;
		x += 4;*/

/*		if( isLeader ) {
			CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, va("%i", i+4), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
		}*/
		x += 20;
		
		if( ci->health > 80 ) {
			CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT,  .2f, .2f, tclr, va("%i", ci->health < 0 ? 0 : ci->health ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
		} else if( ci->health > 0 ) {
			CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT,  .2f, .2f, colorYellow, va("%i", ci->health < 0 ? 0 : ci->health ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
		} else {
			CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT,  .2f, .2f, colorRed, va("0%s", ci->health < 0 ? "" : "*" ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
		}
		x += 30;

		CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT,  .2f, .2f, tclr, locStr[i], 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.font3 );
	}
}