Пример #1
0
/*
* CG_ProjectileTrail
*/
void CG_ProjectileTrail( centity_t *cent )
{
	lentity_t	*le;
	float		len;
	vec3_t		vec;
	int			contents;
	int			trailTime;
	float		radius = 6.5f, alpha = 0.35f;
#if 0
	struct shader_s *shader = CG_MediaShader( cgs.media.shaderRocketTrailSmokePuff );
#else
	struct shader_s *shader = CG_MediaShader( cgs.media.shaderSmokePuff );
#endif
	CG_ProjectileFireTrail( cent ); // add fire trail

	if( !cg_projectileTrail->integer )
		return;

	// didn't move
	VectorSubtract( cent->ent.origin, cent->trailOrigin, vec );
	len = VectorNormalize( vec );
	if( !len )
		return;

	// density is found by quantity per second
	trailTime = (int)(1000.0f / cg_projectileTrail->value );
	if( trailTime < 1 ) trailTime = 1;

	// we don't add more than one sprite each frame. If frame
	// ratio is too slow, people will prefer having less sprites on screen
	if( cent->localEffects[LOCALEFFECT_ROCKETTRAIL_LAST_DROP] + trailTime < cg.time ) {
		cent->localEffects[LOCALEFFECT_ROCKETTRAIL_LAST_DROP] = cg.time;

		contents = ( CG_PointContents( cent->trailOrigin ) & CG_PointContents( cent->ent.origin ) );
		if( contents & MASK_WATER ) {
			shader = CG_MediaShader( cgs.media.shaderWaterBubble );
			radius = 3 + crandom();
			alpha = 1.0f;
		}

		// racesow
		if( cg_raceGhosts->integer && (unsigned int)cent->current.ownerNum != cg.predictedPlayerState.POVnum )
			alpha *= cg_raceGhostsAlpha->value;
		// !racesow

		clamp( alpha, 0.0f, 1.0f );
		le = CG_AllocSprite( LE_PUFF_SHRINK, cent->trailOrigin, radius, 20, 
			1.0f, 1.0f, 1.0f, alpha,
			0, 0, 0, 0, 
			shader );
		VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 3 );
		le->ent.rotation = rand () % 360;
	}
}
Пример #2
0
/*
* CG_NewBloodTrail
*/
void CG_NewBloodTrail( centity_t *cent )
{
	lentity_t *le;
	float len;
	vec3_t vec;
	int contents;
	int trailTime;
	float radius = 2.5f, alpha = cg_bloodTrailAlpha->value;
	struct shader_s *shader = CG_MediaShader( cgs.media.shaderBloodTrailPuff );

	if( !cg_showBloodTrail->integer )
		return;

	if( !cg_bloodTrail->integer )
		return;

	// didn't move
	VectorSubtract( cent->ent.origin, cent->trailOrigin, vec );
	len = VectorNormalize( vec );
	if( !len )
		return;

	// density is found by quantity per second
	trailTime = (int)( 1000.0f / cg_bloodTrail->value );
	if( trailTime < 1 ) trailTime = 1;

	// we don't add more than one sprite each frame. If frame
	// ratio is too slow, people will prefer having less sprites on screen
	if( cent->localEffects[LOCALEFFECT_BLOODTRAIL_LAST_DROP] + trailTime < cg.time )
	{
		cent->localEffects[LOCALEFFECT_BLOODTRAIL_LAST_DROP] = cg.time;

		contents = ( CG_PointContents( cent->trailOrigin ) & CG_PointContents( cent->ent.origin ) );
		if( contents & MASK_WATER )
		{
			shader = CG_MediaShader( cgs.media.shaderBloodTrailLiquidPuff );
			radius = 4 + crandom();
			alpha = 0.5f * cg_bloodTrailAlpha->value;
		}

		clamp( alpha, 0.0f, 1.0f );
		le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, cent->trailOrigin, radius, 8,
			1.0f, 1.0f, 1.0f, alpha,
			0, 0, 0, 0,
			shader );
		VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 3 );
		le->ent.rotation = rand() % 360;
	}
}
Пример #3
0
void CG_Dash( entity_state_t *state )
{
	lentity_t *le;
	vec3_t pos, dvect, angle = { 0, 0, 0 };

	if( !(cg_cartoonEffects->integer & 4) )
		return;

	// KoFFiE: Calculate angle based on relative position of the previous origin state of the player entity
	VectorSubtract( state->origin, cg_entities[state->number].prev.origin, dvect );

	// ugly inline define -> Ignore when difference between 2 positions was less than this value.
#define IGNORE_DASH 6.0

	if( ( dvect[0] > -IGNORE_DASH ) && ( dvect[0] < IGNORE_DASH ) &&
		( dvect[1] > -IGNORE_DASH ) && ( dvect[1] < IGNORE_DASH ) )
		return;

	VecToAngles( dvect, angle );
	VectorCopy( state->origin, pos );
	angle[1] += 270; // Adjust angle
	pos[2] -= 24; // Adjust the position to ground height

	if( CG_PointContents( pos ) & MASK_WATER )
		return; // no smoke under water :)

	le = CG_AllocModel( LE_DASH_SCALE, pos, angle, 7, //5
		1.0, 1.0, 1.0, 1.0,
		0, 0, 0, 0,
		CG_MediaModel( cgs.media.modDash ),
		NULL
		);
	le->ent.scale = 0.01f;
	le->ent.axis[2][2] *= 2.0f;
}
Пример #4
0
void CG_DustCircle( vec3_t pos, vec3_t dir, float radius, int count )
{
	vec3_t dir_per1;
	vec3_t dir_per2;
	vec3_t dir_temp = { 0.0f, 0.0f, 0.0f };
	int i;
	float angle;

	if( CG_PointContents( pos ) & MASK_WATER )
		return; // no smoke under water :)

	PerpendicularVector( dir_per2, dir );
	CrossProduct( dir, dir_per2, dir_per1 );

	VectorScale( dir_per1, VectorNormalize( dir_per1 ), dir_per1 );
	VectorScale( dir_per2, VectorNormalize( dir_per2 ), dir_per2 );

	for( i = 0; i < count; i++ )
	{
		angle = (float)( 6.2831f / count * i );
		VectorSet( dir_temp, 0.0f, 0.0f, 0.0f );
		VectorMA( dir_temp, sin( angle ), dir_per1, dir_temp );
		VectorMA( dir_temp, cos( angle ), dir_per2, dir_temp );
		//VectorScale(dir_temp, VectorNormalize(dir_temp),dir_temp );
		VectorScale( dir_temp, crandom()*10 + radius, dir_temp );
		CG_Explosion_Puff_2( pos, dir_temp, 10 );
	}
}
Пример #5
0
static int CG_CalcFov( void ) {
	float fov;
	int contents;

	// check if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );
	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
		cg.refdef.rdflags |= RDF_UNDERWATER;
	}
	else {
		cg.refdef.rdflags &= ~RDF_UNDERWATER;
	}

	// set world fov
	fov = cg_fov.value;
	CG_CalcFov2( &cg.refdef, &fov, &cg.refdef.fov_x, &cg.refdef.fov_y );

	// set view weapon fov
	cg.viewWeaponFov = cg_weaponFov.value ? cg_weaponFov.value : cg_fov.value;
	CG_CalcFov2( &cg.refdef, &cg.viewWeaponFov, &cg.refdef.weapon_fov_x, &cg.refdef.weapon_fov_y );

	if ( !cg.cur_lc->zoomed ) {
		cg.cur_lc->zoomSensitivity = 1;
	} else {
		cg.cur_lc->zoomSensitivity = cg.refdef.fov_y / 75.0;
	}

	return (cg.refdef.rdflags & RDF_UNDERWATER);
}
Пример #6
0
/*
* CG_ImpactSmokePuff
*/
void CG_ImpactSmokePuff( vec3_t origin, vec3_t dir, float radius, float alpha, int time, int speed )
{
#define SMOKEPUFF_MAXVIEWDIST 700
	lentity_t *le;
	struct shader_s *shader = CG_MediaShader( cgs.media.shaderSmokePuff );

	if( CG_PointContents( origin ) & MASK_WATER )
	{
		return;
	}

	if( DistanceFast( origin, cg.view.origin ) * cg.view.fracDistFOV > SMOKEPUFF_MAXVIEWDIST )
		return;

	if( !VectorLength( dir ) )
	{
		VectorCopy( cg.view.axis[FORWARD], dir );
		VectorInverse( dir );
	}
	VectorNormalize( dir );
	//offset the origin by half of the radius
	VectorMA( origin, radius*0.5f, dir, origin );

	le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, origin, radius + crandom(), time,
		1, 1, 1, alpha, 0, 0, 0, 0, shader );

	le->ent.rotation = rand() % 360;
	VectorScale( dir, speed, le->velocity );
}
Пример #7
0
static qboolean CG_RainParticleGenerate(cg_atmosphericParticle_t * particle, vec3_t currvec, float currweight)
{
	// Attempt to 'spot' a raindrop somewhere below a sky texture.

	float angle, distance, origz;
	vec3_t testpoint, testend;
	trace_t tr;

	angle = random() * 2 * M_PI;
	distance = 20 + MAX_ATMOSPHERIC_DISTANCE * random();

	testpoint[0] = testend[0] = cg.refdef.vieworg[0] + sin(angle) * distance;
	testpoint[1] = testend[1] = cg.refdef.vieworg[1] + cos(angle) * distance;
	testpoint[2] = origz = cg.refdef.vieworg[2];
	testend[2] = testpoint[2] + MAX_ATMOSPHERIC_HEIGHT;

	while (1) {
		if (testpoint[2] >= MAX_ATMOSPHERIC_HEIGHT)
			return (qfalse);
		if (testend[2] >= MAX_ATMOSPHERIC_HEIGHT)
			testend[2] = MAX_ATMOSPHERIC_HEIGHT - 1;
		CG_Trace(&tr, testpoint, NULL, NULL, testend, ENTITYNUM_NONE, MASK_SOLID | MASK_WATER);
		if (tr.startsolid)	// Stuck in something, skip over it.
		{
			testpoint[2] += 64;
			testend[2] = testpoint[2] + MAX_ATMOSPHERIC_HEIGHT;
		} else if (tr.fraction == 1)	// Didn't hit anything, we're (probably) outside the world
			return (qfalse);
		else if (tr.surfaceFlags & SURF_SKY)	// Hit sky, this is where we start.
			break;
		else
			return (qfalse);
	}

	particle->active = qtrue;
	particle->colour[0] = 0.6 + 0.2 * random();
	particle->colour[1] = 0.6 + 0.2 * random();
	particle->colour[2] = 0.6 + 0.2 * random();
	VectorCopy(tr.endpos, particle->pos);
	VectorCopy(currvec, particle->delta);
	particle->delta[2] += crandom() * 100;
	VectorNormalize2(particle->delta, particle->deltaNormalized);
	particle->height = ATMOSPHERIC_RAIN_HEIGHT + crandom() * 100;
	particle->weight = currweight;
	particle->effectshader = &cg_atmFx.effectshaders[0];

	distance = ((float) (tr.endpos[2] - MIN_ATMOSPHERIC_HEIGHT)) / -particle->delta[2];
	VectorMA(tr.endpos, distance, particle->delta, testend);

	CG_Trace(&tr, particle->pos, NULL, NULL, testend, ENTITYNUM_NONE, MASK_SOLID | MASK_WATER);
	particle->minz = tr.endpos[2];
	tr.endpos[2]--;
	VectorCopy(tr.plane.normal, particle->surfacenormal);
	particle->surface = tr.surfaceFlags;
	particle->contents = CG_PointContents(tr.endpos, ENTITYNUM_NONE);

	return (qtrue);
}
Пример #8
0
/*
================
CG_WaterLevel

Returns waterlevel for entity origin
================
*/
int CG_WaterLevel(centity_t *cent) {
	vec3_t point;
	int contents, sample1, sample2, anim, waterlevel;
	int viewheight;

	anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;

	if (anim == LEGS_WALKCR || anim == LEGS_IDLECR) {
		viewheight = CROUCH_VIEWHEIGHT;
	} else {
		viewheight = DEFAULT_VIEWHEIGHT;
	}

	//
	// get waterlevel, accounting for ducking
	//
	waterlevel = 0;

	point[0] = cent->lerpOrigin[0];
	point[1] = cent->lerpOrigin[1];
	point[2] = cent->lerpOrigin[2] + MINS_Z + 1;
	contents = CG_PointContents(point, -1);

	if (contents & MASK_WATER) {
		sample2 = viewheight - MINS_Z;
		sample1 = sample2 / 2;
		waterlevel = 1;
		point[2] = cent->lerpOrigin[2] + MINS_Z + sample1;
		contents = CG_PointContents(point, -1);

		if (contents & MASK_WATER) {
			waterlevel = 2;
			point[2] = cent->lerpOrigin[2] + MINS_Z + sample2;
			contents = CG_PointContents(point, -1);

			if (contents & MASK_WATER) {
				waterlevel = 3;
			}
		}
	}

	return waterlevel;
}
Пример #9
0
/*
* CG_RenderFlags
*/
static int CG_RenderFlags( void )
{
	int rdflags, contents;

	rdflags = 0;

	// set the RDF_UNDERWATER and RDF_CROSSINGWATER bitflags
	contents = CG_PointContents( cg.view.origin );
	if( contents & MASK_WATER )
	{
		rdflags |= RDF_UNDERWATER;

		// undewater, check above
		contents = CG_PointContents( tv( cg.view.origin[0], cg.view.origin[1], cg.view.origin[2] + 9 ) );
		if( !(contents & MASK_WATER) )
			rdflags |= RDF_CROSSINGWATER;
	}
	else
	{
		// look down a bit
		contents = CG_PointContents( tv( cg.view.origin[0], cg.view.origin[1], cg.view.origin[2] - 9 ) );
		if( contents & MASK_WATER )
			rdflags |= RDF_CROSSINGWATER;
	}

	if( cg.oldAreabits )
		rdflags |= RDF_OLDAREABITS;

	if( cg.portalInView )
		rdflags |= RDF_PORTALINVIEW;

	if( cg_outlineWorld->integer )
		rdflags |= RDF_WORLDOUTLINES;

	if( cg.view.flipped )
		rdflags |= RDF_FLIPPED;

	rdflags |= CG_SkyPortal();

	return rdflags;
}
Пример #10
0
/*
================
CG_WaterLevel

Returns waterlevel for entity origin
================
*/
int CG_WaterLevel(centity_t *cent) {
	vec3_t point;
	int contents, sample1, sample2, anim, waterlevel;

	// get waterlevel, accounting for ducking
	waterlevel = 0;
	VectorCopy(cent->lerpOrigin, point);
	point[2] += MINS_Z + 1;
	anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;

	if (anim == LEGS_WALKCR || anim == LEGS_IDLECR) {
		point[2] += CROUCH_VIEWHEIGHT;
	} else {
		point[2] += DEFAULT_VIEWHEIGHT;
	}

	contents = CG_PointContents(point, -1);

	if (contents & MASK_WATER) {
		sample2 = point[2] - MINS_Z;
		sample1 = sample2 / 2;
		waterlevel = 1;
		point[2] = cent->lerpOrigin[2] + MINS_Z + sample1;
		contents = CG_PointContents(point, -1);

		if (contents & MASK_WATER) {
			waterlevel = 2;
			point[2] = cent->lerpOrigin[2] + MINS_Z + sample2;
			contents = CG_PointContents(point, -1);

			if (contents & MASK_WATER) {
				waterlevel = 3;
			}
		}
	}

	return waterlevel;
}
Пример #11
0
/*
* CG_BloodDamageEffect
*/
void CG_BloodDamageEffect( const vec3_t origin, const vec3_t dir, int damage )
{
	lentity_t *le;
	int count, i;
	float radius = 5.0f, alpha = cg_bloodTrailAlpha->value;
	int time = 8;
	struct shader_s *shader = CG_MediaShader( cgs.media.shaderBloodImpactPuff );
	vec3_t local_dir;

	if( !cg_showBloodTrail->integer )
		return;

	if( !cg_bloodTrail->integer )
		return;

	count = (int)( damage * 0.25f );
	clamp( count, 1, 10 );

	if( CG_PointContents( origin ) & MASK_WATER )
	{
		shader = CG_MediaShader( cgs.media.shaderBloodTrailLiquidPuff );
		radius += ( 1 + crandom() );
		alpha = 0.5f * cg_bloodTrailAlpha->value;
	}

	if( !VectorLength( dir ) )
	{
		VectorNegate( &cg.view.axis[AXIS_FORWARD], local_dir );
	}
	else
	{
		VectorNormalize2( dir, local_dir );
	}

	for( i = 0; i < count; i++ )
	{
		le = CG_AllocSprite( LE_PUFF_SHRINK, origin, radius + crandom(), time,
			1, 1, 1, alpha, 0, 0, 0, 0, shader );

		le->ent.rotation = rand() % 360;

		// randomize dir
		VectorSet( le->velocity,
			-local_dir[0] * 5 + crandom()*5,
			-local_dir[1] * 5 + crandom()*5,
			-local_dir[2] * 5 + crandom()*5 + 3 );
		VectorMA( local_dir, min( 6, count ), le->velocity, le->velocity );
	}
}
Пример #12
0
/*
* CG_CalcViewBob
*/
static void CG_CalcViewBob( void )
{
	float bobMove, bobTime, bobScale;

	if( !cg.view.drawWeapon )
		return;

	// calculate speed and cycle to be used for all cyclic walking effects
	cg.xyspeed = sqrt( cg.predictedPlayerState.pmove.velocity[0]*cg.predictedPlayerState.pmove.velocity[0] + cg.predictedPlayerState.pmove.velocity[1]*cg.predictedPlayerState.pmove.velocity[1] );

	bobScale = 0;
	if( cg.xyspeed < 5 )
		cg.oldBobTime = 0;  // start at beginning of cycle again
	else if( cg_gunbob->integer )
	{
		if( !ISVIEWERENTITY( cg.view.POVent ) )
			bobScale = 0.0f;
		else if( CG_PointContents( cg.view.origin ) & MASK_WATER )
			bobScale =  0.75f;
		else
		{
			centity_t *cent;
			vec3_t mins, maxs;
			trace_t	trace;

			cent = &cg_entities[cg.view.POVent];
			GS_BBoxForEntityState( &cent->current, mins, maxs );
			maxs[2] = mins[2];
			mins[2] -= ( 1.6f*STEPSIZE );

			CG_Trace( &trace, cg.predictedPlayerState.pmove.origin, mins, maxs, cg.predictedPlayerState.pmove.origin, cg.view.POVent, MASK_PLAYERSOLID );
			if( trace.startsolid || trace.allsolid )
			{
				if( cg.predictedPlayerState.pmove.stats[PM_STAT_CROUCHTIME] )
					bobScale = 1.5f;
				else
					bobScale = 2.5f;
			}
		}
	}

	bobMove = cg.frameTime * bobScale;
	bobTime = ( cg.oldBobTime += bobMove );

	cg.bobCycle = (int)bobTime;
	cg.bobFracSin = fabs( sin( bobTime*M_PI ) );
}
Пример #13
0
	static int Player_GetUnderwater( lua_State *L, jpluaEntity_t *ent ) {
		qboolean underwater = qfalse;
	#if defined(PROJECT_GAME)
		if ( ent->waterlevel == 3 ) {
			underwater = qtrue;
		}
	#elif defined(PROJECT_CGAME)
		const vector3 *pos = ((int)(ent - ents) == cg.clientNum)
			? &cg.predictedPlayerState.origin
			: &ent->currentState.pos.trBase; // not cent->lerpOrigin?
		if ( CG_PointContents( pos, -1 ) & (CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA) ) {
			underwater = qtrue;
		}
	#endif
		lua_pushboolean( L, underwater );
		return 1;
	}
