Example #1
0
/*
==================
S_AddLoopingSound
 
Called during entity generation for a frame
Include velocity in case I get around to doing doppler...
==================
*/
void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle )
{
    sfx_t *sfx;

    if ( !s_soundStarted || s_soundMuted )
    {
        return;
    }

    if ( sfxHandle < 0 || sfxHandle >= s_numSfx )
    {
        Com_Printf( S_COLOR_YELLOW, "S_AddLoopingSound: handle %i out of range\n", sfxHandle );
        return;
    }

    sfx = &s_knownSfx[ sfxHandle ];

    if (sfx->inMemory == qfalse)
    {
        S_memoryLoad(sfx);
    }

    if ( !sfx->soundLength )
    {
        Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
    }

    VectorCopy( origin, loopSounds[entityNum].origin );
    VectorCopy( velocity, loopSounds[entityNum].velocity );
    loopSounds[entityNum].active = qtrue;
    loopSounds[entityNum].kill = qtrue;
    loopSounds[entityNum].doppler = qfalse;
    loopSounds[entityNum].oldDopplerScale = 1.0;
    loopSounds[entityNum].dopplerScale = 1.0;
    loopSounds[entityNum].sfx = sfx;

    if (s_doppler->integer && VectorLengthSquared(velocity)>0.0)
    {
        vec3_t	out;
        float	lena, lenb;

        loopSounds[entityNum].doppler = qtrue;
        lena = DistanceSquared(loopSounds[listener_number].origin, loopSounds[entityNum].origin);
        VectorAdd(loopSounds[entityNum].origin, loopSounds[entityNum].velocity, out);
        lenb = DistanceSquared(loopSounds[listener_number].origin, out);
        if ((loopSounds[entityNum].framenum+1) != cls.framecount)
        {
            loopSounds[entityNum].oldDopplerScale = 1.0;
        }
        else
        {
            loopSounds[entityNum].oldDopplerScale = loopSounds[entityNum].dopplerScale;
        }
        loopSounds[entityNum].dopplerScale = lenb/(lena*100);
        if (loopSounds[entityNum].dopplerScale<=1.0)
        {
            loopSounds[entityNum].doppler = qfalse;			// don't bother doing the math
        }
    }

    loopSounds[entityNum].framenum = cls.framecount;
}
Example #2
0
static void CM_TraceThroughLeaf( traceWork_t* tw, const cLeaf_t* leaf )
{
	int			k;
	int			brushnum;
	cbrush_t	*b;
	cPatch_t	*patch;

	// trace line against all brushes in the leaf
	for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
		brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];

		b = &cm.brushes[brushnum];
		if ( b->checkcount == cm.checkcount ) {
			continue;	// already checked this brush in another leaf
		}
		b->checkcount = cm.checkcount;

		if ( !(b->contents & tw->contents) ) {
			continue;
		}

		if (!CM_BoundsIntersect( tw->bounds[0], tw->bounds[1], b->bounds[0], b->bounds[1] ))
			continue;

		CM_TraceThroughBrush( tw, b );
		if ( !tw->trace.fraction ) {
			return;
		}
	}

	// trace line against all patches in the leaf
#ifdef BSPC
	if (1) {
#else
	if ( !cm_noCurves->integer ) {
#endif
		for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
			patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
			if ( !patch ) {
				continue;
			}
			if ( patch->checkcount == cm.checkcount ) {
				continue;	// already checked this patch in another leaf
			}
			patch->checkcount = cm.checkcount;

			if ( !(patch->contents & tw->contents) ) {
				continue;
			}

			CM_TraceThroughPatch( tw, patch );
			if ( !tw->trace.fraction ) {
				return;
			}
		}
	}
}

#define RADIUS_EPSILON		1.0f

/*
================
CM_TraceThroughSphere

get the first intersection of the ray with the sphere
================
*/
void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end ) {
	float l1, l2, length, scale, fraction;
	float a, b, c, d, sqrtd;
	vec3_t v1, dir, intersection;

	// if inside the sphere
	VectorSubtract(start, origin, dir);
	l1 = VectorLengthSquared(dir);
	if (l1 < Square(radius)) {
		tw->trace.fraction = 0;
		tw->trace.startsolid = qtrue;
		// test for allsolid
		VectorSubtract(end, origin, dir);
		l1 = VectorLengthSquared(dir);
		if (l1 < Square(radius)) {
			tw->trace.allsolid = qtrue;
		}
		return;
	}
	//
	VectorSubtract(end, start, dir);
	length = VectorNormalize(dir);
	//
	l1 = CM_DistanceFromLineSquared(origin, start, end, dir);
	VectorSubtract(end, origin, v1);
	l2 = VectorLengthSquared(v1);
	// if no intersection with the sphere and the end point is at least an epsilon away
	if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
		return;
	}
	//
	//	| origin - (start + t * dir) | = radius
	//	a = dir[0]^2 + dir[1]^2 + dir[2]^2;
	//	b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
	//	c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
	//
	VectorSubtract(start, origin, v1);
	// dir is normalized so a = 1
	a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
	b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);
	c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);

	d = b * b - 4.0f * c;// * a;
	if (d > 0) {
		sqrtd = SquareRootFloat(d);
		// = (- b + sqrtd) * 0.5f; // / (2.0f * a);
		fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);
		//
		if (fraction < 0) {
			fraction = 0;
		}
		else {
			fraction /= length;
		}
		if ( fraction < tw->trace.fraction ) {
			tw->trace.fraction = fraction;
			VectorSubtract(end, start, dir);
			VectorMA(start, fraction, dir, intersection);
			VectorSubtract(intersection, origin, dir);
			#ifdef CAPSULE_DEBUG
				l2 = VectorLength(dir);
				if (l2 < radius) {
					int bah = 1;
				}
			#endif
			scale = 1 / (radius+RADIUS_EPSILON);
			VectorScale(dir, scale, dir);
			VectorCopy(dir, tw->trace.plane.normal);
			VectorAdd( tw->modelOrigin, intersection, intersection);
			tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
			tw->trace.contents = CONTENTS_BODY;
		}
	}
	else if (d == 0) {
		//t1 = (- b ) / 2;
		// slide along the sphere
	}
	// no intersection at all
}
Example #3
0
void VEH_TurretThink( Vehicle_t *pVeh, gentity_t *parent, int turretNum )
//-----------------------------------------------------
{
	qboolean	doAim = qfalse;
	float		enemyDist, rangeSq;
	vec3_t		enemyDir;
	turretStats_t *turretStats = &pVeh->m_pVehicleInfo->turret[turretNum];
	vehWeaponInfo_t	*vehWeapon = NULL;
	gentity_t	*turretEnemy = NULL;
	int			curMuzzle = 0;//?
	

	if ( !turretStats || !turretStats->iAmmoMax )
	{//not a valid turret
		return;
	}
	
	if ( turretStats->passengerNum 
		&& pVeh->m_iNumPassengers >= turretStats->passengerNum )
	{//the passenger that has control of this turret is on the ship
		VEH_TurretObeyPassengerControl( pVeh, parent, turretNum );
		return;
	}
	else if ( !turretStats->bAI )//try AI
	{//this turret does not think on its own.
		return;
	}

	vehWeapon = &g_vehWeaponInfo[turretStats->iWeapon];
	rangeSq = (turretStats->fAIRange*turretStats->fAIRange);
	curMuzzle = pVeh->turretStatus[turretNum].nextMuzzle;

	if ( pVeh->turretStatus[turretNum].enemyEntNum < ENTITYNUM_WORLD )
	{
		turretEnemy = &g_entities[pVeh->turretStatus[turretNum].enemyEntNum];
		if ( turretEnemy->health < 0 
			|| !turretEnemy->inuse
			|| turretEnemy == ((gentity_t*)pVeh->m_pPilot)//enemy became my pilot///?
			|| turretEnemy == parent
			|| turretEnemy->r.ownerNum == parent->s.number // a passenger?
			|| ( turretEnemy->client && turretEnemy->client->sess.sessionTeam == TEAM_SPECTATOR )
			|| ( turretEnemy->client && turretEnemy->client->tempSpectate >= level.time ) )
		{//don't keep going after spectators, pilot, self, dead people, etc.
			turretEnemy = NULL;
			pVeh->turretStatus[turretNum].enemyEntNum = ENTITYNUM_NONE;
		}
	}

	if ( pVeh->turretStatus[turretNum].enemyHoldTime < level.time )
	{
		if ( VEH_TurretFindEnemies( pVeh, parent, turretStats, turretNum, curMuzzle ) )
		{
			turretEnemy = &g_entities[pVeh->turretStatus[turretNum].enemyEntNum];
			doAim = qtrue;
		}
		else if ( parent->enemy && parent->enemy->s.number < ENTITYNUM_WORLD )
		{
			turretEnemy = parent->enemy;
			doAim = qtrue;
		}
		if ( turretEnemy )
		{//found one
			if ( turretEnemy->client )
			{//hold on to clients for a min of 3 seconds
				pVeh->turretStatus[turretNum].enemyHoldTime = level.time + 3000;
			}
			else
			{//hold less
				pVeh->turretStatus[turretNum].enemyHoldTime = level.time + 500;
			}
		}
	}
	if ( turretEnemy != NULL )
	{
		if ( turretEnemy->health > 0 )
		{
			// enemy is alive
			WP_CalcVehMuzzle( parent, curMuzzle );
			VectorSubtract( turretEnemy->r.currentOrigin, pVeh->m_vMuzzlePos[curMuzzle], enemyDir );
			enemyDist = VectorLengthSquared( enemyDir );

			if ( enemyDist < rangeSq )
			{
				// was in valid radius
				if ( trap_InPVS( pVeh->m_vMuzzlePos[curMuzzle], turretEnemy->r.currentOrigin ) )
				{
					// Every now and again, check to see if we can even trace to the enemy
					trace_t tr;
					vec3_t start, end;
					VectorCopy( pVeh->m_vMuzzlePos[curMuzzle], start );

					VectorCopy( turretEnemy->r.currentOrigin, end );
					trap_Trace( &tr, start, NULL, NULL, end, parent->s.number, MASK_SHOT );

					if ( tr.entityNum == turretEnemy->s.number
						|| (!tr.allsolid && !tr.startsolid ) )
					{
						doAim = qtrue;	// Can see our enemy
					}
				}
			}
		}
	}

	if ( doAim )
	{
		vec3_t aimAngles;
		if ( VEH_TurretAim( pVeh, parent, turretEnemy, turretStats, vehWeapon, turretNum, curMuzzle, aimAngles ) )
		{
			VEH_TurretCheckFire( pVeh, parent, /*turretEnemy,*/ turretStats, vehWeapon, turretNum, curMuzzle );
		}
	}
}
Example #4
0
void CalcEntitySpot ( const gentity_t *ent, const spot_t spot, vec3_t point ) 
{
	vec3_t	forward, up, right;
	vec3_t	start, end;
	trace_t	tr;

	if ( !ent )
	{
		return;
	}
	ViewHeightFix(ent);
	switch ( spot ) 
	{
	case SPOT_ORIGIN:
		if(VectorCompare(ent->currentOrigin, vec3_origin))
		{//brush
			VectorSubtract(ent->absmax, ent->absmin, point);//size
			VectorMA(ent->absmin, 0.5, point, point);
		}
		else
		{
			VectorCopy ( ent->currentOrigin, point );
		}
		break;

	case SPOT_CHEST:
	case SPOT_HEAD:
		if ( ent->client && VectorLengthSquared( ent->client->renderInfo.eyePoint ) && (ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD) )
		{//Actual tag_head eyespot!
			//FIXME: Stasis aliens may have a problem here...
			VectorCopy( ent->client->renderInfo.eyePoint, point );
			if ( ent->client->NPC_class == CLASS_ATST )
			{//adjust up some
				point[2] += 28;//magic number :)
			}
			if ( ent->NPC )
			{//always aim from the center of my bbox, so we don't wiggle when we lean forward or backwards
				point[0] = ent->currentOrigin[0];
				point[1] = ent->currentOrigin[1];
			}
			else if ( !ent->s.number )
			{
				SubtractLeanOfs( ent, point );
			}
		}
		else
		{
			VectorCopy ( ent->currentOrigin, point );
			if ( ent->client ) 
			{
				point[2] += ent->client->ps.viewheight;
			}
		}
		if ( spot == SPOT_CHEST && ent->client )
		{
			if ( ent->client->NPC_class != CLASS_ATST )
			{//adjust up some
				point[2] -= ent->maxs[2]*0.2f;
			}
		}
		break;

	case SPOT_HEAD_LEAN:
		if ( ent->client && VectorLengthSquared( ent->client->renderInfo.eyePoint ) && (ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD) )
		{//Actual tag_head eyespot!
			//FIXME: Stasis aliens may have a problem here...
			VectorCopy( ent->client->renderInfo.eyePoint, point );
			if ( ent->client->NPC_class == CLASS_ATST )
			{//adjust up some
				point[2] += 28;//magic number :)
			}
			if ( ent->NPC )
			{//always aim from the center of my bbox, so we don't wiggle when we lean forward or backwards
				point[0] = ent->currentOrigin[0];
				point[1] = ent->currentOrigin[1];
			}
			else if ( !ent->s.number )
			{
				SubtractLeanOfs( ent, point );
			}
			//NOTE: automatically takes leaning into account!
		}
		else
		{
			VectorCopy ( ent->currentOrigin, point );
			if ( ent->client ) 
			{
				point[2] += ent->client->ps.viewheight;
			}
			//AddLeanOfs ( ent, point );
		}
		break;

	//FIXME: implement...
	//case SPOT_CHEST:
		//Returns point 3/4 from tag_torso to tag_head?
		//break;

	case SPOT_LEGS:
		VectorCopy ( ent->currentOrigin, point );
		point[2] += (ent->mins[2] * 0.5);
		break;

	case SPOT_WEAPON:
		if( ent->NPC && !VectorCompare( ent->NPC->shootAngles, vec3_origin ) && !VectorCompare( ent->NPC->shootAngles, ent->client->ps.viewangles ))
		{
			AngleVectors( ent->NPC->shootAngles, forward, right, up );
		}
		else
		{
			AngleVectors( ent->client->ps.viewangles, forward, right, up );
		}
		CalcMuzzlePoint( (gentity_t*)ent, forward, right, up, point, 0 );
		//NOTE: automatically takes leaning into account!
		break;

	case SPOT_GROUND:
		// if entity is on the ground, just use it's absmin
		if ( ent->s.groundEntityNum != -1 ) 
		{
			VectorCopy( ent->currentOrigin, point );
			point[2] = ent->absmin[2];
			break;
		}

		// if it is reasonably close to the ground, give the point underneath of it
		VectorCopy( ent->currentOrigin, start );
		start[2] = ent->absmin[2];
		VectorCopy( start, end );
		end[2] -= 64;
		gi.trace( &tr, start, ent->mins, ent->maxs, end, ent->s.number, MASK_PLAYERSOLID, (EG2_Collision)0, 0);
		if ( tr.fraction < 1.0 ) 
		{
			VectorCopy( tr.endpos, point);
			break;
		}

		// otherwise just use the origin
		VectorCopy( ent->currentOrigin, point );
		break;

	default:
		VectorCopy ( ent->currentOrigin, point );
		break;
	}
}
Example #5
0
/*
================
CM_VectorDistanceSquared
================
*/
float CM_VectorDistanceSquared(vec3_t p1, vec3_t p2) {
	vec3_t dir;

	VectorSubtract(p2, p1, dir);
	return VectorLengthSquared(dir);
}
Example #6
0
void S_Base_AddLoopingSound(const vec3_t origin, const vec3_t velocity, int range, sfxHandle_t sfxHandle, int volume, int soundTime)
{
	sfx_t *sfx;

	if (!s_soundStarted || s_soundMuted || !volume)
	{
		return;
	}

	if (numLoopSounds >= MAX_LOOP_SOUNDS)
	{
		return;
	}

	if (sfxHandle < 0 || sfxHandle >= numSfx)
	{
		Com_Printf(S_COLOR_YELLOW "S_AddLoopingSound: handle %i out of range\n", sfxHandle);
		return;
	}

	sfx = &knownSfx[sfxHandle];

	if (sfx->inMemory == qfalse)
	{
		S_memoryLoad(sfx);
	}

	if (!sfx->soundLength)
	{
		Com_Error(ERR_DROP, "%s has length 0", sfx->soundName);
	}

	VectorCopy(origin, loopSounds[numLoopSounds].origin);
	VectorCopy(velocity, loopSounds[numLoopSounds].velocity);
	loopSounds[numLoopSounds].startSample     = soundTime % sfx->soundLength;
	loopSounds[numLoopSounds].active          = qtrue;
	loopSounds[numLoopSounds].kill            = qtrue;
	loopSounds[numLoopSounds].doppler         = qfalse;
	loopSounds[numLoopSounds].oldDopplerScale = 1;
	loopSounds[numLoopSounds].dopplerScale    = 1;
	loopSounds[numLoopSounds].sfx             = sfx;
	loopSounds[numLoopSounds].range           = range ? range : SOUND_RANGE_DEFAULT;
	loopSounds[numLoopSounds].loudUnderWater  = (volume & 1 << UNDERWATER_BIT) != 0;
	if (volume > 65535)
	{
		volume = 65535;
	}
	else if (volume < 0)
	{
		volume = 0;
	}
	loopSounds[numLoopSounds].volume = (int)((float)volume * s_volCurrent);

	if (s_doppler->integer && VectorLengthSquared(velocity) > 0)
	{
		vec3_t out;
		float  lena, lenb;

		// don't do the doppler effect when trumpets of train and station are at the same position
		if (entityPositions[listener_number] != entityPositions[numLoopSounds])
		{
			loopSounds[numLoopSounds].doppler = qtrue;
		}
		else
		{
			loopSounds[numLoopSounds].doppler = qfalse;
		}

		lena = DistanceSquared(entityPositions[listener_number], entityPositions[numLoopSounds]);

		VectorAdd(entityPositions[numLoopSounds], loopSounds[numLoopSounds].velocity, out);

		lenb = DistanceSquared(entityPositions[listener_number], out);

		if ((loopSounds[numLoopSounds].framenum + 1) != cls.framecount)
		{
			loopSounds[numLoopSounds].oldDopplerScale = 1;
		}
		else
		{
			loopSounds[numLoopSounds].oldDopplerScale = loopSounds[numLoopSounds].dopplerScale;
		}

		if (lena == 0) // div/0
		{
			loopSounds[numLoopSounds].dopplerScale = 1; // no doppler
		}
		else
		{
			loopSounds[numLoopSounds].dopplerScale = lenb / (lena * 100);
		}

		if (loopSounds[numLoopSounds].dopplerScale <= 1)
		{
			loopSounds[numLoopSounds].doppler = qfalse;         // don't bother doing the math
		}
		else if (loopSounds[numLoopSounds].dopplerScale > MAX_DOPPLER_SCALE)
		{
			loopSounds[numLoopSounds].dopplerScale = MAX_DOPPLER_SCALE;
		}
	}

	loopSounds[numLoopSounds].framenum = cls.framecount;
	numLoopSounds++;
}
Example #7
0
/*
=================
MakeMeshNormals

Handles all the complicated wrapping and degenerate cases
=================
*/
static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
	int		i, j, k, dist;
	vec3_t	normal;
	vec3_t	sum;
	int		count;
	vec3_t	base;
	vec3_t	delta;
	int		x, y;
	drawVert_t	*dv;
	vec3_t		around[8], temp;
	qboolean	good[8];
	qboolean	wrapWidth, wrapHeight;
	float		len;
