Beispiel #1
0
void CL_FinishMove( usercmd_t *cmd ) {
	int		i;

	// copy the state that the cgame is currently sending
	cmd->weapon = cl.cgameUserCmdValue;
	cmd->forcesel = cl.cgameForceSelection;
	cmd->invensel = cl.cgameInvenSelection;

	if (cl.gcmdSendValue)
	{
		cmd->generic_cmd = cl.gcmdValue;
		//cl.gcmdSendValue = qfalse;
		cl.gcmdSentValue = qtrue;
	}
	else
	{
		cmd->generic_cmd = 0;
	}

	// send the current server time so the amount of movement
	// can be determined without allowing cheating
	cmd->serverTime = cl.serverTime;

	if (cl.cgameViewAngleForceTime > cl.serverTime)
	{
		cl.cgameViewAngleForce[YAW] -= SHORT2ANGLE(cl.snap.ps.delta_angles[YAW]);

		cl.viewangles[YAW] = cl.cgameViewAngleForce[YAW];
		cl.cgameViewAngleForceTime = 0;
	}

	if ( cl_crazyShipControls )
	{
		float pitchSubtract, pitchDelta, yawDelta;

		yawDelta = AngleSubtract(cl.viewangles[YAW],cl_lastViewAngles[YAW]);
		//yawDelta *= (4.0f*pVeh->m_fTimeModifier);
		cl_sendAngles[ROLL] -= yawDelta;

		float nRoll = fabs(cl_sendAngles[ROLL]);

		pitchDelta = AngleSubtract(cl.viewangles[PITCH],cl_lastViewAngles[PITCH]);
		//pitchDelta *= (2.0f*pVeh->m_fTimeModifier);
		pitchSubtract = pitchDelta * (nRoll/90.0f);
		cl_sendAngles[PITCH] += pitchDelta-pitchSubtract;

		//yaw-roll calc should be different
		if (nRoll > 90.0f)
		{
			nRoll -= 180.0f;
		}
		if (nRoll < 0.0f)
		{
			nRoll = -nRoll;
		}
		pitchSubtract = pitchDelta * (nRoll/90.0f);
		if ( cl_sendAngles[ROLL] > 0.0f )
		{
			cl_sendAngles[YAW] += pitchSubtract;
		}
		else
		{
			cl_sendAngles[YAW] -= pitchSubtract;
		}

		cl_sendAngles[PITCH] = AngleNormalize180( cl_sendAngles[PITCH] );
		cl_sendAngles[YAW] = AngleNormalize360( cl_sendAngles[YAW] );
		cl_sendAngles[ROLL] = AngleNormalize180( cl_sendAngles[ROLL] );

		for (i=0 ; i<3 ; i++) {
			cmd->angles[i] = ANGLE2SHORT(cl_sendAngles[i]);
		}
	}
	else
	{
		for (i=0 ; i<3 ; i++) {
			cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
		}
		//in case we switch to the cl_crazyShipControls
		VectorCopy( cl.viewangles, cl_sendAngles );
	}
	//always needed in for the cl_crazyShipControls
	VectorCopy( cl.viewangles, cl_lastViewAngles );
}
Beispiel #2
0
//-----------------------------------------------------
static void turret_aim( gentity_t *self )
//-----------------------------------------------------
{
	vec3_t	enemyDir, org, org2;
	vec3_t	desiredAngles, setAngle;
	float	diffYaw = 0.0f, diffPitch = 0.0f, turnSpeed;
	const float pitchCap = 40.0f;
	gentity_t *top = &g_entities[self->r.ownerNum];
	if ( !top )
	{
		return;
	}

	// move our gun base yaw to where we should be at this time....
	BG_EvaluateTrajectory( &top->s.apos, level.time, top->r.currentAngles );
	top->r.currentAngles[YAW] = AngleNormalize180( top->r.currentAngles[YAW] );
	top->r.currentAngles[PITCH] = AngleNormalize180( top->r.currentAngles[PITCH] );
	turnSpeed = top->speed;

	if ( self->painDebounceTime > level.time )
	{
		desiredAngles[YAW] = top->r.currentAngles[YAW]+flrand(-45,45);
		desiredAngles[PITCH] = top->r.currentAngles[PITCH]+flrand(-10,10);

		if (desiredAngles[PITCH] < -pitchCap)
		{
			desiredAngles[PITCH] = -pitchCap;
		}
		else if (desiredAngles[PITCH] > pitchCap)
		{
			desiredAngles[PITCH] = pitchCap;
		}

		diffYaw = AngleSubtract( desiredAngles[YAW], top->r.currentAngles[YAW] );
		diffPitch = AngleSubtract( desiredAngles[PITCH], top->r.currentAngles[PITCH] );
		turnSpeed = flrand( -5, 5 );
	}
	else if ( self->enemy )
	{
		// ...then we'll calculate what new aim adjustments we should attempt to make this frame
		// Aim at enemy
		VectorCopy( self->enemy->r.currentOrigin, org );
		org[2]+=self->enemy->r.maxs[2]*0.5f;
		if (self->enemy->s.eType == ET_NPC &&
			self->enemy->s.NPC_class == CLASS_VEHICLE &&
			self->enemy->m_pVehicle &&
			self->enemy->m_pVehicle->m_pVehicleInfo->type == VH_WALKER)
		{ //hack!
			org[2] += 32.0f;
		}
		/*
		mdxaBone_t	boltMatrix;

		// Getting the "eye" here
		gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, 
					self->torsoBolt,
					&boltMatrix, self->r.currentAngles, self->s.origin, (cg.time?cg.time:level.time),
					NULL, self->s.modelScale );

		gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org2 );
		*/
		VectorCopy( top->r.currentOrigin, org2 );

		VectorSubtract( org, org2, enemyDir );
		vectoangles( enemyDir, desiredAngles );
		desiredAngles[PITCH] = AngleNormalize180(desiredAngles[PITCH]);

		if (desiredAngles[PITCH] < -pitchCap)
		{
			desiredAngles[PITCH] = -pitchCap;
		}
		else if (desiredAngles[PITCH] > pitchCap)
		{
			desiredAngles[PITCH] = pitchCap;
		}

		diffYaw = AngleSubtract( desiredAngles[YAW], top->r.currentAngles[YAW] );
		diffPitch = AngleSubtract( desiredAngles[PITCH], top->r.currentAngles[PITCH] );
	}
	else
	{//FIXME: Pan back and forth in original facing
		// no enemy, so make us slowly sweep back and forth as if searching for a new one
		desiredAngles[YAW] = sin( level.time * 0.0001f + top->count );
		desiredAngles[YAW] *=  60.0f;
		desiredAngles[YAW] += self->s.angles[YAW];
		desiredAngles[YAW] = AngleNormalize180( desiredAngles[YAW] );
		diffYaw = AngleSubtract( desiredAngles[YAW], top->r.currentAngles[YAW] );
		diffPitch = AngleSubtract( 0, top->r.currentAngles[PITCH] );
		turnSpeed = 1.0f;
	}

	if ( diffYaw )
	{
		// cap max speed....
		if ( fabs(diffYaw) > turnSpeed )
		{
			diffYaw = ( diffYaw >= 0 ? turnSpeed : -turnSpeed );
		}
	}
	if ( diffPitch )
	{
		if ( fabs(diffPitch) > turnSpeed )
		{
			// cap max speed
			diffPitch = (diffPitch > 0.0f ? turnSpeed : -turnSpeed );
		}
	}
	// ...then set up our desired yaw
	VectorSet( setAngle, diffPitch, diffYaw, 0 );

	VectorCopy( top->r.currentAngles, top->s.apos.trBase );
	VectorScale( setAngle, (1000/FRAMETIME), top->s.apos.trDelta );
	top->s.apos.trTime = level.time;
	top->s.apos.trType = TR_LINEAR_STOP;
	top->s.apos.trDuration = FRAMETIME;

	if ( diffYaw || diffPitch )
	{
		top->s.loopSound = G_SoundIndex( "sound/vehicles/weapons/hoth_turret/turn.wav" );
	}
	else
	{
		top->s.loopSound = 0;
	}
}
Beispiel #3
0
void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace)
{
	// See if the vehicle has crashed into the ground.
	Vehicle_t *pSelfVeh = pEnt->m_pVehicle;
	float magnitude = VectorLength( pm->ps->velocity ) * pSelfVeh->m_pVehicleInfo->mass / 50.0f;
	qboolean forceSurfDestruction = qfalse;
#ifdef QAGAME
	gentity_t *hitEnt = trace!=NULL?&g_entities[trace->entityNum]:NULL;

	if (!hitEnt || 
		(pSelfVeh && pSelfVeh->m_pPilot &&
		hitEnt && hitEnt->s.eType == ET_MISSILE && hitEnt->inuse &&
		hitEnt->r.ownerNum == pSelfVeh->m_pPilot->s.number)
		)
	{ 
		return;
	}

	if ( pSelfVeh//I have a vehicle struct
		&& pSelfVeh->m_iRemovedSurfaces )//vehicle has bits removed
	{//spiralling to our deaths, explode on any solid impact
		if ( hitEnt->s.NPC_class == CLASS_VEHICLE )
		{//hit another vehicle, explode!
			//Give credit to whoever got me into this death spiral state
			gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
			gentity_t *killer = NULL;
			if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
				parent->client->ps.otherKillerTime > level.time)
			{
				gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

				if (potentialKiller->inuse && potentialKiller->client)
				{ //he's valid I guess
					killer = potentialKiller;
				}
			}
			//FIXME: damage hitEnt, some, too?  Our explosion should hurt them some, but...
			G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
			return;
		}
		else if ( !VectorCompare( trace->plane.normal, vec3_origin )
			&& (trace->entityNum == ENTITYNUM_WORLD || hitEnt->r.bmodel ) )
		{//have a valid hit plane and we hit a solid brush
			vec3_t	moveDir;
			float	impactDot;
			VectorCopy( pm->ps->velocity, moveDir );
			VectorNormalize( moveDir );
			impactDot = DotProduct( moveDir, trace->plane.normal );
			if ( impactDot <= -0.7f )//hit rather head-on and hard
			{// Just DIE now
				//Give credit to whoever got me into this death spiral state
				gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
				gentity_t *killer = NULL;
				if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
					parent->client->ps.otherKillerTime > level.time)
				{
					gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

					if (potentialKiller->inuse && potentialKiller->client)
					{ //he's valid I guess
						killer = potentialKiller;
					}
				}
				G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
				return;
			}
		}
	}
	
	if ( trace->entityNum < ENTITYNUM_WORLD
		&& hitEnt->s.eType == ET_MOVER
		&& hitEnt->s.apos.trType != TR_STATIONARY//rotating
		&& (hitEnt->spawnflags&16) //IMPACT
		&& Q_stricmp( "func_rotating", hitEnt->classname ) == 0 )
	{//hit a func_rotating that is supposed to destroy anything it touches!
		//guarantee the hit will happen, thereby taking off a piece of the ship
		forceSurfDestruction = qtrue;
	}
	else if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
		&& pm->ps->velocity[2] > -100.0f )