Пример #14
0
/*
* CG_LeadBubbleTrail
*/
static void CG_LeadBubbleTrail( trace_t *tr, vec3_t water_start )
{
	// if went through water, determine where the end and make a bubble trail
	vec3_t dir, pos;

	VectorSubtract( tr->endpos, water_start, dir );
	VectorNormalize( dir );
	VectorMA( tr->endpos, -2, dir, pos );

	if( CG_PointContents( pos ) & MASK_WATER )
		VectorCopy( pos, tr->endpos );
	else
		CG_Trace( tr, pos, vec3_origin, vec3_origin, water_start, tr->ent ? cg_entities[tr->ent].current.number : 0, MASK_WATER );

	VectorAdd( water_start, tr->endpos, pos );
	VectorScale( pos, 0.5, pos );

	CG_BubbleTrail( water_start, tr->endpos, 32 );
}
Пример #15
0
/*
=======================================================================================================================================
CG_BubbleThink
=======================================================================================================================================
*/
void CG_BubbleThink(localEntity_t *le) {
	int contents;
	vec3_t newOrigin;
	trace_t trace;

	// calculate new position
	BG_EvaluateTrajectory(&le->pos, cg.time, newOrigin);
	// trace a line from previous position to new position
	CG_Trace(&trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID);

	contents = CG_PointContents(trace.endpos, -1);

	if (!(contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) {
		// bubble isn't in liquid anymore, remove it
		CG_FreeLocalEntity(le);
		return;
	}

	CG_AddMoveScaleFade(le);
}
Пример #16
0
void CG_ExplosionsDust( vec3_t pos, vec3_t dir, float radius )
{
	const int count = 32; /* Number of sprites used to create the circle */
	lentity_t *le;
	struct shader_s *shader = CG_MediaShader( cgs.media.shaderSmokePuff3 );

	vec3_t dir_per1;
	vec3_t dir_per2;
	vec3_t dir_temp = { 0.0f, 0.0f, 0.0f };
	int i;
	float angle;

	if( CG_PointContents( pos ) & MASK_WATER )
		return; // no smoke under water :)

	PerpendicularVector( dir_per2, dir );
	CrossProduct( dir, dir_per2, dir_per1 );

	//VectorScale( dir_per1, VectorNormalize( dir_per1 ), dir_per1 );
	//VectorScale( dir_per2, VectorNormalize( dir_per2 ), dir_per2 );

	// make a circle out of the specified number (int count) of sprites
	for( i = 0; i < count; i++ )
	{
		angle = (float)( 6.2831f / count * i );
		VectorSet( dir_temp, 0.0f, 0.0f, 0.0f );
		VectorMA( dir_temp, sin( angle ), dir_per1, dir_temp );
		VectorMA( dir_temp, cos( angle ), dir_per2, dir_temp );
		//VectorScale(dir_temp, VectorNormalize(dir_temp),dir_temp );
		VectorScale( dir_temp, crandom()*8 + radius + 16.0f, dir_temp );
		// make the sprite smaller & alpha'd
		le = CG_AllocSprite( LE_ALPHA_FADE, pos, 10, 10,
			1.0f, 1.0f, 1.0f, 1.0f,
			0, 0, 0, 0,
			shader );
		VectorCopy( dir_temp, le->velocity );
	}       
}
Пример #17
0
static int CG_CalcFov( void ) {
	float	x;
	float	phase;
	float	v;
	int		contents;
	float	fov_x, fov_y;
	float	zoomFov;
	float	f;
	int		inwater;

	if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
		// if in intermission, use a fixed value
		fov_x = 90;
	} else {
		// user selectable
		if ( cgs.dmflags & DF_FIXED_FOV ) {
			// dmflag to prevent wide fov for all clients
			fov_x = 90;
		} else {
			fov_x = cg_fov.value;
			if ( fov_x < 1 ) {
				fov_x = 1;
			} else if ( fov_x > 160 ) {
				fov_x = 160;
			}
		}

		// account for zooms
		zoomFov = cg_zoomFov.value;
		if ( zoomFov < 1 ) {
			zoomFov = 1;
		} else if ( zoomFov > 160 ) {
			zoomFov = 160;
		}

		if ( cg.zoomed ) {
			f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
			if ( f > 1.0 ) {
				fov_x = zoomFov;
			} else {
				fov_x = fov_x + f * ( zoomFov - fov_x );
			}
		} else {
			f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
			if ( f > 1.0 ) {
				fov_x = fov_x;
			} else {
				fov_x = zoomFov + f * ( fov_x - zoomFov );
			}
		}
	}

	x = cg.refdef.width / tan( fov_x / 360 * M_PI );
	fov_y = atan2( cg.refdef.height, x );
	fov_y = fov_y * 360 / M_PI;

	// warp if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );
	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
		phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
		v = WAVE_AMPLITUDE * sin( phase );
		fov_x += v;
		fov_y -= v;
		inwater = qtrue;
	}
	else {
		inwater = qfalse;
	}


	// set it
	cg.refdef.fov_x = fov_x;
	cg.refdef.fov_y = fov_y;

	if ( !cg.zoomed ) {
		cg.zoomSensitivity = 1;
	} else {
		cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
	}

	return inwater;
}
Пример #18
0
/*
================
CG_AddFragment
================
*/
void CG_AddFragment( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;

	if ( le->pos.trType == TR_STATIONARY ) {
		// sink into the ground if near the removal time
		int		t;
		float	oldZ;
		
		t = le->endTime - cg.time;
		if ( t < SINK_TIME ) {
			// we must use an explicit lighting origin, otherwise the
			// lighting would be lost as soon as the origin went
			// into the ground
			VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
			le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
			oldZ = le->refEntity.origin[2];
			le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
			CG_AddRefEntityWithMinLight( &le->refEntity );
			le->refEntity.origin[2] = oldZ;
		} else {
			CG_AddRefEntityWithMinLight( &le->refEntity );
		}

		return;
	}

	// calculate new position
	BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );

	// trace a line from previous position to new position
	CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
	if ( trace.fraction == 1.0 ) {
		// still in free fall
		VectorCopy( newOrigin, le->refEntity.origin );

		if ( le->leFlags & LEF_TUMBLE ) {
			vec3_t angles;

			BG_EvaluateTrajectory( &le->angles, cg.time, angles );
			AnglesToAxis( angles, le->refEntity.axis );
		}

		CG_AddRefEntityWithMinLight( &le->refEntity );

		// add a blood trail
		if ( le->leBounceSoundType == LEBS_BLOOD ) {
			CG_BloodTrail( le );
		}

		return;
	}

	// if it is in a nodrop zone, remove it
	// this keeps gibs from waiting at the bottom of pits of death
	// and floating levels
	if ( CG_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
		CG_FreeLocalEntity( le );
		return;
	}

	// leave a mark
	CG_FragmentBounceMark( le, &trace );

	// do a bouncy sound
	CG_FragmentBounceSound( le, &trace );

	// reflect the velocity on the trace plane
	CG_ReflectVelocity( le, &trace );

	CG_AddRefEntityWithMinLight( &le->refEntity );
}
Пример #19
0
static int CG_CalcFov( void )
{
	float     y;
	float     phase;
	float     v;
	int       contents;
	float     fov_x, fov_y;
	float     zoomFov;
	float     f;
	int       inwater;
	int       attribFov;
	usercmd_t cmd;
	usercmd_t oldcmd;
	int       cmdNum;

	cmdNum = trap_GetCurrentCmdNumber();
	trap_GetUserCmd( cmdNum, &cmd );
	trap_GetUserCmd( cmdNum - 1, &oldcmd );

	// switch follow modes if necessary: cycle between free -> follow -> third-person follow
	if ( usercmdButtonPressed( cmd.buttons, BUTTON_USE_HOLDABLE ) && !usercmdButtonPressed( oldcmd.buttons, BUTTON_USE_HOLDABLE ) )
	{
		if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
		{
			if ( !cg.chaseFollow )
			{
				cg.chaseFollow = qtrue;
			}
			else
			{
				cg.chaseFollow = qfalse;
				trap_SendClientCommand( "follow\n" );
			}
		}
		else if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
		{
			trap_SendClientCommand( "follow\n" );
		}
	}

	if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
	     ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) ||
	     ( cg.renderingThirdPerson ) )
	{
		// if in intermission or third person, use a fixed value
		fov_y = BASE_FOV_Y;
	}
	else
	{
		// don't lock the fov globally - we need to be able to change it
		if ( ( attribFov = trap_Cvar_VariableIntegerValue( BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fovCvar ) ) )
		{
			if ( attribFov < 80 )
			{
				attribFov = 80;
			}
			else if ( attribFov >= 140 )
			{
				attribFov = 140;
			}
		}
		else
		{
			attribFov = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fov;
		}
		attribFov *= 0.75;
		fov_y = attribFov;

		if ( fov_y < 1.0f )
		{
			fov_y = 1.0f;
		}
		else if ( fov_y > MAX_FOV_Y )
		{
			fov_y = MAX_FOV_Y;
		}

		if ( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
		     BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_FOVWARPS ) )
		{
			float fraction = ( float )( cg.time - cg.spawnTime ) / FOVWARPTIME;

			fov_y = MAX_FOV_WARP_Y - ( ( MAX_FOV_WARP_Y - fov_y ) * fraction );
		}

		// account for zooms
		zoomFov = BG_Weapon( cg.predictedPlayerState.weapon )->zoomFov * 0.75f;

		if ( zoomFov < 1.0f )
		{
			zoomFov = 1.0f;
		}
		else if ( zoomFov > attribFov )
		{
			zoomFov = attribFov;
		}

		// only do all the zoom stuff if the client CAN zoom
		// FIXME: zoom control is currently hard coded to WBUTTON_ATTACK2
		if ( BG_Weapon( cg.predictedPlayerState.weapon )->canZoom )
		{
			if ( cg.zoomed )
			{
				f = ( cg.time - cg.zoomTime ) / ( float ) ZOOM_TIME;

				if ( f > 1.0f )
				{
					fov_y = zoomFov;
				}
				else
				{
					fov_y = fov_y + f * ( zoomFov - fov_y );
				}

				// WBUTTON_ATTACK2 isn't held so unzoom next time
				if ( !usercmdButtonPressed( cmd.buttons, BUTTON_ATTACK2 ) || cg.snap->ps.weaponstate == WEAPON_RELOADING )
				{
					cg.zoomed = qfalse;
					cg.zoomTime = MIN( cg.time,
					                   cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
				}
			}
			else
			{
				f = ( cg.time - cg.zoomTime ) / ( float ) ZOOM_TIME;

				if ( f < 1.0f )
				{
					fov_y = zoomFov + f * ( fov_y - zoomFov );
				}

				// WBUTTON_ATTACK2 is held so zoom next time
				if ( usercmdButtonPressed( cmd.buttons, BUTTON_ATTACK2 ) && cg.snap->ps.weaponstate != WEAPON_RELOADING )
				{
					cg.zoomed = qtrue;
					cg.zoomTime = MIN( cg.time,
					                   cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
				}
			}
		}
		else if ( cg.zoomed )
		{
			cg.zoomed = qfalse;
		}
	}

	y = cg.refdef.height / tan( 0.5f * DEG2RAD( fov_y ) );
	fov_x = atan2( cg.refdef.width, y );
	fov_x = 2.0f * RAD2DEG( fov_x );

	// warp if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );

	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
	{
		phase = cg.time / 1000.0f * WAVE_FREQUENCY * M_PI * 2.0f;
		v = WAVE_AMPLITUDE * sin( phase );
		fov_x += v;
		fov_y -= v;
		inwater = qtrue;
	}
	else
	{
		inwater = qfalse;
	}

	// set it
	cg.refdef.fov_x = fov_x;
	cg.refdef.fov_y = fov_y;

	if ( !cg.zoomed )
	{
		cg.zoomSensitivity = 1.0f;
	}
	else
	{
		cg.zoomSensitivity = cg.refdef.fov_y / 75.0f;
	}

	return inwater;
}
Пример #20
0
/*
====================
CG_ParseSpawnVars

Parses a brace bounded set of key / value pairs out of the
level's entity strings into cg.spawnVars[]

This does not actually spawn an entity.
====================
*/
qboolean CG_ParseSpawnVars( void ) {
    char            keyname[MAX_TOKEN_CHARS];
    char            com_token[MAX_TOKEN_CHARS];
    char    token[MAX_TOKEN_CHARS];
    //char buf[MAX_TOKEN_CHARS];
    const char *line;
    qboolean newLine;
    vec3_t origin;
    int wait;
    titem_t ti;
    int val;
    int skipItem;
    int i;
    //char *gametypeName;
    //char *value;
    int angle;
    int spawnflags;
    qboolean spawnPoint;
    qboolean redSpawn;
    qboolean blueSpawn;
    qboolean initial;
    qboolean deathmatch;
    qboolean portal;
    qboolean portalHasTarget;
    qboolean startTimer;
    qboolean stopTimer;
    qboolean gotOrigin;
    int pointContents;
    static char *gametypeNames[] = { "ffa", "tournament", "single", "team", /*FIXME clanarena*/ "ca",  "ctf", "oneflag", "obelisk", "harvester", "ft", "dom", "ad", "rr", "race" };

    //Com_Printf("cgs.gametype : %d\n", cgs.gametype);
    cg.numSpawnVars = 0;
    cg.numSpawnVarChars = 0;

    // parse the opening brace
    if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
        // end of spawn string
        return qfalse;
    }
    if ( com_token[0] != '{' ) {
        CG_Error( "CG_ParseSpawnVars: found %s when expecting {",com_token );
    }

    // go through all the key / value pairs
    while ( 1 ) {
        // parse key
        if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
            CG_Error( "CG_ParseSpawnVars: EOF without closing brace" );
        }

        if ( keyname[0] == '}' ) {
            break;
        }

        // parse value
        if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
            CG_Error( "CG_ParseSpawnVars: EOF without closing brace" );
        }

        if ( com_token[0] == '}' ) {
            CG_Error( "CG_ParseSpawnVars: closing brace without data" );
        }
        if ( cg.numSpawnVars == MAX_SPAWN_VARS ) {
            CG_Error( "CG_ParseSpawnVars: MAX_SPAWN_VARS" );
        }
        cg.spawnVars[ cg.numSpawnVars ][0] = CG_AddSpawnVarToken( keyname );
        cg.spawnVars[ cg.numSpawnVars ][1] = CG_AddSpawnVarToken( com_token );
        cg.numSpawnVars++;

        if (!Q_stricmp(keyname, "enableDust")) {
            cg.mapEnableDust = atoi(com_token);
        } else if (!Q_stricmp(keyname, "enableBreath")) {
            cg.mapEnableBreath = atoi(com_token);
        }
        //CG_Printf("spawnvars  %s : %s\n", cg.spawnVars[ cg.numSpawnVars - 1 ][0], cg.spawnVars[ cg.numSpawnVars - 1 ][1]);
    }

    if (cgs.gametype == GT_CA) {
        //return qtrue;
    }

    ti = noitem;
    wait = 0;
    skipItem = 0;
    angle = 0;
    spawnflags = 0;
    spawnPoint = qfalse;
    redSpawn = qfalse;
    blueSpawn = qfalse;
    initial = qfalse;
    deathmatch = qfalse;
    portal = qfalse;
    portalHasTarget = qfalse;
    startTimer = qfalse;
    stopTimer = qfalse;
    gotOrigin = qfalse;

    // get the rest
    while (1) {
        // parse key
        if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
            //CG_Printf("all done parsing ents\n");
            break;
        }

        //Com_Printf("'%s'\n", keyname);

        if (keyname[0] == '{') {
            //CG_Printf("{\n");
            // clear values
            ti = noitem;
            wait = 0;
            skipItem = 0;
            angle = 0;
            spawnflags = 0;
            spawnPoint = qfalse;
            redSpawn = qfalse;
            blueSpawn = qfalse;
            initial = qfalse;
            deathmatch = qfalse;
            portal = qfalse;
            portalHasTarget = qfalse;
            startTimer = qfalse;
            stopTimer = qfalse;
            gotOrigin = qfalse;
            continue;
        }
        if ( keyname[0] == '}' ) {
            //CG_Printf("}\n");
            if (spawnPoint) {
                //Com_Printf("spawn: %f %f %f   angle:%d  spawnflags:%d  r:%d b:%d\n", origin[0], origin[1], origin[2], angle, spawnflags, redSpawn, blueSpawn);
                i = cg.numSpawnPoints;
                if (i >= MAX_SPAWN_POINTS) {
                    continue;
                }

                VectorCopy(origin, cg.spawnPoints[i].origin);
                cg.spawnPoints[i].angle = angle;
                cg.spawnPoints[i].spawnflags = spawnflags;
                cg.spawnPoints[i].redSpawn = redSpawn;
                cg.spawnPoints[i].blueSpawn = blueSpawn;
                cg.spawnPoints[i].initial = initial;
                cg.spawnPoints[i].deathmatch = deathmatch;
                cg.numSpawnPoints++;
                continue;
            }
            if (portal) {
                if (!portalHasTarget) {
                    if (cg.numMirrorSurfaces > MAX_MIRROR_SURFACES) {
                        Com_Printf("^3max mirror surfaces (%d)\n", MAX_MIRROR_SURFACES);
                        continue;
                    }
                    VectorCopy(origin, cg.mirrorSurfaces[cg.numMirrorSurfaces]);
                    cg.numMirrorSurfaces++;
                    //Com_Printf("origin: %f %f %f\n", origin[0], origin[1], origin[2]);
                }
                //Com_Printf("^1origin: %f %f %f  (hasTarget %d)\n", origin[0], origin[1], origin[2], portalHasTarget);
                continue;
            }
            if (startTimer) {
                cg.hasStartTimer = qtrue;
                VectorCopy(origin, cg.startTimerOrigin);
                Com_Printf("^5start timer %f %f %f\n", origin[0], origin[1], origin[2]);
                continue;
            }
            if (stopTimer) {
                cg.hasStopTimer = qtrue;
                VectorCopy(origin, cg.stopTimerOrigin);
                Com_Printf("^5stop timer %f %f %f\n", origin[0], origin[1], origin[2]);
                continue;
            }

            if (gotOrigin) {
                pointContents = CG_PointContents(origin, 0);
            } else {
                pointContents = 0;
            }

            if (skipItem) {
                continue;
            } else if (pointContents & 0x1) {
                // it's in an invalid place, some maps have this  qzdm20 has 2 megas
                continue;
            } else if (ti == redArmor) {
                if (!wait)
                    wait = 25;
                AddTimedItem(&cg.numRedArmors, cg.redArmors, origin, wait);
            } else if (ti == yellowArmor) {
                if (!wait)
                    wait = 25;
                AddTimedItem(&cg.numYellowArmors, cg.yellowArmors, origin, wait);
            } else if (ti == greenArmor) {
                if (!wait)
                    wait = 25;
                AddTimedItem(&cg.numGreenArmors, cg.greenArmors, origin, wait);
            } else if (ti == megaHealth) {
                if (!wait)
                    wait = 35;
                AddTimedItem(&cg.numMegaHealths, cg.megaHealths, origin, wait);
            } else if (ti == quad) {
                if (!wait)
                    wait = 120;
                AddTimedItem(&cg.numQuads, cg.quads, origin, wait);
            } else if (ti == battleSuit) {
                if (!wait)
                    wait = 120;
                AddTimedItem(&cg.numBattleSuits, cg.battleSuits, origin, wait);
            }

            continue;
        }

        // parse value
        if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
            CG_Error( "CG_ParseSpawnVars: EOF without closing brace" );
        }

        if ( com_token[0] == '}' ) {
            CG_Error( "CG_ParseSpawnVars: closing brace without data" );
        }

        //CG_Printf("^3ent  %s : %s\n", keyname, com_token);

        if (!Q_stricmp(keyname, "classname")) {
            if (!Q_stricmp(com_token, "info_player_deathmatch")  ||  !Q_stricmp(com_token, "info_player_start")) {
                //FIXME spawnflags 4
                spawnPoint = qtrue;
                deathmatch = qtrue;
                blueSpawn = qtrue;
                redSpawn = qtrue;
                //Com_Printf("deathmatch spawn %d\n", cg.numSpawnPoints);
            } else if (!Q_stricmp(com_token, "team_CTF_redspawn")) {
                spawnPoint = qtrue;
                redSpawn = qtrue;
            } else if (!Q_stricmp(com_token, "team_CTF_bluespawn")) {
                spawnPoint = qtrue;
                blueSpawn = qtrue;
            } else if (!Q_stricmp(com_token, "team_CTF_redplayer")) {
                spawnPoint = qtrue;
                redSpawn = qtrue;
                initial = qtrue;
            } else if (!Q_stricmp(com_token, "team_CTF_blueplayer")) {
                spawnPoint = qtrue;
                blueSpawn = qtrue;
                initial = qtrue;
            } else if (!Q_stricmp(com_token, "item_armor_body")) {
                // red armor
                //Com_Printf("red armor\n");
                ti = redArmor;
            } else if (!Q_stricmp(com_token, "item_armor_combat")) {
                // yellow armor
                //Com_Printf("yellow armor\n");
                ti = yellowArmor;
            } else if (!Q_stricmp(com_token, "item_armor_jacket")) {
                ti = greenArmor;
            } else if (!Q_stricmp(com_token, "item_health_mega")) {
                //Com_Printf("mega health\n");
                ti = megaHealth;
            } else if (!Q_stricmp(com_token, "item_quad")) {
                //Com_Printf("quad\n");
                ti = quad;
            } else if (!Q_stricmp(com_token, "item_enviro")) {
                // battlesuit
                //Com_Printf("battlesuit?\n");
                ti = battleSuit;
                // count ??
            } else if (!Q_stricmp(com_token, "misc_portal_surface")) {
                //Com_Printf("^3portal surface\n");
                portal = qtrue;
            } else if (!Q_stricmp(com_token, "target_starttimer")) {
                startTimer = qtrue;
            } else if (!Q_stricmp(com_token, "target_stoptimer")) {
                stopTimer = qtrue;
            } else {
                //FIXME other?  regen?
            }


        } else if (!Q_stricmp(keyname, "origin")) {
            if (SC_ParseVec3FromStr(com_token, origin) == -1) {
                //Com_Printf("FIXME getting origin for entitytoken %s", com_token);
                origin[0] = 0.0;
                origin[1] = 0.0;
                origin[2] = 0.0;
            }
            gotOrigin = qtrue;
            //Com_Printf("*** origin: %f %f %f\n", origin[0], origin[1], origin[2]);
        } else if (!Q_stricmp(keyname, "target")) {
            portalHasTarget = qtrue;
            //Q_strncpyz(buf, com_token, sizeof(buf));
            //Com_Printf("^5target == '%s'\n", buf);
        } else if (!Q_stricmp(keyname, "wait")) {
            wait = atoi(com_token);
        } else if (!Q_stricmp(keyname, "notteam")) {
            val = atoi(com_token);
            //if (val  &&  cgs.gametype >= GT_TEAM) {
            if (val  &&  CG_IsTeamGame(cgs.gametype)) {
                skipItem = 1;
            }
        } else if (!Q_stricmp(keyname, "not_gametype")) {
            const char *value = com_token;
            const char *gametypeName;
            const char *s;

            //FIXME could be more than one digit in the list ??

            if (isdigit(com_token[0])) {
                val = atoi(com_token);
                if (cgs.protocol == PROTOCOL_QL) {
                    if (cgs.gametype == GT_RACE) {
                        if (val == 2) {
                            skipItem = 1;
                        }
                    } else {
                        if (cgs.gametype == val) {
                            skipItem = 1;
                        }
                    }
                } else {
                    if (cgs.gametype == val) {
                        skipItem = 1;
                    }
                }
            } else {  // string value
                s = NULL;
                if (cgs.gametype < ARRAY_LEN(gametypeNames)) {
                    gametypeName = gametypeNames[cgs.gametype];
                    s = strstr(value, gametypeName);
                }
                if (!s) {
                    // try alternate quake live gametype names
                    if (cgs.gametype == GT_TEAM) {
                        s = strstr(value, "tdm");
                    } else if (cgs.gametype == GT_TOURNAMENT) {
                        s = strstr(value, "duel");
                    } else if (cgs.gametype == GT_HARVESTER) {
                        s = strstr(value, "har");
                    } else if (cgs.gametype == GT_1FCTF) {
                        s = strstr(value, "1f");
                    } else if (cgs.gametype == GT_OBELISK) {
                        s = strstr(value, "obj");
                    }
                }
                if (s) {
                    skipItem = 1;
                }
            }
        } else if (!Q_stricmp(keyname, "gametype")) {
            //FIXME this is wrong, see g_spawn.c
            //val = atoi(com_token);
            //if (val != cgs.gametype) {
            //    skipItem = 1;
            //}
            qboolean found = qfalse;

            skipItem = 1;
            line = com_token;
            newLine = qfalse;
            while (*line  &&  newLine == qfalse) {
                int ln;
                //Com_Printf("line1: '%s'\n", line);
                //FIXME const
                line = (char *)CG_GetTokenGameType(line, token, qfalse, &newLine);
                //Com_Printf("newline: %d\n", newLine);
                //Com_Printf("line2: '%s'\n", line);
                //Com_Printf("    token: '%s'\n", token);
                ln = strlen(token);
                if (ln  &&  *token) {
                    if (token[ln - 1] == ',') {
                        token[ln - 1] = '\0';
                    }
                }
                for (i = 0;  i < (sizeof(gametypeNames) / sizeof(char *));  i++) {
                    if (!Q_stricmp(token, gametypeNames[i])) {
                        found = qtrue;
                        break;
                    }
                }
                if (!found) {
                    // try alternate quakelive name for 'team'
                    if (!Q_stricmp(token, "tdm")) {
                        if (cgs.gametype == GT_TEAM) {
                            skipItem = 0;
                        }
                    } else if (!Q_stricmp(token, "duel")) {
                        if (cgs.gametype == GT_TOURNAMENT) {
                            skipItem = 0;
                        }
                    } else if (!Q_stricmp(token, "har")) {
                        if (cgs.gametype == GT_HARVESTER) {
                            skipItem = 0;
                        }
                    } else if (!Q_stricmp(token, "1f")) {
                        if (cgs.gametype == GT_1FCTF) {
                            skipItem = 0;
                        }
                    } else if (!Q_stricmp(token, "ob")) {
                        if (cgs.gametype == GT_OBELISK) {
                            skipItem = 0;
                        }
                    } else {
                        Com_Printf("FIXME gametype : '%s'  '%s'\n", com_token, token);
                    }
                } else if (cgs.gametype < ARRAY_LEN(gametypeNames)  &&  !Q_stricmp(token, gametypeNames[cgs.gametype])) {
                    skipItem = 0;
                }
            }
#if 0
            if (!found) {
                Com_Printf("FIXME gametype : %s\n", com_token);
            }

            if (cgs.gametype >= ARRAY_LEN(gametypeNames)  ||  Q_stricmp(com_token, gametypeNames[cgs.gametype])) {
                skipItem = 1;
            }
#endif
        } else if (!Q_stricmp(keyname, "notfree")) {
            val = atoi(com_token);
            if (val  &&  (cgs.gametype == GT_FFA ||  cgs.gametype == GT_TOURNAMENT)) {
                skipItem = 1;
            }
        } else if (!Q_stricmp(keyname, "notsingle")) {
            val = atoi(com_token);
            if (val  &&  cgs.gametype == GT_SINGLE_PLAYER) {
                skipItem = 1;
            }
        } else if (!Q_stricmp(keyname, "angle")) {
            angle = atoi(com_token);
        } else if (!Q_stricmp(keyname, "spawnflags")) {
            spawnflags = atoi(com_token);
        }

            //  count
    }

    return qtrue;
}
Пример #21
0
static int CG_CalcFov( void ) {
	static float lastfov = 90;      // for transitions back from zoomed in modes
	float x;
	float phase;
	float v;
	int contents;
	float fov_x, fov_y;
	float zoomFov;
	float f;
	int inwater;
	qboolean dead;

	CG_Zoom();

	if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
		dead = qtrue;
		cg.zoomedBinoc = qfalse;
		cg.zoomTime = 0;
		cg.zoomval = 0;
	} else {
		dead = qfalse;
	}

	if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
		// if in intermission, use a fixed value
		fov_x = 90;
	} else {
		// user selectable
		if ( cgs.dmflags & DF_FIXED_FOV ) {
			// dmflag to prevent wide fov for all clients
			fov_x = 90;
		} else {
			fov_x = cg_fov.value;
			if ( fov_x < 1 ) {
				fov_x = 1;
			} else if ( fov_x > 160 ) {
				fov_x = 160;
			}
		}

		// account for zooms
		if ( cg.zoomval ) {
			zoomFov = cg.zoomval;   // (SA) use user scrolled amount

			if ( zoomFov < 1 ) {
				zoomFov = 1;
			} else if ( zoomFov > 160 ) {
				zoomFov = 160;
			}
		} else {
			zoomFov = lastfov;
		}

		// do smooth transitions for the binocs
		if ( cg.zoomedBinoc ) {        // binoc zooming in
			f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
			if ( f > 1.0 ) {
				fov_x = zoomFov;
			} else {
				fov_x = fov_x + f * ( zoomFov - fov_x );
			}
			lastfov = fov_x;
		} else if ( cg.zoomval ) {    // zoomed by sniper/snooper
			fov_x = cg.zoomval;
			lastfov = fov_x;
		} else {                    // binoc zooming out
			f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
			if ( f <= 1.0 ) {
				fov_x = zoomFov + f * ( fov_x - zoomFov );
			}
		}
	}

	// DHM - Nerve :: zoom in for Limbo or Spectator
	if ( cgs.gametype == GT_WOLF ) {
		if ( cg.snap->ps.pm_flags & PMF_FOLLOW && cg.snap->ps.weapon == WP_SNIPERRIFLE ) {
			fov_x = cg_zoomDefaultSniper.value;
		}
	}
	// dhm - end

	if ( !dead && ( cg.weaponSelect == WP_SNOOPERSCOPE ) ) {
		cg.refdef.rdflags |= RDF_SNOOPERVIEW;
	} else {
		cg.refdef.rdflags &= ~RDF_SNOOPERVIEW;
	}

	if ( cg.snap->ps.persistant[PERS_HWEAPON_USE] ) {
		fov_x = 55;
	}

	x = cg.refdef.width / tan( fov_x / 360 * M_PI );
	fov_y = atan2( cg.refdef.height, x );
	fov_y = fov_y * 360 / M_PI;

	// warp if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );
	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
		phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
		v = WAVE_AMPLITUDE * sin( phase );
		fov_x += v;
		fov_y -= v;
		inwater = qtrue;
		cg.refdef.rdflags |= RDF_UNDERWATER;
	} else {
		cg.refdef.rdflags &= ~RDF_UNDERWATER;
		inwater = qfalse;
	}

	contents = CG_PointContents( cg.refdef.vieworg, -1 );
	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
		cg.refdef.rdflags |= RDF_UNDERWATER;
	} else {
		cg.refdef.rdflags &= ~RDF_UNDERWATER;
	}

	// set it
	cg.refdef.fov_x = fov_x;
	cg.refdef.fov_y = fov_y;

	if ( !cg.zoomedBinoc ) {
		// NERVE - SMF - fix for zoomed in/out movement bug
		if ( cg.zoomval ) {
			if ( cg.snap->ps.weapon == WP_SNOOPERSCOPE ) {
				cg.zoomSensitivity = 0.3f * ( cg.zoomval / 90.f );  // NERVE - SMF - changed to get less sensitive as you zoom in;
			}
//				cg.zoomSensitivity = 0.2;
			else {
				cg.zoomSensitivity = 0.6 * ( cg.zoomval / 90.f );   // NERVE - SMF - changed to get less sensitive as you zoom in
			}
//				cg.zoomSensitivity = 0.1;
		} else {
			cg.zoomSensitivity = 1;
		}
		// -NERVE - SMF
	} else {
		cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
	}

	return inwater;
}
Пример #22
0
//----------------------------
// Draw
//----------------------------
void CEmitter::Draw()
{
	// Emitters don't draw themselves, but they may need to add an attached model
	if ( mFlags & FX_ATTACHED_MODEL )
	{
		mRefEnt.nonNormalizedAxes = qtrue;

		VectorCopy( mOrigin1, mRefEnt.origin );

		// ensure that we are sized
		for ( int i = 0; i < 3; i++ )
		{
			VectorScale( mRefEnt.axis[i], mRefEnt.radius, mRefEnt.axis[i] );
		}

		theFxHelper.AddFxToScene( &mRefEnt );
	}

	// If we are emitting effects, we had better be careful because just calling it every cgame frame could
	//	either choke up the effects system on a fast machine, or look really nasty on a low end one.
	if ( mFlags & FX_EMIT_FX )
	{
		vec3_t	org, v;
		float	ftime, time2, 
				step;
		int		i, t, dif;

#define TRAIL_RATE		8 // we "think" at about a 60hz rate

		// Pick a target step distance and square it
		step = mDensity + crandom() * mVariance;
		step *= step;

		dif = 0;

		for ( t = mOldTime; t <= theFxHelper.mTime; t += TRAIL_RATE ) 
		{
			dif += TRAIL_RATE;

			// ?Not sure if it's better to update this before or after updating the origin
			VectorMA( mOldVelocity, dif * 0.001f, mAccel, v );

			// Calc the time differences
			ftime = dif * 0.001f;
			time2 = ftime * ftime * 0.5f;

			// Predict the new position
			for ( i = 0 ; i < 3 ; i++ ) 
			{
				org[i] = mOldOrigin[i] + ftime * v[i] + time2 * v[i];
			}
	
			// Only perform physics if this object is tagged to do so
			if ( (mFlags & FX_APPLY_PHYSICS) )
			{
				bool solid;

				if ( mFlags & FX_EXPENSIVE_PHYSICS )
				{
					solid = true; // by setting this to true, we force a real trace to happen
				}
				else
				{
					// if this returns solid, we need to do a trace
					solid = !!(CG_PointContents( org, ENTITYNUM_WORLD ) & MASK_SHOT);
				}

				if ( solid )
				{
					trace_t	trace;

					if ( mFlags & FX_USE_BBOX )
					{
						theFxHelper.Trace( &trace, mOldOrigin, mMin, mMax, org, -1, MASK_SHOT );
					}
					else
					{
						theFxHelper.Trace( &trace, mOldOrigin, NULL, NULL, org, -1, MASK_SHOT );
					}

					// Hit something
					if ( trace.fraction < 1.0f || trace.startsolid || trace.allsolid )
					{
						return;
					}
				}
			}

			// Is it time to draw an effect?
			if ( DistanceSquared( org, mOldOrigin ) >= step )
			{ 
				// Pick a new target step distance and square it
				step = mDensity + crandom() * mVariance;
				step *= step;

				// We met the step criteria so, we should add in the effect
				theFxScheduler.PlayEffect( mEmitterFxID, org, mRefEnt.axis );

				VectorCopy( org, mOldOrigin );
				VectorCopy( v, mOldVelocity );
				dif = 0;
				mOldTime = t;
			}
		}
	}

	drawnFx++;
}
Пример #23
0
/*
==========================
CG_MachineGunEjectBrass
==========================
*/
static void CG_MachineGunEjectBrass( centity_t *cent ) {
	localEntity_t	*le;
	refEntity_t		*re;
	vec3_t			velocity, xvelocity;
	vec3_t			offset, xoffset;
	float			waterScale = 1.0f;
	vec3_t			v[3];

	if ( cg_brassTime.integer <= 0 ) {
		return;
	}

	le = CG_AllocLocalEntity();
	re = &le->refEntity;

	velocity[0] = 0;
	velocity[1] = -50 + 40 * crandom();
	velocity[2] = 100 + 50 * crandom();

	le->leType = LE_FRAGMENT;
	le->startTime = cg.time;
	le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();

	le->pos.trType = TR_GRAVITY;
	le->pos.trTime = cg.time - (rand()&15);

	AnglesToAxis( cent->lerpAngles, v );

	offset[0] = 8;
	offset[1] = -4;
	offset[2] = 24;

	xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
	xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
	xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
	VectorAdd( cent->lerpOrigin, xoffset, re->origin );

	VectorCopy( re->origin, le->pos.trBase );

	if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
		waterScale = 0.10f;
	}

	xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
	xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
	xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
	VectorScale( xvelocity, waterScale, le->pos.trDelta );

	AxisCopy( axisDefault, re->axis );
	re->hModel = cgs.media.machinegunBrassModel;

	le->bounceFactor = 0.4 * waterScale;

	le->angles.trType = TR_LINEAR;
	le->angles.trTime = cg.time;
	le->angles.trBase[0] = rand()&31;
	le->angles.trBase[1] = rand()&31;
	le->angles.trBase[2] = rand()&31;
	le->angles.trDelta[0] = 2;
	le->angles.trDelta[1] = 1;
	le->angles.trDelta[2] = 0;

	le->leFlags = LEF_TUMBLE;
	le->leBounceSoundType = LEBS_BRASS;
	le->leMarkType = LEMT_NONE;
}
Пример #24
0
static void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {
	localEntity_t	*le;
	refEntity_t		*re;
	entityState_t	*es;
	vec3_t			velocity, xvelocity, origin;
	vec3_t			offset, xoffset;
	vec3_t			v[3];
	int				t, startTime, step;

	float	waterScale = 1.0f;

	if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {
		return;
	}

	step = 50;

	es = &cent->currentState;
	startTime = cent->trailTime;
	t = step * ( (startTime + step) / step );

	BG_EvaluateTrajectory( &es->pos, cg.time, origin );

	le = CG_AllocLocalEntity();
	re = &le->refEntity;

	velocity[0] = 60 - 120 * crandom();
	velocity[1] = 40 - 80 * crandom();
	velocity[2] = 100 - 200 * crandom();

	le->leType = LE_MOVE_SCALE_FADE;
	le->leFlags = LEF_TUMBLE;
	le->leBounceSoundType = LEBS_NONE;
	le->leMarkType = LEMT_NONE;

	le->startTime = cg.time;
	le->endTime = le->startTime + 600;

	le->pos.trType = TR_GRAVITY;
	le->pos.trTime = cg.time;

	AnglesToAxis( cent->lerpAngles, v );

	offset[0] = 2;
	offset[1] = 2;
	offset[2] = 2;

	xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
	xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
	xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];

	VectorAdd( origin, xoffset, re->origin );
	VectorCopy( re->origin, le->pos.trBase );

	if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
		waterScale = 0.10f;
	}

	xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
	xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
	xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
	VectorScale( xvelocity, waterScale, le->pos.trDelta );

	AxisCopy( axisDefault, re->axis );
    re->shaderTime = cg.time / 1000.0f;
    re->reType = RT_SPRITE;
    re->radius = 0.25f;
	re->customShader = cgs.media.railRingsShader;
	le->bounceFactor = 0.3f;

    re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;
    re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;
    re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;
    re->shaderRGBA[3] = 63;

    le->color[0] = wi->flashDlightColor[0] * 0.2;
    le->color[1] = wi->flashDlightColor[1] * 0.2;
    le->color[2] = wi->flashDlightColor[2] * 0.2;
    le->color[3] = 0.25f;

	le->angles.trType = TR_LINEAR;
	le->angles.trTime = cg.time;
	le->angles.trBase[0] = rand()&31;
	le->angles.trBase[1] = rand()&31;
	le->angles.trBase[2] = rand()&31;
	le->angles.trDelta[0] = 1;
	le->angles.trDelta[1] = 0.5;
	le->angles.trDelta[2] = 0;

}
Пример #25
0
/*
* CG_GS_PointContents
*/
static int CG_GS_PointContents( vec3_t point, int timeDelta )
{
	assert( !timeDelta );
	return CG_PointContents( point );
}
Пример #26
0
static int CG_CalcFov( void ) {
	float	x;
	float	phase;
	float	v;
	int		contents;
	float	fov_x, fov_y;
	float	zoomFov;
	float	f;

	if ( cg.cur_lc->predictedPlayerState.pm_type == PM_INTERMISSION ) {
		// if in intermission, use a fixed value
		cg.fov = fov_x = 90;
	} else {
		// user selectable
		if ( cgs.dmflags & DF_FIXED_FOV ) {
			// dmflag to prevent wide fov for all clients
			fov_x = 90;
		} else {
			fov_x = cg_fov.value;
			if ( fov_x < 1 ) {
				fov_x = 1;
			} else if ( fov_x > 160 ) {
				fov_x = 160;
			}
		}

		cg.fov = fov_x;

		// account for zooms
		zoomFov = cg_zoomFov.value;
		if ( zoomFov < 1 ) {
			zoomFov = 1;
		} else if ( zoomFov > 160 ) {
			zoomFov = 160;
		}

		if ( cg.cur_lc->zoomed ) {
			f = ( cg.time - cg.cur_lc->zoomTime ) / (float)ZOOM_TIME;
			if ( f > 1.0 ) {
				fov_x = zoomFov;
			} else {
				fov_x = fov_x + f * ( zoomFov - fov_x );
			}
		} else {
			f = ( cg.time - cg.cur_lc->zoomTime ) / (float)ZOOM_TIME;
			if ( f <= 1.0 ) {
				fov_x = zoomFov + f * ( fov_x - zoomFov );
			}
		}
	}

	// Do FOV Correction for some viewports
	if ((cg.numViewports == 2) || (cg.numViewports == 3 && cg.viewport == 2)) {
		if (cg_splitviewVertical.integer == 1) {
			// Tall/narrow view
			fov_x *= 0.6f; // 0.5 would be correct, but fov gets real small.
		} else {
			// Short/wide view
			fov_x *= 1.4f; // 1.5 would be correct, but fov gets real big.
		}
	}
	x = cg.refdef.width / tan( fov_x / 360 * M_PI );
	fov_y = atan2( cg.refdef.height, x );
	fov_y = fov_y * 360 / M_PI;

	// warp if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );
	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
		phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
		v = WAVE_AMPLITUDE * sin( phase );
		fov_x += v;
		fov_y -= v;
		cg.refdef.rdflags |= RDF_UNDERWATER;
	}
	else {
		cg.refdef.rdflags &= ~RDF_UNDERWATER;
	}


	// set it
	cg.refdef.fov_x = fov_x;
	cg.refdef.fov_y = fov_y;

	if ( !cg.cur_lc->zoomed ) {
		cg.cur_lc->zoomSensitivity = 1;
	} else {
		cg.cur_lc->zoomSensitivity = cg.refdef.fov_y / 75.0;
	}

	return (cg.refdef.rdflags & RDF_UNDERWATER);
}
/*
================
CG_AddFragment
================
*/
void CG_AddFragment( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;

	if (le->forceAlpha)
	{
		le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA;
		le->refEntity.shaderRGBA[3] = le->forceAlpha;
	}

	if ( le->pos.trType == TR_STATIONARY ) {
		// sink into the ground if near the removal time
		int		t;
		float	t_e;
		
		t = le->endTime - cg.time;
		if ( t < (SINK_TIME*2) ) {
			le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA;
			t_e = (float)((float)(le->endTime - cg.time)/(SINK_TIME*2));
			t_e = (int)((t_e)*255);

			if (t_e > 255)
			{
				t_e = 255;
			}
			if (t_e < 1)
			{
				t_e = 1;
			}

			if (le->refEntity.shaderRGBA[3] && t_e > le->refEntity.shaderRGBA[3])
			{
				t_e = le->refEntity.shaderRGBA[3];
			}

			le->refEntity.shaderRGBA[3] = t_e;

			trap->R_AddRefEntityToScene( &le->refEntity );
		} else {
			trap->R_AddRefEntityToScene( &le->refEntity );
		}

		return;
	}

	// calculate new position
	BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );

	// trace a line from previous position to new position
	CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
	if ( trace.fraction == 1.0 ) {
		// still in free fall
		VectorCopy( newOrigin, le->refEntity.origin );

		if ( le->leFlags & LEF_TUMBLE ) {
			vec3_t angles;

			BG_EvaluateTrajectory( &le->angles, cg.time, angles );
			AnglesToAxis( angles, le->refEntity.axis );
			ScaleModelAxis(&le->refEntity);
		}

		trap->R_AddRefEntityToScene( &le->refEntity );

		// add a blood trail
		if ( le->leBounceSoundType == LEBS_BLOOD ) {
			CG_BloodTrail( le );
		}

		return;
	}

	// if it is in a nodrop zone, remove it
	// this keeps gibs from waiting at the bottom of pits of death
	// and floating levels
	if ( CG_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
		CG_FreeLocalEntity( le );
		return;
	}

	if (!trace.startsolid)
	{
		// leave a mark
		CG_FragmentBounceMark( le, &trace );

		// do a bouncy sound
		CG_FragmentBounceSound( le, &trace );

		if (le->bounceSound)
		{ //specified bounce sound (debris)
			trap->S_StartSound(le->pos.trBase, ENTITYNUM_WORLD, CHAN_AUTO, le->bounceSound);
		}

		// reflect the velocity on the trace plane
		CG_ReflectVelocity( le, &trace );

		trap->R_AddRefEntityToScene( &le->refEntity );
	}
}
Пример #28
0
static int CG_CalcFov( void ) {
	float	x;
	float	phase;
	float	v;
	int		contents;
	float	fov_x, fov_y;
	float	f;
	int		inwater;
	float	cgFov = cg_fov.value;

	if (cgFov < 1)
	{
		cgFov = 1;
	}
	if (cgFov > 97)
	{
		cgFov = 97;
	}

	if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
		// if in intermission, use a fixed value
		fov_x = 80;//90;
	} else {
		// user selectable
		if ( cgs.dmflags & DF_FIXED_FOV ) {
			// dmflag to prevent wide fov for all clients
			fov_x = 80;//90;
		} else {
			fov_x = cgFov;
			if ( fov_x < 1 ) {
				fov_x = 1;
			} else if ( fov_x > 160 ) {
				fov_x = 160;
			}
		}

		if (cg.predictedPlayerState.zoomMode == 2)
		{ //binoculars
			if (zoomFov > 40.0f)
			{
				zoomFov -= cg.frametime * 0.075f;

				if (zoomFov < 40.0f)
				{
					zoomFov = 40.0f;
				}
				else if (zoomFov > cgFov)
				{
					zoomFov = cgFov;
				}
			}

			fov_x = zoomFov;
		}
		else if (cg.predictedPlayerState.zoomMode)
		{
			if (!cg.predictedPlayerState.zoomLocked)
			{
				if (zoomFov > 50)
				{ //Now starting out at nearly half zoomed in
					zoomFov = 50;
				}
				zoomFov -= cg.frametime * 0.035f;//0.075f;

				if (zoomFov < MAX_ZOOM_FOV)
				{
					zoomFov = MAX_ZOOM_FOV;
				}
				else if (zoomFov > cgFov)
				{
					zoomFov = cgFov;
				}
				else
				{	// Still zooming
					static zoomSoundTime = 0;

					if (zoomSoundTime < cg.time || zoomSoundTime > cg.time + 10000)
					{
						trap_S_StartSound(cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_LOCAL, cgs.media.disruptorZoomLoop);
						zoomSoundTime = cg.time + 300;
					}
				}
			}

			fov_x = zoomFov;
		}
		else 
		{
			zoomFov = 80;

			f = ( cg.time - cg.predictedPlayerState.zoomTime ) / ZOOM_OUT_TIME;
			if ( f > 1.0 ) 
			{
				fov_x = fov_x;
			} 
			else 
			{
				fov_x = cg.predictedPlayerState.zoomFov + f * ( fov_x - cg.predictedPlayerState.zoomFov );
			}
		}
	}

	x = cg.refdef.width / tan( fov_x / 360 * M_PI );
	fov_y = atan2( cg.refdef.height, x );
	fov_y = fov_y * 360 / M_PI;

	// warp if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );
	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
		phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
		v = WAVE_AMPLITUDE * sin( phase );
		fov_x += v;
		fov_y -= v;
		inwater = qtrue;
	}
	else {
		inwater = qfalse;
	}


	// set it
	cg.refdef.fov_x = fov_x;
	cg.refdef.fov_y = fov_y;

	if (cg.predictedPlayerState.zoomMode)
	{
		cg.zoomSensitivity = zoomFov/cgFov;
	}
	else if ( !cg.zoomed ) {
		cg.zoomSensitivity = 1;
	} else {
		cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
	}

	return inwater;
}
Пример #29
0
static int CG_CalcFov( void )
{
  float     y;
  float     phase;
  float     v;
  int       contents;
  float     fov_x, fov_y;
  float     zoomFov;
  float     f;
  int       inwater;
  int       attribFov;
  usercmd_t cmd;
  usercmd_t oldcmd;
  int       cmdNum;

  cmdNum = trap_GetCurrentCmdNumber( );
  trap_GetUserCmd( cmdNum, &cmd );
  trap_GetUserCmd( cmdNum - 1, &oldcmd );

  // switch follow modes if necessary: cycle between free -> follow -> third-person follow
  if( cmd.buttons & BUTTON_USE_HOLDABLE && !( oldcmd.buttons & BUTTON_USE_HOLDABLE ) )
  {
    if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) 
    {
      if( !cg.chaseFollow )
        cg.chaseFollow = qtrue;
      else
      {
        cg.chaseFollow = qfalse;
        trap_SendClientCommand( "follow\n" );
      }
    }
    else if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
      trap_SendClientCommand( "follow\n" );
  }

  if( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
      ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) || 
      ( cg.renderingThirdPerson ) )
  {
    // if in intermission or third person, use a fixed value
    fov_y = BASE_FOV_Y;
  }
  else
  {
    // don't lock the fov globally - we need to be able to change it
    attribFov = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fov * 0.75f;
    fov_y = attribFov;

    if ( fov_y < 1.0f )
      fov_y = 1.0f;
    else if ( fov_y > MAX_FOV_Y )
      fov_y = MAX_FOV_Y;

    if( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
        BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_FOVWARPS ) )
    {
      float fraction = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME;

      fov_y = MAX_FOV_WARP_Y - ( ( MAX_FOV_WARP_Y - fov_y ) * fraction );
    }

    // account for zooms
    zoomFov = BG_Weapon( cg.predictedPlayerState.weapon )->zoomFov * 0.75f;
    if ( zoomFov < 1.0f )
      zoomFov = 1.0f;
    else if ( zoomFov > attribFov )
      zoomFov = attribFov;

    // only do all the zoom stuff if the client CAN zoom
    // FIXME: zoom control is currently hard coded to BUTTON_ATTACK2
    if( BG_Weapon( cg.predictedPlayerState.weapon )->canZoom )
    {
      if ( cg.zoomed )
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f > 1.0f )
          fov_y = zoomFov;
        else
          fov_y = fov_y + f * ( zoomFov - fov_y );

        // BUTTON_ATTACK2 isn't held so unzoom next time
        if( !( cmd.buttons & BUTTON_ATTACK2 ) )
        {
          cg.zoomed   = qfalse;
          cg.zoomTime = MIN( cg.time, 
              cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
        }
      }
      else
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f <= 1.0f )
          fov_y = zoomFov + f * ( fov_y - zoomFov );

        // BUTTON_ATTACK2 is held so zoom next time
        if( cmd.buttons & BUTTON_ATTACK2 )
        {
          cg.zoomed   = qtrue;
          cg.zoomTime = MIN( cg.time, 
              cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
        }
      }
    }
  }

  y = cg.refdef.height / tan( 0.5f * DEG2RAD( fov_y ) );
  fov_x = atan2( cg.refdef.width, y );
  fov_x = 2.0f * RAD2DEG( fov_x );

  // warp if underwater
  contents = CG_PointContents( cg.refdef.vieworg, -1 );

  if( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
  {
    phase = cg.time / 1000.0f * WAVE_FREQUENCY * M_PI * 2.0f;
    v = WAVE_AMPLITUDE * sin( phase );
    fov_x += v;
    fov_y -= v;
    inwater = qtrue;
  }
  else
    inwater = qfalse;

  if( ( cg.predictedPlayerEntity.currentState.eFlags & EF_POISONCLOUDED ) &&
      ( cg.time - cg.poisonedTime < PCLOUD_DISORIENT_DURATION) &&
      cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 &&
      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    float scale = 1.0f - (float)( cg.time - cg.poisonedTime ) /
                  BG_PlayerPoisonCloudTime( &cg.predictedPlayerState );
      
    phase = ( cg.time - cg.poisonedTime ) / 1000.0f * PCLOUD_ZOOM_FREQUENCY * M_PI * 2.0f;
    v = PCLOUD_ZOOM_AMPLITUDE * sin( phase ) * scale;
    fov_x += v;
    fov_y += v;
  }


  // set it
  cg.refdef.fov_x = fov_x;
  cg.refdef.fov_y = fov_y;

  if( !cg.zoomed )
    cg.zoomSensitivity = 1.0f;
  else
    cg.zoomSensitivity = cg.refdef.fov_y / 75.0f;

  return inwater;
}
Пример #30
0
//----------------------------
// Update Origin
//----------------------------
bool CParticle::UpdateOrigin()
{
	vec3_t	new_origin;
//	float	ftime, time2;

	UpdateVelocity();

	// Calc the time differences
//	ftime = theFxHelper.mFrameTime * 0.001f;
	//time2 = ftime * ftime * 0.5f;
//	time2=0;

	// Predict the new position
	new_origin[0] = mOrigin1[0] + theFxHelper.mFloatFrameTime * mVel[0];// + time2 * mVel[0];
	new_origin[1] = mOrigin1[1] + theFxHelper.mFloatFrameTime * mVel[1];// + time2 * mVel[1];
	new_origin[2] = mOrigin1[2] + theFxHelper.mFloatFrameTime * mVel[2];// + time2 * mVel[2];

	// Only perform physics if this object is tagged to do so
	if ( (mFlags & FX_APPLY_PHYSICS) )
	{
		bool solid;

		if ( mFlags & FX_EXPENSIVE_PHYSICS )
		{
			solid = true; // by setting this to true, we force a real trace to happen
		}
		else
		{
			// if this returns solid, we need to do a trace
			solid = !!(CG_PointContents( new_origin, ENTITYNUM_WORLD ) & ( MASK_SHOT | CONTENTS_WATER ));
		}

		if ( solid )
		{
			trace_t	trace;
			float	dot;

			if ( mFlags & FX_USE_BBOX )
			{
				theFxHelper.Trace( &trace, mOrigin1, mMin, mMax, new_origin, -1, ( MASK_SHOT | CONTENTS_WATER ) );
			}
			else
			{
				theFxHelper.Trace( &trace, mOrigin1, NULL, NULL, new_origin, -1, ( MASK_SHOT | CONTENTS_WATER ) );
			}

			// Hit something
			if ( trace.fraction < 1.0f )//|| trace.startsolid || trace.allsolid )
			{
				if ( mFlags & FX_IMPACT_RUNS_FX && !(trace.surfaceFlags & SURF_NOIMPACT ))
				{
					theFxScheduler.PlayEffect( mImpactFxID, trace.endpos, trace.plane.normal );
				}

				if ( mFlags & FX_KILL_ON_IMPACT	)
				{
					// time to die
					return false;
				}

				VectorMA( mVel, theFxHelper.mFloatFrameTime * trace.fraction, mAccel, mVel );

				dot = DotProduct( mVel, trace.plane.normal );

				VectorMA( mVel, -2 * dot, trace.plane.normal, mVel );

				VectorScale( mVel, mElasticity, mVel );

				// If the velocity is too low, make it stop moving, rotating, and turn off physics to avoid
				//	doing expensive operations when they aren't needed
				if ( trace.plane.normal[2] > 0 && mVel[2] < 4 )
				{
					VectorClear( mVel );
					VectorClear( mAccel );

					mFlags &= ~(FX_APPLY_PHYSICS|FX_IMPACT_RUNS_FX);
				}

				// Set the origin to the exact impact point
				VectorCopy( trace.endpos, mOrigin1 );
				return true;
			}
		}
	}

	// No physics were done to this object, move it
	VectorCopy( new_origin, mOrigin1 );

	return true;
}