static	int	neighbors[8][2] = {
	{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
	};

	wrapWidth = qfalse;
	for ( i = 0 ; i < height ; i++ ) {
		VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
		len = VectorLengthSquared( delta );
		if ( len > 1.0 ) {
			break;
		}
	}
	if ( i == height ) {
		wrapWidth = qtrue;
	}

	wrapHeight = qfalse;
	for ( i = 0 ; i < width ; i++ ) {
		VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
		len = VectorLengthSquared( delta );
		if ( len > 1.0 ) {
			break;
		}
	}
	if ( i == width) {
		wrapHeight = qtrue;
	}


	for ( i = 0 ; i < width ; i++ ) {
		for ( j = 0 ; j < height ; j++ ) {
			count = 0;
			dv = &ctrl[j][i];
			VectorCopy( dv->xyz, base );
			for ( k = 0 ; k < 8 ; k++ ) {
				VectorClear( around[k] );
				good[k] = qfalse;

				for ( dist = 1 ; dist <= 3 ; dist++ ) {
					x = i + neighbors[k][0] * dist;
					y = j + neighbors[k][1] * dist;
					if ( wrapWidth ) {
						if ( x < 0 ) {
							x = width - 1 + x;
						} else if ( x >= width ) {
							x = 1 + x - width;
						}
					}
					if ( wrapHeight ) {
						if ( y < 0 ) {
							y = height - 1 + y;
						} else if ( y >= height ) {
							y = 1 + y - height;
						}
					}

					if ( x < 0 || x >= width || y < 0 || y >= height ) {
						break;					// edge of patch
					}
					VectorSubtract( ctrl[y][x].xyz, base, temp );
					if ( VectorNormalize2( temp, temp ) == 0 ) {
						continue;				// degenerate edge, get more dist
					} else {
						good[k] = qtrue;
						VectorCopy( temp, around[k] );
						break;					// good edge
					}
				}
			}

			VectorClear( sum );
			for ( k = 0 ; k < 8 ; k++ ) {
				if ( !good[k] || !good[(k+1)&7] ) {
					continue;	// didn't get two points
				}
				CrossProduct( around[(k+1)&7], around[k], normal );
				if ( VectorNormalize2( normal, normal ) == 0 ) {
					continue;
				}
				VectorAdd( normal, sum, sum );
				count++;
			}
			if ( count == 0 ) {
//printf("bad normal\n");
				count = 1;
			}
			VectorNormalize2( sum, dv->normal );
		}
	}
}
Example #8
0
// now we're at poly level, check each model space transformed poly against the model world transfomed ray
static bool G2_RadiusTracePolys(
								const mdxmSurface_t *surface, 
								CTraceSurface &TS
								)
{
	int	i,j;
	vec3_t basis1;
	vec3_t basis2;
	vec3_t taxis;
	vec3_t saxis;

	basis2[0]=0.0f;
	basis2[1]=0.0f;
	basis2[2]=1.0f;

	vec3_t v3RayDir;
	VectorSubtract(TS.rayEnd, TS.rayStart, v3RayDir);

	CrossProduct(v3RayDir,basis2,basis1);

	if (DotProduct(basis1,basis1)<.1f)
	{
		basis2[0]=0.0f;
		basis2[1]=1.0f;
		basis2[2]=0.0f;
		CrossProduct(v3RayDir,basis2,basis1);
	}

	CrossProduct(v3RayDir,basis1,basis2);
	// Give me a shot direction not a bunch of zeros :) -Gil
//	assert(DotProduct(basis1,basis1)>.0001f);
//	assert(DotProduct(basis2,basis2)>.0001f);

	VectorNormalize(basis1);
	VectorNormalize(basis2);

	const float c=cosf(0);//theta
	const float s=sinf(0);//theta

	VectorScale(basis1, 0.5f * c / TS.m_fRadius,taxis);
	VectorMA(taxis,     0.5f * s / TS.m_fRadius,basis2,taxis);

	VectorScale(basis1,-0.5f * s /TS.m_fRadius,saxis);
	VectorMA(    saxis, 0.5f * c /TS.m_fRadius,basis2,saxis);

	const float * const verts = (float *)TS.TransformedVertsArray[surface->thisSurfaceIndex];
	const int numVerts = surface->numVerts;
	
	int flags=63;
	//rayDir/=lengthSquared(raydir);
	const float f = VectorLengthSquared(v3RayDir); 
	v3RayDir[0]/=f;
	v3RayDir[1]/=f;
	v3RayDir[2]/=f;

	for ( j = 0; j < numVerts; j++ ) 
	{
		const int pos=j*5;
		vec3_t delta;
		delta[0]=verts[pos+0]-TS.rayStart[0];
		delta[1]=verts[pos+1]-TS.rayStart[1];
		delta[2]=verts[pos+2]-TS.rayStart[2];
		const float s=DotProduct(delta,saxis)+0.5f;
		const float t=DotProduct(delta,taxis)+0.5f;
		const float u=DotProduct(delta,v3RayDir);
		int vflags=0;

		if (s>0)
		{
			vflags|=1;
		}
		if (s<1)
		{
			vflags|=2;
		}
		if (t>0)
		{
			vflags|=4;
		}
		if (t<1)
		{
			vflags|=8;
		}
		if (u>0)
		{
			vflags|=16;
		}
		if (u<1)
		{
			vflags|=32;
		}

		vflags=(~vflags);
		flags&=vflags;
		GoreVerts[j].flags=vflags;
	}

	if (flags)
	{
		return false; // completely off the gore splotch  (so presumably hit nothing? -Ste)
	}
	const int numTris = surface->numTriangles;
	const mdxmTriangle_t * const tris = (mdxmTriangle_t *) ((byte *)surface + surface->ofsTriangles);

	for ( j = 0; j < numTris; j++ ) 
	{
		assert(tris[j].indexes[0]>=0&&tris[j].indexes[0]<numVerts);
		assert(tris[j].indexes[1]>=0&&tris[j].indexes[1]<numVerts);
		assert(tris[j].indexes[2]>=0&&tris[j].indexes[2]<numVerts);
		flags=63&
			GoreVerts[tris[j].indexes[0]].flags&
			GoreVerts[tris[j].indexes[1]].flags&
			GoreVerts[tris[j].indexes[2]].flags;
		if (flags)
		{
			continue;
		}
		else
		{
			// we hit a triangle, so init a collision record...
			//
			for (i=0; i<MAX_G2_COLLISIONS;i++)
			{
				if (TS.collRecMap[i].mEntityNum == -1)
				{
					CCollisionRecord  	&newCol = TS.collRecMap[i];
					
					newCol.mPolyIndex = j;
					newCol.mEntityNum = TS.entNum;
					newCol.mSurfaceIndex = surface->thisSurfaceIndex;
					newCol.mModelIndex = TS.modelIndex;
//					if (face>0)
//					{
						newCol.mFlags = G2_FRONTFACE;
//					}
//					else
//					{
//						newCol.mFlags = G2_BACKFACE;
//					}

					//get normal from triangle				
					const float *A = &verts[(tris[j].indexes[0] * 5)];
					const float *B = &verts[(tris[j].indexes[1] * 5)];
					const float *C = &verts[(tris[j].indexes[2] * 5)];
					vec3_t normal;
					vec3_t edgeAC, edgeBA;

					VectorSubtract(C, A, edgeAC);
					VectorSubtract(B, A, edgeBA);
					CrossProduct(edgeBA, edgeAC, normal);

					// transform normal (but don't translate) into world angles
					TransformPoint(normal, newCol.mCollisionNormal, &worldMatrix);
					VectorNormalize(newCol.mCollisionNormal);

					newCol.mMaterial = newCol.mLocation = 0;
					// exit now if we should
					if (TS.eG2TraceType == G2_RETURNONHIT)
					{
						TS.hitOne = true;
						return true;
					}

					//i don't know the hitPoint, but let's just assume it's the first vert for now...
					const float *hitPoint = A;
					vec3_t			  distVect;

					VectorSubtract(hitPoint, TS.rayStart, distVect);
					newCol.mDistance = VectorLength(distVect);

					// put the hit point back into world space
					TransformAndTranslatePoint(hitPoint, newCol.mCollisionPosition, &worldMatrix);
					newCol.mBarycentricI = newCol.mBarycentricJ = 0.0f;

					break;
				}
			}
			if (i==MAX_G2_COLLISIONS)
			{
				//assert(i!=MAX_G2_COLLISIONS);		// run out of collision record space - happens OFTEN
				TS.hitOne = true;	//force stop recursion
				return true;	// return true to avoid wasting further time, but no hit will result without a record
			}
		}
	}

	return false;
}
Example #9
0
/*
==================
PM_StepSlideMove

==================
*/
void PM_StepSlideMove( float gravMod ) 
{
	vec3_t		start_o, start_v;
	vec3_t		down_o, down_v;
	vec3_t		slideMove, stepUpMove;
	trace_t		trace;
	vec3_t		up, down;
	qboolean	cantStepUpFwd, isGiant = qfalse;;
	int			stepSize = STEPSIZE;

	VectorCopy (pm->ps->origin, start_o);
	VectorCopy (pm->ps->velocity, start_v);

	if ( PM_InReboundHold( pm->ps->legsAnim ) )
	{
		gravMod = 0.0f;
	}

	if ( PM_SlideMove( gravMod ) == 0 ) {
		return;		// we got exactly where we wanted to go first try	
	}//else Bumped into something, see if we can step over it

	if ( pm->gent && pm->gent->client && pm->gent->client->NPC_class == CLASS_VEHICLE && pm->gent->m_pVehicle->m_pVehicleInfo->hoverHeight > 0 )
	{//Hovering vehicles don't do steps
		//FIXME: maybe make hovering vehicles go up steps, but not down them?
		return;
	}

	if ( pm->gent 
		&& pm->gent->client
		&& (pm->gent->client->NPC_class == CLASS_ATST||pm->gent->client->NPC_class == CLASS_RANCOR) )
	{
		isGiant = qtrue;
		if ( pm->gent->client->NPC_class == CLASS_RANCOR )
		{
			if ( (pm->gent->spawnflags&1) )
			{
				stepSize = 64;//hack for Mutant Rancor stepping
			}
			else
			{
				stepSize = 48;//hack for Rancor stepping
			}
		}
		else
		{
			stepSize = 70;//hack for AT-ST stepping, slightly taller than a standing stormtrooper
		}
	}
	else if ( pm->maxs[2] <= 0 )
	{//short little guys can't go up steps... FIXME: just make this a flag for certain NPCs- especially ones that roll?
		stepSize = 4;
	}

	//Q3Final addition...
	VectorCopy(start_o, down);
	down[2] -= stepSize;
	pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
	VectorSet(up, 0, 0, 1);
	// never step up when you still have up velocity
	if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
			DotProduct(trace.plane.normal, up) < 0.7)) {
		return;
	}

	if ( !pm->ps->velocity[0] && !pm->ps->velocity[1] ) 
	{//All our velocity was cancelled sliding
		return;
	}

	VectorCopy (pm->ps->origin, down_o);
	VectorCopy (pm->ps->velocity, down_v);

	VectorCopy (start_o, up);
	up[2] += stepSize;

	// test the player position if they were a stepheight higher

	pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
	if ( trace.allsolid || trace.startsolid || trace.fraction == 0) {
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend can't step\n", c_pmove);
		}
		return;		// can't step up
	}

	if ( pm->debugLevel )
	{
		G_DebugLine(start_o,trace.endpos,2000,0xffffff,qtrue); 
	}