#else
	if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
		&& pm->ps->velocity[2] > -100.0f )
#endif
		/*
	if ( (pSelfVeh->m_ulFlags&VEH_GEARSOPEN) 
		&& trace->plane.normal[2] > 0.7f
		&& fabs(pSelfVeh->m_vOrientation[PITCH]) < 0.2f
		&& fabs(pSelfVeh->m_vOrientation[ROLL]) < 0.2f )*/
	{//we're landing, we're cool
		//this was annoying me -rww
		//FIXME: this shouldn't even be getting called when the vehicle is at rest!
#ifdef QAGAME
		if (hitEnt && (hitEnt->s.eType == ET_PLAYER || hitEnt->s.eType == ET_NPC) && pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
		{ //always smack players
		}
		else
#endif
		{
			return;
		}
	}
	if ( pSelfVeh &&
		(pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER) && //this is kind of weird on tauntauns and atst's..
		(magnitude >= 100||forceSurfDestruction) )
	{
		if ( pEnt->m_pVehicle->m_iHitDebounce < pm->cmd.serverTime 
			|| forceSurfDestruction )
		{//a bit of a hack, may conflict with getting shot, but...
			//FIXME: impact sound and effect should be gotten from g_vehicleInfo...?
			//FIXME: should pass in trace.endpos and trace.plane.normal
			vec3_t	vehUp;
#ifndef QAGAME
			bgEntity_t *hitEnt;
#endif

			if ( trace && !pSelfVeh->m_iRemovedSurfaces && !forceSurfDestruction )
			{
				qboolean turnFromImpact = qfalse, turnHitEnt = qfalse;
				float l = pm->ps->speed*0.5f;
				vec3_t	bounceDir;
#ifndef QAGAME
				bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
				if ( (trace->entityNum == ENTITYNUM_WORLD || hitEnt->s.solid == SOLID_BMODEL)//bounce off any brush
					 && !VectorCompare(trace->plane.normal, vec3_origin) )//have a valid plane to bounce off of
				{ //bounce off in the opposite direction of the impact
					if (pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER)
					{
						pm->ps->speed *= pml.frametime;
						VectorCopy(trace->plane.normal, bounceDir);
					}
					else if ( trace->plane.normal[2] >= MIN_LANDING_SLOPE//flat enough to land on
						&& pSelfVeh->m_LandTrace.fraction < 1.0f //ground present
						&& pm->ps->speed <= MIN_LANDING_SPEED )
					{//could land here, don't bounce off, in fact, return altogether!
						return;
					}
					else
					{
						if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
						{
							turnFromImpact = qtrue;
						}
						VectorCopy(trace->plane.normal, bounceDir);
					}
				}
				else if ( pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER )
				{//check for impact with another fighter
#ifndef QAGAME
					bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
					if ( hitEnt->s.NPC_class == CLASS_VEHICLE
						&& hitEnt->m_pVehicle 
						&& hitEnt->m_pVehicle->m_pVehicleInfo
						&& hitEnt->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
					{//two vehicles hit each other, turn away from the impact
						turnFromImpact = qtrue;
						turnHitEnt = qtrue;
#ifndef QAGAME
						VectorSubtract( pm->ps->origin, hitEnt->s.origin, bounceDir );
#else
						VectorSubtract( pm->ps->origin, hitEnt->r.currentOrigin, bounceDir );
#endif
						VectorNormalize( bounceDir );
					}
				}
				if ( turnFromImpact )
				{//bounce off impact surf and turn away
					vec3_t	pushDir={0}, turnAwayAngles, turnDelta;
					float	turnStrength, pitchTurnStrength, yawTurnStrength;
					vec3_t	moveDir;
					float bounceDot, turnDivider;
					//bounce
					if ( !turnHitEnt )
					{//hit wall
						VectorScale(bounceDir, (pm->ps->speed*0.25f/pSelfVeh->m_pVehicleInfo->mass), pushDir);
					}
					else
					{//hit another fighter
#ifndef QAGAME
						VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, bounceDir );
#else
						if ( hitEnt->client )
						{
							VectorScale( bounceDir, (pm->ps->speed+hitEnt->client->ps.speed)*0.5f, pushDir );
						}
						else
						{
							VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, pushDir );
						}
#endif
						VectorScale(pushDir, (l/pSelfVeh->m_pVehicleInfo->mass), pushDir);
						VectorScale(pushDir, 0.1f, pushDir);
					}
					VectorNormalize2( pm->ps->velocity, moveDir );
					bounceDot = DotProduct( moveDir, bounceDir )*-1;
					if ( bounceDot < 0.1f )
					{
						bounceDot = 0.1f;
					}
					VectorScale( pushDir, bounceDot, pushDir );
					VectorAdd(pm->ps->velocity, pushDir, pm->ps->velocity);
					//turn
					turnDivider = (pSelfVeh->m_pVehicleInfo->mass/400.0f);
					if ( turnHitEnt )
					{//don't turn as much when hit another ship
						turnDivider *= 4.0f;
					}
					if ( turnDivider < 0.5f )
					{
						turnDivider = 0.5f;
					}
					turnStrength = (magnitude/2000.0f);
					if ( turnStrength < 0.1f )
					{
						turnStrength = 0.1f;
					}
					else if ( turnStrength > 2.0f )
					{
						turnStrength = 2.0f;
					}
					//get the angles we are going to turn towards
					vectoangles( bounceDir, turnAwayAngles );
					//get the delta from our current angles to those new angles
					AnglesSubtract( turnAwayAngles, pSelfVeh->m_vOrientation, turnDelta );
					//now do pitch
					if ( !bounceDir[2] )
					{//shouldn't be any pitch
					}
					else
					{
						pitchTurnStrength = turnStrength*turnDelta[PITCH];
						if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
						{
							pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
						}
						else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
						{
							pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
						}
						pSelfVeh->m_vFullAngleVelocity[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
					}
					//now do yaw
					if ( !bounceDir[0] 
						&& !bounceDir[1] )
					{//shouldn't be any yaw
					}
					else
					{
						yawTurnStrength = turnStrength*turnDelta[YAW];
						if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
						{
							yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
						}
						else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
						{
							yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
						}
						pSelfVeh->m_vFullAngleVelocity[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
					}
#ifdef QAGAME//server-side, turn the guy we hit away from us, too
					if ( turnHitEnt//make the other guy turn and get pushed
						&& hitEnt->client //must be a valid client
						&& !FighterIsLanded( hitEnt->m_pVehicle, &hitEnt->client->ps )//but not if landed
						&& !(hitEnt->spawnflags&2) )//and not if suspended
					{
						l = hitEnt->client->ps.speed;
						//now bounce *them* away and turn them
						//flip the bounceDir
						VectorScale( bounceDir, -1, bounceDir );
						//do bounce
						VectorScale( bounceDir, (pm->ps->speed+l)*0.5f, pushDir );
						VectorScale(pushDir, (l*0.5f/hitEnt->m_pVehicle->m_pVehicleInfo->mass), pushDir);
						VectorNormalize2( hitEnt->client->ps.velocity, moveDir );
						bounceDot = DotProduct( moveDir, bounceDir )*-1;
						if ( bounceDot < 0.1f )
						{
							bounceDot = 0.1f;
						}
						VectorScale( pushDir, bounceDot, pushDir );
						VectorAdd(hitEnt->client->ps.velocity, pushDir, hitEnt->client->ps.velocity);
						//turn
						turnDivider = (hitEnt->m_pVehicle->m_pVehicleInfo->mass/400.0f);
						if ( turnHitEnt )
						{//don't turn as much when hit another ship
							turnDivider *= 4.0f;
						}
						if ( turnDivider < 0.5f )
						{
							turnDivider = 0.5f;
						}
						//get the angles we are going to turn towards
						vectoangles( bounceDir, turnAwayAngles );
						//get the delta from our current angles to those new angles
						AnglesSubtract( turnAwayAngles, hitEnt->m_pVehicle->m_vOrientation, turnDelta );
						//now do pitch
						if ( !bounceDir[2] )
						{//shouldn't be any pitch
						}
						else
						{
							pitchTurnStrength = turnStrength*turnDelta[PITCH];
							if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
							{
								pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
							}
							else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
							{
								pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
							}
							hitEnt->m_pVehicle->m_vFullAngleVelocity[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						}
						//now do yaw
						if ( !bounceDir[0] 
							&& !bounceDir[1] )
						{//shouldn't be any yaw
						}
						else
						{
							yawTurnStrength = turnStrength*turnDelta[YAW];
							if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
							{
								yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
							}
							else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
							{
								yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
							}
							hitEnt->m_pVehicle->m_vFullAngleVelocity[ROLL] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						}
						//NOTE: will these angle changes stick or will they be stomped 
						//		when the vehicle goes through its own update and re-grabs 
						//		its angles from its pilot...?  Should we do a 
						//		SetClientViewAngles on the pilot?
					}
#endif
				}
			}

#ifdef QAGAME
			if (!hitEnt)
			{
				return;
			}

			AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
			if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
			{
				//tempent use bad!
				G_AddEvent((gentity_t *)pEnt, EV_PLAY_EFFECT_ID, pSelfVeh->m_pVehicleInfo->iImpactFX);
			}
			pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
			magnitude /= pSelfVeh->m_pVehicleInfo->toughness * 50.0f; 

			if (hitEnt && (hitEnt->s.eType != ET_TERRAIN || !(hitEnt->spawnflags & 1) || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER))
			{ //don't damage the vehicle from terrain that doesn't want to damage vehicles
				if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
				{ //increase the damage...
					float mult = (pSelfVeh->m_vOrientation[PITCH]*0.1f);
					if (mult < 1.0f)
					{
						mult = 1.0f;
					}
					if (hitEnt->inuse && hitEnt->takedamage)
					{ //if the other guy takes damage, don't hurt us a lot for ramming him
						//unless it's a vehicle, then we get 1.5 times damage
						if (hitEnt->s.eType == ET_NPC &&
							hitEnt->s.NPC_class == CLASS_VEHICLE &&
							hitEnt->m_pVehicle)
						{
							mult = 1.5f;
						}
						else
						{
							mult = 0.5f;
						}
					}

					magnitude *= mult;
				}
				pSelfVeh->m_iLastImpactDmg = magnitude;
				//FIXME: what about proper death credit to the guy who shot you down?
				//FIXME: actually damage part of the ship that impacted?
				G_Damage( (gentity_t *)pEnt, NULL, NULL, NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT

				if (pSelfVeh->m_pVehicleInfo->surfDestruction)
				{
					G_FlyVehicleSurfaceDestruction((gentity_t *)pEnt, trace, magnitude, forceSurfDestruction );
				}

				pSelfVeh->m_ulFlags |= VEH_CRASHING;
			}

			if (hitEnt &&
				hitEnt->inuse &&
				hitEnt->takedamage)
			{ //damage this guy because we hit him
				float pmult = 1.0f;
				int finalD;
				gentity_t *attackEnt;

				if ( (hitEnt->s.eType == ET_PLAYER && hitEnt->s.number < MAX_CLIENTS) ||
					 (hitEnt->s.eType == ET_NPC && hitEnt->s.NPC_class != CLASS_VEHICLE) )
				{ //probably a humanoid, or something
					if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
					{ //player die good.. if me fighter
						pmult = 2000.0f;
					}
					else
					{
						pmult = 40.0f;
					}

					if (hitEnt->client &&
						BG_KnockDownable(&hitEnt->client->ps) &&
						G_CanBeEnemy((gentity_t *)pEnt, hitEnt))
					{ //smash!
						if (hitEnt->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
						{
							hitEnt->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
							hitEnt->client->ps.forceHandExtendTime = pm->cmd.serverTime + 1100;
							hitEnt->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
						}

						hitEnt->client->ps.otherKiller = pEnt->s.number;
						hitEnt->client->ps.otherKillerTime = pm->cmd.serverTime + 5000;
						hitEnt->client->ps.otherKillerDebounceTime = pm->cmd.serverTime + 100;

						//add my velocity into his to force him along in the correct direction from impact
						VectorAdd(hitEnt->client->ps.velocity, pm->ps->velocity, hitEnt->client->ps.velocity);
						//upward thrust
						hitEnt->client->ps.velocity[2] += 200.0f;
					}
				}

				if (pSelfVeh->m_pPilot)
				{
					attackEnt = (gentity_t *)pSelfVeh->m_pPilot;
				}
				else
				{
					attackEnt = (gentity_t *)pEnt;
				}

				finalD = magnitude*pmult;
				if (finalD < 1)
				{
					finalD = 1;
				}
				G_Damage( hitEnt, attackEnt, attackEnt, NULL, pm->ps->origin, finalD, 0, MOD_MELEE );//FIXME: MOD_IMPACT
			}
#else	//this is gonna result in "double effects" for the client doing the prediction.
		//it doesn't look bad though. could just use predicted events, but I'm too lazy.
			hitEnt = PM_BGEntForNum(trace->entityNum);

			if (!hitEnt || hitEnt->s.owner != pEnt->s.number)
			{ //don't hit your own missiles!
				AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
				pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
				trap_FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp, -1, -1 );

				pSelfVeh->m_ulFlags |= VEH_CRASHING;
			}
#endif
		}
	}
}
Beispiel #4
0
/*
==============
R_CalcBone
==============
*/
void R_CalcBone(mdsHeader_t *header, const refEntity_t *refent, int boneNum)
{
	thisBoneInfo = &boneInfo[boneNum];
	if (thisBoneInfo->torsoWeight)
	{
		cTBonePtr = &cBoneListTorso[boneNum];
		isTorso   = qtrue;
		if (thisBoneInfo->torsoWeight == 1.0f)
		{
			fullTorso = qtrue;
		}
	}
	else
	{
		isTorso   = qfalse;
		fullTorso = qfalse;
	}
	cBonePtr = &cBoneList[boneNum];

	bonePtr = &bones[boneNum];

	// we can assume the parent has already been uncompressed for this frame + lerp
	if (thisBoneInfo->parent >= 0)
	{
		parentBone     = &bones[thisBoneInfo->parent];
		parentBoneInfo = &boneInfo[thisBoneInfo->parent];
	}
	else
	{
		parentBone     = NULL;
		parentBoneInfo = NULL;
	}

#ifdef HIGH_PRECISION_BONES
	// rotation
	if (fullTorso)
	{
		VectorCopy(cTBonePtr->angles, angles);
	}
	else
	{
		VectorCopy(cBonePtr->angles, angles);
		if (isTorso)
		{
			VectorCopy(cTBonePtr->angles, tangles);
			// blend the angles together
			for (j = 0; j < 3; j++)
			{
				diff = tangles[j] - angles[j];
				if (Q_fabs(diff) > 180)
				{
					diff = AngleNormalize180(diff);
				}
				angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff;
			}
		}
	}
#else
	// rotation
	if (fullTorso)
	{
		sh = (short *)cTBonePtr->angles;
		pf = angles;
		ANGLES_SHORT_TO_FLOAT(pf, sh);
	}
	else
	{
		sh = (short *)cBonePtr->angles;
		pf = angles;
		ANGLES_SHORT_TO_FLOAT(pf, sh);
		if (isTorso)
		{
			int j;

			sh = (short *)cTBonePtr->angles;
			pf = tangles;
			ANGLES_SHORT_TO_FLOAT(pf, sh);
			// blend the angles together
			for (j = 0; j < 3; j++)
			{
				diff = tangles[j] - angles[j];
				if (Q_fabs(diff) > 180)
				{
					diff = AngleNormalize180(diff);
				}
				angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff;
			}
		}
	}
#endif
	AnglesToAxis(angles, bonePtr->matrix);

	// translation
	if (parentBone)
	{

#ifdef HIGH_PRECISION_BONES
		if (fullTorso)
		{
			angles[0] = cTBonePtr->ofsAngles[0];
			angles[1] = cTBonePtr->ofsAngles[1];
			angles[2] = 0;
			LocalAngleVector(angles, vec);
			LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation);
		}
		else
		{
			angles[0] = cBonePtr->ofsAngles[0];
			angles[1] = cBonePtr->ofsAngles[1];
			angles[2] = 0;
			LocalAngleVector(angles, vec);

			if (isTorso)
			{
				tangles[0] = cTBonePtr->ofsAngles[0];
				tangles[1] = cTBonePtr->ofsAngles[1];
				tangles[2] = 0;
				LocalAngleVector(tangles, v2);

				// blend the angles together
				SLerp_Normal(vec, v2, thisBoneInfo->torsoWeight, vec);
				LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation);

			}
			else        // legs bone
			{
				LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation);
			}
		}
#else
		if (fullTorso)
		{
			sh      = (short *)cTBonePtr->ofsAngles; pf = angles;
			*(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0;
			LocalAngleVector(angles, vec);
			LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation);
		}
		else
		{
			sh      = (short *)cBonePtr->ofsAngles; pf = angles;
			*(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0;
			LocalAngleVector(angles, vec);

			if (isTorso)
			{
				sh      = (short *)cTBonePtr->ofsAngles;
				pf      = tangles;
				*(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = SHORT2ANGLE(*(sh++)); *(pf++) = 0;
				LocalAngleVector(tangles, v2);

				// blend the angles together
				SLerp_Normal(vec, v2, thisBoneInfo->torsoWeight, vec);
				LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation);

			}
			else        // legs bone
			{
				LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation);
			}
		}
#endif
	}
	else        // just use the frame position
	{
		bonePtr->translation[0] = frame->parentOffset[0];
		bonePtr->translation[1] = frame->parentOffset[1];
		bonePtr->translation[2] = frame->parentOffset[2];
	}

	if (boneNum == header->torsoParent)     // this is the torsoParent
	{
		VectorCopy(bonePtr->translation, torsoParentOffset);
	}

	validBones[boneNum] = 1;

	rawBones[boneNum] = *bonePtr;
	newBones[boneNum] = 1;

}
Beispiel #5
0
/*
==============
R_CalcBoneLerp
==============
*/
void R_CalcBoneLerp(mdsHeader_t *header, const refEntity_t *refent, int boneNum)
{
	if (!refent || !header || boneNum < 0 || boneNum >= MDS_MAX_BONES)
	{
		return;
	}

	thisBoneInfo = &boneInfo[boneNum];

	if (!thisBoneInfo)
	{
		return;
	}

	if (thisBoneInfo->parent >= 0)
	{
		parentBone     = &bones[thisBoneInfo->parent];
		parentBoneInfo = &boneInfo[thisBoneInfo->parent];
	}
	else
	{
		parentBone     = NULL;
		parentBoneInfo = NULL;
	}

	if (thisBoneInfo->torsoWeight)
	{
		cTBonePtr    = &cBoneListTorso[boneNum];
		cOldTBonePtr = &cOldBoneListTorso[boneNum];
		isTorso      = qtrue;
		if (thisBoneInfo->torsoWeight == 1.0f)
		{
			fullTorso = qtrue;
		}
	}
	else
	{
		isTorso   = qfalse;
		fullTorso = qfalse;
	}
	cBonePtr    = &cBoneList[boneNum];
	cOldBonePtr = &cOldBoneList[boneNum];

	bonePtr = &bones[boneNum];

	newBones[boneNum] = 1;

	// rotation (take into account 170 to -170 lerps, which need to take the shortest route)
	if (fullTorso)
	{
		sh  = (short *)cTBonePtr->angles;
		sh2 = (short *)cOldTBonePtr->angles;
		pf  = angles;

		a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
		*(pf++) = a1 - torsoBacklerp * diff;
		a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
		*(pf++) = a1 - torsoBacklerp * diff;
		a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
		*(pf++) = a1 - torsoBacklerp * diff;

	}
	else
	{
		sh  = (short *)cBonePtr->angles;
		sh2 = (short *)cOldBonePtr->angles;
		pf  = angles;

		a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
		*(pf++) = a1 - backlerp * diff;
		a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
		*(pf++) = a1 - backlerp * diff;
		a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
		*(pf++) = a1 - backlerp * diff;

		if (isTorso)
		{
			int j;

			sh  = (short *)cTBonePtr->angles;
			sh2 = (short *)cOldTBonePtr->angles;
			pf  = tangles;

			a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
			*(pf++) = a1 - torsoBacklerp * diff;
			a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
			*(pf++) = a1 - torsoBacklerp * diff;
			a1      = SHORT2ANGLE(*(sh++)); a2 = SHORT2ANGLE(*(sh2++)); diff = AngleNormalize180(a1 - a2);
			*(pf++) = a1 - torsoBacklerp * diff;

			// blend the angles together
			for (j = 0; j < 3; j++)
			{
				diff = tangles[j] - angles[j];
				if (Q_fabs(diff) > 180)
				{
					diff = AngleNormalize180(diff);
				}
				angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff;
			}

		}

	}
	AnglesToAxis(angles, bonePtr->matrix);

	if (parentBone)
	{
		if (fullTorso)
		{
			sh  = (short *)cTBonePtr->ofsAngles;
			sh2 = (short *)cOldTBonePtr->ofsAngles;
		}
		else
		{
			sh  = (short *)cBonePtr->ofsAngles;
			sh2 = (short *)cOldBonePtr->ofsAngles;
		}

		pf      = angles;
		*(pf++) = SHORT2ANGLE(*(sh++));
		*(pf++) = SHORT2ANGLE(*(sh++));
		*(pf++) = 0;
		LocalAngleVector(angles, v2);       // new

		pf      = angles;
		*(pf++) = SHORT2ANGLE(*(sh2++));
		*(pf++) = SHORT2ANGLE(*(sh2++));
		*(pf++) = 0;
		LocalAngleVector(angles, vec);      // old

		// blend the angles together
		if (fullTorso)
		{
			SLerp_Normal(vec, v2, torsoFrontlerp, dir);
		}
		else
		{
			SLerp_Normal(vec, v2, frontlerp, dir);
		}

		// translation
		if (!fullTorso && isTorso)        // partial legs/torso, need to lerp according to torsoWeight
		{   // calc the torso frame
			sh  = (short *)cTBonePtr->ofsAngles;
			sh2 = (short *)cOldTBonePtr->ofsAngles;

			pf      = angles;
			*(pf++) = SHORT2ANGLE(*(sh++));
			*(pf++) = SHORT2ANGLE(*(sh++));
			*(pf++) = 0;
			LocalAngleVector(angles, v2);       // new

			pf      = angles;
			*(pf++) = SHORT2ANGLE(*(sh2++));
			*(pf++) = SHORT2ANGLE(*(sh2++));
			*(pf++) = 0;
			LocalAngleVector(angles, vec);      // old

			// blend the angles together
			SLerp_Normal(vec, v2, torsoFrontlerp, v2);

			// blend the torso/legs together
			SLerp_Normal(dir, v2, thisBoneInfo->torsoWeight, dir);

		}

		LocalVectorMA(parentBone->translation, thisBoneInfo->parentDist, dir, bonePtr->translation);
	}
	else        // just interpolate the frame positions
	{
		bonePtr->translation[0] = frontlerp * frame->parentOffset[0] + backlerp * oldFrame->parentOffset[0];
		bonePtr->translation[1] = frontlerp * frame->parentOffset[1] + backlerp * oldFrame->parentOffset[1];
		bonePtr->translation[2] = frontlerp * frame->parentOffset[2] + backlerp * oldFrame->parentOffset[2];
	}

	if (boneNum == header->torsoParent)     // this is the torsoParent
	{
		VectorCopy(bonePtr->translation, torsoParentOffset);
	}
	validBones[boneNum] = 1;

	rawBones[boneNum] = *bonePtr;
	newBones[boneNum] = 1;
}
Beispiel #6
0
float AngleDelta(float angle1, float angle2) {
	return AngleNormalize180(angle1 - angle2);
}
/*
=======================================================================================================================================
AIFunc_Helga_Melee
=======================================================================================================================================
*/
char *AIFunc_Helga_Melee(cast_state_t *cs) {
	gentity_t *ent = &g_entities[cs->entityNum];
	gentity_t *enemy;
	cast_state_t *ecs;
	int hitDelay = -1, anim;
	trace_t tr;
	float enemyDist;
	aicast_predictmove_t move;
	vec3_t vec;

	cs->aiFlags |= AIFL_SPECIAL_FUNC;

	if (!ent->client->ps.torsoTimer || !ent->client->ps.legsTimer) {
		cs->aiFlags &= ~AIFL_SPECIAL_FUNC;
		return AIFunc_DefaultStart(cs);
	}

	if (cs->enemyNum < 0) {
		ent->client->ps.legsTimer = 0;     // allow legs us to move
		ent->client->ps.torsoTimer = 0;    // allow legs us to move
		cs->aiFlags &= ~AIFL_SPECIAL_FUNC;
		return AIFunc_DefaultStart(cs);
	}

	ecs = AICast_GetCastState(cs->enemyNum);
	enemy = &g_entities[cs->enemyNum];

	anim = (ent->client->ps.torsoAnim & ~ANIM_TOGGLEBIT) - BG_AnimationIndexForString("attack3", cs->entityNum);

	if (anim < 0 || anim >= NUM_HELGA_ANIMS) {
		// animation interupted
		cs->aiFlags &= ~AIFL_SPECIAL_FUNC;
		return AIFunc_DefaultStart(cs);
		// G_Error("AIFunc_HelgaZombieMelee: helgaBoss using invalid or unknown attack anim");
	}

	if (cs->animHitCount < MAX_HELGA_IMPACTS && helgaHitTimes[anim][cs->animHitCount] >= 0) {
		// face them
		VectorCopy(cs->bs->origin, vec);
		vec[2] += ent->client->ps.viewheight;
		VectorSubtract(enemy->client->ps.origin, vec, vec);
		VectorNormalize(vec);
		vectoangles(vec, cs->ideal_viewangles);
		cs->ideal_viewangles[PITCH] = AngleNormalize180(cs->ideal_viewangles[PITCH]);
		// get hitDelay
		if (!cs->animHitCount) {
			hitDelay = helgaHitTimes[anim][cs->animHitCount];
		} else {
			hitDelay = helgaHitTimes[anim][cs->animHitCount] - helgaHitTimes[anim][cs->animHitCount - 1];
		}
		// check for inflicting damage
		if (level.time - cs->weaponFireTimes[cs->weaponNum] > hitDelay) {
			// do melee damage
			enemyDist = VectorDistance(enemy->r.currentOrigin, ent->r.currentOrigin);
			enemyDist -= g_entities[cs->enemyNum].r.maxs[0];
			enemyDist -= ent->r.maxs[0];

			if (enemyDist < 10 + AICast_WeaponRange(cs, cs->weaponNum)) {
				trap_Trace(&tr, ent->r.currentOrigin, NULL, NULL, enemy->r.currentOrigin, ent->s.number, MASK_SHOT);

				if (tr.entityNum == cs->enemyNum) {
					G_Damage(&g_entities[tr.entityNum], ent, ent, vec3_origin, tr.endpos, helgaHitDamage[anim], 0, MOD_GAUNTLET);
					G_AddEvent(enemy, EV_GENERAL_SOUND, G_SoundIndex(aiDefaults[ent->aiCharacter].soundScripts[STAYSOUNDSCRIPT]));
				}
			}

			cs->weaponFireTimes[cs->weaponNum] = level.time;
			cs->animHitCount++;
		}
	}
	// if they are outside range, move forward
	AICast_PredictMovement(ecs, 2, 0.3, &move, &g_entities[cs->enemyNum].client->pers.cmd, -1);
	VectorSubtract(move.endpos, cs->bs->origin, vec);
	vec[2] = 0;
	enemyDist = VectorLength(vec);
	enemyDist -= g_entities[cs->enemyNum].r.maxs[0];
	enemyDist -= ent->r.maxs[0];

	if (enemyDist > 8) { // we can get closer
		// if (!ent->client->ps.legsTimer) {
		// 	cs->castScriptStatus.scriptNoMoveTime = 0;
		trap_EA_MoveForward(cs->entityNum);
		//}
		// ent->client->ps.legsTimer = 0;		// allow legs us to move
	}

	return NULL;
}
Beispiel #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 );
	}
}
Beispiel #9
0
/*
===============
CG_OffsetShoulderView

===============
*/
void CG_OffsetShoulderView( void )
{
	int          i;
	int          cmdNum;
	usercmd_t    cmd, oldCmd;
	vec3_t       rotationAngles;
	vec3_t       axis[ 3 ], rotaxis[ 3 ];
	float        deltaMousePitch;
	static float mousePitch;
	vec3_t       forward, right, up;
	classModelConfig_t *classModelConfig;

	// Ignore following pitch; it's too jerky otherwise.
	if ( !cg_thirdPersonPitchFollow.integer )
	{
		cg.refdefViewAngles[ PITCH ] = 0.0f;
	}

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

	classModelConfig = BG_ClassModelConfig( cg.snap->ps.stats[ STAT_CLASS ] );
	VectorMA( cg.refdef.vieworg, classModelConfig->shoulderOffsets[ 0 ], forward, cg.refdef.vieworg );
	VectorMA( cg.refdef.vieworg, classModelConfig->shoulderOffsets[ 1 ], right, cg.refdef.vieworg );
	VectorMA( cg.refdef.vieworg, classModelConfig->shoulderOffsets[ 2 ], up, cg.refdef.vieworg );

	// If someone is playing like this, the rest is already taken care of
	// so just get the firstperson effects and leave.
	if ( !cg.demoPlayback && !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
	{
		CG_OffsetFirstPersonView();
		return;
	}

	// Get mouse input for camera rotation.
	cmdNum = trap_GetCurrentCmdNumber();
	trap_GetUserCmd( cmdNum, &cmd );
	trap_GetUserCmd( cmdNum - 1, &oldCmd );

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

	if ( fabs( deltaMousePitch ) < 200.0f )
	{
		mousePitch += deltaMousePitch;
	}

	// Handle pitch.
	rotationAngles[ PITCH ] = mousePitch;

	rotationAngles[ PITCH ] = AngleNormalize180( rotationAngles[ PITCH ] + AngleNormalize180( cg.refdefViewAngles[ PITCH ] ) );

	if ( rotationAngles [ PITCH ] < -90.0f ) { rotationAngles [ PITCH ] = -90.0f; }

	if ( rotationAngles [ PITCH ] > 90.0f ) { rotationAngles [ PITCH ] = 90.0f; }

	// Yaw and Roll are much easier.
	rotationAngles[ YAW ] = SHORT2ANGLE( cmd.angles[ YAW ] ) + cg.refdefViewAngles[ YAW ];
	rotationAngles[ ROLL ] = 0.0f;

	// Perform the rotations.
	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 );
	}

	AxisToAngles( rotaxis, rotationAngles );

	// Actually set the viewangles.
	for ( i = 0; i < 3; i++ )
	{
		cg.refdefViewAngles[ i ] = rotationAngles[ i ];
	}

	// Now run the first person stuff so we get various effects added.
	CG_OffsetFirstPersonView();
}
Beispiel #10
0
void GunRackAddItem( gitem_t *gun, vec3_t org, vec3_t angs, float ffwd, float fright, float fup )
{
	vec3_t		fwd, right;
	gentity_t	*it_ent = G_Spawn();
	qboolean	rotate = qtrue;

	AngleVectors( angs, fwd, right, NULL );

	if ( it_ent && gun )
	{
		// FIXME: scaling the ammo will probably need to be tweaked to a reasonable amount...adjust as needed
		// Set base ammo per type
		if ( gun->giType == IT_WEAPON )
		{
			it_ent->spawnflags |= 16;// VERTICAL

			switch( gun->giTag )
			{
			case WP_BLASTER:
				it_ent->count = 15;
				break;
			case WP_REPEATER:
				it_ent->count = 100;
				break;
			case WP_ROCKET_LAUNCHER:
				it_ent->count = 4;
				break;
			}
		}
		else
		{
			rotate = qfalse;

			// must deliberately make it small, or else the objects will spawn inside of each other.
			VectorSet( it_ent->maxs, 6.75f, 6.75f, 6.75f );
			VectorScale( it_ent->maxs, -1, it_ent->mins );
		}

		it_ent->spawnflags |= 1;// ITMSF_SUSPEND
		it_ent->classname = G_NewString(gun->classname);	//copy it so it can be freed safely
		G_SpawnItem( it_ent, gun );

		// FinishSpawningItem handles everything, so clear the thinkFunc that was set in G_SpawnItem
		FinishSpawningItem( it_ent );

		if ( gun->giType == IT_AMMO )
		{
			if ( gun->giTag == AMMO_BLASTER ) // I guess this just has to use different logic??
			{
				if ( g_spskill->integer >= 2 )
				{
					it_ent->count += 10; // give more on higher difficulty because there will be more/harder enemies?
				}
			}
			else
			{
				// scale ammo based on skill
				switch ( g_spskill->integer )
				{
				case 0: // do default
					break;
				case 1:
					it_ent->count *= 0.75f;
					break;
				case 2:
					it_ent->count *= 0.5f;
					break;
				}
			}
		}

		it_ent->nextthink = 0;

		VectorCopy( org, it_ent->s.origin );
		VectorMA( it_ent->s.origin, fright, right, it_ent->s.origin );
		VectorMA( it_ent->s.origin, ffwd, fwd, it_ent->s.origin );
		it_ent->s.origin[2] += fup;

		VectorCopy( angs, it_ent->s.angles );

		// by doing this, we can force the amount of ammo we desire onto the weapon for when it gets picked-up
		it_ent->flags |= ( FL_DROPPED_ITEM | FL_FORCE_PULLABLE_ONLY );
		it_ent->physicsBounce = 0.1f;

		for ( int t = 0; t < 3; t++ )
		{
			if ( rotate )
			{
				if ( t == YAW )
				{
					it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + 180 + Q_flrand(-1.0f, 1.0f) * 14 );
				}
				else
				{
					it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + Q_flrand(-1.0f, 1.0f) * 4 );
				}
			}
			else
			{
				if ( t == YAW )
				{
					it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + 90 + Q_flrand(-1.0f, 1.0f) * 4 );
				}
			}
		}

		G_SetAngles( it_ent, it_ent->s.angles );
		G_SetOrigin( it_ent, it_ent->s.origin );
		gi.linkentity( it_ent );
	}
}
Beispiel #11
0
//MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
//If you really need to violate this rule for SP, then use ifdefs.
//By BG-compatible, I mean no use of game-specific data - ONLY use
//stuff available in the MP bgEntity (in SP, the bgEntity is #defined
//as a gentity, but the MP-compatible access restrictions are based
//on the bgEntity structure in the MP codebase) -rww
// ProcessOrientCommands the Vehicle.
static void ProcessOrientCommands( Vehicle_t *pVeh )
{
	/********************************************************************************/
	/*	BEGIN	Here is where make sure the vehicle is properly oriented.	BEGIN	*/
	/********************************************************************************/
	bgEntity_t *parent = pVeh->m_pParentEntity;
	playerState_t *parentPS, *riderPS;
	
#ifdef _JK2MP
	bgEntity_t *rider = NULL;
	if (parent->s.owner != ENTITYNUM_NONE)
	{
		rider = PM_BGEntForNum(parent->s.owner); //&g_entities[parent->r.ownerNum];
	}
#else
	gentity_t *rider = parent->owner;
#endif

	// Bucking so we can't do anything.
#ifndef _JK2MP //bad for prediction - fixme
	if ( pVeh->m_ulFlags & VEH_BUCKING || pVeh->m_ulFlags & VEH_FLYING || pVeh->m_ulFlags & VEH_CRASHING )
	{
		return;
	}
#endif

#ifdef _JK2MP
	if ( !rider )
#else
	if ( !rider || !rider->client )
#endif
	{
		rider = parent;
	}



#ifdef _JK2MP
	parentPS = parent->playerState;
	riderPS = rider->playerState;
#else
	parentPS = &parent->client->ps;
	riderPS = &rider->client->ps;
#endif

	if (rider)
	{
#ifdef _JK2MP
	float angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
	if (parentPS && parentPS->speed)
	{
		float s = parentPS->speed;
		float maxDif = pVeh->m_pVehicleInfo->turningSpeed*4.0f; //magic number hackery
		if (s < 0.0f)
		{
			s = -s;
		}
		angDif *= s/pVeh->m_pVehicleInfo->speedMax;
		if (angDif > maxDif)
		{
			angDif = maxDif;
		}
		else if (angDif < -maxDif)
		{
			angDif = -maxDif;
		}
		pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f));
	}
