示例#1
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 );
			trap_R_AddRefEntityToScene( &le->refEntity );
			le->refEntity.origin[2] = oldZ;
		} 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 );
		}

		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;
	}

	// 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 );

	trap_R_AddRefEntityToScene( &le->refEntity );
}
示例#2
0
//------------------------------------------------------
void SFxHelper::Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max,
						vec3_t end, int skipEntNum, int flags )
{
	CG_Trace( tr, start, min, max, end, skipEntNum, flags );
}
/*
================
CG_AddFragment
================
*/
void CG_AddFragment( localEntity_t *le ) 
{
	vec3_t	newOrigin;
	trace_t	trace;
	// used to sink into the ground, but it looks better to maybe just fade them out
	int		t;
	
	t = le->endTime - cg.time;

	if ( t < FRAG_FADE_TIME ) 
	{
		le->refEntity.renderfx |= RF_ALPHA_FADE;
		le->refEntity.shaderRGBA[0] = le->refEntity.shaderRGBA[1] = le->refEntity.shaderRGBA[2] = 255;
		le->refEntity.shaderRGBA[3] = ((float)t / FRAG_FADE_TIME) * 255.0f;
	}

	if ( le->pos.trType == TR_STATIONARY ) 
	{
		if ( !(cgi_CM_PointContents( le->refEntity.origin, 0 ) & CONTENTS_SOLID )) 
		{
			// thing is no longer in solid, so let gravity take it back
			VectorCopy( le->refEntity.origin, le->pos.trBase );
			VectorClear( le->pos.trDelta );
			le->pos.trTime = cg.time;
			le->pos.trType = TR_GRAVITY;
		}

		cgi_R_AddRefEntityToScene( &le->refEntity );

		return;
	}

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

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

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

			EvaluateTrajectory( &le->angles, cg.time, angles );
			AnglesToAxis( angles, le->refEntity.axis );
			for(int k = 0; k < 3; k++)
			{
				VectorScale(le->refEntity.axis[k], le->radius, le->refEntity.axis[k]);
			}

		}

		cgi_R_AddRefEntityToScene( &le->refEntity );

		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 ( cgi_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) 
	{
		CG_FreeLocalEntity( le );
		return;
	}

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

	// reflect the velocity on the trace plane
	CG_ReflectVelocity( le, &trace );
	//FIXME: if LEF_TUMBLE, change avelocity too?

	cgi_R_AddRefEntityToScene( &le->refEntity );
}
/*
================
CG_DrawRadarSymbols

================
*/
static void CG_DrawRadarSymbols_AIR( int vehicle ) {
	unsigned int i;
	centity_t	*self = &cg.predictedPlayerEntity;
	vec3_t		pos, pos1, pos2;
	vec3_t		dir;
	float		dist;
	float		range = availableVehicles[vehicle].radarRange;
	float		scale;
	float		hdg = self->currentState.angles[1];
	float		angle;
	vec3_t		angles;
	int			otherveh;
	vec3_t		otherpos;
	int			icon;
	int			drawnTargets = 0;
	trace_t		res;

	// radar screen and mode
	CG_DrawPic( 440, 280, 200, 200, cgs.media.HUDradar );
	CG_DrawSmallString( 615, 340, "AIR", 1.0f);

	// current range
	if( cg.RADARRangeSetting ) {
		range /= (2 * cg.RADARRangeSetting);
	}

	// adjust for radar screen size
	scale = range/64;

	// tell range
	CG_DrawSmallString( 595, 320, va("%.0f", range), 1.0f);

	// ground vehicle adjustment for angle
	if( (availableVehicles[vehicle].cat & CAT_GROUND) ||
		(availableVehicles[vehicle].cat & CAT_BOAT) ) {
		hdg += self->currentState.angles2[ROLL];
		if( hdg > 360 ) hdg -= 360;
		else if( hdg < 0 ) hdg += 360;
	}

	// pos
	VectorCopy( self->currentState.pos.trBase, pos );

	// walk through list of targets
	for( i = 0; i < cg.radarTargets; i++ ) {
		// dont show self
		if( cg.radarEnts[i] == &cg.predictedPlayerEntity ) continue;

		// dont show dead ones
		if( cg.radarEnts[i]->currentState.eFlags & EF_DEAD ) continue;

		// get other vehicle
		if( cg.radarEnts[i]->currentState.eType == ET_MISC_VEHICLE ) {
			otherveh = cg.radarEnts[i]->currentState.modelindex;
		} else {
			otherveh = cgs.clientinfo[cg.radarEnts[i]->currentState.clientNum].vehicle;
		}
		VectorCopy( cg.radarEnts[i]->currentState.pos.trBase, otherpos );

		// get dir and dist
		VectorSet( pos1, otherpos[0], otherpos[1], 0 );
		VectorSet( pos2, pos[0], pos[1], 0 );
		VectorSubtract( pos1, pos2, dir );
		dist = VectorNormalize(dir);
		// check out of range
		if( dist > range ) continue;
		// scale dist to radar screen
		dist /= scale;

		// get screen dir
		vectoangles( dir, angles );
		angle = angles[1]-hdg;
		if( angle > 360 ) angle -= 360;
		else if( angle < 0 ) angle += 360;
		if( angle >= 90 && angle <= 270 ) {
			if( !(cg.radarEnts[i]->currentState.ONOFF & OO_RADAR) ) continue;
		}
		angles[1] -= hdg - 90;
		if( angles[1] > 360 ) angles[1] -= 360;
		else if( angles[1] < 0 ) angles[1] += 360;
		angles[0] = angles[2] = 0;
		AngleVectors( angles, dir, 0, 0 );
		VectorScale( dir, dist, dir );

		// check LOS and/or RADAR on
		if( !(cg.radarEnts[i]->currentState.ONOFF & OO_RADAR) ) {
			CG_Trace( &res, pos, NULL, NULL, otherpos, cg.snap->ps.clientNum, MASK_SOLID );
			if( res.fraction < 1.0f ) continue;
		}
		// which icon (if at all, dont show lqms)
		if( (availableVehicles[otherveh].cat & CAT_PLANE) || 
			(availableVehicles[otherveh].cat & CAT_HELO) ) {
			float alt = otherpos[2] - pos[2];
			icon = RD_AIR_SAME_ENEMY;
			if( alt > 1000 ) icon += 3;
			else if( alt < -1000 ) icon += 6;
		} else {
			continue;
		}
		// friend or foe
		if( cgs.gametype >= GT_TEAM ) {
			if( cgs.clientinfo[cg.radarEnts[i]->currentState.clientNum].team ==
				cgs.clientinfo[self->currentState.clientNum].team ) 
				icon++;
		}

		// draw
		CG_DrawPic( 558 + dir[0], 386 - dir[1], 8, 8, cgs.media.radarIcons[icon] );
		// check if we should draw any more targets
		drawnTargets++;
		if( drawnTargets >= cg_radarTargets.integer ) break;
	}

	cg.radarTargets = 0;

}
/*
================
CG_DrawStatusBar_MFQ3

================
*/
void CG_DrawStatusBar_MFQ3( void ) {
	int			color;
	centity_t	*cent;
	playerState_t	*ps;
	int			value;
	int			vehicle = cgs.clientinfo[cg.predictedPlayerState.clientNum].vehicle;
	int			w;

	static vec4_t colors[] = { 
//		{ 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
		{ 1.0f, 0.89f, 0.0f, 1.0f } ,		// normal, yellow
		{ 1.0f, 0.0f, 0.0f, 1.0f },		// low health, red
		{0.5f, 0.5f, 0.5f, 1.0f},			// weapon firing, grey
		{ 1.0f, 1.0f, 1.0f, 1.0f },		// health > 100, white
		{ 0.3f, 1.0f, 0.3f, 1.0f }		// green
	};

	if ( cg_drawStatus.integer == 0 ) {
		return;
	}

	cent = &cg_entities[cg.snap->ps.clientNum];
	ps = &cg.snap->ps;

	// aiming/targetting reticles
	CG_Draw_Reticles();

	// main background
	CG_DrawPic( 0, 430, 640, 50, cgs.media.HUDmain );
	
	//
	// flag
	//
	if( cg.predictedPlayerState.objectives & OB_REDFLAG ) {
		CG_DrawStatusBarFlag( 640 - ICON_SIZE, ClientBase::TEAM_RED );
	} else if( cg.predictedPlayerState.objectives & OB_BLUEFLAG ) {
		CG_DrawStatusBarFlag( 640 - ICON_SIZE, ClientBase::TEAM_BLUE );
	}

	//
	// RADAR
	//
	if( cent->currentState.ONOFF & OO_RADAR_AIR ) {
		CG_DrawRadarSymbols_AIR(vehicle);
	} else if( cent->currentState.ONOFF & OO_RADAR_GROUND ) {
		CG_DrawRadarSymbols_GROUND(vehicle);
	} else if( availableVehicles[vehicle].radarRange || 
		availableVehicles[vehicle].radarRange2 ) {
		CG_DrawPic( 440, 280, 200, 200, cgs.media.HUDradar );
		CG_DrawSmallString( 595, 320, "OFF", 1.0f);
	}

	//
	// GPS
	//
	if( cg.GPS ) {
		trace_t	tr;
		vec3_t	start, end;
		// main
		CG_DrawPic( -14, 380, 512, 102, cgs.media.HUDgps );
		// heading
		value = 360 - (int)ps->vehicleAngles[1];
		CG_DrawSmallString( 234, 420, va("%i",value), 1.0f );
		// altitude
		VectorCopy( ps->origin, start );
		start[2] += availableVehicles[vehicle].mins[2];
		VectorCopy( start, end );
		end[2] -= 2000;
		CG_Trace( &tr, start, vec3_origin, vec3_origin, end, cg.snap->ps.clientNum, MASK_SOLID|MASK_WATER );
		value = (int)(tr.fraction * 2000);
		if( value > 100 ) color = 3;
		else if( value > 50 ) color = 4;
		else if( value > 25 ) color = 0;
		else color = 1;
		if( value < 2000 ) {
			CG_DrawSmallStringColor( 374, 420, va("%i",value), colors[color] );
		} else {
			CG_DrawSmallStringColor( 374, 420, "XXXX", colors[color] );
		}

		// x coord
		value = (int)ps->origin[0];
		CG_DrawSmallString( 264, 423, va("%i",value), 0.7f );
		// y coord
		value = (int)ps->origin[1];
		CG_DrawSmallString( 320, 423, va("%i",value), 0.7f );
	} 

	//
	// INFO
	//
	if( !cg.INFO ) {	// bit dirty to have NOT but oh well...
		// main
		CG_DrawPic( 0, 330, 150, 150, cgs.media.HUDext );
		if( availableVehicles[vehicle].caps & HC_GEAR ) {
			if( cent->currentState.ONOFF & OO_GEAR ) {
				CG_DrawSmallStringColor( 2, 390, "Gear", colors[4] );
			} else {
				CG_DrawSmallString( 2, 390, "Gear", 1.0f );
			}
		}
		if( availableVehicles[vehicle].caps & HC_SPEEDBRAKE ) {
			if( cent->currentState.ONOFF & OO_SPEEDBRAKE ) {
				CG_DrawSmallStringColor( 2, 410, "Speedbrakes", colors[4] );
			} else {
				CG_DrawSmallString( 2, 410, "Speedbrakes", 1.0f );
			}
		} else {
			if( cent->currentState.ONOFF & OO_SPEEDBRAKE ) {
				CG_DrawSmallStringColor( 2, 410, "Brakes", colors[4] );
			} else {
				CG_DrawSmallString( 2, 410, "Brakes", 1.0f );
			}
		}

		value = ps->stats[STAT_FUEL];
		if ( value > 10 ) {
			color =  3;	// white
		} else if (value > 5) {
			color = 0;	// yellow
		} else {
			color = 1;	// red
		}
		if( (availableVehicles[vehicle].cat & CAT_PLANE) ||
			(availableVehicles[vehicle].cat & CAT_HELO) ||
			(availableVehicles[vehicle].cat & CAT_BOAT) ) {
			value *= 100;
		}
		CG_DrawSmallStringColor( 2, 430, va("Fuel %i", value), colors[color]);
	} 

	//
	// FLARES
	//
	if( ps->ammo[WP_FLARE+8] > 0 ) {
		CG_DrawBigString( 600, 462, va("%i", ps->ammo[WP_FLARE]), 1.0f );
	}

	//
	// speed and throttle
	//
	value = ps->speed/10;
	if ( value > availableVehicles[vehicle].stallspeed * SPEED_GREEN_ARC ) {
		color = 3;		// white
	} else if (value > availableVehicles[vehicle].stallspeed * SPEED_YELLOW_ARC ) {
		color = 4;	// green
	} else if (value >= availableVehicles[vehicle].stallspeed) {
		color = 0;	// yellow
	} else {
		color = 1;	// red
	}

	w = CG_DrawStrlen(va("%i",value)) * BIGCHAR_WIDTH;
	CG_DrawBigStringColor(285-w, 460, va("%i",value), colors[color]);
	
	if( ps->throttle > availableVehicles[vehicle].maxthrottle ) {
		value = ps->throttle - availableVehicles[vehicle].maxthrottle;
	} else {
		value = ps->throttle;
	}
	CG_DrawPic(295, 443, 50, 37, cgs.media.throttle[value]);

	//
	// health
	//
	value = (100*ps->stats[STAT_HEALTH]/ps->stats[STAT_MAX_HEALTH]);
	if( value > 100 ) value = 100;
	if ( value < 10 ) {
		color = 1;
	} else if (value < 25) {
		color = 0;  
	} else {
		color = 3;
	}

	w = CG_DrawStrlen(va("%i",value)) * BIGCHAR_WIDTH;
	CG_DrawBigStringColor( 398-w, 460, va("%i",value), colors[color]);

	//
	// ammo
	//
	if( cent->currentState.weaponNum >= 0 ) {
		value = ps->ammo[cent->currentState.weaponNum];
		w = CG_DrawStrlen(va("%i",value)) * BIGCHAR_WIDTH;
		CG_DrawBigString (500-w, 460, va("%i",value),1.0f);
		CG_DrawPic( 416, 440, 24, 45, 
			availableWeapons[availableVehicles[vehicle].weapons[cent->currentState.weaponNum]].iconHandle );
	}

	//
	// ammo mg
	//
	if( ps->ammo[WP_MACHINEGUN+8] > 0 ) {
		if( cent->currentState.weaponNum >= 0 ) {
			value = ps->ammo[0];
			w = CG_DrawStrlen(va("%i",value)) * BIGCHAR_WIDTH;
			CG_DrawBigString (180-w, 460, va("%i",value),1.0f);
			CG_DrawPic( 200, 440, 24, 45, availableWeapons[availableVehicles[vehicle].weapons[0]].iconHandle );
		}
	}
}
示例#6
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);
			trap_R_AddRefEntityToScene(&le->refEntity);
			le->refEntity.origin[2] = oldZ;
		}
		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)
		{
#if 0
			vec3_t          angles;

			BG_EvaluateTrajectory(&le->angles, cg.time, angles);
			AnglesToAxis(angles, le->refEntity.axis);
#else
			// Tr3B - new quaternion code
			quat_t          qrot;

			// angular rotation for this frame
			float           angle = le->angVel * (cg.time - le->angles.trTime) * 0.001 / 2;

			// create the rotation quaternion
			qrot[3] = cos(angle);	// real part
			VectorScale(le->rotAxis, sin(angle), qrot);	// imaginary part
			QuatNormalize(qrot);

			// create the new orientation
			QuatMultiply0(le->quatOrient, qrot);

			// apply the combined previous rotations around other axes
			QuatMultiply1(le->quatOrient, le->quatRot, qrot);

			// convert the orientation into the form the renderer wants
			QuatToAxis(qrot, le->refEntity.axis);
			le->angles.trTime = cg.time;
#endif
		}

		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(trap_CM_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);

	trap_R_AddRefEntityToScene(&le->refEntity);
}
示例#7
0
static void CG_OffsetThirdPersonView( void ) {
	vec3_t forward, right, up;
	vec3_t view;
	vec3_t focusAngles;
	trace_t trace;
	static vec3_t mins = { -4, -4, -4 };
	static vec3_t maxs = { 4, 4, 4 };
	vec3_t focusPoint;
	float focusDist;
	float forwardScale, sideScale;

	cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;

	VectorCopy( cg.refdefViewAngles, focusAngles );

	// if dead, look at killer
	if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
		focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
		cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
	}

	if ( focusAngles[PITCH] > 45 ) {
		focusAngles[PITCH] = 45;        // don't go too far overhead
	}
	AngleVectors( focusAngles, forward, NULL, NULL );

	VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );

	VectorCopy( cg.refdef.vieworg, view );

	view[2] += 8;

	cg.refdefViewAngles[PITCH] *= 0.5;

	AngleVectors( cg.refdefViewAngles, forward, right, up );

	forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
	sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
	VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
	VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );

	// trace a ray from the origin to the viewpoint to make sure the view isn't
	// in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything

	CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );

	if ( trace.fraction != 1.0 ) {
		VectorCopy( trace.endpos, view );
		view[2] += ( 1.0 - trace.fraction ) * 32;
		// try another trace to this position, because a tunnel may have the ceiling
		// close enough that this is poking out

		CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
		VectorCopy( trace.endpos, view );
	}


	VectorCopy( view, cg.refdef.vieworg );

	// select pitch to look at focus point from vieword
	VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
	focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
	if ( focusDist < 1 ) {
		focusDist = 1;  // should never happen
	}
	cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
	cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
}
示例#8
0
/*
===============
CG_OffsetThirdPersonView

===============
*/
void CG_OffsetThirdPersonView( void )
{
	int           i;
	vec3_t        forward, right, up;
	vec3_t        view;
	trace_t       trace;
	static vec3_t mins = { -8, -8, -8 };
	static vec3_t maxs = { 8, 8, 8 };
	vec3_t        focusPoint;
	vec3_t        surfNormal;
	int           cmdNum;
	usercmd_t     cmd, oldCmd;
	float         range;
	vec3_t        mouseInputAngles;
	vec3_t        rotationAngles;
	vec3_t        axis[ 3 ], rotaxis[ 3 ];
	float         deltaPitch;
	static float  pitch;
	static vec3_t killerPos = { 0, 0, 0 };

	// If cg_thirdpersonShoulderViewMode == 2, do shoulder view instead
	// If cg_thirdpersonShoulderViewMode == 1, do shoulder view when chasing
	//   a wallwalker because it's really erratic to watch
	if ( cg_thirdPersonShoulderViewMode.integer == 2 )
	{
		CG_OffsetShoulderView();
		return;
	}

	BG_GetClientNormal( &cg.predictedPlayerState, surfNormal );
	// Set the view origin to the class's view height
	VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg );

	// Set the focus point where the camera will look (at the player's vieworg)
	VectorCopy( cg.refdef.vieworg, focusPoint );

	// If player is dead, we want the player to be between us and the killer
	// so pretend that the player was looking at the killer, then place cam behind them.
	if ( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
	{
		int killerEntNum = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];

		// already looking at ourself
		if ( killerEntNum != cg.snap->ps.clientNum )
		{
			vec3_t lookDirection;

			if ( cg.wasDeadLastFrame == qfalse || !cg_staticDeathCam.integer )
			{
				VectorCopy( cg_entities[ killerEntNum ].lerpOrigin, killerPos );
				cg.wasDeadLastFrame = qtrue;
			}

			VectorSubtract( killerPos, cg.refdef.vieworg, lookDirection );
			vectoangles( lookDirection, cg.refdefViewAngles );
		}
	}

	// get cg_thirdPersonRange
	range = cg_thirdPersonRange.value;

	// Calculate the angle of the camera's position around the player.
	// Unless in demo, PLAYING in third person, or in dead-third-person cam, allow the player
	// to control camera position offsets using the mouse position.
	if ( cg.demoPlayback ||
	     ( ( cg.snap->ps.pm_flags & PMF_FOLLOW ) &&
	       ( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 ) ) )
	{
		// Collect our input values from the mouse.
		cmdNum = trap_GetCurrentCmdNumber();
		trap_GetUserCmd( cmdNum, &cmd );
		trap_GetUserCmd( cmdNum - 1, &oldCmd );

		// Prevent pitch from wrapping and clamp it within a [-75, 90] range.
		// Cgame has no access to ps.delta_angles[] here, so we need to reproduce
		// it ourselves.
		deltaPitch = SHORT2ANGLE( cmd.angles[ PITCH ] - oldCmd.angles[ PITCH ] );

		if ( fabs( deltaPitch ) < 200.0f )
		{
			pitch += deltaPitch;
		}

		mouseInputAngles[ PITCH ] = pitch;
		mouseInputAngles[ YAW ] = -1.0f * SHORT2ANGLE( cmd.angles[ YAW ] );  // yaw is inverted
		mouseInputAngles[ ROLL ] = 0.0f;

		for ( i = 0; i < 3; i++ )
		{
			mouseInputAngles[ i ] = AngleNormalize180( mouseInputAngles[ i ] );
		}

		// Set the rotation angles to be the view angles offset by the mouse input
		// Ignore the original pitch though; it's too jerky otherwise
		if ( !cg_thirdPersonPitchFollow.integer )
		{
			cg.refdefViewAngles[ PITCH ] = 0.0f;
		}

		for ( i = 0; i < 3; i++ )
		{
			rotationAngles[ i ] = AngleNormalize180( cg.refdefViewAngles[ i ] ) + mouseInputAngles[ i ];
			AngleNormalize180( rotationAngles[ i ] );
		}

		// Don't let pitch go too high/too low or the camera flips around and
		// that's really annoying.
		// However, when we're not on the floor or ceiling (wallwalk) pitch
		// may not be pitch, so just let it go.
		if ( surfNormal[ 2 ] > 0.5f || surfNormal[ 2 ] < -0.5f )
		{
			if ( rotationAngles[ PITCH ] > 85.0f )
			{
				rotationAngles[ PITCH ] = 85.0f;
			}
			else if ( rotationAngles[ PITCH ] < -85.0f )
			{
				rotationAngles[ PITCH ] = -85.0f;
			}
		}

		// Perform the rotations specified by rotationAngles.
		AnglesToAxis( rotationAngles, axis );

		if ( !( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
		     !BG_RotateAxis( cg.snap->ps.grapplePoint, axis, rotaxis, qfalse,
		                     cg.snap->ps.eFlags & EF_WALLCLIMBCEILING ) )
		{
			AxisCopy( axis, rotaxis );
		}

		// Convert the new axis back to angles.
		AxisToAngles( rotaxis, rotationAngles );
	}
	else
	{
		if ( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 )
		{
			// If we're playing the game in third person, the viewangles already
			// take care of our mouselook, so just use them.
			for ( i = 0; i < 3; i++ )
			{
				rotationAngles[ i ] = cg.refdefViewAngles[ i ];
			}
		}
		else // dead
		{
			rotationAngles[ PITCH ] = 20.0f;
			rotationAngles[ YAW ] = cg.refdefViewAngles[ YAW ];
		}
	}

	rotationAngles[ YAW ] -= cg_thirdPersonAngle.value;

	// Move the camera range distance back.
	AngleVectors( rotationAngles, forward, right, up );
	VectorCopy( cg.refdef.vieworg, view );
	VectorMA( view, -range, forward, view );

	// Ensure that the current camera position isn't out of bounds and that there
	// is nothing between the camera and the player.

	// Trace a ray from the origin to the viewpoint to make sure the view isn't
	// in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything
	CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );

	if ( trace.fraction != 1.0f )
	{
		VectorCopy( trace.endpos, view );
		view[ 2 ] += ( 1.0f - trace.fraction ) * 32;
		// Try another trace to this position, because a tunnel may have the ceiling
		// close enogh that this is poking out.

		CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
		VectorCopy( trace.endpos, view );
	}

	// Set the camera position to what we calculated.
	VectorCopy( view, cg.refdef.vieworg );

	// The above checks may have moved the camera such that the existing viewangles
	// may not still face the player. Recalculate them to do so.
	// but if we're dead, don't bother because we'd rather see what killed us
	if ( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 )
	{
		VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
		vectoangles( focusPoint, cg.refdefViewAngles );
	}
}
示例#9
0
文件: cg_view.c 项目: mvdevs/mvsdk
// This can be called every interval, at the user's discretion.
static void CG_UpdateThirdPersonCameraDamp(void)
{
	trace_t trace;
	vec3_t	locdiff;
	float dampfactor, dtime, ratio;

	// Set the cameraIdealLoc
	CG_CalcIdealThirdPersonViewLocation();
	
	
	// First thing we do is calculate the appropriate damping factor for the camera.
	dampfactor=0.0;
	if (cg_thirdPersonCameraDamp.value != 0.0)
	{
		double pitch;

		// Note that the camera pitch has already been capped off to 89.
		pitch = Q_fabs(cameraFocusAngles[PITCH]);

		// The higher the pitch, the larger the factor, so as you look up, it damps a lot less.
		pitch /= 89.0;	
		dampfactor = (1.0-cg_thirdPersonCameraDamp.value)*(pitch*pitch);

		dampfactor += cg_thirdPersonCameraDamp.value;

		// Now we also multiply in the stiff factor, so that faster yaw changes are stiffer.
		if (cameraStiffFactor > 0.0f)
		{	// The cameraStiffFactor is how much of the remaining damp below 1 should be shaved off, i.e. approach 1 as stiffening increases.
			dampfactor += (1.0-dampfactor)*cameraStiffFactor;
		}
	}

	if (dampfactor>=1.0)
	{	// No damping.
		VectorCopy(cameraIdealLoc, cameraCurLoc);
	}
	else if (dampfactor>=0.0)
	{	
		// Calculate the difference from the current position to the new one.
		VectorSubtract(cameraIdealLoc, cameraCurLoc, locdiff);

		// Now we calculate how much of the difference we cover in the time allotted.
		// The equation is (Damp)^(time)
		dampfactor = 1.0-dampfactor;	// We must exponent the amount LEFT rather than the amount bled off
		dtime = (float)(cg.time-cameraLastFrame) * (1.0/(float)CAMERA_DAMP_INTERVAL);	// Our dampfactor is geared towards a time interval equal to "1".

		// Note that since there are a finite number of "practical" delta millisecond values possible, 
		// the ratio should be initialized into a chart ultimately.
		ratio = JK2_powf(dampfactor, dtime);
		
		// This value is how much distance is "left" from the ideal.
		VectorMA(cameraIdealLoc, -ratio, locdiff, cameraCurLoc);
		/////////////////////////////////////////////////////////////////////////////////////////////////////////
	}

	// Now we trace from the new target location to the new view location, to make sure there is nothing in the way.
	CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_CAMERACLIP);

	if (trace.fraction < 1.0)
	{
		VectorCopy( trace.endpos, cameraCurLoc );

		//FIXME: when the trace hits movers, it gets very very jaggy... ?
		/*
		//this doesn't actually help any
		if ( trace.entityNum != ENTITYNUM_WORLD )
		{
			centity_t *cent = &cg_entities[trace.entityNum];
			gentity_t *gent = &g_entities[trace.entityNum];
			if ( cent != NULL && gent != NULL )
			{
				if ( cent->currentState.pos.trType == TR_LINEAR || cent->currentState.pos.trType == TR_LINEAR_STOP )
				{
					vec3_t	diff;
					VectorSubtract( cent->lerpOrigin, gent->currentOrigin, diff );
					VectorAdd( cameraCurLoc, diff, cameraCurLoc );
				}
			}
		}
		*/
	}

	// Note that previously there was an upper limit to the number of physics traces that are done through the world
	// for the sake of camera collision, since it wasn't calced per frame.  Now it is calculated every frame.
	// This has the benefit that the camera is a lot smoother now (before it lerped between tested points),
	// however two full volume traces each frame is a bit scary to think about.
}
示例#10
0
/*
* CG_AddLocalEntities
*/
void CG_AddLocalEntities( void )
{
#define FADEINFRAMES 2
	int f;
	lentity_t *le, *next, *hnode;
	entity_t *ent;
	float scale, frac, fade, time, scaleIn, fadeIn;
	float backlerp;
	vec3_t angles;

	time = cg.frameTime;
	backlerp = 1.0f - cg.lerpfrac;

	hnode = &cg_localents_headnode;
	for( le = hnode->next; le != hnode; le = next )
	{
		next = le->next;

		frac = ( cg.time - le->start ) * 0.01f;
		f = ( int )floor( frac );
		clamp_low( f, 0 );

		// it's time to DIE
		if( f >= le->frames - 1 )
		{
			le->type = LE_FREE;
			CG_FreeLocalEntity( le );
			continue;
		}

		if( le->frames > 1 )
		{
			scale = 1.0f - frac / ( le->frames - 1 );
			scale = bound( 0.0f, scale, 1.0f );
			fade = scale * 255.0f;

			// quick fade in, if time enough
			if( le->frames > FADEINFRAMES * 2 )
			{
				scaleIn = frac / (float)FADEINFRAMES;
				clamp( scaleIn, 0.0f, 1.0f );
				fadeIn = scaleIn * 255.0f;
			}
			else
				fadeIn = 255.0f;
		}
		else
		{
			scale = 1.0f;
			fade = 255.0f;
			fadeIn = 255.0f;
		}

		ent = &le->ent;

		if( le->light && scale )
			CG_AddLightToScene( ent->origin, le->light * scale, le->lightcolor[0], le->lightcolor[1], le->lightcolor[2] );

		if( le->type == LE_LASER )
		{
			CG_QuickPolyBeam( ent->origin, ent->origin2, ent->radius, ent->customShader ); // wsw : jalfixme: missing the color (comes inside ent->skinnum)
			continue;
		}

		if( le->type == LE_DASH_SCALE )
		{
			if( f < 1 ) ent->scale = 0.2 * frac;
			else
			{
				VecToAngles( &ent->axis[AXIS_RIGHT], angles );
				ent->axis[1*3+1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length
				ent->axis[1*3+0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length
				ent->axis[0*3+1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width
				ent->axis[0*3+0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width
				ent->axis[2*3+2] -= 0.052f;              //height

				if( ent->axis[AXIS_UP+2] <= 0 )
				{
					le->type = LE_FREE;
					CG_FreeLocalEntity( le );
				}
			}
		}
		if( le->type == LE_DASH_SCALE_2 )
		{
			if( f < 1 ) ent->scale = 0.25 * frac;
			else
			{
				VecToAngles( &ent->axis[AXIS_RIGHT], angles );
				ent->axis[1*3+1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length
				ent->axis[1*3+0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length
				ent->axis[0*3+1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width
				ent->axis[0*3+0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width
				ent->axis[2*3+2] -= 0.018f;              //height

				ent->origin[1]  -= 0.6f *sin( DEG2RAD ( angles[YAW] ) ); //velocity
				ent->origin[0]  -= 0.6f *cos( DEG2RAD ( angles[YAW] ) ); //velocity

				if( ent->axis[AXIS_UP+2] <= 0 )
				{
					le->type = LE_FREE;
					CG_FreeLocalEntity( le );
				}
			}
		}
		if( le->type == LE_PUFF_SCALE )
		{
			if( frac < 1 ) ent->scale = 7.0f*frac;
			else ent->scale = 7.0f - 4.0f*( frac-1 );
			if( ent->scale < 0 )
			{
				le->type = LE_FREE;
				CG_FreeLocalEntity( le );
			}

		}
		if( le->type == LE_PUFF_SCALE_2 )
		{
			if( le->frames - f < 4 )
				ent->scale = 1.0f - 1.0f * ( frac - abs( 4-le->frames ) )/4;
		}
		if( le->type == LE_PUFF_SHRINK )
		{
			if( frac < 3 )
				ent->scale = 1.0f - 0.2f * frac/4;
			else
			{
				ent->scale = 0.8 - 0.8*( frac-3 )/3;
				VectorScale( le->velocity, 0.85f, le->velocity );
			}
		}

		if( le->type == LE_EXPLOSION_TRACER )
		{
			if( cg.time - ent->rotation > 10.0f )
			{
				ent->rotation = cg.time;
				if( ent->radius - 16*frac > 4 )
					CG_Explosion_Puff( ent->origin, ent->radius-16*frac, le->frames - f );
			}
		}

		switch( le->type )
		{
		case LE_NO_FADE:
			break;
		case LE_RGB_FADE:
			fade = min( fade, fadeIn );
			ent->shaderRGBA[0] = ( uint8_t )( fade * le->color[0] );
			ent->shaderRGBA[1] = ( uint8_t )( fade * le->color[1] );
			ent->shaderRGBA[2] = ( uint8_t )( fade * le->color[2] );
			break;
		case LE_SCALE_ALPHA_FADE:
			fade = min( fade, fadeIn );
			ent->scale = 1.0f + 1.0f / scale;
			ent->scale = min( ent->scale, 5.0f );
			ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] );
			break;
		case LE_INVERSESCALE_ALPHA_FADE:
			fade = min( fade, fadeIn );
			ent->scale = scale + 0.1f;
			clamp( ent->scale, 0.1f, 1.0f );
			ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] );
			break;
		case LE_ALPHA_FADE:
			fade = min( fade, fadeIn );
			ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] );
			break;
		default:
			break;
		}

		ent->backlerp = backlerp;

		if ( le->avelocity[0] || le->avelocity[1] || le->avelocity[2] ) {
			VectorMA( le->angles, time, le->avelocity, le->angles );
			AnglesToAxis( le->angles, le->ent.axis );
		}

		// apply rotational friction
		if( le->bounce ) { // FIXME?
			int i;
			const float adj = 100 * 6 * time; // magic constants here

			for( i = 0; i < 3; i++ ) {
				if( le->avelocity[i] > 0.0f ) {
					le->avelocity[i] -= adj;
					if( le->avelocity[i] < 0.0f ) {
						le->avelocity[i] = 0.0f;
					}
				}
				else if ( le->avelocity[i] < 0.0f ) {
					le->avelocity[i] += adj;
					if ( le->avelocity[i] > 0.0f ) {
						le->avelocity[i] = 0.0f;
					}
				}
			}
		}

		if( le->bounce )
		{
			trace_t	trace;
			vec3_t next_origin;

			VectorMA( ent->origin, time, le->velocity, next_origin );

			CG_Trace( &trace, ent->origin, debris_mins, debris_maxs, next_origin, 0, MASK_SOLID );

			// remove the particle when going out of the map
			if( ( trace.contents & CONTENTS_NODROP ) || ( trace.surfFlags & SURF_SKY ) )
			{
				le->frames = 0;
			}
			else if( trace.fraction != 1.0 ) // found solid
			{
				float dot;
				float xyzspeed, orig_xyzspeed;
				float bounce;
				
				orig_xyzspeed = VectorLength( le->velocity );

				// Reflect velocity
				dot = DotProduct( le->velocity, trace.plane.normal );
				VectorMA( le->velocity, -2.0f * dot, trace.plane.normal, le->velocity );
				//put new origin in the impact point, but move it out a bit along the normal
				VectorMA( trace.endpos, 1, trace.plane.normal, ent->origin );

				// make sure we don't gain speed from bouncing off
				bounce = 2.0f * le->bounce * 0.01f;
				if( bounce < 1.5f )
					bounce = 1.5f;
				xyzspeed = orig_xyzspeed / bounce;

				VectorNormalize( le->velocity );
				VectorScale( le->velocity, xyzspeed, le->velocity );
	
				//the entity has not speed enough. Stop checks
				if( xyzspeed * time < 1.0f )
				{
					trace_t traceground;
					vec3_t ground_origin;
					//see if we have ground
					VectorCopy( ent->origin, ground_origin );
					ground_origin[2] += ( debris_mins[2] - 4 );
					CG_Trace( &traceground, ent->origin, debris_mins, debris_maxs, ground_origin, 0, MASK_SOLID );
					if( traceground.fraction != 1.0 )
					{
						le->bounce = 0;
						VectorClear( le->velocity );
						VectorClear( le->accel );
						VectorClear( le->avelocity );
						if( le->type == LE_EXPLOSION_TRACER )
						{
							// blx
							le->type = LE_FREE;
							CG_FreeLocalEntity( le );
						}
					}
				}

			}
			else
			{
				VectorCopy( ent->origin, ent->origin2 );
				VectorCopy( next_origin, ent->origin );
			}
		}
		else
		{
			VectorCopy( ent->origin, ent->origin2 );
			VectorMA( ent->origin, time, le->velocity, ent->origin );
		}

		VectorCopy( ent->origin, ent->lightingOrigin );
		VectorMA( le->velocity, time, le->accel, le->velocity );

		CG_AddEntityToScene( ent );
	}
}
示例#11
0
/*
* CG_BulletExplosion
*/
void CG_BulletExplosion( const vec3_t pos, const vec_t *dir, const trace_t *trace )
{
	lentity_t *le;
	vec3_t angles;
	vec3_t local_dir, end;
	trace_t	local_trace;
	const trace_t *tr;

	assert( dir || trace );

	if( dir )
	{
		vec3_t local_pos;

		// find what are we hitting
		VectorCopy( pos, local_pos );
		VectorMA( pos, -1.0, dir, end );
		CG_Trace( &local_trace, local_pos, vec3_origin, vec3_origin, end, cg.view.POVent, MASK_SHOT );
		if( local_trace.fraction == 1.0 )
			return;

		tr = &local_trace;
		VectorCopy( dir, local_dir );
	}
	else
	{
		tr = trace;
		VectorCopy( tr->plane.normal, local_dir );
	}

	VecToAngles( local_dir, angles );

	if( tr->surfFlags & SURF_FLESH ||
		( tr->ent > 0 && cg_entities[tr->ent].current.type == ET_PLAYER ) ||
		( tr->ent > 0 && cg_entities[tr->ent].current.type == ET_CORPSE ) )
	{
		le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 3, //3 frames for weak
			1, 0, 0, 1, //full white no inducted alpha
			0, 0, 0, 0, //dlight
			CG_MediaModel( cgs.media.modBulletExplode ),
			NULL );
		le->ent.rotation = rand() % 360;
		le->ent.scale = 1.0f;
		if( ISVIEWERENTITY( tr->ent ) )
			le->ent.renderfx |= RF_VIEWERMODEL;
	}
	else if( cg_particles->integer && (tr->surfFlags & SURF_DUST) )
	{
		// throw particles on dust
		CG_ImpactSmokePuff( tr->endpos, tr->plane.normal, 4, 0.6f, 6, 8 );
	}
	else
	{
		le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 3, //3 frames for weak
			1, 1, 1, 1, //full white no inducted alpha
			0, 0, 0, 0, //dlight
			CG_MediaModel( cgs.media.modBulletExplode ),
			NULL );
		le->ent.rotation = rand() % 360;
		le->ent.scale = 1.0f;
		if( cg_particles->integer )
		{
			CG_ImpactSmokePuff( tr->endpos, tr->plane.normal, 2, 0.6f, 6, 8 );
		}

		if( !( tr->surfFlags & SURF_NOMARKS ) )
			CG_SpawnDecal( pos, local_dir, random()*360, 8, 1, 1, 1, 1, 10, 1, false, CG_MediaShader( cgs.media.shaderBulletMark ) );
	}
}
示例#12
0
/*
==================
CG_BuildableStatusDisplay
==================
*/
static void CG_BuildableStatusDisplay( centity_t *cent )
{
  entityState_t   *es = &cent->currentState;
  vec3_t          origin;
  float           healthScale;
  int             health;
  float           x, y;
  vec4_t          color;
  qboolean        powered, marked;
  trace_t         tr;
  float           d;
  buildStat_t     *bs;
  int             i, j;
  int             entNum;
  vec3_t          trOrigin;
  vec3_t          right;
  qboolean        visible = qfalse;
  vec3_t          mins, maxs;
  entityState_t   *hit;
  int             anim;

  if( BG_Buildable( es->modelindex )->team == TEAM_ALIENS )
    bs = &cgs.alienBuildStat;
  else
    bs = &cgs.humanBuildStat;

  if( !bs->loaded )
    return;

  d = Distance( cent->lerpOrigin, cg.refdef.vieworg );
  if( d > STATUS_MAX_VIEW_DIST )
    return;

  Vector4Copy( bs->foreColor, color );

  // trace for center point
  BG_BuildableBoundingBox( es->modelindex, mins, maxs );

  // hack for shrunken barricades
  anim = es->torsoAnim & ~( ANIM_FORCEBIT | ANIM_TOGGLEBIT );
  if( es->modelindex == BA_A_BARRICADE &&
      ( anim == BANIM_DESTROYED || !( es->eFlags & EF_B_SPAWNED ) ) )
    maxs[ 2 ] = (int)( maxs[ 2 ] * BARRICADE_SHRINKPROP );

  VectorCopy( cent->lerpOrigin, origin );

  // center point
  origin[ 2 ] += mins[ 2 ];
  origin[ 2 ] += ( abs( mins[ 2 ] ) + abs( maxs[ 2 ] ) ) / 2;

  entNum = cg.predictedPlayerState.clientNum;

  // if first try fails, step left, step right
  for( j = 0; j < 3; j++ )
  {
    VectorCopy( cg.refdef.vieworg, trOrigin );
    switch( j )
    {
      case 1:
        // step right
        AngleVectors( cg.refdefViewAngles, NULL, right, NULL );
        VectorMA( trOrigin, STATUS_PEEK_DIST, right, trOrigin );
        break;
      case 2:
        // step left
        AngleVectors( cg.refdefViewAngles, NULL, right, NULL );
        VectorMA( trOrigin, -STATUS_PEEK_DIST, right, trOrigin );
        break;
      default:
        break;
    }
    // look through up to 3 players and/or transparent buildables
    for( i = 0; i < 3; i++ )
    {
      CG_Trace( &tr, trOrigin, NULL, NULL, origin, entNum, MASK_SHOT );
      if( tr.entityNum == cent->currentState.number )
      {
        visible = qtrue;
        break;
      }

      if( tr.entityNum == ENTITYNUM_WORLD )
        break;

      hit  = &cg_entities[ tr.entityNum ].currentState;

      if( tr.entityNum < MAX_CLIENTS || ( hit->eType == ET_BUILDABLE &&
          ( !( es->eFlags & EF_B_SPAWNED ) ||
            BG_Buildable( hit->modelindex )->transparentTest ) ) )
      {
        entNum = tr.entityNum;
        VectorCopy( tr.endpos, trOrigin );
      }
      else
        break;
    }
  }
  // hack to make the kit obscure view
  if( cg_drawGun.integer && visible &&
      cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS &&
      CG_WorldToScreen( origin, &x, &y ) )
  {
    if( x > 450 && y > 290 )
      visible = qfalse;
  }

  if( !visible && cent->buildableStatus.visible )
  {
    cent->buildableStatus.visible   = qfalse;
    cent->buildableStatus.lastTime  = cg.time;
  }
  else if( visible && !cent->buildableStatus.visible )
  {
    cent->buildableStatus.visible   = qtrue;
    cent->buildableStatus.lastTime  = cg.time;
  }

  // Fade up
  if( cent->buildableStatus.visible )
  {
    if( cent->buildableStatus.lastTime + STATUS_FADE_TIME > cg.time )
      color[ 3 ] = (float)( cg.time - cent->buildableStatus.lastTime ) / STATUS_FADE_TIME;
  }

  // Fade down
  if( !cent->buildableStatus.visible )
  {
    if( cent->buildableStatus.lastTime + STATUS_FADE_TIME > cg.time )
      color[ 3 ] = 1.0f - (float)( cg.time - cent->buildableStatus.lastTime ) / STATUS_FADE_TIME;
    else
      return;
  }

  health = es->generic1;
  healthScale = (float)health / BG_Buildable( es->modelindex )->health;

  if( health > 0 && healthScale < 0.01f )
    healthScale = 0.01f;
  else if( healthScale < 0.0f )
    healthScale = 0.0f;
  else if( healthScale > 1.0f )
    healthScale = 1.0f;

  if( CG_WorldToScreen( origin, &x, &y ) )
  {
    float  picH = bs->frameHeight;
    float  picW = bs->frameWidth;
    float  picX = x;
    float  picY = y;
    float  scale;
    float  subH, subY;
    float  clipX, clipY, clipW, clipH;
    vec4_t frameColor;

    // this is fudged to get the width/height in the cfg to be more realistic
    scale = ( picH / d ) * 3;

    powered = es->eFlags & EF_B_POWERED;
    marked = es->eFlags & EF_B_MARKED;

    picH *= scale;
    picW *= scale;
    picX -= ( picW * 0.5f );
    picY -= ( picH * 0.5f );

    // sub-elements such as icons and number
    subH = picH - ( picH * bs->verticalMargin );
    subY = picY + ( picH * 0.5f ) - ( subH * 0.5f );

    clipW = ( 640.0f * cg_viewsize.integer ) / 100.0f;
    clipH = ( 480.0f * cg_viewsize.integer ) / 100.0f;
    clipX = 320.0f - ( clipW * 0.5f );
    clipY = 240.0f - ( clipH * 0.5f );
    CG_SetClipRegion( clipX, clipY, clipW, clipH );

    if( bs->frameShader )
    {
      Vector4Copy( bs->backColor, frameColor );
      frameColor[ 3 ] = color[ 3 ];
      trap_R_SetColor( frameColor );
      CG_DrawPic( picX, picY, picW, picH, bs->frameShader );
      trap_R_SetColor( NULL );
    }

    if( health > 0 )
    {
      float hX, hY, hW, hH;
      vec4_t healthColor;

      hX = picX + ( bs->healthPadding * scale );
      hY = picY + ( bs->healthPadding * scale );
      hH = picH - ( bs->healthPadding * 2.0f * scale );
      hW = picW * healthScale - ( bs->healthPadding * 2.0f * scale );

      if( healthScale == 1.0f )
        Vector4Copy( bs->healthLowColor, healthColor );
      else if( healthScale >= 0.75f )
        Vector4Copy( bs->healthGuardedColor, healthColor );
      else if( healthScale >= 0.50f )
        Vector4Copy( bs->healthElevatedColor, healthColor );
      else if( healthScale >= 0.25f )
        Vector4Copy( bs->healthHighColor, healthColor );
      else
        Vector4Copy( bs->healthSevereColor, healthColor );

      healthColor[ 3 ] = color[ 3 ];
      trap_R_SetColor( healthColor );

      CG_DrawPic( hX, hY, hW, hH, cgs.media.whiteShader );
      trap_R_SetColor( NULL );
    }

    if( bs->overlayShader )
    {
      float oW = bs->overlayWidth;
      float oH = bs->overlayHeight;
      float oX = x;
      float oY = y;

      oH *= scale;
      oW *= scale;
      oX -= ( oW * 0.5f );
      oY -= ( oH * 0.5f );

      trap_R_SetColor( frameColor );
      CG_DrawPic( oX, oY, oW, oH, bs->overlayShader );
      trap_R_SetColor( NULL );
    }

    trap_R_SetColor( color );
    if( !powered )
    {
      float pX;

      pX = picX + ( subH * bs->horizontalMargin );
      CG_DrawPic( pX, subY, subH, subH, bs->noPowerShader );
    }

    if( marked )
    {
      float mX;

      mX = picX + picW - ( subH * bs->horizontalMargin ) - subH;
      CG_DrawPic( mX, subY, subH, subH, bs->markedShader );
    }

    {
      float nX;
      int healthMax;
      int healthPoints;

      healthMax = BG_Buildable( es->modelindex )->health;
      healthPoints = (int)( healthScale * healthMax );
      if( health > 0 && healthPoints < 1 )
        healthPoints = 1;
      nX = picX + ( picW * 0.5f ) - 2.0f - ( ( subH * 4 ) * 0.5f );

      if( healthPoints > 999 )
        nX -= 0.0f;
      else if( healthPoints > 99 )
        nX -= subH * 0.5f;
      else if( healthPoints > 9 )
        nX -= subH * 1.0f;
      else
        nX -= subH * 1.5f;

      CG_DrawField( nX, subY, 4, subH, subH, healthPoints );
    }

    trap_R_SetColor( NULL );
    CG_ClearClipRegion( );
  }
}
示例#13
0
/*
================
CG_AddMissile
================
*/
static void CG_AddMissile( localEntity_t *le ) {
	refEntity_t			*re;
	const weaponInfo_t	*weapon;
	trace_t				trace;
	centity_t			*other;
	qboolean			inWater;

	// just existing for server entity deletion
	if ( le->leFlags & LEF_FINISHED ) {
		return;
	}

	// get weapon info
	if ( le->ti.weapon > WP_NUM_WEAPONS ) {
		le->ti.weapon = 0;
	}
	weapon = &cg_weapons[le->ti.weapon];

	re = &le->refEntity;

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

	// special case for flames
	if ( re->reType == RT_SPRITE ) {
		int deltaTime;

		// check for water
		if ( trap_CM_PointContents( re->origin, 0 ) & CONTENTS_WATER ) {
			// do a trace to get water surface normals
			CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, le->owner, MASK_WATER );
			CG_FreeLocalEntity( le );

			CG_MakeExplosion( trace.endpos, trace.plane.normal, 
				cgs.media.ringFlashModel, cgs.media.vaporShader,
				500, qfalse, qtrue );
			return;
		}

		// change radius over time
		deltaTime = cg.time - le->startTime;
		re->radius = deltaTime * deltaTime * ( random()*0.4f + 0.8f ) / 2000.0f + 9;

		// do a trace sometimes
		if ( le->ti.trailTime++ > 5 ) {
			le->ti.trailTime = 0;

			CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, le->owner, MASK_SHOT );
			VectorCopy( re->origin, re->oldorigin );

			// hit something
			if ( trace.fraction < 1.0 ) {
				CG_MissileHitWall( le->ti.weapon, 0, trace.endpos, trace.plane.normal, IMPACTSOUND_DEFAULT );
				CG_FreeLocalEntity( le );
				return;
			}
		}

		// add to refresh list
		trap_R_AddRefEntityToScene( re );
		return;
	}

	// add trails
	if ( weapon->missileTrailFunc ) weapon->missileTrailFunc( &le->ti, cg.time );

	// add dynamic light
	if ( weapon->missileDlight ) {
		trap_R_AddLightToScene( re->origin, weapon->missileDlight, 
			weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );
	}

	// flicker between two skins
	re->skinNum = cg.clientFrame & 1;

	// convert direction of travel into axis
	if ( VectorNormalize2( le->pos.trDelta, re->axis[0] ) == 0 ) {
		re->axis[0][2] = 1;
	}

	// spin as it moves
	if ( le->pos.trType != TR_STATIONARY ) {
		if ( le->pos.trType == TR_GRAVITY ) {
			RotateAroundDirection( re->axis, cg.time / 4 );
		} else if ( le->pos.trType == TR_WATER_GRAVITY ) {
			RotateAroundDirection( re->axis, cg.time / 8 );
		} else {
			RotateAroundDirection( re->axis, cg.time );
		}
	} else {
		RotateAroundDirection( re->axis, 0 );
	}

	// trace a line from previous position to new position
	CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, le->owner, MASK_SHOT );
	VectorCopy( re->origin, re->oldorigin );

	// draw BIG grenades
	if ( weLi[le->ti.weapon].category == CT_EXPLOSIVE ) {
		AxisScale( re->axis, GRENADE_SCALE, re->axis );
	}

	if ( trace.fraction != 1.0 ) {
		// hit the sky or something like that
		if ( trace.surfaceFlags & SURF_NOIMPACT ) {
			le->leFlags |= LEF_FINISHED;
			le->endTime = cg.time + 500;
			return;
		}

		// impact
		other = &cg_entities[trace.entityNum];

		if ( le->bounceFactor > 0 && ( le->bounceFactor == BOUNCE_FACTOR_HALF || other->currentState.eType != ET_PLAYER ) ) {
			// reflect the velocity on the trace plane
			CG_ReflectVelocity( le, &trace );
			if ( cg.predictedImpacts < MAX_PREDICTED_IMPACTS ) {
				cg.predictedImpacts++;
				cg.predictedImpactsDecTime = cg.time;
			}

			// do bounce sound
			if ( rand() & 1 ) {
				trap_S_StartSound( le->pos.trBase, 0, CHAN_AUTO, cgs.media.hgrenb1aSound );
			} else {
				trap_S_StartSound( le->pos.trBase, 0, CHAN_AUTO, cgs.media.hgrenb2aSound );
			}
		} else {
			// explode missile
			if ( cg.predictedImpacts < MAX_PREDICTED_IMPACTS ) {
				cg.predictedImpacts++;
				cg.predictedImpactsDecTime = cg.time;
			}

			if ( other->currentState.eType == ET_PLAYER ) {
				CG_MissileHitPlayer( le->ti.weapon, 0, trace.endpos, trace.plane.normal, trace.entityNum );
			} else if ( !(trace.surfaceFlags & SURF_NOIMPACT) ) {
				CG_MissileHitWall( le->ti.weapon, 0, trace.endpos, trace.plane.normal, 
					(trace.surfaceFlags & SURF_METALSTEPS) ? IMPACTSOUND_METAL : IMPACTSOUND_DEFAULT );
			}
			// store the entity for deleting the server entity
			le->leFlags |= LEF_FINISHED;
			le->endTime = cg.time + 500;
			return;
		}
	}

	// check for medium change
	if ( trap_CM_PointContents( re->origin, 0 ) & CONTENTS_WATER ) inWater = qtrue;
	else inWater = qfalse;

	if (  ( !inWater && le->pos.trType == TR_WATER_GRAVITY )
		|| ( inWater && le->pos.trType == TR_GRAVITY ) ) {
		// setup new tr
		vec3_t	newDelta;

		BG_EvaluateTrajectoryDelta( &le->pos, cg.time, newDelta );
		VectorCopy( re->origin, le->pos.trBase );
		VectorCopy( newDelta, le->pos.trDelta );
		le->pos.trTime = cg.time;
		if ( inWater ) le->pos.trType = TR_WATER_GRAVITY;
		else le->pos.trType = TR_GRAVITY;
	}	

	// add to refresh list
	trap_R_AddRefEntityToScene( re );
}
示例#14
0
/*
==================
CG_AddMoveScale
==================
*/
static void CG_AddMoveScale( localEntity_t *le ) {
	refEntity_t	*re;
	vec3_t		delta;
	float		len;

	re = &le->refEntity;

	if ( !( le->leFlags & (LEF_DONT_SCALE | LEF_ALT_SCALE) ) ) {
		re->radius = le->radius * ( cg.time - le->startTime ) * le->lifeRate + 8;
	}
	if ( le->leFlags & LEF_ALT_SCALE ) {
		if ( re->hModel ) {
			if ( (le->leFlags & LEF_AXIS_ALIGNED) && le->radius ) {
				// it has a variing scale
				AxisClear( re->axis );
				AxisScale( re->axis, re->radius + le->radius * (cg.time - le->startTime) / (le->endTime - le->startTime), re->axis );
			}
			if ( !(le->leFlags & LEF_AXIS_ALIGNED) ) {
				// model looks in flight direction
				vec3_t	delta, angles;
				
				BG_EvaluateTrajectoryDelta( &le->pos, cg.time, delta );
				vectoangles( delta, angles );
				AnglesToAxis( angles, re->axis );
				if ( re->radius || le->radius ) AxisScale( re->axis, re->radius + le->radius * (cg.time - le->startTime) / (le->endTime - le->startTime), re->axis );
			}
		} else {
			// sprites scale like this
			re->radius += le->radius * cg.frametime / (le->endTime - le->startTime);
		}
	}

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

	// check for collisions
	if ( le->leFlags & LEF_COLLISIONS ) {
		// do a trace sometimes
		if ( le->ti.trailTime++ > 5 ) {
			trace_t		trace;

			le->ti.trailTime = 0;

			CG_Trace( &trace, re->oldorigin, NULL, NULL, re->origin, le->owner, MASK_SHOT );
			VectorCopy( re->origin, re->oldorigin );

			// hit something
			if ( trace.fraction < 1.0 ) {
				entityState_t	*s1;
				int		life;

				// do impact effect
				s1 = &cg_entities[le->owner].currentState;
				life = s1->groundEntityNum;

				if ( !( trace.surfaceFlags & SURF_NOIMPACT ) ) {
					if ( s1->generic1 & PF_IMPACT_MODEL ) {
						CG_MakeExplosion( trace.endpos, trace.plane.normal, 
								   cgs.gameModels[s1->modelindex2],	cgs.gameShaders[s1->otherEntityNum2],
								   life, qfalse, qfalse );
					} else if ( s1->modelindex2 ) {
						CG_MakeExplosion( trace.endpos, trace.plane.normal, 
								   cgs.media.dishFlashModel, cgs.gameShaders[s1->modelindex2],
								   life, qtrue, qtrue );
					}
				}

				CG_FreeLocalEntity( le );
				return;
			}
		}
	}

	// if the view would be "inside" the sprite, kill the sprite
	// so it doesn't add too much overdraw
	VectorSubtract( re->origin, cg.refdef.vieworg, delta );
	len = VectorLength( delta );
	if ( len < le->radius ) {
		CG_FreeLocalEntity( le );
		return;
	}

	trap_R_AddRefEntityToScene( re );
}
示例#15
0
static void CG_OffsetThirdPersonView( void )
{
  vec3_t        forward, right, up;
  vec3_t        view;
  vec3_t        focusAngles;
  trace_t       trace;
  static vec3_t mins = { -8, -8, -8 };
  static vec3_t maxs = { 8, 8, 8 };
  vec3_t        focusPoint;
  float         focusDist;
  float         forwardScale, sideScale;
  vec3_t        surfNormal;

  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING )
  {
    if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
      VectorSet( surfNormal, 0.0f, 0.0f, -1.0f );
    else
      VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal );
  }
  else
    VectorSet( surfNormal, 0.0f, 0.0f, 1.0f );

  VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg );

  VectorCopy( cg.refdefViewAngles, focusAngles );

  // if dead, look at killer
  if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
  {
    focusAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];
    cg.refdefViewAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];
  }

  //if ( focusAngles[PITCH] > 45 ) {
  //  focusAngles[PITCH] = 45;    // don't go too far overhead
  //}
  AngleVectors( focusAngles, forward, NULL, NULL );

  VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );

  VectorCopy( cg.refdef.vieworg, view );

  VectorMA( view, cg_thirdpersonheight.integer, surfNormal, view ); //12

  //cg.refdefViewAngles[PITCH] *= 0.5;

  AngleVectors( cg.refdefViewAngles, forward, right, up );

  forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
  sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
  VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
  VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );

  // trace a ray from the origin to the viewpoint to make sure the view isn't
  // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything

  if( !cg_cameraMode.integer )
  {
    CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );

    if( trace.fraction != 1.0 )
    {
      VectorCopy( trace.endpos, view );
      view[ 2 ] += ( 1.0 - trace.fraction ) * 32;
      // try another trace to this position, because a tunnel may have the ceiling
      // close enogh that this is poking out

      CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
      VectorCopy( trace.endpos, view );
    }
  }

  VectorCopy( view, cg.refdef.vieworg );

  // select pitch to look at focus point from vieword
  VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
  focusDist = sqrt( focusPoint[ 0 ] * focusPoint[ 0 ] + focusPoint[ 1 ] * focusPoint[ 1 ] );
  if ( focusDist < 1 ) {
    focusDist = 1;  // should never happen
  }
  cg.refdefViewAngles[ PITCH ] = -180 / M_PI * atan2( focusPoint[ 2 ], focusDist );
  cg.refdefViewAngles[ YAW ] -= cg_thirdPersonAngle.value;
}
示例#16
0
static void CG_DumpSpeaker_f( void )
{
/*	char sscrfilename[MAX_QPATH];
	char soundfile[MAX_STRING_CHARS];
	int i, wait, random;
	char *extptr, *buffptr;
	fileHandle_t f;

		// Check for argument
	if( trap_Argc() < 2 || trap_Argc() > 4 )
	{
		CG_Printf( "Usage: dumpspeaker <soundfile> ( <wait=value>|<random=value> )\n" );
		return;
	}

	wait = random = 0;

	// parse the other parameters
	for( i = 2; i < trap_Argc(); i++ ) {
		char *valueptr = NULL;

		trap_Argv( i, soundfile, sizeof(soundfile) );

		for( buffptr = soundfile; *buffptr; buffptr++ ) {
			if( *buffptr == '=' ) {
				valueptr = buffptr + 1;
				break;
			}
		}

		Q_strncpyz( soundfile, soundfile, buffptr - soundfile + 1 );

		if( !Q_stricmp( soundfile, "wait" ) )
			wait = atoi( valueptr );
		else if( !Q_stricmp( soundfile, "random" ) )
			random = atoi( valueptr );
	}

	// parse soundfile
	trap_Argv( 1, soundfile, sizeof(soundfile) );

	// Open soundfile
	Q_strncpyz( sscrfilename, cgs.mapname, sizeof(sscrfilename) );
	extptr = sscrfilename + strlen( sscrfilename ) - 4;
	if( extptr < sscrfilename || Q_stricmp( extptr, ".bsp" ) )
	{
		CG_Printf( "Unable to dump, unknown map name?\n" );
		return;
	}
	Q_strncpyz( extptr, ".sscr", 5 );
	trap_FS_FOpenFile( sscrfilename, &f, FS_APPEND_SYNC );
	if( !f )
	{
		CG_Printf( "Failed to open '%s' for writing.\n", sscrfilename );
		return;
	}

		// Build the entity definition
	Com_sprintf( soundfile, sizeof(soundfile), "{\n\"classname\" \"target_speaker\"\n\"origin\" \"%i %i %i\"\n\"noise\" \"%s\"\n",
												(int) cg.snap->ps.origin[0], (int) cg.snap->ps.origin[1], (int) cg.snap->ps.origin[2], soundfile );

	if( wait ) {
		Q_strcat( soundfile, sizeof(soundfile), va( "\"wait\" \"%i\"\n", wait ) );
	}
	if( random ) {
		Q_strcat( soundfile, sizeof(soundfile), va( "\"random\" \"%i\"\n", random ) );
	}
	Q_strcat( soundfile, sizeof(soundfile), "}\n\n" );

		// And write out/acknowledge
	trap_FS_Write( soundfile, strlen( soundfile ), f );
	trap_FS_FCloseFile( f );
	CG_Printf( "Entity dumped to '%s' (%i %i %i).\n", sscrfilename,
			   (int) cg.snap->ps.origin[0], (int) cg.snap->ps.origin[1], (int) cg.snap->ps.origin[2] );*/
	bg_speaker_t	speaker;
	trace_t			tr;
	vec3_t			end;

	if( !cg.editingSpeakers ) {
		CG_Printf( "Speaker Edit mode needs to be activated to dump speakers\n" );
		return;
	}

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

	speaker.volume = 127;
	speaker.range = 1250;

	VectorMA( cg.refdef_current->vieworg, 32, cg.refdef_current->viewaxis[0], end );
	CG_Trace( &tr, cg.refdef_current->vieworg, NULL, NULL, end, -1, MASK_SOLID );

	if( tr.fraction < 1.f ) {
		VectorCopy( tr.endpos, speaker.origin );
		VectorMA( speaker.origin, -4, cg.refdef_current->viewaxis[0], speaker.origin );
	} else {
		VectorCopy( tr.endpos, speaker.origin );
	}

	if( !BG_SS_StoreSpeaker( &speaker ) ) {
		CG_Printf( S_COLOR_RED "ERROR: Failed to store speaker\n" );
	}
}