//===Another slidemove forward================================================================================
	// try slidemove from this position
	VectorCopy( trace.endpos, pm->ps->origin );
	VectorCopy( start_v, pm->ps->velocity );
	cantStepUpFwd = PM_SlideMove( gravMod ); 
//===Another slidemove forward================================================================================

	if ( pm->debugLevel )
	{
		G_DebugLine(trace.endpos,pm->ps->origin,2000,0xffffff,qtrue);
	}
	//compare the initial slidemove and this slidemove from a step up position
	VectorSubtract( down_o, start_o, slideMove );
	VectorSubtract( trace.endpos, pm->ps->origin, stepUpMove );

	if ( fabs(stepUpMove[0]) < 0.1 && fabs(stepUpMove[1]) < 0.1 && VectorLengthSquared( slideMove ) > VectorLengthSquared( stepUpMove ) )
	{
		//slideMove was better, use it
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
	}
	else
	{
		qboolean skipStep = qfalse;
		// push down the final amount
		VectorCopy (pm->ps->origin, down);
		down[2] -= stepSize;
		pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
		if ( pm->debugLevel )
		{
			G_DebugLine(pm->ps->origin,trace.endpos,2000,0xffffff,qtrue);
		}
		if ( g_stepSlideFix->integer )
		{
			if ( pm->ps->clientNum < MAX_CLIENTS
				&& trace.plane.normal[2] < MIN_WALK_NORMAL )
			{//normal players cannot step up slopes that are too steep to walk on!
				vec3_t stepVec;
				//okay, the step up ends on a slope that it too steep to step up onto,
				//BUT:
				//If the step looks like this:
				//  (B)\__
				//        \_____(A)
				//Then it might still be okay, so we figure out the slope of the entire move
				//from (A) to (B) and if that slope is walk-upabble, then it's okay
				VectorSubtract( trace.endpos, down_o, stepVec );
				VectorNormalize( stepVec ); 
				if ( stepVec[2] > (1.0f-MIN_WALK_NORMAL) )
				{
					if ( pm->debugLevel )
					{
						G_DebugLine(down_o,trace.endpos,2000,0x0000ff,qtrue);
					}
					skipStep = qtrue;
				}
			}
		}

		if ( !trace.allsolid
			&& !skipStep ) //normal players cannot step up slopes that are too steep to walk on!
		{
			if ( pm->ps->clientNum 
				&& isGiant 
				&& g_entities[trace.entityNum].client
				&& pm->gent
				&& pm->gent->client
				&& pm->gent->client->NPC_class == CLASS_RANCOR )
			{//Rancor don't step on clients
				if ( g_stepSlideFix->integer )
				{
					VectorCopy (down_o, pm->ps->origin);
					VectorCopy (down_v, pm->ps->velocity);
				}
				else
				{
					VectorCopy (start_o, pm->ps->origin);
					VectorCopy (start_v, pm->ps->velocity);
				}
			}
			else if ( pm->ps->clientNum 
				&& isGiant 
				&& g_entities[trace.entityNum].client
				&& g_entities[trace.entityNum].client->playerTeam == pm->gent->client->playerTeam )
			{//AT-ST's don't step up on allies
				if ( g_stepSlideFix->integer )
				{
					VectorCopy (down_o, pm->ps->origin);
					VectorCopy (down_v, pm->ps->velocity);
				}
				else
				{
					VectorCopy (start_o, pm->ps->origin);
					VectorCopy (start_v, pm->ps->velocity);
				}
			}
			else
			{
				VectorCopy( trace.endpos, pm->ps->origin );
				if ( g_stepSlideFix->integer )
				{
					if ( trace.fraction < 1.0 ) 
					{
						PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
					}
				}
			}
		}
		else
		{
			if ( g_stepSlideFix->integer )
			{
				VectorCopy (down_o, pm->ps->origin);
				VectorCopy (down_v, pm->ps->velocity);
			}
		}
		if ( !g_stepSlideFix->integer )
		{
			if ( trace.fraction < 1.0 ) 
			{
				PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
			}
		}
	}

	/*
	if(cantStepUpFwd && pm->ps->origin[2] < start_o[2] + stepSize && pm->ps->origin[2] >= start_o[2])
	{//We bumped into something we could not step up
		pm->ps->pm_flags |= PMF_BLOCKED;
	}
	else
	{//We did step up, clear the bumped flag
	}
	*/
#if 0
	// if the down trace can trace back to the original position directly, don't step
	pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
	if ( trace.fraction == 1.0 ) {
		// use the original move
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend\n", c_pmove);
		}
	} else 