#else
		pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
#endif
	}


/*	speed = VectorLength( parentPS->velocity );

	// If the player is the rider...
	if ( rider->s.number < MAX_CLIENTS )
	{//FIXME: use the vehicle's turning stat in this calc
		pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
	}
	else
	{
		float turnSpeed = pVeh->m_pVehicleInfo->turningSpeed;
		if ( !pVeh->m_pVehicleInfo->turnWhenStopped 
			&& !parentPS->speed )//FIXME: or !pVeh->m_ucmd.forwardmove?
		{//can't turn when not moving
			//FIXME: or ramp up to max turnSpeed?
			turnSpeed = 0.0f;
		}
#ifdef _JK2MP
		if (rider->s.eType == ET_NPC)
#else
		if ( !rider || rider->NPC )
#endif
		{//help NPCs out some
			turnSpeed *= 2.0f;
#ifdef _JK2MP
			if (parentPS->speed > 200.0f)
#else
			if ( parent->client->ps.speed > 200.0f )
#endif
			{
				turnSpeed += turnSpeed * parentPS->speed/200.0f*0.05f;
			}
		}
		turnSpeed *= pVeh->m_fTimeModifier;

		//default control scheme: strafing turns, mouselook aims
		if ( pVeh->m_ucmd.rightmove < 0 )
		{
			pVeh->m_vOrientation[YAW] += turnSpeed;
		}
		else if ( pVeh->m_ucmd.rightmove > 0 )
		{
			pVeh->m_vOrientation[YAW] -= turnSpeed;
		}

		if ( pVeh->m_pVehicleInfo->malfunctionArmorLevel && pVeh->m_iArmor <= pVeh->m_pVehicleInfo->malfunctionArmorLevel )
		{//damaged badly
		}
	}*/

	/********************************************************************************/
	/*	END	Here is where make sure the vehicle is properly oriented.	END			*/
	/********************************************************************************/
}
Beispiel #12
0
//-----------------------------------------------------
qboolean VEH_TurretAim( Vehicle_t *pVeh, 
						 gentity_t *parent, 
						 gentity_t *turretEnemy,
						 turretStats_t *turretStats, 
						 vehWeaponInfo_t *vehWeapon, 
						 int turretNum, int curMuzzle, vec3_t desiredAngles )
