Beispiel #1
0
/*
* G_SpawnQueue_AddClient
*/
void G_SpawnQueue_AddClient( edict_t *ent )
{
	g_teamspawnqueue_t *queue;
	int i;

	if( !ent || !ent->r.client )
		return;

	if( ENTNUM( ent ) <= 0 || ENTNUM( ent ) > gs.maxclients )
		return;

	if( ent->r.client->team < TEAM_SPECTATOR|| ent->r.client->team >= GS_MAX_TEAMS )
		return;

	queue = &g_spawnQueues[ent->r.client->team];

	for( i = queue->start; i < queue->head; i++ )
	{
		if( queue->list[i % MAX_CLIENTS] == ENTNUM( ent ) )
			return;
	}

	G_SpawnQueue_RemoveClient( ent );
	queue->list[queue->head % MAX_CLIENTS] = ENTNUM( ent );
	queue->head++;

	if( queue->spectate_team )
		G_ChasePlayer( ent, NULL, true, 0 );
}
Beispiel #2
0
/*
* G_ClearSnap
* We just run G_SnapFrame, the server just sent the snap to the clients,
* it's now time to clean up snap specific data to start the next snap from clean.
*/
void G_ClearSnap( void )
{
	edict_t	*ent;

	game.realtime = trap_Milliseconds(); // level.time etc. might not be real time

	// clear gametype's clock override
	gs.gameState.longstats[GAMELONG_CLOCKOVERRIDE] = 0;

	// clear all events in the snap
	for( ent = &game.edicts[0]; ENTNUM( ent ) < game.numentities; ent++ )
	{
		if( ISEVENTENTITY( &ent->s ) )  // events do not persist after a snapshot
		{
			G_FreeEdict( ent );
			continue;
		}

		// events only last for a single message
		ent->s.events[0] = ent->s.events[1] = 0;
		ent->s.eventParms[0] = ent->s.eventParms[1] = 0;
		ent->numEvents = 0;
		ent->eventPriority[0] = ent->eventPriority[1] = false;
		ent->s.teleported = qfalse; // remove teleported bit.

		// remove effect bits that are (most likely) added from gametypes
		ent->s.effects = ( ent->s.effects & (EF_TAKEDAMAGE|EF_CARRIER|EF_FLAG_TRAIL|EF_ROTATE_AND_BOB|EF_STRONG_WEAPON|EF_GHOST) );
	}

	// recover some info, let players respawn and finally clear the snap structures
	for( ent = &game.edicts[0]; ENTNUM( ent ) < game.numentities; ent++ )
	{
		if( !GS_MatchPaused() )
		{
			// copy origin to old origin ( this old_origin is for snaps )
			if( !( ent->r.svflags & SVF_TRANSMITORIGIN2 ) )
				VectorCopy( ent->s.origin, ent->s.old_origin );

			G_CheckClientRespawnClick( ent );
		}

		if( GS_MatchPaused() )
			ent->s.sound = entity_sound_backup[ENTNUM( ent )];

		// clear the snap temp info
		memset( &ent->snap, 0, sizeof( ent->snap ) );
		if( ent->r.client && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED )
		{
			memset( &ent->r.client->resp.snap, 0, sizeof( ent->r.client->resp.snap ) );

			// set race stats to invisible
			RS_clearHUDStats( ent->r.client ); // racesow - clear with our function
		}
	}

	g_snapStarted = false;
}
Beispiel #3
0
/*
* G_Client_DeadView
*/
static void G_Client_DeadView( edict_t *ent )
{
	edict_t	*body;
	gclient_t *client;
	trace_t	trace;

	client = ent->r.client;

	// find the body
	for( body = game.edicts + gs.maxclients; ENTNUM( body ) < gs.maxclients + BODY_QUEUE_SIZE + 1; body++ )
	{
		if( !body->r.inuse || body->r.svflags & SVF_NOCLIENT )
			continue;
		if( body->activator == ent )  // this is our body
			break;
	}

	if( body->activator != ent )
	{                          // ran all the list and didn't find our body
		return;
	}

	// move us to body position
	VectorCopy( body->s.origin, ent->s.origin );
	VectorCopy( body->s.origin, ent->s.old_origin );
	ent->s.teleported = qtrue;
	client->ps.viewangles[ROLL] = 0;
	client->ps.viewangles[PITCH] = 0;

	// see if our killer is still in view
	if( body->enemy && ( body->enemy != ent ) )
	{
		G_Trace( &trace, ent->s.origin, vec3_origin, vec3_origin, body->enemy->s.origin, body, MASK_OPAQUE );
		if( trace.fraction != 1.0f )
		{
			body->enemy = NULL;
		}
		else
		{
			client->ps.viewangles[YAW] = LookAtKillerYAW( ent, NULL, body->enemy );
		}
	}
	else
	{    // nobody killed us, so just circle around the body ?

	}

	G_ProjectThirdPersonView( ent->s.origin, client->ps.viewangles, body );
	VectorCopy( client->ps.viewangles, ent->s.angles );
	VectorCopy( ent->s.origin, client->ps.pmove.origin );
	VectorClear( client->ps.pmove.velocity );

	GS_SnapPosition( client->ps.pmove.origin, ent->r.mins, ent->r.maxs, ENTNUM( ent ), 0 );
}
Beispiel #4
0
static unsigned int G_FindPointedPlayer( edict_t *self ) {
	trace_t trace;
	int i, j, bestNum = 0;
	vec3_t boxpoints[8];
	float value, dist, value_best = 0.90f;   // if nothing better is found, print nothing
	edict_t *other;
	vec3_t vieworg, dir, viewforward;

	if( G_IsDead( self ) ) {
		return 0;
	}

	// we can't handle the thirdperson modifications in server side :/
	VectorSet( vieworg, self->r.client->ps.pmove.origin[0], self->r.client->ps.pmove.origin[1], self->r.client->ps.pmove.origin[2] + self->r.client->ps.viewheight );
	AngleVectors( self->r.client->ps.viewangles, viewforward, NULL, NULL );

	for( i = 0; i < gs.maxclients; i++ ) {
		other = PLAYERENT( i );
		if( !other->r.inuse ) {
			continue;
		}
		if( !other->r.client ) {
			continue;
		}
		if( other == self ) {
			continue;
		}
		if( !other->r.solid || ( other->r.svflags & SVF_NOCLIENT ) ) {
			continue;
		}

		VectorSubtract( other->s.origin, self->s.origin, dir );
		dist = VectorNormalize2( dir, dir );
		if( dist > 1000 ) {
			continue;
		}

		value = DotProduct( dir, viewforward );

		if( value > value_best ) {
			BuildBoxPoints( boxpoints, other->s.origin, tv( 4, 4, 4 ), tv( 4, 4, 4 ) );
			for( j = 0; j < 8; j++ ) {
				G_Trace( &trace, vieworg, vec3_origin, vec3_origin, boxpoints[j], self, MASK_SHOT | MASK_OPAQUE );
				if( trace.ent && trace.ent == ENTNUM( other ) ) {
					value_best = value;
					bestNum = ENTNUM( other );
				}
			}
		}
	}

	return bestNum;
}
Beispiel #5
0
static int G_Teams_CompareMembers( const void *a, const void *b )
{
	edict_t *edict_a = game.edicts + *(int *)a;
	edict_t *edict_b = game.edicts + *(int *)b;
	int score_a = edict_a->r.client->level.stats.score;
	int score_b = edict_b->r.client->level.stats.score;
	int result = ( level.gametype.inverseScore ? -1 : 1 ) * ( score_b - score_a );
	if (!result)
		result = Q_stricmp( edict_a->r.client->netname, edict_b->r.client->netname );
	if (!result)
		result = ENTNUM( edict_a ) - ENTNUM( edict_b );
	return result;
}
Beispiel #6
0
void G_ScoreboardMessage_AddChasers( int entnum, int entnum_self )
{
	char entry[MAX_TOKEN_CHARS];
	int i;
	edict_t *e;
	size_t len;

	len = strlen( scoreboardString );
	if( !len )
		return;

	// add personal spectators
	Q_strncpyz( entry, "&y ", sizeof( entry ) );
	ADD_SCOREBOARD_ENTRY( scoreboardString, len, entry );

	for( i = 0; i < teamlist[TEAM_SPECTATOR].numplayers; i++ )
	{
		e = game.edicts + teamlist[TEAM_SPECTATOR].playerIndices[i];

		if( ENTNUM( e ) == entnum_self )
			continue;

		if( e->r.client->connecting || trap_GetClientState( PLAYERNUM( e ) ) < CS_SPAWNED )
			continue;

		if( !e->r.client->resp.chase.active || e->r.client->resp.chase.target != entnum )
			continue;

		Q_snprintfz( entry, sizeof( entry ), "%i ", PLAYERNUM( e ) );
		ADD_SCOREBOARD_ENTRY( scoreboardString, len, entry );
	}
}
Beispiel #7
0
//Sunflower spiral with Fibonacci numbers 
static void G_Fire_SunflowerPattern( edict_t *self, vec3_t start, vec3_t dir, int *seed, int count, 
	int hspread, int vspread, int range, float damage, int kick, int stun, int dflags, int mod, int timeDelta )
{
	int i;
	float r;
	float u;
	float fi;
	trace_t trace;

	for( i = 0; i < count; i++ )
	{
		fi = i * 2.4; //magic value creating Fibonacci numbers
		r = cos( (float)*seed + fi ) * hspread * sqrt(fi);
		u = sin( (float)*seed + fi ) * vspread * sqrt(fi); 

		GS_TraceBullet( &trace, start, dir, r, u, range, ENTNUM( self ), timeDelta );
		if( trace.ent != -1 )
		{
			if( game.edicts[trace.ent].takedamage )
			{
				G_Damage( &game.edicts[trace.ent], self, self, dir, dir, trace.endpos, damage, kick, stun, dflags, mod );
			}
			else
			{
				if( !( trace.surfFlags & SURF_NOIMPACT ) )
				{
				}
			}
		}
	}
}
Beispiel #8
0
void G_PlayerAward( edict_t *ent, const char *awardMsg )
{
	edict_t *other;
	char cmd[MAX_STRING_CHARS];
	gameaward_t *ga;
	int i, size;
	score_stats_t *stats;

	if( !awardMsg || !awardMsg[0] || !ent->r.client )
		return;

	Q_snprintfz( cmd, sizeof( cmd ), "aw \"%s\"", awardMsg );
	trap_GameCmd( ent, cmd );

	if( dedicated->integer )
		G_Printf( "%s", COM_RemoveColorTokens( va( "%s receives a '%s' award.\n", ent->r.client->netname, awardMsg ) ) );

	ent->r.client->level.stats.awards++;
	teamlist[ent->s.team].stats.awards++;
	G_Gametype_ScoreEvent( ent->r.client, "award", awardMsg );

	stats = &ent->r.client->level.stats;
	if( !stats->awardAllocator )
		stats->awardAllocator = LinearAllocator( sizeof( gameaward_t ), 0, _G_LevelMalloc, _G_LevelFree );

	// ch : this doesnt work for race right?
	if( GS_MatchState() == MATCH_STATE_PLAYTIME || GS_MatchState() == MATCH_STATE_POSTMATCH )
	{
		// ch : we store this locally to send to MM
		// first check if we already have this one on the clients list
		size = LA_Size( stats->awardAllocator );
		ga = NULL;
		for( i = 0; i < size; i++ )
		{
			ga = ( gameaward_t * )LA_Pointer( stats->awardAllocator, i );
			if( !strncmp( ga->name, awardMsg, sizeof(ga->name)-1 ) )
				break;
		}

		if( i >= size )
		{
			ga = ( gameaward_t * )LA_Alloc( stats->awardAllocator );
			memset( ga, 0, sizeof(*ga) );
			ga->name = G_RegisterLevelString( awardMsg );
		}

		if( ga )
			ga->count++;
	}

	// add it to every player who's chasing this player
	for( other = game.edicts + 1; PLAYERNUM( other ) < gs.maxclients; other++ )
	{
		if( !other->r.client || !other->r.inuse || !other->r.client->resp.chase.active )
			continue;

		if( other->r.client->resp.chase.target == ENTNUM( ent ) )
			trap_GameCmd( other, cmd );
	}
}
Beispiel #9
0
/*
* GClip_FindBoxInRadius
* Returns entities that have their boxes within a spherical area
*/
edict_t *GClip_FindBoxInRadius4D( edict_t *from, vec3_t org, float rad, int timeDelta )
{
	int i, j;
	c4clipedict_t *check;
	vec3_t mins, maxs;
	int fromNum;

	if( !from ) from = world;
	fromNum = ENTNUM( from ) + 1;

	for( i = fromNum; i < game.numentities; i++ )
	{
		if( !game.edicts[i].r.inuse )
			continue;

		check = GClip_GetClipEdictForDeltaTime( i, timeDelta );
		if( !check->r.inuse )
			continue;
		if( check->r.solid == SOLID_NOT )
			continue;
		// make absolute mins and maxs
		for( j = 0; j < 3; j++ )
		{
			mins[j] = check->s.origin[j] + check->r.mins[j];
			maxs[j] = check->s.origin[j] + check->r.maxs[j];
		}
		if( !BoundsAndSphereIntersect( mins, maxs, org, rad ) )
			continue;

		return &game.edicts[i]; // return realtime entity
	}

	return NULL;
}
Beispiel #10
0
/*
* AI_InitEntitiesData
*/
void AI_InitEntitiesData( void )
{
	int newlinks, newjumplinks;
	edict_t *ent;

	if( !nav.num_nodes )
	{
		if( g_numbots->integer ) trap_Cvar_Set( "g_numbots", "0" );
		return;
	}

	// create nodes for navigable map entities ( must happen after finding teams )
	for( ent = game.edicts + 1 + gs.maxclients; ENTNUM( ent ) < game.numentities; ent++ )
		AI_AddNavigableEntity( ent );

	// add all clients to goalEntities so they can be tracked as enemies
	for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ )
		AI_AddGoalEntity( ent );

	// link all newly added nodes
	newlinks = AI_LinkServerNodes( nav.serverNodesStart );
	newjumplinks = AI_LinkCloseNodes_JumpPass( nav.serverNodesStart );

	if( developer->integer )
	{
		G_Printf( "       : added nodes:%i.\n", nav.num_nodes - nav.serverNodesStart );
		G_Printf( "       : total nodes:%i.\n", nav.num_nodes );
		G_Printf( "       : added links:%i.\n", newlinks );
		G_Printf( "       : added jump links:%i.\n", newjumplinks );
	}

	G_Printf( "       : AI Navigation Initialized.\n" );

	nav.loaded = qtrue;
}
Beispiel #11
0
/*
* W_Touch_Plasma
*/
static void W_Touch_Plasma( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags )
{
	int hitType;
	vec3_t dir;

	if( surfFlags & SURF_NOIMPACT )
	{
		G_FreeEdict( ent );
		return;
	}

	hitType = G_Projectile_HitStyle( ent, other );
	if( hitType == PROJECTILE_TOUCH_NOT )
		return;

	if( other->takedamage )
	{
		VectorNormalize2( ent->velocity, dir );

		if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile
		{
			G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta );
		}
		else
		{
			VectorNormalize2( ent->velocity, dir );
		}

		G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, ent->projectileInfo.maxDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, DAMAGE_KNOCKBACK_SOFT, ent->style );
	}

	W_Plasma_Explosion( ent, other, plane, surfFlags );
}
Beispiel #12
0
/*
* G_RunEntities
* treat each object in turn
* even the world and clients get a chance to think
*/
static void G_RunEntities( void )
{
	edict_t	*ent;

	for( ent = &game.edicts[0]; ENTNUM( ent ) < game.numentities; ent++ )
	{
		if( !ent->r.inuse )
			continue;
		if( ISEVENTENTITY( &ent->s ) )
			continue; // events do not think

		level.current_entity = ent;

		// backup oldstate ( for world frame ).
		ent->olds = ent->s;

		// if the ground entity moved, make sure we are still on it
		if( !ent->r.client )
		{
			if( ( ent->groundentity ) && ( ent->groundentity->linkcount != ent->groundentity_linkcount ) )
				G_CheckGround( ent );
		}

		G_RunEntity( ent );

		if( ent->takedamage )
			ent->s.effects |= EF_TAKEDAMAGE;
		else
			ent->s.effects &= ~EF_TAKEDAMAGE;
	}
}
Beispiel #13
0
void G_Fire_SpiralPattern( edict_t *self, vec3_t start, vec3_t dir, int *seed, int count, int spread, int range, float damage, int kick, int stun, int dflags, int mod, int timeDelta )
{
	int i;
	float r;
	float u;
	trace_t trace;

	for( i = 0; i < count; i++ )
	{
		r = cos( *seed + i ) * spread * i;
		u = sin( *seed + i ) * spread * i;

		GS_TraceBullet( &trace, start, dir, r, u, range, ENTNUM( self ), timeDelta );
		if( trace.ent != -1 )
		{
			if( game.edicts[trace.ent].takedamage )
			{
				G_Damage( &game.edicts[trace.ent], self, self, dir, dir, trace.endpos, damage, kick, stun, dflags, mod );
			}
			else
			{
				if( !( trace.surfFlags & SURF_NOIMPACT ) )
				{
				}
			}
		}
	}
}
Beispiel #14
0
/*
* W_Touch_Rocket
*/
static void W_Touch_Rocket( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) {
	int mod_splash;
	vec3_t dir;
	int hitType;

	if( surfFlags & SURF_NOIMPACT ) {
		G_FreeEdict( ent );
		return;
	}

	hitType = G_Projectile_HitStyle( ent, other );
	if( hitType == PROJECTILE_TOUCH_NOT ) {
		return;
	}

	if( other->takedamage ) {
		int directHitDamage = ent->projectileInfo.maxDamage;

		VectorNormalize2( ent->velocity, dir );

		if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) { // use hybrid direction from splash and projectile

			G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta );
		} else {
			VectorNormalize2( ent->velocity, dir );

			if( hitType == PROJECTILE_TOUCH_DIRECTAIRHIT ) {
				directHitDamage += DIRECTAIRTHIT_DAMAGE_BONUS;
			} else if( hitType == PROJECTILE_TOUCH_DIRECTHIT ) {
				directHitDamage += DIRECTHIT_DAMAGE_BONUS;
			}
		}

		G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, directHitDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style );
	}

	if( ent->s.effects & EF_STRONG_WEAPON ) {
		mod_splash = MOD_ROCKET_SPLASH_S;
	} else {
		mod_splash = MOD_ROCKET_SPLASH_W;
	}

	G_RadiusDamage( ent, ent->r.owner, plane, other, mod_splash );

	// spawn the explosion
	if( !( surfFlags & SURF_NOIMPACT ) ) {
		edict_t *event;
		vec3_t explosion_origin;

		VectorMA( ent->s.origin, -0.02, ent->velocity, explosion_origin );
		event = G_SpawnEvent( EV_ROCKET_EXPLOSION, DirToByte( plane ? plane->normal : NULL ), explosion_origin );
		event->s.firemode = ( ent->s.effects & EF_STRONG_WEAPON ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK;
		event->s.weapon = ( ( ent->projectileInfo.radius * 1 / 8 ) > 255 ) ? 255 : ( ent->projectileInfo.radius * 1 / 8 );
	}

	// free the rocket at next frame
	G_FreeEdict( ent );
}
Beispiel #15
0
/*
* W_Fire_Lasergun
*/
edict_t	*W_Fire_Lasergun( edict_t *self, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int range, int mod, int timeDelta )
{
	edict_t	*laser;
	qboolean newLaser;
	trace_t	tr;
	vec3_t dir;

	if( GS_Instagib() )
		damage = 9999;

	laser = _FindOrSpawnLaser( self, ET_LASERBEAM, &newLaser );
	if( newLaser )
	{
		// the quad start sound is added from the server
		if( self->r.client && self->r.client->ps.inventory[POWERUP_QUAD] > 0 )
			G_Sound( self, CHAN_AUTO, trap_SoundIndex( S_QUAD_FIRE ), ATTN_NORM );
	}

	laser_damage = damage;
	laser_knockback = knockback;
	laser_stun = stun;
	laser_attackerNum = ENTNUM( self );
	laser_mod = mod;
	laser_missed = qtrue;

	GS_TraceLaserBeam( &tr, start, angles, range, ENTNUM( self ), timeDelta, _LaserImpact );

	laser->r.svflags |= SVF_FORCEOWNER;
	VectorCopy( start, laser->s.origin );
	AngleVectors( angles, dir, NULL, NULL );
	VectorMA( laser->s.origin, range, dir, laser->s.origin2 );

	laser->think = G_Laser_Think;
	laser->nextThink = level.time + 100;

	if( laser_missed && self->r.client )
		G_AwardPlayerMissedLasergun( self, mod );

	// calculate laser's mins and maxs for linkEntity
	G_SetBoundsForSpanEntity( laser, 8 );

	GClip_LinkEntity( laser );

	return laser;
}
Beispiel #16
0
/*
* G_Teams_InvitePlayer
*/
static void G_Teams_InvitePlayer( int team, edict_t *ent )
{
	int i;

	if( team < TEAM_PLAYERS || team >= GS_MAX_TEAMS )
		return;

	if( !ent->r.inuse || !ent->r.client )
		return;

	for( i = 0; teamlist[team].invited[i] && i < MAX_CLIENTS; i++ )
	{
		if( teamlist[team].invited[i] == ENTNUM( ent ) )
			return;
	}

	teamlist[team].invited[i] = ENTNUM( ent );
}
Beispiel #17
0
/*
* W_Fire_Bullet
*/
void W_Fire_Bullet( edict_t *self, vec3_t start, vec3_t angles, int seed, int range, int spread, float damage, int knockback, int stun, int mod, int timeDelta )
{
	vec3_t dir;
	edict_t *event;
	float r, u;
	double alpha, s;
	trace_t trace;
	int dmgflags = DAMAGE_STUN_CLAMP|DAMAGE_KNOCKBACK_SOFT;

	if( GS_Instagib() )
		damage = 9999;

	AngleVectors( angles, dir, NULL, NULL );

	// send the event
	event = G_SpawnEvent( EV_FIRE_BULLET, seed, start );
	event->s.ownerNum = ENTNUM( self );
	event->r.svflags = SVF_TRANSMITORIGIN2;
	VectorScale( dir, 4096, event->s.origin2 ); // DirToByte is too inaccurate
	event->s.weapon = WEAP_MACHINEGUN;
	if( mod == MOD_MACHINEGUN_S )
		event->s.weapon |= EV_INVERSE;

	// circle shape
	alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI]
	s = fabs( Q_crandom( &seed ) ); // [0..1]
	r = s * cos( alpha ) * spread;
	u = s * sin( alpha ) * spread;

	GS_TraceBullet( &trace, start, dir, r, u, range, ENTNUM( self ), timeDelta );
	if( trace.ent != -1 )
	{
		if( game.edicts[trace.ent].takedamage )
		{
			G_Damage( &game.edicts[trace.ent], self, self, dir, dir, trace.endpos, damage, knockback, stun, dmgflags, mod );
		}
		else
		{
			if( !( trace.surfFlags & SURF_NOIMPACT ) )
			{
			}
		}
	}
}
Beispiel #18
0
nav_ents_t *AI_GetGoalentForEnt( edict_t *target )
{
	int entnum;

	if( !target )
		return NULL;

	entnum = ENTNUM( target );
	return nav.entsGoals[entnum];
}
Beispiel #19
0
/*
* W_Fire_LinearProjectile - Spawn a generic linear projectile without a model, touch func, sound nor mod
*/
static edict_t *W_Fire_LinearProjectile( edict_t *self, vec3_t start, vec3_t angles, int speed,
										float damage, int minKnockback, int maxKnockback, int stun, int minDamage, int radius, int timeout, int timeDelta )
{
	edict_t	*projectile;
	vec3_t dir;

	projectile = G_Spawn();
	VectorCopy( start, projectile->s.origin );
	VectorCopy( start, projectile->s.old_origin );
	VectorCopy( start, projectile->olds.origin );

	VectorCopy( angles, projectile->s.angles );
	AngleVectors( angles, dir, NULL, NULL );
	VectorScale( dir, speed, projectile->velocity );
	GS_SnapVelocity( projectile->velocity );

	projectile->movetype = MOVETYPE_LINEARPROJECTILE;
	projectile->s.linearProjectile = qtrue;

	projectile->r.solid = SOLID_YES;
	projectile->r.clipmask = ( !GS_RaceGametype() ) ? MASK_SHOT : MASK_SOLID;

	projectile->r.svflags = SVF_PROJECTILE;
	// enable me when drawing exception is added to cgame
	projectile->r.svflags |= SVF_TRANSMITORIGIN2;
	VectorClear( projectile->r.mins );
	VectorClear( projectile->r.maxs );
	projectile->s.modelindex = 0;
	projectile->r.owner = self;
	projectile->s.ownerNum = ENTNUM( self );
	projectile->touch = W_Touch_Projectile; //generic one. Should be replaced after calling this func
	projectile->nextThink = level.time + timeout;
	projectile->think = G_FreeEdict;
	projectile->classname = NULL; // should be replaced after calling this func.
	projectile->style = 0;
	projectile->s.sound = 0;
	projectile->timeStamp = level.time;
	projectile->s.linearProjectileTimeStamp = game.serverTime;
	projectile->timeDelta = timeDelta;

	projectile->projectileInfo.minDamage = min( minDamage, damage );
	projectile->projectileInfo.maxDamage = damage;
	projectile->projectileInfo.minKnockback = min( minKnockback, maxKnockback );
	projectile->projectileInfo.maxKnockback = maxKnockback;
	projectile->projectileInfo.stun = stun;
	projectile->projectileInfo.radius = radius;

	GClip_LinkEntity( projectile );

	// update some data required for the transmission
	VectorCopy( projectile->velocity, projectile->s.linearProjectileVelocity );
	projectile->s.team = self->s.team;
	projectile->s.modelindex2 = ( abs( timeDelta ) > 255 ) ? 255 : (unsigned int)abs( timeDelta );
	return projectile;
}
Beispiel #20
0
/*
* G_Match_RemoveAllProjectiles
*/
void G_Match_RemoveAllProjectiles( void )
{
	edict_t *ent;

	for( ent = game.edicts + gs.maxclients; ENTNUM( ent ) < game.numentities; ent++ )
	{
		if( ent->r.inuse && !ent->r.client && ent->r.svflags & SVF_PROJECTILE && ent->r.solid != SOLID_NOT )
		{
			G_FreeEdict( ent );
		}
	}
}
Beispiel #21
0
/*
* G_RunFrame
* Advances the world
*/
void G_RunFrame( unsigned int msec, unsigned int serverTime )
{
	G_CheckCvars();

	game.localTime = time( NULL );

	game.serverTime = serverTime;
	G_UpdateFrameTime( msec );

	if( !g_snapStarted )
		G_StartFrameSnap();

	G_CallVotes_Think();

	// "freeze" match clock
	if( GS_MatchWaiting() || GS_MatchPaused() )
	{
		gs.gameState.longstats[GAMELONG_MATCHSTART] += msec;
	}

	if( GS_MatchPaused() )
	{
		edict_t *ent;

		// "freeze" linear projectiles
		for( ent = game.edicts + gs.maxclients; ENTNUM( ent ) < game.numentities; ent++ )
		{
			if( ent->s.linearProjectile )
				ent->s.linearProjectileTimeStamp += msec;
		}

		G_RunClients();
		G_RunGametype();
		G_LevelGarbageCollect();
		return;
	}

	level.framenum++;
	level.time += msec;
	level.think_client_entity = G_GetNextThinkClient( level.think_client_entity );

	G_SpawnQueue_Think();

	// run the world
	G_asCallMapPreThink();
	G_RunClients();
	G_RunEntities();
	G_RunGametype();
	G_asCallMapPostThink();
	GClip_BackUpCollisionFrame();

	G_LevelGarbageCollect();
}
Beispiel #22
0
/*
* W_Touch_Grenade
*/
static void W_Touch_Grenade( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags )
{
	int hitType;
	vec3_t dir;

	if( surfFlags & SURF_NOIMPACT )
	{
		G_FreeEdict( ent );
		return;
	}

	hitType = G_Projectile_HitStyle( ent, other );
	if( hitType == PROJECTILE_TOUCH_NOT )
		return;

	// don't explode on doors and plats that take damage
	if( !other->takedamage || ISBRUSHMODEL( other->s.modelindex ) )
	{
		G_AddEvent( ent, EV_GRENADE_BOUNCE, ( ent->s.effects & EF_STRONG_WEAPON ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK, true );
		return;
	}

	if( other->takedamage )
	{
		int directHitDamage = ent->projectileInfo.maxDamage;

		VectorNormalize2( ent->velocity, dir );

		if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile
		{
			G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta );
		}
		else
		{
			VectorNormalize2( ent->velocity, dir );

			// no direct hit bonuses for grenades
			/*
			if( hitType == PROJECTILE_TOUCH_DIRECTAIRHIT )
				directHitDamage += DIRECTAIRTHIT_DAMAGE_BONUS;
			else if( hitType == PROJECTILE_TOUCH_DIRECTHIT )
				directHitDamage += DIRECTHIT_DAMAGE_BONUS;
			*/
		}

		G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, directHitDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style );
	}

	ent->enemy = other;
	W_Grenade_ExplodeDir( ent, plane ? plane->normal : NULL );
}
Beispiel #23
0
static edict_t *G_ClosestFlagBase( edict_t *ent )
{
	int i;
	edict_t *t, *best;
	float dist, best_dist;
	static qboolean firstTime = qtrue;
	static unsigned int lastLevelSpawnCount;
	static edict_t *flagBases[GS_MAX_TEAMS];

	// store pointers to flag bases if called for the first time in this level spawn
	if( firstTime || lastLevelSpawnCount != game.levelSpawnCount )
	{
		for( t = game.edicts + 1 + gs.maxclients; ENTNUM( t ) < game.numentities; t++ )
		{
			if( t->s.type != ET_FLAG_BASE )
				continue;
			flagBases[t->s.team] = t;
		}

		// ok, remember last time we were called
		firstTime = qfalse;
		lastLevelSpawnCount = game.levelSpawnCount;
	}

	best = NULL;
	best_dist = 9999999;

	// find the closest flag base starting from TEAM_ALPHA
	for( i = TEAM_ALPHA; i < GS_MAX_TEAMS; i++ )
	{
		t = flagBases[i];
		if( !t )
			continue;

		// if equally distant from two bases, consider this item neutral
		dist = Distance( ent->s.origin, t->s.origin );
		if( best && fabs( dist - best_dist ) < 10 )
		{
			best = NULL;
			break;
		}

		if( dist < best_dist )
		{
			best_dist = dist;
			best = t;
		}
	}

	return best;
}
Beispiel #24
0
/*
* W_Fire_Bullet
*/
void W_Fire_Bullet( edict_t *self, vec3_t start, vec3_t fv, vec3_t rv, vec3_t uv, int seed, int range, 
	int hspread, int vspread, float damage, int knockback, int stun, int mod, int timeDelta ) {
	edict_t *event;
	float r, u;
	double alpha, s;
	trace_t trace;
	int dmgflags = DAMAGE_STUN_CLAMP | DAMAGE_KNOCKBACK_SOFT;

	if( GS_Instagib() ) {
		damage = 9999;
	}

	// send the event
	event = G_SpawnEvent( EV_FIRE_BULLET, seed, start );
	event->s.ownerNum = ENTNUM( self );
	VectorCopy( fv, event->s.origin2 );
	VectorCopy( rv, event->s.origin3 );
	event->s.weapon = WEAP_MACHINEGUN;
	event->s.firemode = ( mod == MOD_MACHINEGUN_S ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK;

	// circle shape
	alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI]
	s = fabs( Q_crandom( &seed ) ); // [0..1]
	r = s * cos( alpha ) * hspread;
	u = s * sin( alpha ) * vspread;

	GS_TraceBullet( &trace, start, fv, rv, uv, r, u, range, ENTNUM( self ), timeDelta );
	if( trace.ent != -1 ) {
		if( game.edicts[trace.ent].takedamage ) {
			G_Damage( &game.edicts[trace.ent], self, self, fv, fv, trace.endpos, damage, knockback, stun, dmgflags, mod );
		} else {
			if( !( trace.surfFlags & SURF_NOIMPACT ) ) {
			}
		}
	}
}
Beispiel #25
0
/*
* W_Touch_GunbladeBlast
*/
static void W_Touch_GunbladeBlast( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags )
{
	vec3_t dir;
	int hitType;

	if( surfFlags & SURF_NOIMPACT )
	{
		G_FreeEdict( ent );
		return;
	}

	hitType = G_Projectile_HitStyle( ent, other );
	if( hitType == PROJECTILE_TOUCH_NOT )
		return;

	if( other->takedamage )
	{
		VectorNormalize2( ent->velocity, dir );

		if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile
		{
			G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta );
		}
		else
		{
			VectorNormalize2( ent->velocity, dir );
		}

		G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, ent->projectileInfo.maxDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style );
	}

	G_RadiusDamage( ent, ent->r.owner, plane, other, MOD_GUNBLADE_S );

	// add explosion event
	if( ( !other->takedamage || ISBRUSHMODEL( other->s.modelindex ) ) )
	{
		edict_t *event;

		event = G_SpawnEvent( EV_GUNBLADEBLAST_IMPACT, DirToByte( plane ? plane->normal : NULL ), ent->s.origin );
		event->s.weapon = ( ( ent->projectileInfo.radius * 1/8 ) > 127 ) ? 127 : ( ent->projectileInfo.radius * 1/8 );
		event->s.skinnum = ( ( ent->projectileInfo.maxKnockback * 1/8 ) > 255 ) ? 255 : ( ent->projectileInfo.maxKnockback * 1/8 );
	}

	// free at next frame
	G_FreeEdict( ent );
}
Beispiel #26
0
/*
* G_Trace
* 
* Moves the given mins/maxs volume through the world from start to end.
* 
* Passedict and edicts owned by passedict are explicitly not checked.
* ------------------------------------------------------------------
* mins and maxs are relative

* if the entire move stays in a solid volume, trace.allsolid will be set,
* trace.startsolid will be set, and trace.fraction will be 0

* if the starting point is in a solid, it will be allowed to move out
* to an open area

* passedict is explicitly excluded from clipping checks (normally NULL)
*/
static void GClip_Trace( trace_t *tr, vec3_t start, vec3_t mins, vec3_t maxs, 
	vec3_t end, edict_t *passedict, int contentmask, int timeDelta )
{
	moveclip_t clip;

	if( !tr )
		return;

	if( !mins )
		mins = vec3_origin;
	if( !maxs )
		maxs = vec3_origin;

	if( passedict == world )
	{
		memset( tr, 0, sizeof( trace_t ) );
		tr->fraction = 1;
		tr->ent = -1;
	}
	else
	{
		// clip to world
		trap_CM_TransformedBoxTrace( tr, start, end, mins, maxs, NULL, contentmask, NULL, NULL );
		tr->ent = tr->fraction < 1.0 ? world->s.number : -1;
		if( tr->fraction == 0 )
			return; // blocked by the world
	}

	memset( &clip, 0, sizeof( moveclip_t ) );
	clip.trace = tr;
	clip.contentmask = contentmask;
	clip.start = start;
	clip.end = end;
	clip.mins = mins;
	clip.maxs = maxs;
	clip.passent = passedict ? ENTNUM( passedict ) : -1;

	VectorCopy( mins, clip.mins2 );
	VectorCopy( maxs, clip.maxs2 );

	// create the bounding box of the entire move
	GClip_TraceBounds( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );

	// clip to other solid entities
	GClip_ClipMoveToEntities( &clip, timeDelta );
}
Beispiel #27
0
/*
* TVM_ClientEndSnapFrame
* 
* Called for each player at the end of the server frame
* and right after spawning
*/
void TVM_ClientEndSnapFrame( edict_t *ent )
{
	edict_t *spec;
	tvm_relay_t *relay = ent->relay;

	assert( ent && ent->local && ent->r.client && !ent->r.client->chase.active );

	if( relay->playernum < 0 )
		spec = NULL;
	else
		spec = relay->edicts + relay->playernum + 1;

	if( relay->frame.valid && !relay->frame.multipov )
	{
		assert( spec );
		ent->r.client->ps = spec->r.client->ps;
		ent->r.client->ps.pmove.pm_type = PM_CHASECAM;
		ent->r.client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
		ent->r.client->ps.POVnum = PLAYERNUM( spec ) + 1;
		ent->s = spec->s;
		ent->s.number = ENTNUM( ent );
		return;
	}

	if( spec && spec->r.inuse && spec->r.client )
	{
		memcpy( ent->r.client->ps.stats, spec->r.client->ps.stats, sizeof( ent->r.client->ps.stats ) );
		memcpy( ent->r.client->ps.inventory, spec->r.client->ps.inventory, sizeof( ent->r.client->ps.inventory ) );
	}
	else
	{
		memset( ent->r.client->ps.stats, 0, sizeof( ent->r.client->ps.stats ) );
		memset( ent->r.client->ps.inventory, 0, sizeof( ent->r.client->ps.inventory ) );
	}

	ent->r.client->ps.viewheight = ent->viewheight;
	if( relay->playernum < 0 )
		ent->r.client->ps.POVnum = 255; // FIXME
	else
		ent->r.client->ps.POVnum = relay->playernum + 1;
	if( TVM_ClientIsZoom( ent ) )
		ent->r.client->ps.fov = ent->r.client->pers.zoomfov;
	else
		ent->r.client->ps.fov = ent->r.client->pers.fov;
}
Beispiel #28
0
/*
* G_SpawnQueue_RemoveClient - Check all queues for this client and remove it
*/
void G_SpawnQueue_RemoveClient( edict_t *ent )
{
	g_teamspawnqueue_t *queue;
	int i, team;

	if( !ent->r.client )
		return;

	for( team = TEAM_SPECTATOR; team < GS_MAX_TEAMS; team++ )
	{
		queue = &g_spawnQueues[team];
		for( i = queue->start; i < queue->head; i++ )
		{
			if( queue->list[i % MAX_CLIENTS] == ENTNUM( ent ) )
				queue->list[i % MAX_CLIENTS] = -1;
		}
	}
}
Beispiel #29
0
/*
* G_Teams_PlayerIsInvited
*/
static bool G_Teams_PlayerIsInvited( int team, edict_t *ent )
{
	int i;

	if( team < TEAM_PLAYERS || team >= GS_MAX_TEAMS )
		return false;

	if( !ent->r.inuse || !ent->r.client )
		return false;

	for( i = 0; teamlist[team].invited[i] && i < MAX_CLIENTS; i++ )
	{
		if( teamlist[team].invited[i] == ENTNUM( ent ) )
			return true;
	}

	return false;
}
Beispiel #30
0
/*
* W_Fire_Electrobolt_Weak
*/
edict_t *W_Fire_Electrobolt_Weak( edict_t *self, vec3_t start, vec3_t angles, float speed, float damage, int minKnockback, int maxKnockback, int stun, int timeout, int mod, int timeDelta )
{
	edict_t	*bolt;

	if( GS_Instagib() )
		damage = 9999;

	// projectile, weak mode
	bolt = W_Fire_LinearProjectile( self, start, angles, speed, damage, minKnockback, maxKnockback, stun, 0, 0, timeout, timeDelta );
	bolt->s.modelindex = trap_ModelIndex( PATH_ELECTROBOLT_WEAK_MODEL );
	bolt->s.type = ET_ELECTRO_WEAK; //add particle trail and light
	bolt->s.ownerNum = ENTNUM( self );
	bolt->touch = W_Touch_Bolt;
	bolt->classname = "bolt";
	bolt->style = mod;
	bolt->s.effects &= ~EF_STRONG_WEAPON;

	return bolt;
}