#endif
	{
		// use the step move
		float	delta;

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
Example #10
0
void CGCam_FollowUpdate ( void )
{
	vec3_t		center, dir, cameraAngles, vec, focus[MAX_CAMERA_GROUP_SUBJECTS];//No more than 16 subjects in a cameraGroup
	gentity_t	*from = NULL;
	centity_t	*fromCent = NULL;
	int			num_subjects = 0, i;
	qboolean	focused = qfalse;
	
	if ( client_camera.cameraGroup && client_camera.cameraGroup[0] )
	{
		//Stay centered in my cameraGroup, if I have one
		while( NULL != (from = G_Find(from, FOFS(cameraGroup), client_camera.cameraGroup)))
		{
			/*
			if ( from->s.number == client_camera.aimEntNum )
			{//This is the misc_camera_focus, we'll be removing this ent altogether eventually
				continue;
			}
			*/

			if ( num_subjects >= MAX_CAMERA_GROUP_SUBJECTS )
			{
				gi.Printf(S_COLOR_RED"ERROR: Too many subjects in shot composition %s", client_camera.cameraGroup);
				break;
			}

			fromCent = &cg_entities[from->s.number];
			if ( !fromCent )
			{
				continue;
			}

			focused = qfalse;
			if ( from->client && client_camera.cameraGroupTag && client_camera.cameraGroupTag[0] && fromCent->gent->ghoul2.size() )
			{
				int newBolt = gi.G2API_AddBolt( &fromCent->gent->ghoul2[from->playerModel], client_camera.cameraGroupTag );
				if ( newBolt != -1 )
				{
					mdxaBone_t	boltMatrix;
					vec3_t	fromAngles = {0,from->client->ps.legsYaw,0};

					gi.G2API_GetBoltMatrix( fromCent->gent->ghoul2, from->playerModel, newBolt, &boltMatrix, fromAngles, fromCent->lerpOrigin, cg.time, cgs.model_draw, fromCent->currentState.modelScale );
					gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, focus[num_subjects] );

					focused = qtrue;
				}
			}
			if ( !focused )
			{
				if ( from->s.pos.trType != TR_STATIONARY )
//				if ( from->s.pos.trType == TR_INTERPOLATE )
				{//use interpolated origin?
					if ( !VectorCompare( vec3_origin, fromCent->lerpOrigin ) )
					{//hunh?  Somehow we've never seen this gentity on the client, so there is no lerpOrigin, so cheat over to the game and use the currentOrigin
						VectorCopy( from->currentOrigin, focus[num_subjects] );
					}
					else
					{
						VectorCopy( fromCent->lerpOrigin, focus[num_subjects] );
					}
				}
				else
				{
					VectorCopy(from->currentOrigin, focus[num_subjects]);
				} 
				//FIXME: make a list here of their s.numbers instead so we can do other stuff with the list below
				if ( from->client )
				{//Track to their eyes - FIXME: maybe go off a tag?
					//FIXME: 
					//Based on FOV and distance to subject from camera, pick the point that
					//keeps eyes 3/4 up from bottom of screen... what about bars?
					focus[num_subjects][2] += from->client->ps.viewheight;
				}
			}
			if ( client_camera.cameraGroupZOfs )
			{
				focus[num_subjects][2] += client_camera.cameraGroupZOfs;
			}
			num_subjects++;
		}

		if ( !num_subjects )	// Bad cameragroup 
		{
#ifndef FINAL_BUILD
			gi.Printf(S_COLOR_RED"ERROR: Camera Focus unable to locate cameragroup: %s\n", client_camera.cameraGroup);
#endif
			return;
		}

		//Now average all points
		VectorCopy( focus[0], center );
		for( i = 1; i < num_subjects; i++ )
		{
			VectorAdd( focus[i], center, center );
		}
		VectorScale( center, 1.0f/((float)num_subjects), center );
	}
	else
	{
		return;
	}

	//Need to set a speed to keep a distance from
	//the subject- fixme: only do this if have a distance
	//set
	VectorSubtract( client_camera.subjectPos, center, vec );
	client_camera.subjectSpeed = VectorLengthSquared( vec ) * 100.0f / cg.frametime;

	/*
	if ( !cg_skippingcin.integer )
	{
		Com_Printf( S_COLOR_RED"org: %s\n", vtos(center) );
	}
	*/
	VectorCopy( center, client_camera.subjectPos );

	VectorSubtract( center, cg.refdef.vieworg, dir );//can't use client_camera.origin because it's not updated until the end of the move.

	//Get desired angle
	vectoangles(dir, cameraAngles);
	
	if ( client_camera.followInitLerp )
	{//Lerping
		float frac = cg.frametime/100.0f * client_camera.followSpeed/100.f;
		for( i = 0; i < 3; i++ )
		{
			cameraAngles[i] = AngleNormalize180( cameraAngles[i] );
			cameraAngles[i] = AngleNormalize180( client_camera.angles[i] + frac * AngleNormalize180(cameraAngles[i] - client_camera.angles[i]) );
			cameraAngles[i] = AngleNormalize180( cameraAngles[i] );
		}
#if 0
		Com_Printf( "%s\n", vtos(cameraAngles) );
#endif
	}
	else
	{//Snapping, should do this first time if follow_lerp_to_start_duration is zero
		//will lerp from this point on
		client_camera.followInitLerp = qtrue;
		for( i = 0; i < 3; i++ )
		{//normalize so that when we start lerping, it doesn't freak out
			cameraAngles[i] = AngleNormalize180( cameraAngles[i] );
		}
		//So tracker doesn't move right away thinking the first angle change
		//is the subject moving... FIXME: shouldn't set this until lerp done OR snapped?
		client_camera.subjectSpeed = 0;
	}

	//Point camera to lerp angles
	/*
	if ( !cg_skippingcin.integer )
	{
		Com_Printf( "ang: %s\n", vtos(cameraAngles) );
	}
	*/
	VectorCopy( cameraAngles, client_camera.angles );
}
Example #11
0
void CGCam_TrackEntUpdate ( void )
{//FIXME: only do every 100 ms
	gentity_t	*trackEnt = NULL;
	gentity_t	*newTrackEnt = NULL;
	qboolean	reached = qfalse;
	vec3_t		vec;
	float		dist;

	if ( client_camera.trackEntNum >= 0 && client_camera.trackEntNum < ENTITYNUM_WORLD )
	{//We're already heading to a path_corner
		trackEnt = &g_entities[client_camera.trackEntNum];
		VectorSubtract( trackEnt->currentOrigin, client_camera.origin, vec );
		dist = VectorLengthSquared( vec );
		if ( dist < 256 )//16 squared
		{//FIXME: who should be doing the using here?
			G_UseTargets( trackEnt, trackEnt );
			reached = qtrue;
		}
	}
	
	if ( trackEnt && reached )
	{
		
		if ( trackEnt->target && trackEnt->target[0] )
		{//Find our next path_corner
			newTrackEnt = G_Find( NULL, FOFS(targetname), trackEnt->target );
			if ( newTrackEnt )
			{
				if ( newTrackEnt->radius < 0 )
				{//Don't bother trying to maintain a radius
					client_camera.distance = 0;
					client_camera.speed = client_camera.initSpeed;
				}
				else if ( newTrackEnt->radius > 0 )
				{
					client_camera.distance = newTrackEnt->radius;
				}

				if ( newTrackEnt->speed < 0 )
				{//go back to our default speed
					client_camera.speed = client_camera.initSpeed;
				}
				else if ( newTrackEnt->speed > 0 )
				{
					client_camera.speed = newTrackEnt->speed/10.0f;
				}
			}
		}
		else
		{//stop thinking if this is the last one
			CGCam_TrackDisable();
		}
	}

	if ( newTrackEnt )
	{//Update will lerp this
		client_camera.info_state |= CAMERA_TRACKING; 
		client_camera.trackEntNum = newTrackEnt->s.number; 
		VectorCopy( newTrackEnt->currentOrigin, client_camera.trackToOrg );
	}

	client_camera.nextTrackEntUpdateTime = cg.time + 100;
}
Example #12
0
/*
===============
SV_AddEntitiesVisibleFromPoint
===============
*/
static void SV_AddEntitiesVisibleFromPoint( int psIndex, int clientNum, vec3_t origin, clientSnapshot_t *frame, 
									snapshotEntityNumbers_t *eNums, qboolean portal ) {
	int		e, i;
	sharedEntity_t *ent;
	svEntity_t	*svEnt;
	int		l;
	int		clientarea, clientcluster;
	int		leafnum;
	byte	*clientpvs;
	byte	*bitvector;

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

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

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

	clientpvs = CM_ClusterPVS (clientcluster);

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

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

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

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

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

		svEnt = SV_SvEntityForGentity( ent );

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

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

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

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

		bitvector = clientpvs;

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

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

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

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

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

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

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

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

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

				if ( ment == ent ) {
					continue;
				}

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

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

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

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

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

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

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

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

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

	}