//-----------------------------------------------------
{
	vec3_t	curAngles, addAngles, newAngles, yawAngles, pitchAngles;
	float	aimCorrect = qfalse;

	WP_CalcVehMuzzle( parent, curMuzzle );
	//get the current absolute angles of the turret right now
	vectoangles( pVeh->m_vMuzzleDir[curMuzzle], curAngles );
	//subtract out the vehicle's angles to get the relative alignment
	AnglesSubtract( curAngles, pVeh->m_vOrientation, curAngles );

	if ( turretEnemy )
	{
		aimCorrect = qtrue;
		// ...then we'll calculate what new aim adjustments we should attempt to make this frame
		// Aim at enemy
		VEH_TurretAnglesToEnemy( pVeh, curMuzzle, vehWeapon->fSpeed, turretEnemy, turretStats->bAILead, desiredAngles ); 
	}
	//subtract out the vehicle's angles to get the relative desired alignment
	AnglesSubtract( desiredAngles, pVeh->m_vOrientation, desiredAngles );
	//Now clamp the desired relative angles
	//clamp yaw
	desiredAngles[YAW] = AngleNormalize180( desiredAngles[YAW] );
	if ( pVeh->m_pVehicleInfo->turret[turretNum].yawClampLeft
		&& desiredAngles[YAW] > pVeh->m_pVehicleInfo->turret[turretNum].yawClampLeft )
	{
		aimCorrect = qfalse;
		desiredAngles[YAW] = pVeh->m_pVehicleInfo->turret[turretNum].yawClampLeft;
	}
	if ( pVeh->m_pVehicleInfo->turret[turretNum].yawClampRight
		&& desiredAngles[YAW] < pVeh->m_pVehicleInfo->turret[turretNum].yawClampRight )
	{
		aimCorrect = qfalse;
		desiredAngles[YAW] = pVeh->m_pVehicleInfo->turret[turretNum].yawClampRight;
	}
	//clamp pitch
	desiredAngles[PITCH] = AngleNormalize180( desiredAngles[PITCH] );
	if ( pVeh->m_pVehicleInfo->turret[turretNum].pitchClampDown
		&& desiredAngles[PITCH] > pVeh->m_pVehicleInfo->turret[turretNum].pitchClampDown )
	{
		aimCorrect = qfalse;
		desiredAngles[PITCH] = pVeh->m_pVehicleInfo->turret[turretNum].pitchClampDown;
	}
	if ( pVeh->m_pVehicleInfo->turret[turretNum].pitchClampUp
		&& desiredAngles[PITCH] < pVeh->m_pVehicleInfo->turret[turretNum].pitchClampUp )
	{
		aimCorrect = qfalse;
		desiredAngles[PITCH] = pVeh->m_pVehicleInfo->turret[turretNum].pitchClampUp;
	}
	//Now get the offset we want from our current relative angles
	AnglesSubtract( desiredAngles, curAngles, addAngles );
	//Now cap the addAngles for our fTurnSpeed
	if ( addAngles[PITCH] > turretStats->fTurnSpeed )
	{
		//aimCorrect = qfalse;//???
		addAngles[PITCH] = turretStats->fTurnSpeed;
	}
	else if ( addAngles[PITCH] < -turretStats->fTurnSpeed )
	{
		//aimCorrect = qfalse;//???
		addAngles[PITCH] = -turretStats->fTurnSpeed;
	}
	if ( addAngles[YAW] > turretStats->fTurnSpeed )
	{
		//aimCorrect = qfalse;//???
		addAngles[YAW] = turretStats->fTurnSpeed;
	}
	else if ( addAngles[YAW] < -turretStats->fTurnSpeed )
	{
		//aimCorrect = qfalse;//???
		addAngles[YAW] = -turretStats->fTurnSpeed;
	}
	//Now add the additional angles back in to our current relative angles
	//FIXME: add some AI aim error randomness...?
	newAngles[PITCH] = AngleNormalize180( curAngles[PITCH]+addAngles[PITCH] );
	newAngles[YAW] = AngleNormalize180( curAngles[YAW]+addAngles[YAW] );
	//Now set the bone angles to the new angles
	//set yaw
	if ( turretStats->yawBone )
	{
		VectorClear( yawAngles );
		yawAngles[turretStats->yawAxis] = newAngles[YAW];
		NPC_SetBoneAngles( parent, turretStats->yawBone, yawAngles );
	}
	//set pitch
	if ( turretStats->pitchBone )
	{
		VectorClear( pitchAngles );
		pitchAngles[turretStats->pitchAxis] = newAngles[PITCH];
		NPC_SetBoneAngles( parent, turretStats->pitchBone, pitchAngles );
	}
	//force muzzle to recalc next check
	pVeh->m_iMuzzleTime[curMuzzle] = 0;

	return aimCorrect;
}
Beispiel #13
0
void CGCam_FollowUpdate ( void )
{
	vec3_t		center, dir, cameraAngles, vec, focus[MAX_CAMERA_GROUP_SUBJECTS];//No more than 16 subjects in a cameraGroup
	gentity_t	*from = NULL;
	centity_t	*fromCent = NULL;
	int			num_subjects = 0, i;
	qboolean	focused = qfalse;
	
	if ( client_camera.cameraGroup && client_camera.cameraGroup[0] )
	{
		//Stay centered in my cameraGroup, if I have one
		while( NULL != (from = G_Find(from, FOFS(cameraGroup), client_camera.cameraGroup)))
		{
			/*
			if ( from->s.number == client_camera.aimEntNum )
			{//This is the misc_camera_focus, we'll be removing this ent altogether eventually
				continue;
			}
			*/

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

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

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

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

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

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

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

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

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

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

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

	//Point camera to lerp angles
	/*
	if ( !cg_skippingcin.integer )
	{
		Com_Printf( "ang: %s\n", vtos(cameraAngles) );
	}
	*/
	VectorCopy( cameraAngles, client_camera.angles );
}
Beispiel #14
0
/*
==============
R_CalcBones

The list of bones[] should only be built and modified from within here
==============
*/
void R_CalcBones( mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones, int renderend ) {

	int i, j;
	int   *boneRefs;
	float torsoWeight;
	mdsBoneFrame_t  *bones, *bonePtr, *parentBone;
	mdsFrame_t      *frame, *torsoFrame;
	mdsBoneInfo_t   *boneInfo, *thisBoneInfo, *parentBoneInfo;
	mdsBoneFrameCompressed_t    *cBonePtr, *cTBonePtr,  *cBoneList, *cBoneListTorso;
	vec3_t t, torsoAxis[3], tmpAxis[3];
	vec3_t torsoParentOffset = {0};
	vec4_t m1[4];
	vec4_t m2[4] = {{0}, {0}, {0}, {0}};
	int frameSize;


	bones = smpbones[renderend];
	frameSize = (int) ( sizeof( mdsFrame_t ) + ( header->numBones - 1 ) * sizeof( mdsBoneFrameCompressed_t ) );
	frame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames + refent->frame * frameSize );
	torsoFrame = ( mdsFrame_t * )( (byte *)header + header->ofsFrames + refent->torsoFrame * frameSize );

	boneInfo = ( mdsBoneInfo_t * )( (byte *)header + header->ofsBones );
	boneRefs = boneList;
	Matrix3Transpose( refent->torsoAxis, torsoAxis );
	cBoneList = frame->bones;
	cBoneListTorso = torsoFrame->bones;

	for ( i = 0; i < numBones; i++, boneRefs++ ) {
		// R_CalcBone( header, refent, *boneRefs );
		int boneNum;
		short   *sh;
		float   *pf, diff;
		vec3_t tangles, angles, vec, v2;
		qboolean isTorso, fullTorso;

		fullTorso = qfalse;
		boneNum = *boneRefs;
		thisBoneInfo = &boneInfo[boneNum];
		if ( thisBoneInfo->torsoWeight ) {
			isTorso = qtrue;
			if ( thisBoneInfo->torsoWeight == 1.0f ) {
				fullTorso = qtrue;
			}
		} else {
			isTorso = qfalse;
		}
		cTBonePtr = &cBoneListTorso[boneNum];
		cBonePtr = &cBoneList[boneNum];

		bonePtr = &bones[ boneNum ];

		// we can assume the parent has already been uncompressed for this frame + lerp
		if ( thisBoneInfo->parent >= 0 ) {
			parentBone = &bones[ thisBoneInfo->parent ];
			parentBoneInfo = &boneInfo[ thisBoneInfo->parent ];
		} else {
			parentBone = NULL;
			parentBoneInfo = NULL;
		}

		// rotation
		if ( fullTorso ) {
			sh = (short *)cTBonePtr->angles;
			pf = angles;
			ANGLES_SHORT_TO_FLOAT( pf, sh );
		} else {
			sh = (short *)cBonePtr->angles;
			pf = angles;
			ANGLES_SHORT_TO_FLOAT( pf, sh );
			if ( isTorso ) {
				sh = (short *)cTBonePtr->angles;
				pf = tangles;
				ANGLES_SHORT_TO_FLOAT( pf, sh );
				// blend the angles together
				for ( j = 0; j < 3; j++ ) {
					diff = tangles[j] - angles[j];
					if ( fabs( diff ) > 180 ) {
						diff = AngleNormalize180( diff );
					}
					angles[j] = angles[j] + thisBoneInfo->torsoWeight * diff;
				}
			}
		}
		AnglesToAxis( angles, bonePtr->matrix );

		// translation
		if ( parentBone ) {

			if ( fullTorso ) {
				sh = (short *)cTBonePtr->ofsAngles; pf = angles;
				*( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0;
				LocalAngleVector( angles, vec );
			} else {

				sh = (short *)cBonePtr->ofsAngles; pf = angles;
				*( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0;
				LocalAngleVector( angles, vec );

				if ( isTorso ) {
					sh = (short *)cTBonePtr->ofsAngles;
					pf = tangles;
					*( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = SHORT2ANGLE( *( sh++ ) ); *( pf++ ) = 0;
					LocalAngleVector( tangles, v2 );

					// blend the angles together
					SLerp_Normal( vec, v2, thisBoneInfo->torsoWeight, vec );

				}
			}
			LocalVectorMA( parentBone->translation, thisBoneInfo->parentDist, vec, bonePtr->translation );
		} else { // just use the frame position
			bonePtr->translation[0] = frame->parentOffset[0];
			bonePtr->translation[1] = frame->parentOffset[1];
			bonePtr->translation[2] = frame->parentOffset[2];
		}
		if ( boneNum == header->torsoParent ) {
			VectorCopy( bonePtr->translation, torsoParentOffset );
		}
	}

	// adjust for torso rotations
	torsoWeight = 0;
	boneRefs = boneList;
	for ( i = 0; i < numBones; i++, boneRefs++ ) {

		thisBoneInfo = &boneInfo[ *boneRefs ];
		bonePtr = &bones[ *boneRefs ];
		// add torso rotation
		if ( thisBoneInfo->torsoWeight > 0 ) {

			if ( !( thisBoneInfo->flags & BONEFLAG_TAG ) ) {

				// 1st multiply with the bone->matrix
				// 2nd translation for rotation relative to bone around torso parent offset
				VectorSubtract( bonePtr->translation, torsoParentOffset, t );
				Matrix4FromAxisPlusTranslation( bonePtr->matrix, t, m1 );
				// 3rd scaled rotation
				// 4th translate back to torso parent offset
				// use previously created matrix if available for the same weight
				if ( torsoWeight != thisBoneInfo->torsoWeight ) {
					Matrix4FromScaledAxisPlusTranslation( torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2 );
					torsoWeight = thisBoneInfo->torsoWeight;
				}
				// multiply matrices to create one matrix to do all calculations
				Matrix4MultiplyInto3x3AndTranslation( m2, m1, bonePtr->matrix, bonePtr->translation );

			} else {    // tag's require special handling

				// rotate each of the axis by the torsoAngles
				LocalScaledMatrixTransformVector( bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0] );
				LocalScaledMatrixTransformVector( bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1] );
				LocalScaledMatrixTransformVector( bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2] );
				memcpy( bonePtr->matrix, tmpAxis, sizeof( tmpAxis ) );

				// rotate the translation around the torsoParent
				VectorSubtract( bonePtr->translation, torsoParentOffset, t );
				LocalScaledMatrixTransformVector( t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation );
				VectorAdd( bonePtr->translation, torsoParentOffset, bonePtr->translation );

			}
		}
	}
}
Beispiel #15
0
void ProcessOrientCommands( Vehicle_t *pVeh )
{
	/********************************************************************************/
	/*	BEGIN	Here is where make sure the vehicle is properly oriented.	BEGIN	*/
	/********************************************************************************/
	playerState_t *riderPS;
	playerState_t *parentPS;

#ifdef _JK2MP
	float angDif;

	if (pVeh->m_pPilot)
	{
		riderPS = pVeh->m_pPilot->playerState;
	}
	else
	{
		riderPS = pVeh->m_pParentEntity->playerState;
	}
	parentPS = pVeh->m_pParentEntity->playerState;

	//pVeh->m_vOrientation[YAW] = 0.0f;//riderPS->viewangles[YAW];
	angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
	if (parentPS && parentPS->speed)
	{
		float s = parentPS->speed;
		float maxDif = pVeh->m_pVehicleInfo->turningSpeed*4.0f; //magic number hackery
		if (s < 0.0f)
		{
			s = -s;
		}
		angDif *= s/pVeh->m_pVehicleInfo->speedMax;
		if (angDif > maxDif)
		{
			angDif = maxDif;
		}
		else if (angDif < -maxDif)
		{
			angDif = -maxDif;
		}
		pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f));

		if (parentPS->electrifyTime > pm->cmd.serverTime)
		{ //do some crazy stuff
			pVeh->m_vOrientation[YAW] += (sin(pm->cmd.serverTime/1000.0f)*3.0f)*pVeh->m_fTimeModifier;
		}
	}