Example #13
0
/*
==================
S_Base_AddLoopingSound

Called during entity generation for a frame
Include velocity in case I get around to doing doppler...
==================
*/
static void S_Base_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
	sfx_t *sfx;

	if ( !s_soundStarted || s_soundMuted ) {
		return;
	}

	if (entityNum >= MAX_LOOP_SOUNDS  ||  entityNum < 0) {
		Com_Printf(S_COLOR_YELLOW "%s() invalid entity number %d\n", __FUNCTION__, entityNum);
		return;
	}

	if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
		Com_Printf( S_COLOR_YELLOW "%s() handle %i out of range\n", __FUNCTION__, sfxHandle );
		return;
	}

	sfx = &s_knownSfx[ sfxHandle ];
	//Com_Printf("S_Base_AddLoopingSound %d : %s  velocity %f\n", sfxHandle, sfx->soundName, VectorLengthSquared(velocity));

	if (sfx->inMemory == qfalse) {
		S_memoryLoad(sfx);
	}

	if ( !sfx->soundLength ) {
		Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
	}

	VectorCopy( origin, loopSounds[entityNum].origin );
	VectorCopy( velocity, loopSounds[entityNum].velocity );
	loopSounds[entityNum].active = qtrue;
	loopSounds[entityNum].kill = qtrue;
	loopSounds[entityNum].doppler = qfalse;
	loopSounds[entityNum].oldDopplerScale = 1.0;
	loopSounds[entityNum].dopplerScale = 1.0;
	loopSounds[entityNum].sfx = sfx;

	if (s_doppler->integer && VectorLengthSquared(velocity)>0.0) {
		vec3_t	out;
		float	lena, lenb;

		//Com_Printf("distance: %f\n", Distance(loopSounds[listener_number].origin, loopSounds[entityNum].origin));
		//Com_Printf("distance: %f\n", Distance(listener_origin, loopSounds[entityNum].origin));

		loopSounds[entityNum].doppler = qtrue;
		//lena = DistanceSquared(loopSounds[listener_number].origin, loopSounds[entityNum].origin);
		lena = DistanceSquared(listener_origin, loopSounds[entityNum].origin);
		VectorAdd(loopSounds[entityNum].origin, loopSounds[entityNum].velocity, out);
		//lenb = DistanceSquared(loopSounds[listener_number].origin, out);
		lenb = DistanceSquared(listener_origin, out);
		if ((loopSounds[entityNum].framenum+1) != cls.framecount) {
			loopSounds[entityNum].oldDopplerScale = 1.0;
		} else {
			loopSounds[entityNum].oldDopplerScale = loopSounds[entityNum].dopplerScale;
		}
		loopSounds[entityNum].dopplerScale = lenb/(lena*100);
		if (loopSounds[entityNum].dopplerScale<=1.0) {
			loopSounds[entityNum].doppler = qfalse;			// don't bother doing the math
		} else if (loopSounds[entityNum].dopplerScale>MAX_DOPPLER_SCALE) {
		//} else if (loopSounds[entityNum].dopplerScale > 2.0) {
			loopSounds[entityNum].dopplerScale = MAX_DOPPLER_SCALE;
			//loopSounds[entityNum].dopplerScale = 2.0;
		}
		//if (loopSounds[entityNum].doppler) {
			//Com_Printf("dopplerscale %f\n", loopSounds[entityNum].dopplerScale);
		//}
		//if (loopSounds[entityNum].doppler) {
			//Com_Printf("doppler set: %d\n", loopSounds[entityNum].doppler);
		//}
	}

	loopSounds[entityNum].framenum = cls.framecount;
}
Example #14
0
void GCam_FollowUpdate ( void )
{
	vec3_t		center, dir, cameraAngles, vec, focus[MAX_CAMERA_GROUP_SUBJECTS];//No more than 16 subjects in a cameraGroup
	gentity_t	*from = NULL;
	//centity_t	*fromCent = NULL;
	int			num_subjects = 0, i;
	qboolean	focused = qfalse;
	
	if ( client_camera.cameraGroup[0] == -1 )
	{//follow disabled
		return;
	}

	for( i = 0; i < MAX_CAMERA_GROUP_SUBJECTS; i++ )
	{
		//fromCent = &cg_entities[client_camera.cameraGroup[i]];
		from = &g_entities[client_camera.cameraGroup[i]];
		if ( !from )
		{
			continue;
		}

		focused = qfalse;
		
		if ( (from->s.eType == ET_PLAYER 
			|| from->s.eType == ET_NPC 
			|| from->s.number < MAX_CLIENTS)
			&& client_camera.cameraGroupTag && client_camera.cameraGroupTag[0] )
		{
			int newBolt = trap_G2API_AddBolt( &from->ghoul2, 0, client_camera.cameraGroupTag );
			if ( newBolt != -1 )
			{
				mdxaBone_t	boltMatrix;
				vec3_t		angle;

				VectorSet(angle, 0, from->client->ps.viewangles[YAW], 0);

				trap_G2API_GetBoltMatrix( &from->ghoul2, 0, newBolt, &boltMatrix, angle, from->client->ps.origin, level.time, NULL, from->modelScale );
				BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, focus[num_subjects] );

				focused = qtrue;
			}
		}
		if ( !focused )
		{
			VectorCopy(from->r.currentOrigin, focus[num_subjects]);
			if ( from->s.eType == ET_PLAYER 
				|| from->s.eType == ET_NPC 
				|| from->s.number < MAX_CLIENTS )
			{//Track to their eyes - FIXME: maybe go off a tag?
				focus[num_subjects][2] += from->client->ps.viewheight;
			}
		}
		if ( client_camera.cameraGroupZOfs )
		{
			focus[num_subjects][2] += client_camera.cameraGroupZOfs;
		}
		num_subjects++;
	}

	if ( !num_subjects )	// Bad cameragroup 
	{
#ifndef FINAL_BUILD
		G_Printf(S_COLOR_RED"ERROR: Camera Focus unable to locate cameragroup: %s\n", client_camera.cameraGroup);
#endif
		return;
	}

	//Now average all points
	VectorCopy( focus[0], center );
	for( i = 1; i < num_subjects; i++ )
	{
		VectorAdd( focus[i], center, center );
	}
	VectorScale( center, 1.0f/((float)num_subjects), center );

	//Need to set a speed to keep a distance from
	//the subject- fixme: only do this if have a distance
	//set
	VectorSubtract( client_camera.subjectPos, center, vec );
	client_camera.subjectSpeed = VectorLengthSquared( vec ) * 100.0f / g_TimeSinceLastFrame;

	VectorCopy( center, client_camera.subjectPos );

	VectorSubtract( center, camerapos, dir );//can't use client_camera.origin because it's not updated until the end of the move.

	//Get desired angle
	vectoangles(dir, cameraAngles);
	
	if ( client_camera.followInitLerp )
	{//Lerping
		float frac = g_TimeSinceLastFrame/100.0f * client_camera.followSpeed/100.f;
		for( i = 0; i < 3; i++ )
		{
			cameraAngles[i] = AngleNormalize180( cameraAngles[i] );
			cameraAngles[i] = AngleNormalize180( client_camera.angles[i] + frac * AngleNormalize180(cameraAngles[i] - client_camera.angles[i]) );
			cameraAngles[i] = AngleNormalize180( cameraAngles[i] );
		}
	}
	else
	{//Snapping, should do this first time if follow_lerp_to_start_duration is zero
		//will lerp from this point on
		client_camera.followInitLerp = qtrue;
		for( i = 0; i < 3; i++ )
		{//normalize so that when we start lerping, it doesn't freak out
			cameraAngles[i] = AngleNormalize180( cameraAngles[i] );
		}
		//So tracker doesn't move right away thinking the first angle change
		//is the subject moving... FIXME: shouldn't set this until lerp done OR snapped?
		client_camera.subjectSpeed = 0;
	}
	VectorCopy( cameraAngles, client_camera.angles );
}
Example #15
0
/*
** SurfIsOffscreen
**
** Determines if a surface is completely offscreen.
*/
static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
	float shortest = 100000000;
	int entityNum;
	int numTriangles;
	shader_t *shader;
	int		fogNum;
	int dlighted;
	vec4_t clip, eye;
	int i;
	unsigned int pointOr = 0;
	unsigned int pointAnd = (unsigned int)~0;

	if ( glConfig.smpActive ) {		// FIXME!  we can't do RB_BeginSurface/RB_EndSurface stuff with smp!
		return qfalse;
	}

	R_RotateForViewer();

	R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
	RB_BeginSurface( shader, fogNum );
	rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );

	assert( tess.numVertexes < 128 );

	for ( i = 0; i < tess.numVertexes; i++ )
	{
		int j;
		unsigned int pointFlags = 0;

		R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );

		for ( j = 0; j < 3; j++ )
		{
			if ( clip[j] >= clip[3] )
			{
				pointFlags |= (1 << (j*2));
			}
			else if ( clip[j] <= -clip[3] )
			{
				pointFlags |= ( 1 << (j*2+1));
			}
		}
		pointAnd &= pointFlags;
		pointOr |= pointFlags;
	}

	// trivially reject
	if ( pointAnd )
	{
		return qtrue;
	}

	// determine if this surface is backfaced and also determine the distance
	// to the nearest vertex so we can cull based on portal range.  Culling
	// based on vertex distance isn't 100% correct (we should be checking for
	// range to the surface), but it's good enough for the types of portals
	// we have in the game right now.
	numTriangles = tess.numIndexes / 3;

	for ( i = 0; i < tess.numIndexes; i += 3 )
	{
		vec3_t normal;
		float len;

		VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal );

		len = VectorLengthSquared( normal );			// lose the sqrt
		if ( len < shortest )
		{
			shortest = len;
		}

		if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 )
		{
			numTriangles--;
		}
	}
	if ( !numTriangles )
	{
		return qtrue;
	}

	// mirrors can early out at this point, since we don't do a fade over distance
	// with them (although we could)
	if ( IsMirror( drawSurf, entityNum ) )
	{
		return qfalse;
	}

	if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
	{
		return qtrue;
	}

	return qfalse;
}
Example #16
0
static void SVT3_AddEntitiesVisibleFromPoint( int clientNum, const vec3_t origin, q3clientSnapshot_t* frame,
	snapshotEntityNumbers_t* eNums, bool portal, bool localClient ) {
	// during an error shutdown message we may need to transmit
	// the shutdown message after the server has shutdown, so
	// specfically check for it
	if ( !sv.state ) {
		return;
	}

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

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

	byte* clientpvs = CM_ClusterPVS( clientcluster );

	idEntity3* playerEnt = SVT3_EntityNum( clientNum );
	if ( playerEnt->GetSvFlagSelfPortal() ) {
		SVT3_AddEntitiesVisibleFromPoint( clientNum, playerEnt->GetOrigin2(), frame, eNums, portal, localClient );
	}

	int l;
	for ( int e = 0; e < sv.q3_num_entities; e++ ) {
		idEntity3* ent = SVT3_EntityNum( e );

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

		if ( ent->GetNumber() != e ) {
			common->DPrintf( "FIXING ENT->S.NUMBER!!!\n" );
			ent->SetNumber( e );
		}

		// entities can be flagged to explicitly not be sent to the client
		if ( ent->GetSvFlags() & Q3SVF_NOCLIENT ) {
			continue;
		}

		// entities can be flagged to be sent to only one client
		if ( ent->GetSvFlagSingleClient() ) {
			if ( ent->GetSingleClient() != clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to everyone but one client
		if ( ent->GetSvFlagNotSingleClient() ) {
			if ( ent->GetSingleClient() == clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to a given mask of clients
		if ( ent->GetSvFlagClientMask() ) {
			if ( clientNum >= 32 ) {
				common->Error( "Q3SVF_CLIENTMASK: cientNum > 32\n" );
			}
			if ( ~ent->GetSingleClient() & ( 1 << clientNum ) ) {
				continue;
			}
		}

		q3svEntity_t* svEnt = &sv.q3_svEntities[ e ];

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

		// if this client is viewing from a camera, only add ents visible from portal ents
		if ( playerEnt->GetEFlagViewingCamera() && !portal ) {
			if ( ent->GetSvFlags() & Q3SVF_PORTAL ) {
				SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
				SVT3_AddEntitiesVisibleFromPoint( clientNum, ent->GetOrigin2(), frame, eNums, true, localClient );
			}
			continue;
		}

		// broadcast entities are always sent
		if ( ent->GetSvFlags() & Q3SVF_BROADCAST ) {
			SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
			continue;
		}

		byte* bitvector = clientpvs;

		// Gordon: just check origin for being in pvs, ignore bmodel extents
		if ( ent->GetSvFlagIgnoreBModelExtents() ) {
			if ( bitvector[ svEnt->originCluster >> 3 ] & ( 1 << ( svEnt->originCluster & 7 ) ) ) {
				SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
			}
			continue;
		}

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

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

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

		//----(SA) added "visibility dummies"
		if ( ent->GetSvFlags() & WOLFSVF_VISDUMMY ) {
			//find master;
			idEntity3* ment = SVT3_EntityNum( ent->GetOtherEntityNum() );

			q3svEntity_t* master = &sv.q3_svEntities[ ent->GetOtherEntityNum() ];

			if ( master->snapshotCounter == sv.q3_snapshotCounter || !ment->GetLinked() ) {
				goto notVisible;
			}

			SVT3_AddEntToSnapshot( clientNum, master, ment, eNums );
			// master needs to be added, but not this dummy ent
			goto notVisible;
		} else if ( ent->GetSvFlags() & WOLFSVF_VISDUMMY_MULTIPLE ) {
			{
				for ( int h = 0; h < sv.q3_num_entities; h++ ) {
					idEntity3* ment = SVT3_EntityNum( h );

					if ( ment == ent ) {
						continue;
					}

					q3svEntity_t* master = &sv.q3_svEntities[ h ];

					if ( !ment->GetLinked() ) {
						continue;
					}

					if ( ment->GetNumber() != h ) {
						common->DPrintf( "FIXING vis dummy multiple ment->S.NUMBER!!!\n" );
						ment->SetNumber( h );
					}

					if ( ment->GetSvFlags() & Q3SVF_NOCLIENT ) {
						continue;
					}

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

					if ( ment->GetOtherEntityNum() == ent->GetNumber() ) {
						SVT3_AddEntToSnapshot( clientNum, master, ment, eNums );
					}
				}
				goto notVisible;
			}
		}

		// add it
		SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );

		// if its a portal entity, add everything visible from its camera position
		if ( ent->GetSvFlags() & Q3SVF_PORTAL ) {
			if ( ent->GetGeneric1() ) {
				vec3_t dir;
				VectorSubtract( ent->GetOrigin(), origin, dir );
				if ( VectorLengthSquared( dir ) > ( float )ent->GetGeneric1() * ent->GetGeneric1() ) {
					continue;
				}
			}
			SVT3_AddEntitiesVisibleFromPoint( clientNum, ent->GetOrigin2(), frame, eNums, true, localClient );
		}

		continue;

notVisible:

		// Ridah, if this entity has changed events, then send it regardless of whether we can see it or not
		// DHM - Nerve :: not in multiplayer please
		if ( GGameType & ( GAME_WolfSP | GAME_WolfMP ) && svt3_gametype->integer == Q3GT_SINGLE_PLAYER && localClient ) {
			if ( ent->GetEventTime() == svs.q3_time ) {
				ent->SetEFlagNoDraw();		// don't draw, just process event
				SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
			} else if ( ent->GetEType() == Q3ET_PLAYER ) {
				// keep players around if they are alive and active (so sounds dont get messed up)
				if ( !ent->GetEFlagDead() ) {
					ent->SetEFlagNoDraw();		// don't draw, just process events and sounds
					SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
				}
			}
		}
	}
Example #17
0
/*
==================
PM_StepSlideMove

==================
*/
void PM_StepSlideMove( float gravMod ) 
{
	vec3_t		start_o, start_v;
	vec3_t		down_o, down_v;
	vec3_t		slideMove, stepUpMove;
	trace_t		trace;
	vec3_t		up, down;
	qboolean	cantStepUpFwd, isATST = qfalse;;
	int			stepSize = STEPSIZE;

	VectorCopy (pm->ps->origin, start_o);
	VectorCopy (pm->ps->velocity, start_v);

	if ( PM_SlideMove( gravMod ) == 0 ) {
		return;		// we got exactly where we wanted to go first try	
	}//else Bumped into something, see if we can step over it

	if ( pm->gent && pm->gent->client && pm->gent->client->NPC_class == CLASS_ATST)
	{
		isATST = qtrue;
		stepSize = 66;//hack for AT-ST stepping, slightly taller than a standing stormtrooper
	}
	else if ( pm->maxs[2] <= 0 )
	{//short little guys can't go up steps... FIXME: just make this a flag for certain NPCs- especially ones that roll?
		stepSize = 4;
	}

	//Q3Final addition...
	VectorCopy(start_o, down);
	down[2] -= stepSize;
	pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, G2_NOCOLLIDE, 0);
	VectorSet(up, 0, 0, 1);
	// never step up when you still have up velocity
	if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
			DotProduct(trace.plane.normal, up) < 0.7)) {
		return;
	}

	if ( !pm->ps->velocity[0] && !pm->ps->velocity[1] ) 
	{//All our velocity was cancelled sliding
		return;
	}

	VectorCopy (pm->ps->origin, down_o);
	VectorCopy (pm->ps->velocity, down_v);

	VectorCopy (start_o, up);
	up[2] += stepSize;

	// test the player position if they were a stepheight higher

	pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask, G2_NOCOLLIDE, 0);
	if ( trace.allsolid || trace.startsolid || trace.fraction == 0) {
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend can't step\n", c_pmove);
		}
		return;		// can't step up
	}

	// try slidemove from this position
	VectorCopy (trace.endpos, pm->ps->origin);
	VectorCopy (start_v, pm->ps->velocity);

	cantStepUpFwd = PM_SlideMove( gravMod );

	//compare the initial slidemove and this slidemove from a step up position
	VectorSubtract( down_o, start_o, slideMove );
	VectorSubtract( trace.endpos, pm->ps->origin, stepUpMove );

	if ( fabs(stepUpMove[0]) < 0.1 && fabs(stepUpMove[1]) < 0.1 && VectorLengthSquared( slideMove ) > VectorLengthSquared( stepUpMove ) )
	{
		//slideMove was better, use it
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
	}
	else
	{
		// push down the final amount
		VectorCopy (pm->ps->origin, down);
		down[2] -= stepSize;
		pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, G2_NOCOLLIDE, 0);
		if ( !trace.allsolid ) 
		{
			if ( pm->ps->clientNum 
				&& isATST 
				&& g_entities[trace.entityNum].client 
				&& g_entities[trace.entityNum].client->playerTeam == pm->gent->client->playerTeam )
			{//AT-ST's don't step up on allies
			}
			else
			{
				VectorCopy( trace.endpos, pm->ps->origin );
			}
		}
		if ( trace.fraction < 1.0 ) 
		{
			PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
		}
	}
	
	/*
	if(cantStepUpFwd && pm->ps->origin[2] < start_o[2] + stepSize && pm->ps->origin[2] >= start_o[2])
	{//We bumped into something we could not step up
		pm->ps->pm_flags |= PMF_BLOCKED;
	}
	else
	{//We did step up, clear the bumped flag
		pm->ps->pm_flags &= ~PMF_BUMPED;
	}
	*/
#if 0
	// if the down trace can trace back to the original position directly, don't step
	pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
	if ( trace.fraction == 1.0 ) {
		// use the original move
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend\n", c_pmove);
		}
	} else 
#endif
	{
		// use the step move
		float	delta;

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
Example #18
0
/*
===============
SV_AddEntitiesVisibleFromPoint
===============
*/
static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame,
									snapshotEntityNumbers_t *eNums, qboolean portal ) {
	int		e, i;
	sharedEntity_t *ent;
	svEntity_t	*svEnt;
	int		l;
	int		clientarea, clientcluster;
	int		leafnum;
	int		c_fullsend;
	byte	*clientpvs;
	byte	*bitvector;

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

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

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

	clientpvs = CM_ClusterPVS (clientcluster);

	c_fullsend = 0;

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

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

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

		svEnt = SV_SvEntityForGentity( ent );

		if ( sv.gentitiesMV != NULL && sv.gentitySizeMV > 0 )
		{
			mvsharedEntity_t *mvEnt = MV_EntityNum(e);

			if ( VM_MVAPILevel( gvm ) >= 2 ) {
				// MV entities can be flagged to be sent only to
				// spectators or non-spectators
				if ( frame->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ||
					(frame->ps.pm_flags & PMF_FOLLOW) )
				{
					if ( mvEnt->mvFlags & MVF_NOSPEC )
						continue;
				}
				else
				{
					if ( mvEnt->mvFlags & MVF_SPECONLY )
						continue;
				}
			}

			// MV entities can be flagged to be sent only to specific
			// clients (can't filter following spectators this way)
			if ( mvEnt->snapshotIgnore[frame->ps.clientNum] ) continue;
			else if ( mvEnt->snapshotEnforce[frame->ps.clientNum] )
			{
				SV_AddEntToSnapshot( svEnt, ent, eNums );
				continue;
			}
		}

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

		// entities can be flagged to be sent to only one client
		if ( ent->r.svFlags & SVF_SINGLECLIENT ) {
			if ( ent->r.singleClient != frame->ps.clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to everyone but one client
		if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) {
			if ( ent->r.singleClient == frame->ps.clientNum ) {
				continue;
			}
		}

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

		// broadcast entities are always sent, and so is the main player so we don't see noclip weirdness
		if ( ent->r.svFlags & SVF_BROADCAST || (e == frame->ps.clientNum) || (ent->r.broadcastClients[frame->ps.clientNum/32] & (1<<(frame->ps.clientNum%32))))
		{
			SV_AddEntToSnapshot( svEnt, ent, eNums );
			continue;
		}

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

		bitvector = clientpvs;

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

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

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

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

	}
/*
===============
SV_AddEntitiesVisibleFromPoint
===============
*/
static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, 
									snapshotEntityNumbers_t *eNums, qboolean portal ) {
	int		e, i;
	sharedEntity_t *ent;
	svEntity_t	*svEnt;
	int		l;
	int		clientarea, clientcluster;
	int		leafnum;
	byte	*clientpvs;
	byte	*bitvector;

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

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

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

	clientpvs = CM_ClusterPVS (clientcluster);

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

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

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

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

		// entities can be flagged to be sent to only one client
		if ( ent->r.svFlags & SVF_SINGLECLIENT ) {
			if ( ent->r.singleClient != frame->ps.clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to everyone but one client
		if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) {
			if ( ent->r.singleClient == frame->ps.clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to a given mask of clients
		if ( ent->r.svFlags & SVF_CLIENTMASK ) {
			if (frame->ps.clientNum >= 32)
				Com_Error( ERR_DROP, "SVF_CLIENTMASK: clientNum >= 32" );
			if (~ent->r.singleClient & (1 << frame->ps.clientNum))
				continue;
		}

		svEnt = SV_SvEntityForGentity( ent );

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

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

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

		bitvector = clientpvs;

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

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

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

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

	}
//-----------------------------------------------------
static qboolean turretG2_find_enemies( gentity_t *self )
//-----------------------------------------------------
{
    qboolean	found = qfalse;
    int			i, count;
    float		bestDist = self->radius * self->radius;
    float		enemyDist;
    vec3_t		enemyDir, org, org2;
    qboolean	foundClient = qfalse;
    gentity_t	*entity_list[MAX_GENTITIES], *target, *bestTarget = NULL;

    if ( self->aimDebounceTime > level.time ) // time since we've been shut off
    {
        // We were active and alert, i.e. had an enemy in the last 3 secs
        if ( self->painDebounceTime < level.time )
        {
            if ( !(self->spawnflags&SPF_TURRETG2_TURBO) )
            {
                G_Sound(self, CHAN_BODY, G_SoundIndex( "sound/chars/turret/ping.wav" ));
            }
            self->painDebounceTime = level.time + 1000;
        }
    }

    VectorCopy( self->r.currentOrigin, org2 );
    if ( self->spawnflags & 2 )
    {
        org2[2] += 20;
    }
    else
    {
        org2[2] -= 20;
    }

    count = G_RadiusList( org2, self->radius, self, qtrue, entity_list );

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

        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&&self->targetname&&Q_stricmp(target->NPC_targetname,self->targetname)!=0) )//not in invicible bbrush, but can only be broken by an NPC that is not me
            {
                continue;
            }
            //else: we will shoot at bbrushes!
        }
        if ( target == self || !target->takedamage || target->health <= 0 || ( target->flags & FL_NOTARGET ))
        {
            continue;
        }
        if ( target->client && target->client->sess.sessionTeam == TEAM_SPECTATOR )
        {
            continue;
        }
        if ( self->alliedTeam )
        {
            if ( target->client )
            {
                if ( target->client->sess.sessionTeam == self->alliedTeam )
                {
                    // A bot/client/NPC we don't want to shoot
                    continue;
                }
            }
            else if ( target->teamnodmg == self->alliedTeam )
            {
                // An ent we don't want to shoot
                continue;
            }
        }
        if ( !trap_InPVS( org2, target->r.currentOrigin ))
        {
            continue;
        }

        if ( target->client )
        {
            VectorCopy( target->client->renderInfo.eyePoint, org );
        }
        else
        {
            VectorCopy( target->r.currentOrigin, org );
        }

        if ( self->spawnflags & 2 )
        {
            org[2] -= 15;
        }
        else
        {
            org[2] += 5;
        }

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

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

            if ( enemyDist < bestDist || (target->client && !foundClient))// all things equal, keep current
            {
                if ( self->attackDebounceTime < level.time )
                {
                    // We haven't fired or acquired an enemy in the last 2 seconds-start-up sound
                    if ( !(self->spawnflags&SPF_TURRETG2_TURBO) )
                    {
                        G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/chars/turret/startup.wav" ));
                    }

                    // Wind up turrets for a bit
                    self->attackDebounceTime = level.time + 1400;
                }

                bestTarget = target;
                bestDist = enemyDist;
                found = qtrue;
                if ( target->client )
                {   //prefer clients over non-clients
                    foundClient = qtrue;
                }
            }
        }
    }

    if ( found )
    {
        /*
        if ( !self->enemy )
        {//just aquired one
        	AddSoundEvent( bestTarget, self->r.currentOrigin, 256, AEL_DISCOVERED );
        	AddSightEvent( bestTarget, self->r.currentOrigin, 512, AEL_DISCOVERED, 20 );
        }
        */
        G_SetEnemy( self, bestTarget );
        if ( VALIDSTRING( self->target2 ))
        {
            G_UseTargets2( self, self, self->target2 );
        }
    }

    return found;
}
Example #21
0
/*
=================
R_SubdividePatchToGrid
=================
*/
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
								drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
	int			i, j, k, l;
	drawVert_t	prev, next, mid;
	float		len, maxLen;
	int			dir;
	int			t;
	MAC_STATIC drawVert_t	ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
	float		errorTable[2][MAX_GRID_SIZE];

	for ( i = 0 ; i < width ; i++ ) {
		for ( j = 0 ; j < height ; j++ ) {
			ctrl[j][i] = points[j*width+i];
		}
	}

	for ( dir = 0 ; dir < 2 ; dir++ ) {

		for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
			errorTable[dir][j] = 0;
		}

		// horizontal subdivisions
		for ( j = 0 ; j + 2 < width ; j += 2 ) {
			// check subdivided midpoints against control points

			// FIXME: also check midpoints of adjacent patches against the control points
			// this would basically stitch all patches in the same LOD group together.

			maxLen = 0;
			for ( i = 0 ; i < height ; i++ ) {
				vec3_t		midxyz;
				vec3_t		dir;
				vec3_t		projected;
				float		d;

				// calculate the point on the curve
				for ( l = 0 ; l < 3 ; l++ ) {
					midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
							+ ctrl[i][j+2].xyz[l] ) * 0.25f;
				}

				// see how far off the line it is
				// using dist-from-line will not account for internal
				// texture warping, but it gives a lot less polygons than
				// dist-from-midpoint
				VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
				VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
				VectorNormalize( dir );

				d = DotProduct( midxyz, dir );
				VectorScale( dir, d, projected );
				VectorSubtract( midxyz, projected, midxyz);
				len = VectorLengthSquared( midxyz );			// we will do the sqrt later

				if ( len > maxLen ) {
					maxLen = len;
				}
			}

			maxLen = sqrt(maxLen);
			// if all the points are on the lines, remove the entire columns
			if ( maxLen < 0.1f ) {
				errorTable[dir][j+1] = 999;
				continue;
			}

			// see if we want to insert subdivided columns
			if ( width + 2 > MAX_GRID_SIZE ) {
				errorTable[dir][j+1] = 1.0f/maxLen;
				continue;	// can't subdivide any more
			}

			if ( maxLen <= r_subdivisions->value ) {
				errorTable[dir][j+1] = 1.0f/maxLen;
				continue;	// didn't need subdivision
			}

			errorTable[dir][j+2] = 1.0f/maxLen;

			// insert two columns and replace the peak
			width += 2;
			for ( i = 0 ; i < height ; i++ ) {
				LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
				LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
				LerpDrawVert( &prev, &next, &mid );

				for ( k = width - 1 ; k > j + 3 ; k-- ) {
					ctrl[i][k] = ctrl[i][k-2];
				}
				ctrl[i][j + 1] = prev;
				ctrl[i][j + 2] = mid;
				ctrl[i][j + 3] = next;
			}

			// back up and recheck this set again, it may need more subdivision
			j -= 2;

		}

		Transpose( width, height, ctrl );
		t = width;
		width = height;
		height = t;
	}


	// put all the aproximating points on the curve
	PutPointsOnCurve( ctrl, width, height );

	// cull out any rows or columns that are colinear
	for ( i = 1 ; i < width-1 ; i++ ) {
		if ( errorTable[0][i] != 999 ) {
			continue;
		}
		for ( j = i+1 ; j < width ; j++ ) {
			for ( k = 0 ; k < height ; k++ ) {
				ctrl[k][j-1] = ctrl[k][j];
			}
			errorTable[0][j-1] = errorTable[0][j];
		}
		width--;
	}

	for ( i = 1 ; i < height-1 ; i++ ) {
		if ( errorTable[1][i] != 999 ) {
			continue;
		}
		for ( j = i+1 ; j < height ; j++ ) {
			for ( k = 0 ; k < width ; k++ ) {
				ctrl[j-1][k] = ctrl[j][k];
			}
			errorTable[1][j-1] = errorTable[1][j];
		}
		height--;
	}

#if 1
	// flip for longest tristrips as an optimization
	// the results should be visually identical with or
	// without this step
	if ( height > width ) {
		Transpose( width, height, ctrl );
		InvertErrorTable( errorTable, width, height );
		t = width;
		width = height;
		height = t;
		InvertCtrl( width, height, ctrl );
	}