#else
 	gentity_t *rider = pVeh->m_pParentEntity->owner;
	if ( !rider || !rider->client )
	{
		riderPS = &pVeh->m_pParentEntity->client->ps;
	}
	else
	{
		riderPS = &rider->client->ps;
	}
	parentPS = &pVeh->m_pParentEntity->client->ps;

	if (pVeh->m_ulFlags & VEH_FLYING)
	{
		pVeh->m_vOrientation[YAW] += pVeh->m_vAngularVelocity;
	}
	else if (
		(pVeh->m_ulFlags & VEH_SLIDEBREAKING) ||	// No Angles Control While Out Of Control 
		(pVeh->m_ulFlags & VEH_OUTOFCONTROL) 		// No Angles Control While Out Of Control 
		)
	{
		// Any ability to change orientation?
	}
	else if (
		(pVeh->m_ulFlags & VEH_STRAFERAM)			// No Angles Control While Strafe Ramming
		)
	{
		if (parentPS->hackingTime>0)
		{
			parentPS->hackingTime--;
			pVeh->m_vOrientation[ROLL] += (parentPS->hackingTime<( STRAFERAM_DURATION/2))?(-STRAFERAM_ANGLE):( STRAFERAM_ANGLE);
		}
		else if (pVeh->hackingTime<0)
		{
			parentPS->hackingTime++;
			pVeh->m_vOrientation[ROLL] += (parentPS->hackingTime>(-STRAFERAM_DURATION/2))?( STRAFERAM_ANGLE):(-STRAFERAM_ANGLE);
		}
	}
	else
	{
		pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
	}