#endif

	// calculate normals
	MakeMeshNormals( width, height, ctrl );

	return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
}
//-----------------------------------------------------
void turretG2_base_think( gentity_t *self )
//-----------------------------------------------------
{
    qboolean	turnOff = qtrue;
    float		enemyDist;
    vec3_t		enemyDir, org, org2;

    self->nextthink = level.time + FRAMETIME;

    if ( self->health <= 0 )
    {   //dead
        if (self->spawnflags & SPF_TURRETG2_CANRESPAWN)
        {   //can respawn
            if ( self->genericValue5 && self->genericValue5 < level.time )
            {   //we are dead, see if it's time to respawn
                turretG2_respawn( self );
            }
        }
        return;
    }
    else if ( self->spawnflags & 1 )
    {   // not turned on
        turretG2_turnoff( self );
        turretG2_aim( self );

        // No target
        self->flags |= FL_NOTARGET;
        return;
    }
    else
    {
        // I'm all hot and bothered
        self->flags &= ~FL_NOTARGET;
    }

    if ( self->enemy )
    {
        if ( self->enemy->health < 0
                || !self->enemy->inuse )
        {
            self->enemy = NULL;
        }
    }

    if ( self->last_move_time < level.time )
    {   //MISNOMER: used a enemy recalcing debouncer
        if ( turretG2_find_enemies( self ) )
        {   //found one
            turnOff = qfalse;
            if ( self->enemy->client )
            {   //hold on to clients for a min of 3 seconds
                self->last_move_time = level.time + 3000;
            }
            else
            {   //hold less
                self->last_move_time = level.time + 500;
            }
        }
    }

    if ( self->enemy != NULL )
    {
        if ( self->enemy->client && self->enemy->client->sess.sessionTeam == TEAM_SPECTATOR )
        {   //don't keep going after spectators
            self->enemy = NULL;
        }
        else
        {   //FIXME: remain single-minded or look for a new enemy every now and then?
            // enemy is alive
            VectorSubtract( self->enemy->r.currentOrigin, self->r.currentOrigin, enemyDir );
            enemyDist = VectorLengthSquared( enemyDir );

            if ( enemyDist < self->radius * self->radius )
            {
                // was in valid radius
                if ( trap_InPVS( self->r.currentOrigin, self->enemy->r.currentOrigin ) )
                {
                    // Every now and again, check to see if we can even trace to the enemy
                    trace_t tr;

                    if ( self->enemy->client )
                    {
                        VectorCopy( self->enemy->client->renderInfo.eyePoint, org );
                    }
                    else
                    {
                        VectorCopy( self->enemy->r.currentOrigin, org );
                    }
                    VectorCopy( self->r.currentOrigin, org2 );
                    if ( self->spawnflags & 2 )
                    {
                        org2[2] += 10;
                    }
                    else
                    {
                        org2[2] -= 10;
                    }
                    trap_Trace( &tr, org2, NULL, NULL, org, self->s.number, MASK_SHOT );

                    if ( !tr.allsolid && !tr.startsolid && tr.entityNum == self->enemy->s.number )
                    {
                        turnOff = qfalse;	// Can see our enemy
                    }
                }
            }

        }
    }

    if ( turnOff )
    {
        if ( self->bounceCount < level.time ) // bounceCount is used to keep the thing from ping-ponging from on to off
        {
            turretG2_turnoff( self );
        }
    }
    else
    {
        // keep our enemy for a minimum of 2 seconds from now
        self->bounceCount = level.time + 2000 + random() * 150;
    }

    turretG2_aim( self );
    if ( !turnOff )
    {
        turretG2_head_think( self );
    }
}
Example #23
0
/*
==================
CM_Trace
==================
*/
void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs,
						clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ) {
	int			i;
	traceWork_t	tw;
	vec3_t		offset;

	const cmodel_t* cmod = CM_ClipHandleToModel( model );

	cm.checkcount++;		// for multi-check avoidance

	c_traces++;				// for statistics, may be zeroed

	// fill in a default trace
	Com_Memset( &tw, 0, sizeof(tw) );
	tw.trace.fraction = 1;	// assume it goes the entire distance until shown otherwise
	VectorCopy(origin, tw.modelOrigin);

	if (!cm.numNodes) {
		*results = tw.trace;
		return;	// map not loaded, shouldn't happen
	}

	// allow NULL to be passed in for 0,0,0
	if ( !mins ) {
		mins = vec3_origin;
	}
	if ( !maxs ) {
		maxs = vec3_origin;
	}

	// set basic parms
	tw.contents = brushmask;

	// adjust so that mins and maxs are always symetric, which
	// avoids some complications with plane expanding of rotated
	// bmodels
	for ( i = 0 ; i < 3 ; i++ ) {
		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
		tw.size[0][i] = mins[i] - offset[i];
		tw.size[1][i] = maxs[i] - offset[i];
		tw.start[i] = start[i] + offset[i];
		tw.end[i] = end[i] + offset[i];
	}

	// if a sphere is already specified
	if ( sphere ) {
		tw.sphere = *sphere;
	}
	else {
		tw.sphere.use = capsule;
		tw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2]: tw.size[1][0];
		tw.sphere.halfheight = tw.size[1][2];
		VectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius );
	}

	tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];

	// tw.offsets[signbits] = vector to apropriate corner from origin
	tw.offsets[0][0] = tw.size[0][0];
	tw.offsets[0][1] = tw.size[0][1];
	tw.offsets[0][2] = tw.size[0][2];

	tw.offsets[1][0] = tw.size[1][0];
	tw.offsets[1][1] = tw.size[0][1];
	tw.offsets[1][2] = tw.size[0][2];

	tw.offsets[2][0] = tw.size[0][0];
	tw.offsets[2][1] = tw.size[1][1];
	tw.offsets[2][2] = tw.size[0][2];

	tw.offsets[3][0] = tw.size[1][0];
	tw.offsets[3][1] = tw.size[1][1];
	tw.offsets[3][2] = tw.size[0][2];

	tw.offsets[4][0] = tw.size[0][0];
	tw.offsets[4][1] = tw.size[0][1];
	tw.offsets[4][2] = tw.size[1][2];

	tw.offsets[5][0] = tw.size[1][0];
	tw.offsets[5][1] = tw.size[0][1];
	tw.offsets[5][2] = tw.size[1][2];

	tw.offsets[6][0] = tw.size[0][0];
	tw.offsets[6][1] = tw.size[1][1];
	tw.offsets[6][2] = tw.size[1][2];

	tw.offsets[7][0] = tw.size[1][0];
	tw.offsets[7][1] = tw.size[1][1];
	tw.offsets[7][2] = tw.size[1][2];

	//
	// calculate bounds
	//
	if ( tw.sphere.use ) {
		for ( i = 0 ; i < 3 ; i++ ) {
			if ( tw.start[i] < tw.end[i] ) {
				tw.bounds[0][i] = tw.start[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
				tw.bounds[1][i] = tw.end[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
			} else {
				tw.bounds[0][i] = tw.end[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
				tw.bounds[1][i] = tw.start[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
			}
		}
	}
	else {
		for ( i = 0 ; i < 3 ; i++ ) {
			if ( tw.start[i] < tw.end[i] ) {
				tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
				tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
			} else {
				tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
				tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
			}
		}
	}

	//
	// check for position test special case
	//
	if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {
		if ( model ) {
#ifdef ALWAYS_BBOX_VS_BBOX // bk010201 - FIXME - compile time flag?
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
				tw.sphere.use = qfalse;
				CM_TestInLeaf( &tw, &cmod->leaf );
			}
			else
#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
				CM_TestCapsuleInCapsule( &tw, model );
			}
			else
#endif
			if ( model == CAPSULE_MODEL_HANDLE ) {
				if ( tw.sphere.use ) {
					CM_TestCapsuleInCapsule( &tw, model );
				}
				else {
					CM_TestBoundingBoxInCapsule( &tw, model );
				}
			}
			else {
				CM_TestInLeaf( &tw, &cmod->leaf );
			}
		} else {
			CM_PositionTest( &tw );
		}
	} else {
		//
		// check for point special case
		//
		if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) {
			tw.isPoint = qtrue;
			VectorClear( tw.extents );
		} else {
			tw.isPoint = qfalse;
			tw.extents[0] = tw.size[1][0];
			tw.extents[1] = tw.size[1][1];
			tw.extents[2] = tw.size[1][2];
		}

		//
		// general sweeping through world
		//
		if ( model ) {
#ifdef ALWAYS_BBOX_VS_BBOX
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
				tw.sphere.use = qfalse;
				CM_TraceThroughLeaf( &tw, &cmod->leaf );
			}
			else
#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
				CM_TraceCapsuleThroughCapsule( &tw, model );
			}
			else
#endif
			if ( model == CAPSULE_MODEL_HANDLE ) {
				if ( tw.sphere.use ) {
					CM_TraceCapsuleThroughCapsule( &tw, model );
				}
				else {
					CM_TraceBoundingBoxThroughCapsule( &tw, model );
				}
			}
			else {
				CM_TraceThroughLeaf( &tw, &cmod->leaf );
			}
		} else {
			CM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end );
		}
	}

	// generate endpos from the original, unmodified start/end
	if ( tw.trace.fraction == 1 ) {
		VectorCopy (end, tw.trace.endpos);
	} else {
		for ( i=0 ; i<3 ; i++ ) {
			tw.trace.endpos[i] = start[i] + tw.trace.fraction * (end[i] - start[i]);
		}
	}

        // If allsolid is set (was entirely inside something solid), the plane is not valid.
        // If fraction == 1.0, we never hit anything, and thus the plane is not valid.
        // Otherwise, the normal on the plane should have unit length
        assert(tw.trace.allsolid ||
               tw.trace.fraction == 1.0 ||
               VectorLengthSquared(tw.trace.plane.normal) > 0.9999);
	*results = tw.trace;
}
Example #24
0
static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame,
									snapshotEntityNumbers_t *eNums, qboolean portal ) {
	int		e, i;
	sharedEntity_t *ent;
	svEntity_t	*svEnt;
	int		l;
	int		clientarea, clientcluster;
	int		leafnum;
	byte	*clientpvs;
	byte	*bitvector;
	vec3_t	difference;
	float	length, radius;

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

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

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

	clientpvs = CM_ClusterPVS (clientcluster);

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

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

		if (ent->s.eFlags & EF_PERMANENT)
		{	// he's permanent, so don't send him down!
			continue;
		}

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

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

		// entities can be flagged to be sent to only one client
		if ( ent->r.svFlags & SVF_SINGLECLIENT ) {
			if ( ent->r.singleClient != frame->ps.clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to everyone but one client
		if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) {
			if ( ent->r.singleClient == frame->ps.clientNum ) {
				continue;
			}
		}

		svEnt = SV_SvEntityForGentity( ent );

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

		// broadcast entities are always sent, and so is the main player so we don't see noclip weirdness
		if ( ent->r.svFlags & SVF_BROADCAST || (e == frame->ps.clientNum) || (ent->r.broadcastClients[frame->ps.clientNum/32] & (1<<(frame->ps.clientNum%32))))
		{
			SV_AddEntToSnapshot( svEnt, ent, eNums );
			continue;
		}

		if (ent->s.isPortalEnt)
		{ //rww - portal entities are always sent as well
			SV_AddEntToSnapshot( svEnt, ent, eNums );
			continue;
		}

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

		bitvector = clientpvs;

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

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

		if (g_svCullDist != -1.0f)
		{ //do a distance cull check
			VectorAdd(ent->r.absmax, ent->r.absmin, difference);
			VectorScale(difference, 0.5f, difference);
			VectorSubtract(origin, difference, difference);
			length = VectorLength(difference);

			// calculate the diameter
			VectorSubtract(ent->r.absmax, ent->r.absmin, difference);
			radius = VectorLength(difference);
			if (length-radius >= g_svCullDist)
			{ //then don't add it
				continue;
			}
		}

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

		// if its a portal entity, add everything visible from its camera position
		if ( ent->r.svFlags & SVF_PORTAL ) {
			if ( ent->s.generic1 ) {
				vec3_t dir;
				VectorSubtract(ent->s.origin, origin, dir);
				if ( VectorLengthSquared(dir) > (float) ent->s.generic1 * ent->s.generic1 ) {
					continue;
				}
			}
			SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue );
		}
	}
Example #25
0
static void CM_TestInLeaf( traceWork_t* tw, const cLeaf_t* leaf )
{
	int			k;
	int			brushnum;
	cbrush_t	*b;
	cPatch_t	*patch;

	// test box position against all brushes in the leaf
	for (k=0 ; k<leaf->numLeafBrushes ; k++) {
		brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
		b = &cm.brushes[brushnum];
		if (b->checkcount == cm.checkcount) {
			continue;	// already checked this brush in another leaf
		}
		b->checkcount = cm.checkcount;

		if ( !(b->contents & tw->contents)) {
			continue;
		}
		
		CM_TestBoxInBrush( tw, b );
		if ( tw->trace.allsolid ) {
			return;
		}
	}

	// test against all patches
#ifdef BSPC
	if (1) {
#else
	if ( !cm_noCurves->integer ) {
#endif //BSPC
		for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
			patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
			if ( !patch ) {
				continue;
			}
			if ( patch->checkcount == cm.checkcount ) {
				continue;	// already checked this brush in another leaf
			}
			patch->checkcount = cm.checkcount;

			if ( !(patch->contents & tw->contents)) {
				continue;
			}
			
			if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) {
				tw->trace.startsolid = tw->trace.allsolid = qtrue;
				tw->trace.fraction = 0;
				tw->trace.contents = patch->contents;
				return;
			}
		}
	}
}

/*
==================
CM_TestCapsuleInCapsule

capsule inside capsule check
==================
*/
void CM_TestCapsuleInCapsule( traceWork_t *tw, clipHandle_t model ) {
	int i;
	vec3_t mins, maxs;
	vec3_t top, bottom;
	vec3_t p1, p2, tmp;
	vec3_t offset, symetricSize[2];
	float radius, halfwidth, halfheight, offs, r;

	CM_ModelBounds(model, mins, maxs);

	VectorAdd(tw->start, tw->sphere.offset, top);
	VectorSubtract(tw->start, tw->sphere.offset, bottom);
	for ( i = 0 ; i < 3 ; i++ ) {
		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
		symetricSize[0][i] = mins[i] - offset[i];
		symetricSize[1][i] = maxs[i] - offset[i];
	}
	halfwidth = symetricSize[ 1 ][ 0 ];
	halfheight = symetricSize[ 1 ][ 2 ];
	radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
	offs = halfheight - radius;

	r = Square(tw->sphere.radius + radius);
	// check if any of the spheres overlap
	VectorCopy(offset, p1);
	p1[2] += offs;
	VectorSubtract(p1, top, tmp);
	if ( VectorLengthSquared(tmp) < r ) {
		tw->trace.startsolid = tw->trace.allsolid = qtrue;
		tw->trace.fraction = 0;
	}
	VectorSubtract(p1, bottom, tmp);
	if ( VectorLengthSquared(tmp) < r ) {
		tw->trace.startsolid = tw->trace.allsolid = qtrue;
		tw->trace.fraction = 0;
	}
	VectorCopy(offset, p2);
	p2[2] -= offs;
	VectorSubtract(p2, top, tmp);
	if ( VectorLengthSquared(tmp) < r ) {
		tw->trace.startsolid = tw->trace.allsolid = qtrue;
		tw->trace.fraction = 0;
	}
	VectorSubtract(p2, bottom, tmp);
	if ( VectorLengthSquared(tmp) < r ) {
		tw->trace.startsolid = tw->trace.allsolid = qtrue;
		tw->trace.fraction = 0;
	}
	// if between cylinder up and lower bounds
	if ( (top[2] >= p1[2] && top[2] <= p2[2]) ||
		(bottom[2] >= p1[2] && bottom[2] <= p2[2]) ) {
		// 2d coordinates
		top[2] = p1[2] = 0;
		// if the cylinders overlap
		VectorSubtract(top, p1, tmp);
		if ( VectorLengthSquared(tmp) < r ) {
			tw->trace.startsolid = tw->trace.allsolid = qtrue;
			tw->trace.fraction = 0;
		}
	}
}
Example #26
0
void trigger_push_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
	if ( self->svFlags & SVF_INACTIVE )
	{//set by target_deactivate
		return;
	}

	if( level.time < self->painDebounceTime + self->wait  ) // normal 'wait' check
	{
		if( self->spawnflags & 2048 ) // MULTIPLE - allow multiple entities to touch this trigger in one frame
		{
			if ( self->painDebounceTime && level.time > self->painDebounceTime ) // if we haven't reached the next frame continue to let ents touch the trigger
			{
				return;
			}
		}
		else // only allowing one ent per frame to touch trigger
		{
			return;
		}
	}

	// if the player has already activated this trigger this frame
	if( other && !other->s.number && self->aimDebounceTime == level.time )
	{
		return;		
	}
	
	
	if( self->spawnflags & PUSH_CONVEYOR )
	{   // only push player if he's on the ground
		if( other->s.groundEntityNum == ENTITYNUM_NONE )
		{
			return;
		}
	}

	if ( self->spawnflags & 1 )
	{//PLAYERONLY
		if ( other->s.number != 0 )
		{
			return;
		}
	}
	else
	{
		if ( self->spawnflags & 8 )
		{//NPCONLY
			if ( other->NPC == NULL )
			{
				return;
			}
		}
	}

	if ( !other->client ) {
		if ( other->s.pos.trType != TR_STATIONARY && other->s.pos.trType != TR_LINEAR_STOP && other->s.pos.trType != TR_NONLINEAR_STOP && VectorLengthSquared( other->s.pos.trDelta ) )
		{//already moving
			VectorCopy( other->currentOrigin, other->s.pos.trBase );
			VectorCopy( self->s.origin2, other->s.pos.trDelta );
			other->s.pos.trTime = level.time;
		}
		return;
	}

	if ( other->client->ps.pm_type != PM_NORMAL ) {
		return;
	}
	
	if ( (self->spawnflags&16) )
	{//relative, dir to it * speed
		vec3_t dir;
		VectorSubtract( self->s.origin2, other->currentOrigin, dir );
		if ( self->speed )
		{
			VectorNormalize( dir );
			VectorScale( dir, self->speed, dir );
		}
		VectorCopy( dir, other->client->ps.velocity );
	}
	else if ( (self->spawnflags&4) )
	{//linear dir * speed
		VectorScale( self->s.origin2, self->speed, other->client->ps.velocity );
	}
	else
	{
		VectorCopy( self->s.origin2, other->client->ps.velocity );
	}
	//so we don't take damage unless we land lower than we start here...
	other->client->ps.forceJumpZStart = 0;
	other->client->ps.pm_flags |= PMF_TRIGGER_PUSHED;//pushed by a trigger
	other->client->ps.jumpZStart = other->client->ps.origin[2];

	if ( self->wait == -1 )
	{
		self->e_TouchFunc = touchF_NULL;
	}
	else if ( self->wait > 0 )
	{
		self->painDebounceTime = level.time;
		
	}
	if( other && !other->s.number )
	{	// mark that the player has activated this trigger this frame
		self->aimDebounceTime =level.time;
	}
}
Example #27
0
/*
================
CM_TraceThroughVerticalCylinder

get the first intersection of the ray with the cylinder
the cylinder extends halfheight above and below the origin
================
*/
void CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) {
	float length, scale, fraction, l1, l2;
	float a, b, c, d, sqrtd;
	vec3_t v1, dir, start2d, end2d, org2d, intersection;

	// 2d coordinates
	VectorSet(start2d, start[0], start[1], 0);
	VectorSet(end2d, end[0], end[1], 0);
	VectorSet(org2d, origin[0], origin[1], 0);
	// if between lower and upper cylinder bounds
	if (start[2] <= origin[2] + halfheight &&
				start[2] >= origin[2] - halfheight) {
		// if inside the cylinder
		VectorSubtract(start2d, org2d, dir);
		l1 = VectorLengthSquared(dir);
		if (l1 < Square(radius)) {
			tw->trace.fraction = 0;
			tw->trace.startsolid = qtrue;
			VectorSubtract(end2d, org2d, dir);
			l1 = VectorLengthSquared(dir);
			if (l1 < Square(radius)) {
				tw->trace.allsolid = qtrue;
			}
			return;
		}
	}
	//
	VectorSubtract(end2d, start2d, dir);
	length = VectorNormalize(dir);
	//
	l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
	VectorSubtract(end2d, org2d, v1);
	l2 = VectorLengthSquared(v1);
	// if no intersection with the cylinder and the end point is at least an epsilon away
	if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
		return;
	}
	//
	//
	// (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
	// (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
	// v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
	//						v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
	// t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
	//						v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
	//
	VectorSubtract(start, origin, v1);
	// dir is normalized so we can use a = 1
	a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
	b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
	c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);

	d = b * b - 4.0f * c;// * a;
	if (d > 0) {
		sqrtd = SquareRootFloat(d);
		// = (- b + sqrtd) * 0.5f;// / (2.0f * a);
		fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
		//
		if (fraction < 0) {
			fraction = 0;
		}
		else {
			fraction /= length;
		}
		if ( fraction < tw->trace.fraction ) {
			VectorSubtract(end, start, dir);
			VectorMA(start, fraction, dir, intersection);
			// if the intersection is between the cylinder lower and upper bound
			if (intersection[2] <= origin[2] + halfheight &&
						intersection[2] >= origin[2] - halfheight) {
				//
				tw->trace.fraction = fraction;
				VectorSubtract(intersection, origin, dir);
				dir[2] = 0;
				#ifdef CAPSULE_DEBUG
					l2 = VectorLength(dir);
					if (l2 <= radius) {
						int bah = 1;
					}
				#endif
				scale = 1 / (radius+RADIUS_EPSILON);
				VectorScale(dir, scale, dir);
				VectorCopy(dir, tw->trace.plane.normal);
				VectorAdd( tw->modelOrigin, intersection, intersection);
				tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
				tw->trace.contents = CONTENTS_BODY;
			}
		}
	}
	else if (d == 0) {
		//t[0] = (- b ) / 2 * a;
		// slide along the cylinder
	}
	// no intersection at all
}
Example #28
0
void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace ) 
{
	gentity_t	*dest;

	if ( self->svFlags & SVF_INACTIVE )
	{//set by target_deactivate
		return;
	}
	
	dest = 	G_PickTarget( self->target );
	if (!dest) 
	{
		gi.Printf ("Couldn't find teleporter destination\n");
		return;
	}

	if ( other->client ) 
	{
		if ( other->client->ps.pm_type == PM_DEAD ) 
		{
			if ( !(self->spawnflags&TTSF_DEAD_OK) )
			{//dead men can't teleport
				return;
			}
		}
		if ( other->NPC )
		{
			if ( self->spawnflags & NO_NPCS )
			{
				return;
			}
		}

		if ( other->client->playerTeam != TEAM_FREE && SpotWouldTelefrag2( other, dest->currentOrigin ) )//SpotWouldTelefrag( dest, other->client->playerTeam ) )
		{//Don't go through if something blocking on the other side
			return;
		}
		
		TeleportPlayer( other, dest->s.origin, dest->s.angles );
	}
	//FIXME: check for SVF_NO_TELEPORT
	else if ( !(self->svFlags & SVF_NO_TELEPORT) && !(self->spawnflags & NO_MISSILES) && VectorLengthSquared( other->s.pos.trDelta ) )
	{//It's a mover of some sort and is currently moving
		vec3_t	diffAngles = {0, 0, 0};
		qboolean	snap = qfalse;

		if ( self->lastEnemy )
		{
			VectorSubtract( dest->s.angles, self->lastEnemy->s.angles, diffAngles );
		}
		else
		{//snaps to angle
			VectorSubtract( dest->s.angles, other->currentAngles, diffAngles );
			snap = qtrue;
		}

		TeleportMover( other, dest->s.origin, diffAngles, snap );
	}
}
Example #29
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;
		}
		else if ( target->client->tempSpectate >= level.time )
		{
			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, qfalse, 0, 0 );

		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 #30
0
/*
==================
CM_BiSphereTrace
==================
*/
void CM_BiSphereTrace( trace_t *results, const vec3_t start,
		const vec3_t end, float startRad, float endRad,
		clipHandle_t model, int mask )
{
	int					i;
	traceWork_t	tw;
	float				largestRadius = startRad > endRad ? startRad : endRad;
	cmodel_t		*cmod;

	cmod = CM_ClipHandleToModel( model );

	cm.checkcount++;		// for multi-check avoidance

	c_traces++;				// for statistics, may be zeroed

	// fill in a default trace
	Com_Memset( &tw, 0, sizeof( tw ) );
	tw.trace.fraction = 1.0f; // assume it goes the entire distance until shown otherwise
	VectorCopy( vec3_origin, tw.modelOrigin );
	tw.type = TT_BISPHERE;
	tw.testLateralCollision = qtrue;
	tw.trace.lateralFraction = 1.0f;

	if( !cm.numNodes )
	{
		*results = tw.trace;

		return;	// map not loaded, shouldn't happen
	}

	// set basic parms
	tw.contents = mask;

	VectorCopy( start, tw.start );
	VectorCopy( end, tw.end );

	tw.biSphere.startRadius = startRad;
	tw.biSphere.endRadius = endRad;

	//
	// calculate bounds
	//
	for( i = 0 ; i < 3 ; i++ )
	{
		if( tw.start[ i ] < tw.end[ i ] )
		{
			tw.bounds[ 0 ][ i ] = tw.start[ i ] - tw.biSphere.startRadius;
			tw.bounds[ 1 ][ i ] = tw.end[ i ] + tw.biSphere.endRadius;
		}
		else
		{
			tw.bounds[ 0 ][ i ] = tw.end[ i ] + tw.biSphere.endRadius;
			tw.bounds[ 1 ][ i ] = tw.start[ i ] - tw.biSphere.startRadius;
		}
	}

	tw.isPoint = qfalse;
	tw.extents[ 0 ] = largestRadius;
	tw.extents[ 1 ] = largestRadius;
	tw.extents[ 2 ] = largestRadius;

	//
	// general sweeping through world
	//
	if( model )
		CM_TraceThroughLeaf( &tw, &cmod->leaf );
	else
		CM_TraceThroughTree( &tw, 0, 0.0f, 1.0f, tw.start, tw.end );

	// generate endpos from the original, unmodified start/end
	if( tw.trace.fraction == 1.0f )
	{
		VectorCopy( end, tw.trace.endpos );
	}
	else
	{
		for( i = 0; i < 3; i++ )
			tw.trace.endpos[ i ] = start[ i ] + tw.trace.fraction * ( end[ i ] - start[ i ] );
	}

	// If allsolid is set (was entirely inside something solid), the plane is not valid.
	// If fraction == 1.0, we never hit anything, and thus the plane is not valid.
	// Otherwise, the normal on the plane should have unit length
	assert( tw.trace.allsolid ||
			tw.trace.fraction == 1.0 ||
			VectorLengthSquared(tw.trace.plane.normal ) > 0.9999 );

	*results = tw.trace;
}