#endif

	/********************************************************************************/
	/*	END	Here is where make sure the vehicle is properly oriented.	END			*/
	/********************************************************************************/
}
Beispiel #16
0
//MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
//If you really need to violate this rule for SP, then use ifdefs.
//By BG-compatible, I mean no use of game-specific data - ONLY use
//stuff available in the MP bgEntity (in SP, the bgEntity is #defined
//as a gentity, but the MP-compatible access restrictions are based
//on the bgEntity structure in the MP codebase) -rww
// ProcessOrientCommands the Vehicle.
static void ProcessOrientCommands( Vehicle_t *pVeh ) {
	/********************************************************************************/
	/*	BEGIN	Here is where make sure the vehicle is properly oriented.	BEGIN	*/
	/********************************************************************************/
	bgEntity_t *parent = pVeh->m_pParentEntity;
	playerState_t *parentPS, *riderPS;

	bgEntity_t *rider = NULL;
	if ( parent->s.owner != ENTITYNUM_NONE ) {
		rider = PM_BGEntForNum( parent->s.owner ); //&g_entities[parent->r.ownerNum];
	}

	if ( !rider ) {
		rider = parent;
	}



	parentPS = parent->playerState;
	riderPS = rider->playerState;

	if ( rider ) {
		float angDif = AngleSubtract( pVeh->m_vOrientation->yaw, riderPS->viewangles.yaw );
		if ( parentPS && (int)parentPS->speed ) {
			float s = parentPS->speed;
			float maxDif = pVeh->m_pVehicleInfo->turningSpeed*4.0f; //magic number hackery
			if ( s < 0.0f ) {
				s = -s;
			}
			angDif *= s / pVeh->m_pVehicleInfo->speedMax;
			if ( angDif > maxDif ) {
				angDif = maxDif;
			}
			else if ( angDif < -maxDif ) {
				angDif = -maxDif;
			}
			pVeh->m_vOrientation->yaw = AngleNormalize180( pVeh->m_vOrientation->yaw - angDif*(pVeh->m_fTimeModifier*0.2f) );
		}
	}


	/*	speed = VectorLength( parentPS->velocity );

		// If the player is the rider...
		if ( rider->s.number < MAX_CLIENTS )
		{//FIXME: use the vehicle's turning stat in this calc
		pVeh->m_vOrientation->yaw = riderPS->viewangles->yaw;
		}
		else
		{
		float turnSpeed = pVeh->m_pVehicleInfo->turningSpeed;
		if ( !pVeh->m_pVehicleInfo->turnWhenStopped
		&& !parentPS->speed )//FIXME: or !pVeh->m_ucmd.forwardmove?
		{//can't turn when not moving
		//FIXME: or ramp up to max turnSpeed?
		turnSpeed = 0.0f;
		}
		if (rider->s.eType == ET_NPC)
		{//help NPCs out some
		turnSpeed *= 2.0f;
		if (parentPS->speed > 200.0f)
		{
		turnSpeed += turnSpeed * parentPS->speed/200.0f*0.05f;
		}
		}
		turnSpeed *= pVeh->m_fTimeModifier;

		//default control scheme: strafing turns, mouselook aims
		if ( pVeh->m_ucmd.rightmove < 0 )
		{
		pVeh->m_vOrientation->yaw += turnSpeed;
		}
		else if ( pVeh->m_ucmd.rightmove > 0 )
		{
		pVeh->m_vOrientation->yaw -= turnSpeed;
		}

		if ( pVeh->m_pVehicleInfo->malfunctionArmorLevel && pVeh->m_iArmor <= pVeh->m_pVehicleInfo->malfunctionArmorLevel )
		{//damaged badly
		}
		}*/

	/********************************************************************************/
	/*	END	Here is where make sure the vehicle is properly oriented.	END			*/
	/********************************************************************************/
}