예제 #1
0
/*
===================
PM_AirMove

===================
*/
static void PM_AirMove( void ) {
	int			i;
	vec3_t		wishvel;
	float		fmove, smove;
	vec3_t		wishdir;
	float		wishspeed;
	float		scale;
	usercmd_t	cmd;

	PM_Friction();

	fmove = pm->cmd.forwardmove;
	smove = pm->cmd.rightmove;

	cmd = pm->cmd;
	scale = PM_CmdScale( &cmd );

	// set the movementDir so clients can rotate the legs for strafing
	PM_SetMovementDir();

	// project moves down to flat plane
	pml.forward[2] = 0;
	pml.right[2] = 0;
	VectorNormalize (pml.forward);
	VectorNormalize (pml.right);

	for ( i = 0 ; i < 2 ; i++ ) {
		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
	}
	wishvel[2] = 0;

	VectorCopy (wishvel, wishdir);
	wishspeed = VectorNormalize(wishdir);
	wishspeed *= scale;

	// not on ground, so little effect on velocity
	PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);

	// we may have a ground plane that is very steep, even
	// though we don't have a groundentity
	// slide along the steep plane
	if ( pml.groundPlane ) {
		PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
			pm->ps->velocity, OVERCLIP );
	}

#if 0
	//ZOID:  If we are on the grapple, try stair-stepping
	//this allows a player to use the grapple to pull himself
	//over a ledge
	if (pm->ps->pm_flags & PMF_GRAPPLE_PULL)
		PM_StepSlideMove ( qtrue );
	else
		PM_SlideMove ( qtrue );
#endif

	PM_StepSlideMove ( qtrue );
}
예제 #2
0
/*
===================
PM_LadderMove()
by: Calrathan [Arthur Tomlin]

Right now all I know is that this works for VERTICAL ladders. 
Ladders with angles on them (urban2 for AQ2) haven't been tested.
===================
*/
static void PM_LadderMove( void ) {
	int i;
	vec3_t wishvel;
	float wishspeed;
	vec3_t wishdir;
	float scale;
	float vel;

	PM_Friction ();

	scale = PM_CmdScale( &pm->cmd );

	// user intentions [what the user is attempting to do]
	if ( !scale ) { 
		wishvel[0] = 0;
		wishvel[1] = 0;
		wishvel[2] = 0;
	}
	else {   // if they're trying to move... lets calculate it
		for (i=0 ; i<3 ; i++)
			wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove +
				     scale * pml.right[i]*pm->cmd.rightmove; 
		wishvel[2] += scale * pm->cmd.upmove;
	}

	VectorCopy (wishvel, wishdir);
	wishspeed = VectorNormalize(wishdir);

	if ( wishspeed > pm->ps->speed * pm_ladderScale ) {
		wishspeed = pm->ps->speed * pm_ladderScale;
	}

	PM_Accelerate (wishdir, wishspeed, pm_ladderAccelerate);

	// This SHOULD help us with sloped ladders, but it remains untested.
	if ( pml.groundPlane && DotProduct( pm->ps->velocity,
		pml.groundTrace.plane.normal ) < 0 ) {
		vel = VectorLength(pm->ps->velocity);
		// slide along the ground plane [the ladder section under our feet] 
		PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
			pm->ps->velocity, OVERCLIP );

		VectorNormalize(pm->ps->velocity);
		VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
	}

	PM_SlideMove( qfalse ); // move without gravity
}
예제 #3
0
/*
===================
PM_WaterMove

===================
*/
static void PM_WaterMove( void ) {
	int		i;
	vec3_t	wishvel;
	float	wishspeed;
	vec3_t	wishdir;
	float	scale;
	float	vel;

	if ( PM_CheckWaterJump() ) {
		PM_WaterJumpMove();
		return;
	}
#if 0
	// jump = head for surface
	if ( pm->cmd.upmove >= 10 ) {
		if (pm->ps->velocity[2] > -300) {
			if ( pm->watertype == CONTENTS_WATER ) {
				pm->ps->velocity[2] = 100;
			} else if (pm->watertype == CONTENTS_SLIME) {
				pm->ps->velocity[2] = 80;
			} else {
				pm->ps->velocity[2] = 50;
			}
		}
	}
#endif
	PM_Friction ();

	scale = PM_CmdScale( &pm->cmd );
	//
	// user intentions
	//
	if ( !scale ) {
		wishvel[0] = 0;
		wishvel[1] = 0;
		wishvel[2] = -60;		// sink towards bottom
	} else {
		for (i=0 ; i<3 ; i++)
			wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;

		wishvel[2] += scale * pm->cmd.upmove;
	}

	VectorCopy (wishvel, wishdir);
	wishspeed = VectorNormalize(wishdir);

	if ( wishspeed > pm->ps->speed * pm_swimScale ) {
		wishspeed = pm->ps->speed * pm_swimScale;
	}

	PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);

	// make sure we can go up slopes easily under water
	if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {
		vel = VectorLength(pm->ps->velocity);
		// slide along the ground plane
		PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
			pm->ps->velocity, OVERCLIP );

		VectorNormalize(pm->ps->velocity);
		VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
	}

	PM_SlideMove( qfalse );
}
예제 #4
0
파일: bg_slidemove.c 프로젝트: Chedo/OpenJK
/*
==================
PM_StepSlideMove

==================
*/
void PM_StepSlideMove( qboolean gravity ) { 
	vec3_t		start_o, start_v;
	vec3_t		down_o, down_v;
	trace_t		trace;
//	float		down_dist, up_dist;
//	vec3_t		delta, delta2;
	vec3_t		up, down;
	float		stepSize;
	qboolean	isGiant = qfalse;
	bgEntity_t	*pEnt;
	qboolean skipStep = qfalse;

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

	if ( BG_InReboundHold( pm->ps->legsAnim ) )
	{
		gravity = qfalse;
	}

	if ( PM_SlideMove( gravity ) == 0 ) {
		return;		// we got exactly where we wanted to go first try	
	}

	pEnt = pm_entSelf;

	if (pm->ps->clientNum >= MAX_CLIENTS)
	{
		if (pEnt && pEnt->s.NPC_class == CLASS_VEHICLE &&
			pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->hoverHeight > 0)
		{
			return;
		}
	}

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

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

	VectorCopy (start_o, up);

	if (pm->ps->clientNum >= MAX_CLIENTS)
	{
		// apply ground friction, even if on ladder
		if (pEnt &&
			pEnt->s.NPC_class == CLASS_ATST ||
				(pEnt->s.NPC_class == CLASS_VEHICLE &&
					pEnt->m_pVehicle &&
					pEnt->m_pVehicle->m_pVehicleInfo->type == VH_WALKER)
			)
		{//AT-STs can step high
			up[2] += 66.0f;
			isGiant = qtrue;
		}
		else if ( pEnt && pEnt->s.NPC_class == CLASS_RANCOR )
		{//also can step up high
			up[2] += 64.0f;
			isGiant = qtrue;
		}
		else
		{
			up[2] += STEPSIZE;
		}
	}
	else
	{
		up[2] += STEPSIZE;
	}

	// test the player position if they were a stepheight higher
	pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
	if ( trace.allsolid ) {
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend can't step\n", c_pmove);
		}
		return;		// can't step up
	}

	stepSize = trace.endpos[2] - start_o[2];
	// try slidemove from this position
	VectorCopy (trace.endpos, pm->ps->origin);
	VectorCopy (start_v, pm->ps->velocity);

	PM_SlideMove( gravity );

	// push down the final amount
	VectorCopy (pm->ps->origin, down);
	down[2] -= stepSize;
	pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);

	if ( pm->stepSlideFix )
	{
		if ( pm->ps->clientNum < MAX_CLIENTS
			&& trace.plane.normal[2] < MIN_WALK_NORMAL )
		{//normal players cannot step up slopes that are too steep to walk on!
			vec3_t stepVec;
			//okay, the step up ends on a slope that it too steep to step up onto,
			//BUT:
			//If the step looks like this:
			//  (B)\__
			//        \_____(A)
			//Then it might still be okay, so we figure out the slope of the entire move
			//from (A) to (B) and if that slope is walk-upabble, then it's okay
			VectorSubtract( trace.endpos, down_o, stepVec );
			VectorNormalize( stepVec ); 
			if ( stepVec[2] > (1.0f-MIN_WALK_NORMAL) )
			{
				skipStep = qtrue;
			}
		}
	}

	if ( !trace.allsolid 
		&& !skipStep ) //normal players cannot step up slopes that are too steep to walk on!
	{ 
		if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
			&& isGiant 
			&& trace.entityNum < MAX_CLIENTS
			&& pEnt 
			&& pEnt->s.NPC_class == CLASS_RANCOR )
		{//Rancor don't step on clients
			if ( pm->stepSlideFix )
			{
				VectorCopy (down_o, pm->ps->origin);
				VectorCopy (down_v, pm->ps->velocity);
			}
			else
			{
				VectorCopy (start_o, pm->ps->origin);
				VectorCopy (start_v, pm->ps->velocity);
			}
		}
		/*
		else if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
			&& isGiant 
			&& trace.entityNum < MAX_CLIENTS
			&& pEnt 
			&& pEnt->s.NPC_class == CLASS_ATST 
			&& OnSameTeam( pEnt, traceEnt) )
		{//NPC AT-ST's don't step up on allies
			VectorCopy (start_o, pm->ps->origin);
			VectorCopy (start_v, pm->ps->velocity);
		}
		*/
		else
		{
			VectorCopy (trace.endpos, pm->ps->origin);
			if ( pm->stepSlideFix )
			{
				if ( trace.fraction < 1.0 ) {
					PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
				}
			}
		}
	}
	else
	{
		if ( pm->stepSlideFix )
		{
			VectorCopy (down_o, pm->ps->origin);
			VectorCopy (down_v, pm->ps->velocity);
		}
	}
	if ( !pm->stepSlideFix )
	{
		if ( trace.fraction < 1.0 ) {
			PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
		}
	}

#if 0
	// if the down trace can trace back to the original position directly, don't step
	pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
	if ( trace.fraction == 1.0 ) {
		// use the original move
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend\n", c_pmove);
		}
	} else 
#endif
	{
		// use the step move
		float	delta;

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
예제 #5
0
파일: pmove.c 프로젝트: Izhido/qrevpak
void PM_StepSlideMove_ (void)
{
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	int			i, j;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	
	numbumps = 4;
	
	VectorCopy (pml.velocity, primal_velocity);
	numplanes = 0;
	
	time_left = pml.frametime;

	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
	{
		for (i=0 ; i<3 ; i++)
			end[i] = pml.origin[i] + time_left * pml.velocity[i];

		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);

		if (trace.allsolid)
		{	// entity is trapped in another solid
			pml.velocity[2] = 0;	// don't build up falling damage
			return;
		}

		if (trace.fraction > 0)
		{	// actually covered some distance
			VectorCopy (trace.endpos, pml.origin);
			numplanes = 0;
		}

		if (trace.fraction == 1)
			 break;		// moved the entire distance

		// save entity for contact
		if (pm->numtouch < MAXTOUCH && trace.ent)
		{
			pm->touchents[pm->numtouch] = trace.ent;
			pm->numtouch++;
		}
		
		time_left -= time_left * trace.fraction;

		// slide along this plane
		if (numplanes >= MAX_CLIP_PLANES)
		{	// this shouldn't really happen
			VectorCopy (vec3_origin, pml.velocity);
			break;
		}

		VectorCopy (trace.plane.normal, planes[numplanes]);
		numplanes++;

#if 0
	float		rub;

		//
		// modify velocity so it parallels all of the clip planes
		//
		if (numplanes == 1)
		{	// go along this plane
			VectorCopy (pml.velocity, dir);
			VectorNormalize (dir);
			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);

			// slide along the plane
			PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
			// rub some extra speed off on xy axis
			// not on Z, or you can scrub down walls
			pml.velocity[0] *= rub;
			pml.velocity[1] *= rub;
			pml.velocity[2] *= rub;
		}
		else if (numplanes == 2)
		{	// go along the crease
			VectorCopy (pml.velocity, dir);
			VectorNormalize (dir);
			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);

			// slide along the plane
			CrossProduct (planes[0], planes[1], dir);
			d = DotProduct (dir, pml.velocity);
			VectorScale (dir, d, pml.velocity);

			// rub some extra speed off
			VectorScale (pml.velocity, rub, pml.velocity);
		}
		else
		{
//			Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
			VectorCopy (vec3_origin, pml.velocity);
			break;
		}

#else
//
// modify original_velocity so it parallels all of the clip planes
//
		for (i=0 ; i<numplanes ; i++)
		{
			PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
			for (j=0 ; j<numplanes ; j++)
				if (j != i)
				{
					if (DotProduct (pml.velocity, planes[j]) < 0)
						break;	// not ok
				}
			if (j == numplanes)
				break;
		}
		
		if (i != numplanes)
		{	// go along this plane
		}
		else
		{	// go along the crease
			if (numplanes != 2)
			{
//				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
				VectorCopy (vec3_origin, pml.velocity);
				break;
			}
			CrossProduct (planes[0], planes[1], dir);
			d = DotProduct (dir, pml.velocity);
			VectorScale (dir, d, pml.velocity);
		}
#endif
		//
		// if velocity is against the original velocity, stop dead
		// to avoid tiny occilations in sloping corners
		//
		if (DotProduct (pml.velocity, primal_velocity) <= 0)
		{
			VectorCopy (vec3_origin, pml.velocity);
			break;
		}
	}

	if (pm->s.pm_time)
	{
		VectorCopy (primal_velocity, pml.velocity);
	}
}
예제 #6
0
/*
==================
PM_StepSlideMove
==================
*/
bool PM_StepSlideMove( bool gravity, bool predictive )
{
	vec3_t   start_o, start_v;
#ifndef UNREALARENA
	vec3_t   down_o, down_v;
#endif
	trace_t  trace;
#ifndef UNREALARENA
	vec3_t   normal;
	vec3_t   step_v, step_vNormal;
#endif
	vec3_t   up, down;
	float    stepSize;
	bool stepped = false;

#ifndef UNREALARENA
	BG_GetClientNormal( pm->ps, normal );
#endif

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

	if ( !PM_SlideMove( gravity ) )
	{
#ifdef UNREALARENA
		return stepped; // we got exactly where we wanted to go first try
#else
		VectorCopy( start_o, down );
		VectorMA( down, -STEPSIZE, normal, down );
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, 0 );

		//we can step down
		if ( trace.fraction > 0.01f && trace.fraction < 1.0f &&
		     !trace.allsolid && pml.groundPlane )
		{
			if ( pm->debugLevel > 1 )
			{
				Log::Notice( "%d: step down\n", c_pmove );
			}

			stepped = true;
		}
#endif
	}
	else
	{
		VectorCopy( start_o, down );
#ifdef UNREALARENA
		down[ 2 ] -= STEPSIZE;
#else
		VectorMA( down, -STEPSIZE, normal, down );
#endif
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, 0 );
#ifdef UNREALARENA
		VectorSet( up, 0.0f, 0.0f, 1.0f );
#endif

		// never step up when you still have up velocity
#ifdef UNREALARENA
		if ( pm->ps->velocity[ 2 ] > 0.0f && ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, up ) < 0.7f ) )
#else
		if ( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
		     ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
#endif
		{
			return stepped;
		}

#ifndef UNREALARENA
		// never step up when flying upwards with the jetpack
		if ( pm->ps->velocity[ 2 ] > 0.0f && ( pm->ps->stats[ STAT_STATE2 ] & SS2_JETPACK_ACTIVE ) )
		{
			return stepped;
		}

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

		VectorCopy( start_o, up );
#ifdef UNREALARENA
		up[ 2 ] += STEPSIZE;
#else
		VectorMA( up, STEPSIZE, normal, up );
#endif

		// test the player position if they were a stepheight higher
		pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask, 0 );

		if ( trace.allsolid )
		{
			if ( pm->debugLevel > 1 )
			{
				Log::Notice( "%i:bend can't step\n", c_pmove );
			}

			return stepped; // can't step up
		}

#ifdef UNREALARENA
		stepSize = trace.endpos[ 2 ] - start_o[ 2 ];

		// if the new position is falling then do nothing
		if ( PM_CheckFallingFromLedge( trace.endpos ) )
		{
			VectorCopy( start_o, pm->ps->origin );

			return stepped;
		}
#else
		VectorSubtract( trace.endpos, start_o, step_v );
		VectorCopy( step_v, step_vNormal );
		VectorNormalize( step_vNormal );

		stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
#endif
		// try slidemove from this position
		VectorCopy( trace.endpos, pm->ps->origin );
		VectorCopy( start_v, pm->ps->velocity );

#ifdef UNREALARENA
		PM_SlideMove( gravity, stepSize );
#else
		if ( PM_SlideMove( gravity ) == 0 )
		{
			if ( pm->debugLevel > 1 )
			{
				Log::Notice( "%d: step up\n", c_pmove );
			}

			stepped = true;
		}
#endif

		// push down the final amount
		VectorCopy( pm->ps->origin, down );
#ifdef UNREALARENA
		down[ 2 ] -= stepSize;
#else
		VectorMA( down, -stepSize, normal, down );
#endif
		pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum,
		           pm->tracemask, 0 );

		if ( !trace.allsolid )
		{
#ifdef UNREALARENA
			// if the new position is falling then do nothing
			if ( PM_CheckFallingFromLedge( trace.endpos ) )
			{
				VectorCopy( start_o, pm->ps->origin );

				return stepped;
			}
#endif
			VectorCopy( trace.endpos, pm->ps->origin );
		}

		if ( trace.fraction < 1.0f )
		{
			PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity );
		}
	}

#ifdef UNREALARENA
	if ( !predictive )
	{
		stepped = true;

		// use the step move
		float	delta;

		delta = pm->ps->origin[ 2 ] - start_o[ 2 ];

		if ( delta > 2.0f )
		{
			if ( delta < 7.0f )
			{
				PM_AddEvent( EV_STEP_4 );
			}
			else if ( delta < 11.0f )
			{
				PM_AddEvent( EV_STEP_8 );
			}
			else if ( delta < 15.0f )
			{
				PM_AddEvent( EV_STEP_12 );
			}
			else
			{
				PM_AddEvent( EV_STEP_16 );
			}
		}

		if ( pm->debugLevel > 1 )
		{
			Log::Notice( "%i:stepped\n", c_pmove );
		}
	}
#else
	if ( !predictive && stepped )
	{
		PM_StepEvent( start_o, pm->ps->origin, normal );
	}
#endif

	return stepped;
}
예제 #7
0
/*
==================
PM_StepSlideMove
==================
*/
qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
{
	vec3_t   start_o, start_v;
	vec3_t   down_o, down_v;
	trace_t  trace;
	vec3_t   normal;
	vec3_t   step_v, step_vNormal;
	vec3_t   up, down;
	float    stepSize;
	qboolean stepped = qfalse;

	BG_GetClientNormal( pm->ps, normal );

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

	if ( PM_SlideMove( gravity ) == 0 )
	{
		VectorCopy( start_o, down );
		VectorMA( down, -STEPSIZE, normal, down );
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

		//we can step down
		if ( trace.fraction > 0.01f && trace.fraction < 1.0f &&
		     !trace.allsolid && pml.groundPlane != qfalse )
		{
			if ( pm->debugLevel > 1 )
			{
				Com_Printf( "%d: step down\n", c_pmove );
			}

			stepped = qtrue;
		}
	}
	else
	{
		VectorCopy( start_o, down );
		VectorMA( down, -STEPSIZE, normal, down );
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

		// never step up when you still have up velocity
		if ( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
		     ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
		{
			return stepped;
		}

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

		VectorCopy( start_o, up );
		VectorMA( up, STEPSIZE, normal, up );

		// test the player position if they were a stepheight higher
		pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask );

		if ( trace.allsolid )
		{
			if ( pm->debugLevel > 1 )
			{
				Com_Printf( "%i:bend can't step\n", c_pmove );
			}

			return stepped; // can't step up
		}

		VectorSubtract( trace.endpos, start_o, step_v );
		VectorCopy( step_v, step_vNormal );
		VectorNormalize( step_vNormal );

		stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
		// try slidemove from this position
		VectorCopy( trace.endpos, pm->ps->origin );
		VectorCopy( start_v, pm->ps->velocity );

		if ( PM_SlideMove( gravity ) == 0 )
		{
			if ( pm->debugLevel > 1 )
			{
				Com_Printf( "%d: step up\n", c_pmove );
			}

			stepped = qtrue;
		}

		// push down the final amount
		VectorCopy( pm->ps->origin, down );
		VectorMA( down, -stepSize, normal, down );
		pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

		if ( !trace.allsolid )
		{
			VectorCopy( trace.endpos, pm->ps->origin );
		}

		if ( trace.fraction < 1.0f )
		{
			PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity );
		}
	}

	if ( !predictive && stepped )
	{
		PM_StepEvent( start_o, pm->ps->origin, normal );
	}

	return stepped;
}
예제 #8
0
int
PM_FlyMove (void)
{
	int         bumpcount, numbumps;
	vec3_t      dir;
	float       d;
	int         numplanes;
	vec3_t      planes[MAX_CLIP_PLANES];
	vec3_t      primal_velocity, original_velocity;
	int         i, j;
	trace_t   trace;
	vec3_t      end;
	float       time_left;
	int         blocked;

	numbumps = 4;

	blocked = 0;
	VectorCopy (pmove.velocity, original_velocity);
	VectorCopy (pmove.velocity, primal_velocity);
	numplanes = 0;

	time_left = frametime;

	for (bumpcount = 0; bumpcount < numbumps; bumpcount++) {
		for (i = 0; i < 3; i++)
			end[i] = pmove.origin[i] + time_left * pmove.velocity[i];

		trace = PM_PlayerMove (pmove.origin, end);

		if (trace.startsolid || trace.allsolid) {	// entity is trapped in
													// another solid
			VectorCopy (vec3_origin, pmove.velocity);
			return 3;
		}

		if (trace.fraction > 0) {		// actually covered some distance
			VectorCopy (trace.endpos, pmove.origin);
			numplanes = 0;
		}

		if (trace.fraction == 1)
			break;						// moved the entire distance

		// save entity for contact
		pmove.touchindex[pmove.numtouch] = trace.entnum;
		pmove.numtouch++;

		if (trace.plane.normal[2] > 0.7) {
			blocked |= 1;				// floor
		}
		if (!trace.plane.normal[2]) {
			blocked |= 2;				// step
		}

		time_left -= time_left * trace.fraction;

		// cliped to another plane
		if (numplanes >= MAX_CLIP_PLANES) {	// this shouldn't really happen
			VectorCopy (vec3_origin, pmove.velocity);
			break;
		}

		VectorCopy (trace.plane.normal, planes[numplanes]);
		numplanes++;

//
// modify original_velocity so it parallels all of the clip planes
//
		for (i = 0; i < numplanes; i++) {
			PM_ClipVelocity (original_velocity, planes[i], pmove.velocity, 1);
			for (j = 0; j < numplanes; j++)
				if (j != i) {
					if (DotProduct (pmove.velocity, planes[j]) < 0)
						break;			// not ok
				}
			if (j == numplanes)
				break;
		}

		if (i != numplanes) {			// go along this plane
		} else {						// go along the crease
			if (numplanes != 2) {
//              Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
				VectorCopy (vec3_origin, pmove.velocity);
				break;
			}
			CrossProduct (planes[0], planes[1], dir);
			d = DotProduct (dir, pmove.velocity);
			VectorScale (dir, d, pmove.velocity);
		}

//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
		if (DotProduct (pmove.velocity, primal_velocity) <= 0) {
			VectorCopy (vec3_origin, pmove.velocity);
			break;
		}
	}

	if (pmove.waterjumptime) {
		VectorCopy (primal_velocity, pmove.velocity);
	}
	return blocked;
}
예제 #9
0
파일: pmove.c 프로젝트: Nekrofage/Quake2RPi
void PM_StepSlideMove_ (void)
{
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	int			i, j;
	trace_t	trace;
	vec3_t		end;
	float		time_left;

	numbumps = 4;

	VectorCopy (pml.velocity, primal_velocity);
	numplanes = 0;

	time_left = pml.frametime;

	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
	{
		for (i=0 ; i<3 ; i++)
			end[i] = pml.origin[i] + time_left * pml.velocity[i];

		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);

		if (trace.allsolid)
		{
			/* entity is trapped in another solid */
			pml.velocity[2] = 0; /* don't build up falling damage */
			return;
		}

		if (trace.fraction > 0)
		{
			/* actually covered some distance */
			VectorCopy (trace.endpos, pml.origin);
			numplanes = 0;
		}

		if (trace.fraction == 1)
			break; /* moved the entire distance */

		/* save entity for contact */
		if (pm->numtouch < MAXTOUCH && trace.ent)
		{
			pm->touchents[pm->numtouch] = trace.ent;
			pm->numtouch++;
		}

		time_left -= time_left * trace.fraction;

		/* slide along this plane */
		if (numplanes >= MAX_CLIP_PLANES)
		{
			/* this shouldn't really happen */
			VectorCopy (vec3_origin, pml.velocity);
			break;
		}

		VectorCopy (trace.plane.normal, planes[numplanes]);
		numplanes++;

		/* modify original_velocity so it parallels all of the clip planes */
		for (i=0 ; i<numplanes ; i++)
		{
			PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01f);

			for (j=0 ; j<numplanes ; j++)
				if (j != i)
				{
					if (DotProduct (pml.velocity, planes[j]) < 0)
						break; /* not ok */
				}

			if (j == numplanes)
				break;
		}

		if (i != numplanes)
		{
			/* go along this plane */
		}
		else
		{
			/* go along the crease */
			if (numplanes != 2)
			{
				VectorCopy (vec3_origin, pml.velocity);
				break;
			}

			CrossProduct (planes[0], planes[1], dir);
			d = DotProduct (dir, pml.velocity);
			VectorScale (dir, d, pml.velocity);
		}

		/* if velocity is against the original velocity, stop dead
		   to avoid tiny occilations in sloping corners */
		if (DotProduct (pml.velocity, primal_velocity) <= 0)
		{
			VectorCopy (vec3_origin, pml.velocity);
			break;
		}
	}

	if (pm->s.pm_time)
	{
		VectorCopy (primal_velocity, pml.velocity);
	}
}
예제 #10
0
qboolean	PM_SlideMove( float gravMod ) {
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		normal, planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;
	qboolean	damageSelf = qtrue;
	int			slideMoveContents = pm->tracemask;

	if ( pm->ps->clientNum >= MAX_CLIENTS
		&& !PM_ControlledByPlayer() )
	{//a non-player client, not an NPC under player control
		if ( pml.walking //walking on the ground
			|| (pm->ps->groundEntityNum != ENTITYNUM_NONE //in air
				&& PM_InSpecialJump( pm->ps->legsAnim )//in a special jump
				&& !(pm->ps->eFlags&EF_FORCE_GRIPPED)//not being gripped
				&& !(pm->ps->pm_flags&PMF_TIME_KNOCKBACK)
				&& pm->gent
				&& pm->gent->forcePushTime < level.time) )//not being pushed
		{//
			// If we're a vehicle, ignore this if we're being driven
			if ( !pm->gent //not an game ent
				|| !pm->gent->client //not a client
				|| pm->gent->client->NPC_class != CLASS_VEHICLE//not a vehicle
				|| !pm->gent->m_pVehicle //no vehicle
				|| !pm->gent->m_pVehicle->m_pPilot//no pilot
				|| pm->gent->m_pVehicle->m_pPilot->s.number >= MAX_CLIENTS )//pilot is not the player
			{//then treat do not enter brushes as SOLID
				slideMoveContents |= CONTENTS_BOTCLIP;
			}
		}
	}
	
	numbumps = 4;

	VectorCopy (pm->ps->velocity, primal_velocity);

	if ( gravMod ) 
	{
		VectorCopy( pm->ps->velocity, endVelocity );
		if ( !(pm->ps->eFlags&EF_FORCE_GRIPPED) && !(pm->ps->eFlags&EF_FORCE_DRAINED) )
		{
			endVelocity[2] -= pm->ps->gravity * pml.frametime * gravMod;
		}
		pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
		primal_velocity[2] = endVelocity[2];
		if ( pml.groundPlane ) 
		{
			if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
			{// slide along the ground plane
				PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, 
					pm->ps->velocity, OVERCLIP );
			}
		}
	}

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane ) 
	{
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[0] );
		if ( !PM_GroundSlideOkay( planes[0][2] ) )
		{
			planes[0][2] = 0;
			VectorNormalize( planes[0] );
		}
	} 
	else 
	{
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[numplanes] );
	numplanes++;

	for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {

		// calculate position we are trying to move to
		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

		// see if we can make it there
		pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, slideMoveContents );
		if ( (trace.contents&CONTENTS_BOTCLIP)
			&& (slideMoveContents&CONTENTS_BOTCLIP) )
		{//hit a do not enter brush
			if ( trace.allsolid || trace.startsolid  )//inside the botclip
			{//crap, we're in a do not enter brush, take it out for the remainder of the traces and re-trace this one right now without it
				slideMoveContents &= ~CONTENTS_BOTCLIP;
				pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, slideMoveContents );
			}
			else if ( trace.plane.normal[2] > 0.0f )
			{//on top of a do not enter brush, it, just redo this one trace without it
				pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, (slideMoveContents&~CONTENTS_BOTCLIP) );
			}
		}

		if ( trace.allsolid ) 
		{// entity is completely trapped in another solid
			pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
			return qtrue;
		}

		if ( trace.fraction > 0 ) 
		{// actually covered some distance
			VectorCopy( trace.endpos, pm->ps->origin );
		}

		if ( trace.fraction == 1 ) 
		{
			 break;		// moved the entire distance
		}



		// save entity for contact
		PM_AddTouchEnt( trace.entityNum );

		//Hit it
		if ( trace.surfaceFlags&SURF_NODAMAGE )
		{
			damageSelf = qfalse;
		}
		else if ( trace.entityNum == ENTITYNUM_WORLD && trace.plane.normal[2] > 0.5f )
		{//if we land on the ground, let falling damage do it's thing itself, otherwise do impact damage
			damageSelf = qfalse;
		}
		else
		{
			damageSelf = qtrue;
		}

		if ( PM_ClientImpact( &trace, damageSelf ) )
		{
			continue;
		}

		if (pm->gent->client && 
			pm->gent->client->NPC_class == CLASS_VEHICLE &&
			trace.plane.normal[2]<pm->gent->m_pVehicle->m_pVehicleInfo->maxSlope
			)
		{
			pm->ps->pm_flags |= PMF_BUMPED;
		}

		time_left -= time_left * trace.fraction;

		if ( numplanes >= MAX_CLIP_PLANES ) 
		{// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return qtrue;
		}

		VectorCopy( trace.plane.normal, normal );

 		if ( !PM_GroundSlideOkay( normal[2] ) )
		{//wall-running
			//never push up off a sloped wall
			normal[2] = 0;
			VectorNormalize( normal );
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
		{//no sliding if stuck to wall!
			for ( i = 0 ; i < numplanes ; i++ ) {
				if ( DotProduct( normal, planes[i] ) > 0.99 ) {
					VectorAdd( normal, pm->ps->velocity, pm->ps->velocity );
					break;
				}
			}
			if ( i < numplanes ) {
				continue;
			}
		}
		VectorCopy( normal, planes[numplanes] );
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) {
			into = DotProduct( pm->ps->velocity, planes[i] );
			if ( into >= 0.1 ) {
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) {
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

			// slide along the plane
			PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

			// see if there is a second plane that the new move enters
			for ( j = 0 ; j < numplanes ; j++ ) {
				if ( j == i ) {
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the new move enters
				for ( k = 0 ; k < numplanes ; k++ ) {
					if ( k == i || k == j ) {
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a triple plane interaction
					VectorClear( pm->ps->velocity );
					return qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
	}

	if ( gravMod ) {
		VectorCopy( endVelocity, pm->ps->velocity );
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time ) {
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

	return ( bumpcount != 0 );
}
예제 #11
0
void G_RollMissile( gentity_t *ent )
{
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;
	pml_t		objPML;
	float		bounceAmt = BUMPCLIP;
	gentity_t	*hitEnt = NULL;

	memset( &objPML, 0, sizeof( objPML ) );
	
	G_GroundTrace( ent, &objPML );

	objPML.frametime = (level.time - level.previousTime)*0.001;
	
	numbumps = 4;

	VectorCopy ( ent->s.pos.trDelta, primal_velocity );

	VectorCopy( ent->s.pos.trDelta, endVelocity );
	endVelocity[2] -= g_gravity->value * objPML.frametime;
	ent->s.pos.trDelta[2] = ( ent->s.pos.trDelta[2] + endVelocity[2] ) * 0.5;
	primal_velocity[2] = endVelocity[2];
	if ( objPML.groundPlane ) 
	{//FIXME: never happens!
		// slide along the ground plane
		PM_ClipVelocity( ent->s.pos.trDelta, objPML.groundTrace.plane.normal, ent->s.pos.trDelta, BUMPCLIP );
		VectorScale( ent->s.pos.trDelta, 0.9f, ent->s.pos.trDelta );
	}

	time_left = objPML.frametime;

	// never turn against the ground plane
	if ( objPML.groundPlane ) 
	{
		numplanes = 1;
		VectorCopy( objPML.groundTrace.plane.normal, planes[0] );
	} 
	else 
	{
		numplanes = 0;
	}

	// never turn against original velocity
	/*
	VectorNormalize2( ent->s.pos.trDelta, planes[numplanes] );
	numplanes++;
	*/

	for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) 
	{
		// calculate position we are trying to move to
		VectorMA( ent->currentOrigin, time_left, ent->s.pos.trDelta, end );

		// see if we can make it there
		gi.trace ( &trace, ent->currentOrigin, ent->mins, ent->maxs, end, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 );

		//TEMP HACK:
		//had to move this up above the trace.allsolid check now that for some reason ghoul2 impacts tell me I'm allsolid?!
		//this needs to be fixed, really
		if ( trace.entityNum < ENTITYNUM_WORLD )
		{//hit another ent
			hitEnt = &g_entities[trace.entityNum];
			if ( hitEnt && (hitEnt->takedamage || (hitEnt->contents&CONTENTS_LIGHTSABER) ) )
			{
				G_MissileImpact( ent, &trace );
				if ( ent->s.eType == ET_GENERAL )
				{//exploded
					return;
				}
			}
		}

		if ( trace.allsolid )
		{
			// entity is completely trapped in another solid
			//FIXME: this happens a lot now when we hit a G2 ent... WTF?
			ent->s.pos.trDelta[2] = 0;	// don't build up falling damage, but allow sideways acceleration
			return;// qtrue;
		}

		if ( trace.fraction > 0 ) 
		{
			// actually covered some distance
			VectorCopy( trace.endpos, ent->currentOrigin );
		}

		if ( trace.fraction == 1 ) 
		{
			 break;		// moved the entire distance
		}

		//pm->ps->pm_flags |= PMF_BUMPED;

		// save entity for contact
		//PM_AddTouchEnt( trace.entityNum );

		//Hit it
		/*
		if ( PM_ClientImpact( trace.entityNum, qtrue ) )
		{
			continue;
		}
		*/

		time_left -= time_left * trace.fraction;

		if ( numplanes >= MAX_CLIP_PLANES ) 
		{
			// this shouldn't really happen
			VectorClear( ent->s.pos.trDelta );
			return;// qtrue;
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		for ( i = 0 ; i < numplanes ; i++ ) 
		{
			if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) 
			{
				VectorAdd( trace.plane.normal, ent->s.pos.trDelta, ent->s.pos.trDelta );
				break;
			}
		}
		if ( i < numplanes ) 
		{
			continue;
		}
		VectorCopy( trace.plane.normal, planes[numplanes] );
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//
		if ( &g_entities[trace.entityNum] != NULL && g_entities[trace.entityNum].client ) 
		{//hit a person, bounce off much less
			bounceAmt = OVERCLIP;
		}
		else
		{
			bounceAmt = BUMPCLIP;
		}

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) 
		{
			into = DotProduct( ent->s.pos.trDelta, planes[i] );
			if ( into >= 0.1 ) 
			{
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) 
			{
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity( ent->s.pos.trDelta, planes[i], clipVelocity, bounceAmt );

			// slide along the plane
			PM_ClipVelocity( endVelocity, planes[i], endClipVelocity, bounceAmt );

			// see if there is a second plane that the new move enters
			for ( j = 0 ; j < numplanes ; j++ ) 
			{
				if ( j == i ) 
				{
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) 
				{
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, bounceAmt );
				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, bounceAmt );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) 
				{
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, ent->s.pos.trDelta );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the new move enters
				for ( k = 0 ; k < numplanes ; k++ ) 
				{
					if ( k == i || k == j ) 
					{
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) 
					{
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a triple plane interaction
					VectorClear( ent->s.pos.trDelta );
					return;// qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, ent->s.pos.trDelta );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
		VectorScale( endVelocity, 0.975f, endVelocity );
	}

	VectorCopy( endVelocity, ent->s.pos.trDelta );

	// don't change velocity if in a timer (FIXME: is this correct?)
	/*
	if ( pm->ps->pm_time ) 
	{
		VectorCopy( primal_velocity, ent->s.pos.trDelta );
	}
	*/

	return;// ( bumpcount != 0 );
}
예제 #12
0
/*
==================
PM_StepSlideMove

==================
*/
void PM_StepSlideMove( qboolean gravity ) {
	vec3_t		start_o, start_v;
	vec3_t		down_o, down_v;
	trace_t		trace;
//	float		down_dist, up_dist;
//	vec3_t		delta, delta2;
	vec3_t		up, down;

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

	if ( pm->debugLevel ) {
		qboolean wassolid, slidesucceed;
	
		PM_TraceAll( &trace, pm->ps->origin, pm->ps->origin );
		wassolid = trace.allsolid;
	
		slidesucceed = (PM_SlideMove( gravity ) == 0) ? qtrue : qfalse;
	
		PM_TraceAll( &trace, pm->ps->origin, pm->ps->origin );
		if (trace.allsolid && !wassolid)
			Com_Printf("%i:PM_SlideMove solidified! (%f %f %f) -> (%f %f %f)\n", c_pmove,
				start_o[0],
				start_o[1],
				start_o[2],
				pm->ps->origin[0],
				pm->ps->origin[1],
				pm->ps->origin[2]
			);
	
		if (slidesucceed)
			return;
	} else {
		if ( PM_SlideMove( gravity ) == 0 ) {
			return;		// we got exactly where we wanted to go first try
		}
	}

	if ( pm->debugLevel ) {
		Com_Printf("%i:stepping\n", c_pmove);
	}

	VectorCopy(start_o, down);
	down[2] -= STEPSIZE;

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

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

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

	// test the player position if they were a stepheight higher
	PM_TraceAll( &trace, up, up );
	if ( trace.allsolid ) {
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend can't step\n", c_pmove);
		}
		return;		// can't step up
	}

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

	PM_SlideMove( gravity );

	// push down the final amount
	VectorCopy (pm->ps->origin, down);
	down[2] -= STEPSIZE;

	// check legs separately
	if ( pm->ps->eFlags & (EF_PRONE|EF_PLAYDEAD) ) {
        PM_TraceLegs( &trace, NULL, pm->ps->origin, down, NULL, pm->ps->viewangles, pm->trace, pm->ps->clientNum, pm->tracemask, (pm->ps->eFlags & EF_PRONE) ? true : false );
		if ( trace.allsolid ) {
			// legs don't step, just fuzz.
			VectorCopy( down_o, pm->ps->origin );
			VectorCopy( down_v, pm->ps->velocity );
			if ( pm->debugLevel ) {
				Com_Printf("%i:legs unsteppable\n", c_pmove);
			}
			return;
		}
	}

	pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
	if ( !trace.allsolid ) {
		VectorCopy (trace.endpos, pm->ps->origin);
	}
	if ( trace.fraction < 1.0 ) {
		PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
	}

#if 0
	// if the down trace can trace back to the original position directly, don't step
	PM_TraceAll( &trace, pm->ps->origin, start_o );
	if ( trace.fraction == 1.0 ) {
		// use the original move
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend\n", c_pmove);
		}
	} else 
#endif
	{
		// use the step move
		float	delta;

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
예제 #13
0
/*
==================
PM_StepSlideMove
==================
*/
bool PM_StepSlideMove( bool gravity, bool predictive )
{
  vec3_t    start_o, start_v;
  vec3_t    down_o, down_v;
  trace_t   trace;
  vec3_t    normal;
  vec3_t    step_v, step_vNormal;
  vec3_t    up, down;
  float     stepSize;
  bool  stepped = false;

  if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
  {
    if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
      VectorSet( normal, 0.0f, 0.0f, -1.0f );
    else
      VectorCopy( pm->ps->grapplePoint, normal );
  }
  else
    VectorSet( normal, 0.0f, 0.0f, 1.0f );

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

  if( PM_SlideMove( gravity ) == 0 )
  {
    VectorCopy( start_o, down );
    VectorMA( down, -STEPSIZE, normal, down );
    pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

    //we can step down
    if( trace.fraction > 0.01f && trace.fraction < 1.0f &&
        !trace.allsolid && pml.groundPlane != false )
    {
      if( pm->debugLevel )
        Com_Printf( "%d: step down\n", c_pmove );

      stepped = true;
    }
  }
  else
  {
    VectorCopy( start_o, down );
    VectorMA( down, -STEPSIZE, normal, down );
    pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
    // never step up when you still have up velocity
    if( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
        ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
    {
      return stepped;
    }

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

    VectorCopy( start_o, up );
    VectorMA( up, STEPSIZE, normal, up );

    // test the player position if they were a stepheight higher
    pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask );
    if( trace.allsolid )
    {
      if( pm->debugLevel )
        Com_Printf( "%i:bend can't step\n", c_pmove );

      return stepped;   // can't step up
    }

    VectorSubtract( trace.endpos, start_o, step_v );
    VectorCopy( step_v, step_vNormal );
    VectorNormalize( step_vNormal );

    stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
    // try slidemove from this position
    VectorCopy( trace.endpos, pm->ps->origin );
    VectorCopy( start_v, pm->ps->velocity );

    if( PM_SlideMove( gravity ) == 0 )
    {
      if( pm->debugLevel )
        Com_Printf( "%d: step up\n", c_pmove );

      stepped = true;
    }

    // push down the final amount
    VectorCopy( pm->ps->origin, down );
    VectorMA( down, -stepSize, normal, down );
    pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

    if( !trace.allsolid )
      VectorCopy( trace.endpos, pm->ps->origin );

    if( trace.fraction < 1.0f )
      PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
  }

  if( !predictive && stepped )
    PM_StepEvent( start_o, pm->ps->origin, normal );

  return stepped;
}
예제 #14
0
파일: slidemove.c 프로젝트: icanhas/yantar
qbool
PM_SlideMove(Pmove *pm, Pml *pml, qbool gravity)
{
	int i, j, k, bumpcount, numbumps, numplanes;
	Vec3	dir;
	float	d, time_left, into;
	Vec3	planes[MAX_CLIP_PLANES];
	Vec3	primal_velocity, clipVelocity;
	Trace trace;
	Vec3	end, endVelocity, endClipVelocity;

	numbumps = 4;

	copyv3(pm->ps->velocity, primal_velocity);

	if(gravity){
		copyv3(pm->ps->velocity, endVelocity);
		endVelocity[2] -= pm->ps->gravity * pml->frametime;
		pm->ps->velocity[2] = (pm->ps->velocity[2] + endVelocity[2]) * 0.5f;
		primal_velocity[2] = endVelocity[2];
		if(pml->groundPlane){
			/* slide along the ground plane */
			PM_ClipVelocity(pm->ps->velocity, pml->groundTrace.plane.normal,
				pm->ps->velocity,
				OVERCLIP);
		}
	}

	time_left = pml->frametime;

	/* never turn against the ground plane */
	if(pml->groundPlane){
		numplanes = 1;
		copyv3(pml->groundTrace.plane.normal, planes[0]);
	}else
		numplanes = 0;

	/* never turn against original velocity */
	norm2v3(pm->ps->velocity, planes[numplanes]);
	numplanes++;

	for(bumpcount=0; bumpcount < numbumps; bumpcount++){
		/* calculate position we are trying to move to */
		saddv3(pm->ps->origin, time_left, pm->ps->velocity, end);

		/* see if we can make it there */
		pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, end,
			pm->ps->clientNum,
			pm->tracemask);

		if(trace.allsolid){
			/* entity is completely trapped in another solid */
			pm->ps->velocity[2] = 0;	/* don't build up falling damage, but allow sideways acceleration */
			return qtrue;
		}

		if(trace.fraction > 0)
			/* actually covered some distance */
			copyv3 (trace.endpos, pm->ps->origin);

		if(trace.fraction == 1)
			break;	/* moved the entire distance */

		/* save entity for contact */
		PM_AddTouchEnt(pm, trace.entityNum);

		time_left -= time_left * trace.fraction;

		if(numplanes >= MAX_CLIP_PLANES){
			/* this shouldn't really happen */
			clearv3(pm->ps->velocity);
			return qtrue;
		}

		/*
		 * if this is the same plane we hit before, nudge velocity
		 * out along it, which fixes some epsilon issues with
		 * non-axial planes
		 *  */
		for(i = 0; i < numplanes; i++)
			if(dotv3(trace.plane.normal, planes[i]) > 0.99f){
				addv3(trace.plane.normal, pm->ps->velocity,
					pm->ps->velocity);
				break;
			}
		if(i < numplanes)
			continue;
		copyv3 (trace.plane.normal, planes[numplanes]);
		numplanes++;

		/*
		 * modify velocity so it parallels all of the clip planes
		 */

		/* find a plane that it enters */
		for(i = 0; i < numplanes; i++){
			into = dotv3(pm->ps->velocity, planes[i]);
			if(into >= 0.1f)
				continue;	/* move doesn't interact with the plane */

			/* see how hard we are hitting things */
			if(-into > pml->impactSpeed)
				pml->impactSpeed = -into;

			/* slide along the plane */
			PM_ClipVelocity(pm->ps->velocity, planes[i], clipVelocity, OVERCLIP);

			/* slide along the plane */
			PM_ClipVelocity(endVelocity, planes[i], endClipVelocity, OVERCLIP);

			/* see if there is a second plane that the new move enters */
			for(j = 0; j < numplanes; j++){
				if(j == i)
					continue;
				if(dotv3(clipVelocity, planes[j]) >= 0.1f)
					continue;	/* move doesn't interact with the plane */

				/* try clipping the move to the plane */
				PM_ClipVelocity(clipVelocity, planes[j], clipVelocity, OVERCLIP);
				PM_ClipVelocity(endClipVelocity, planes[j], endClipVelocity, OVERCLIP);

				/* see if it goes back into the first clip plane */
				if(dotv3(clipVelocity, planes[i]) >= 0)
					continue;

				/* slide the original velocity along the crease */
				crossv3 (planes[i], planes[j], dir);
				normv3(dir);
				d = dotv3(dir, pm->ps->velocity);
				scalev3(dir, d, clipVelocity);

				crossv3 (planes[i], planes[j], dir);
				normv3(dir);
				d = dotv3(dir, endVelocity);
				scalev3(dir, d, endClipVelocity);

				/* see if there is a third plane the the new move enters */
				for(k = 0; k < numplanes; k++){
					if(k == i || k == j)
						continue;
					if(dotv3(clipVelocity,
						   planes[k]) >= 0.1f)
						continue;	/* move doesn't interact with the plane */

					/* stop dead at a triple plane interaction */
					clearv3(pm->ps->velocity);
					return qtrue;
				}
			}

			/* if we have fixed all interactions, try another move */
			copyv3(clipVelocity, pm->ps->velocity);
			copyv3(endClipVelocity, endVelocity);
			break;
		}
	}

	if(gravity)
		copyv3(endVelocity, pm->ps->velocity);

	/* don't change velocity if in a timer (FIXME: is this correct?) */
	if(pm->ps->pm_time)
		copyv3(primal_velocity, pm->ps->velocity);

	return (bumpcount != 0);
}
예제 #15
0
파일: slidemove.c 프로젝트: icanhas/yantar
void
PM_StepSlideMove(Pmove *pm, Pml *pml, qbool gravity)
{
	Vec3	start_o, start_v;
/*	Vec3		down_o, down_v; */
	Trace trace;
/* float		down_dist, up_dist;
 * Vec3		delta, delta2; */
	Vec3	up, down;
	float	stepSize;
	float delta;

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

	if(PM_SlideMove(pm, pml, gravity) == 0)
		return;		/* we got exactly where we wanted to go first try */

	copyv3(start_o, down);
	down[2] -= STEPSIZE;
	pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum,
		pm->tracemask);
	setv3(up, 0, 0, 1);
	/* never step up when you still have up velocity */
	if(pm->ps->velocity[2] > 0 && (trace.fraction == 1.0f ||
				       dotv3(trace.plane.normal, up) < 0.7f))
		return;

	/* copyv3 (pm->ps->origin, down_o);
	 * copyv3 (pm->ps->velocity, down_v); */

	copyv3 (start_o, up);
	up[2] += STEPSIZE;

	/* test the player position if they were a stepheight higher */
	pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum,
		pm->tracemask);
	if(trace.allsolid){
		if(pm->debugLevel)
			comprintf("%u:bend can't step\n", cnt);
		return;	/* can't step up */
	}

	stepSize = trace.endpos[2] - start_o[2];
	/* try slidemove from this position */
	copyv3 (trace.endpos, pm->ps->origin);
	copyv3 (start_v, pm->ps->velocity);

	PM_SlideMove(pm, pml, gravity);

	/* push down the final amount */
	copyv3 (pm->ps->origin, down);
	down[2] -= stepSize;
	pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down,
		pm->ps->clientNum,
		pm->tracemask);
	if(!trace.allsolid)
		copyv3 (trace.endpos, pm->ps->origin);
	if(trace.fraction < 1.0f)
		PM_ClipVelocity(pm->ps->velocity, trace.plane.normal,
			pm->ps->velocity,
			OVERCLIP);

#if 0
	/* if the down trace can trace back to the original position directly, don't step */
	pm->trace(&trace, pm->ps->origin, pm->mins, pm->maxs, start_o,
		pm->ps->clientNum,
		pm->tracemask);
	if(trace.fraction == 1.0f){
		/* use the original move */
		copyv3 (down_o, pm->ps->origin);
		copyv3 (down_v, pm->ps->velocity);
		if(pm->debugLevel)
			comprintf("%u:bend\n", cnt);
	}else
#endif
	/* use the step move */
	delta = pm->ps->origin[2] - start_o[2];
	if(delta > 2){
		if(delta < 7)
			PM_AddEvent(pm, pml, EV_STEP_4);
		else if(delta < 11)
			PM_AddEvent(pm, pml, EV_STEP_8);
		else if(delta < 15)
			PM_AddEvent(pm, pml, EV_STEP_12);
		else
			PM_AddEvent(pm, pml, EV_STEP_16);
	}
	if(pm->debugLevel)
		comprintf("%u:stepped\n", cnt);
}
예제 #16
0
/*
==================
PM_StepSlideMove

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
예제 #17
0
/*
===================
PM_WalkMove

===================
*/
static void PM_WalkMove( void ) {
	int			i;
	vec3_t		wishvel;
	float		fmove, smove;
	vec3_t		wishdir;
	float		wishspeed;
	float		scale;
	usercmd_t	cmd;
	float		accelerate;
	float		vel;

	if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
		// begin swimming
		PM_WaterMove();
		return;
	}


	if ( PM_CheckJump () ) {
		// jumped away
		if ( pm->waterlevel > 1 ) {
			PM_WaterMove();
		} else {
			PM_AirMove();
		}
		return;
	}

	PM_Friction ();

	fmove = pm->cmd.forwardmove;
	smove = pm->cmd.rightmove;

	cmd = pm->cmd;
	scale = PM_CmdScale( &cmd );

	// set the movementDir so clients can rotate the legs for strafing
	PM_SetMovementDir();

	// project moves down to flat plane
	pml.forward[2] = 0;
	pml.right[2] = 0;

	// project the forward and right directions onto the ground plane
	PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
	PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
	//
	VectorNormalize (pml.forward);
	VectorNormalize (pml.right);

	for ( i = 0 ; i < 3 ; i++ ) {
		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
	}
	// when going up or down slopes the wish velocity should Not be zero
//	wishvel[2] = 0;

	VectorCopy (wishvel, wishdir);
	wishspeed = VectorNormalize(wishdir);
	wishspeed *= scale;

	// clamp the speed lower if ducking
	if ( pm->ps->pm_flags & PMF_DUCKED ) {
		if ( wishspeed > pm->ps->speed * pm_duckScale ) {
			wishspeed = pm->ps->speed * pm_duckScale;
		}
	}

	// clamp the speed lower if wading or walking on the bottom
	if ( pm->waterlevel ) {
		float	waterScale;

		waterScale = pm->waterlevel / 3.0;
		waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
		if ( wishspeed > pm->ps->speed * waterScale ) {
			wishspeed = pm->ps->speed * waterScale;
		}
	}

	// when a player gets hit, they temporarily lose
	// full control, which allows them to be moved a bit
	if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
		accelerate = pm_airaccelerate;
	} else {
		accelerate = pm_accelerate;
	}

	PM_Accelerate (wishdir, wishspeed, accelerate);

	//Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
	//Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));

	if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
		pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
	} else {
		// don't reset the z velocity for slopes
//		pm->ps->velocity[2] = 0;
	}

	vel = VectorLength(pm->ps->velocity);

	// slide along the ground plane
	PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
		pm->ps->velocity, OVERCLIP );

	// don't decrease velocity when going up or down a slope
	VectorNormalize(pm->ps->velocity);
	VectorScale(pm->ps->velocity, vel, pm->ps->velocity);

	// don't do anything if standing still
	if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
		return;
	}

	PM_StepSlideMove( qfalse );

	//Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));

}
예제 #18
0
qboolean	PM_SlideMove( qboolean gravity ) {
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		normal, planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;
	//qboolean	damageSelf = qtrue;
	
	numbumps = 4;

	VectorCopy (pm->ps->velocity, primal_velocity);
	VectorCopy (pm->ps->velocity, endVelocity);

	if ( gravity ) {
		endVelocity[2] -= pm->ps->gravity * pml.frametime;
		pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
		primal_velocity[2] = endVelocity[2];
		if ( pml.groundPlane ) {
			if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
			{// slide along the ground plane
				PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
					pm->ps->velocity, OVERCLIP );
			}
		}
	}

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane ) {
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[0] );
		if ( !PM_GroundSlideOkay( planes[0][2] ) )
		{
			planes[0][2] = 0;
			VectorNormalize( planes[0] );
		}
	} else {
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[numplanes] );
	numplanes++;

	for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {

		// calculate position we are trying to move to
		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

		// see if we can make it there
		pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); //Normal player tracemask is SOLID,PLAYERCLIP,BODY,TERRAIN

		if (trace.allsolid) {
			// entity is completely trapped in another solid
			pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration. wallbug!?
			return qtrue;
		}

		if (trace.fraction > 0) {
			// actually covered some distance
			VectorCopy (trace.endpos, pm->ps->origin);
		}

		if (trace.fraction == 1) {
			 break;		// moved the entire distance
		}

		// save entity for contact
		PM_AddTouchEnt( trace.entityNum );

		if (pm->ps->clientNum >= MAX_CLIENTS)
		{
			bgEntity_t *pEnt = pm_entSelf;

			if (pEnt && pEnt->s.eType == ET_NPC && pEnt->s.NPC_class == CLASS_VEHICLE &&
				pEnt->m_pVehicle)
			{ //do vehicle impact stuff then
				if (!pEnt->playerState->stats[STAT_RACEMODE])
					PM_VehicleImpact(pEnt, &trace);
			}
		}
#ifdef _GAME
		else
		{
			if ( PM_ClientImpact( &trace ) )
			{
				continue;
			}
		}
#endif

		time_left -= time_left * trace.fraction;

		if (numplanes >= MAX_CLIP_PLANES) {
			// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return qtrue;
		}

		VectorCopy( trace.plane.normal, normal );

		if ( !PM_GroundSlideOkay( normal[2] ) )
		{//wall-running
			//never push up off a sloped wall
			normal[2] = 0;
			VectorNormalize( normal );
		}
		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
		{//no sliding if stuck to wall!
			for ( i = 0 ; i < numplanes ; i++ ) {
				if ( VectorCompare( normal, planes[i] ) ) {//DotProduct( normal, planes[i] ) > 0.99 ) {
					VectorAdd( normal, pm->ps->velocity, pm->ps->velocity );
					break;
				}
			}
			if ( i < numplanes ) {
				continue;
			}
		}
		VectorCopy (normal, planes[numplanes]);
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) {
			into = DotProduct( pm->ps->velocity, planes[i] );
			if ( into >= 0.1 ) {
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) {
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

			// slide along the plane
			PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

			// see if there is a second plane that the new move enters
			for ( j = 0 ; j < numplanes ; j++ ) {
				if ( j == i ) {
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the new move enters
				for ( k = 0 ; k < numplanes ; k++ ) {
					if ( k == i || k == j ) {
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a triple plane interaction
					VectorClear( pm->ps->velocity );
					return qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
	}

	if ( gravity ) {
		VectorCopy( endVelocity, pm->ps->velocity );
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time ) {
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

	return ( bumpcount != 0 );
}
예제 #19
0
/*
===================
MoveCmdToDesiredDir

Given a movement command, computes the desired
direction and speed of that movement, projected
onto the ground plane (if any).  The unitized
direction is stored in the "dir" vector and the
speed (magnitude) is the function's return value.

"axies" are the forward, right, and up axial direction
vectors for movement.  Note that the up direction
vector isn't actually used.

"physics" is the physics description that
applies to this command set.

"max_speed" is the entity's maximum movement speed.
That is, it's the velocity in units per second if
the command's forward move value is 127.

"water_level" is the entity's water level (1 for
wading, 2 for chest deep, 3 for immersed, 0 for no
water).  Presumably if the water level is 2 or higher,
the physics type will be PHYS_WATER, although this
isn't guaranteed.

FIXME: This function's interface could be simplified
if just a motion state pointer was passed in instead
of the user command, axies, maximum speed, and water
level.  The downside is that the user command and
axies would either need to be recomputed each call
or stored in the motion state.  One of these options
uses more processing time that necessary and the other
uses more memory than necessary.  Still, it might be
in the interest of cleanliness to spend more time or
memory for this purpose.  Or it might not.
===================
*/
float MoveCmdToDesiredDir(usercmd_t *cmd, vec3_t *axies, physics_t *physics,
						  float max_speed, float water_level, vec3_t move_dir)
{
	int i, max_cmd_speed;
	float scale, move_speed;
	float wade_drag, max_wade_speed;
	vec3_t forward, right;

	// The axial directions may need to be modified (projected onto the XY
	// plane), so this local copy guarantees the inputted vectors will
	// remain unchanged
	VectorCopy(axies[0], forward);
	VectorCopy(axies[1],   right);

	// Compute the speed conversion factor from the movement commands to the actual speed
	//
	// NOTE: This code is based on PM_CmdScale() from bg_pmove.c.
	max_cmd_speed = fabs(cmd->forwardmove);
	if (max_cmd_speed < fabs(cmd->rightmove))
		max_cmd_speed = fabs(cmd->rightmove);
	if (max_cmd_speed < fabs(cmd->upmove))
		max_cmd_speed = fabs(cmd->upmove);

	if (max_cmd_speed > 0)
		scale = (max_speed * max_cmd_speed) /
				(127.0 * sqrt(Square(cmd->forwardmove) +
							  Square(cmd->rightmove) +
							  Square(cmd->upmove)));
	else
		scale = 0;

	// Compute the velocity vector this set of movement commands translates to
	//
	// NOTE: This code is based in part on PM_WalkMove(), PM_WaterMove(),
	// PM_AirMove(), and PM_FlyMove() from from bg_pmove.c.

	// Air movement and ground movement require some special setup
	if ( (physics->type == PHYS_GRAVITY) ||
		 (physics->type == PHYS_GROUND) )
	{
		// When doing air movement and normal walking, project the movement on the X-Y plane
		forward[2] = 0.0;
		right[2] = 0.0;

		// When moving on the ground, project movement onto the angle of the ground plane
		//
		// NOTE: This is one of the few functions in bg_pmove.c that can be called
		// by outside functions.
		//
		// NOTE: It *IS* correct that these clippings occur before the
		// renormalization required by projecting the forward and right
		// vectors to the X-Y plane.  This may be a bug in bg_pmove.c, but
		// even in that case, this code is bug compliant.
		//
		// NOTE: It is intentional that this code checks specifically for
		// ground physics, even though there could be a (very steep) ground
		// normal in the gravity case.  This strikes me as a bug in the
		// bg_pmove.c code but...  Again, this code is just bug compliant.
		if (physics->type == PHYS_GROUND)
		{
			PM_ClipVelocity(forward, physics->ground, forward, OVERCLIP);
			PM_ClipVelocity(  right, physics->ground,   right, OVERCLIP);
		}

		// These direction vectors must be normalized again
		VectorNormalize(forward);
		VectorNormalize(  right);
	}

	// The entity can sink when in water
	if ( (scale <= 0) && (physics->type == PHYS_WATER) )
	{
		VectorSet(move_dir, 0, 0, -1);
		move_speed = 60.0;
	}

	// Otherwise compute the velocity normally
	else
	{
		// Project movement commands in each axis direction
		for (i = 0; i < 3; i++)
			move_dir[i] = forward[i] * cmd->forwardmove +
							right[i] * cmd->rightmove;

		// Also apply the upward movement if the entity's situation allows it
		if ( (physics->type == PHYS_WATER) || (physics->type == PHYS_FLIGHT) )
			move_dir[2] += cmd->upmove;

		// Compute the movement speed in that direction and normalize the velocity
		//
		// NOTE: Technically it would be more precise to just normalize the movement
		// direction and then multiply the movement speed by the scale.  Unfortunately,
		// the server code does the operation like this, and the rest of the physics
		// depends on this imprecision, so it must be copied here as well.
		VectorScale(move_dir, scale, move_dir);
		move_speed = VectorNormalize(move_dir);
	}

	// The player has a lower top speed when in water
	if ( (physics->type == PHYS_WATER) &&
		 (move_speed > max_speed * pm_swimScale) )
	{
		move_speed = max_speed * pm_swimScale;
	}

	// Crouching on the ground also lowers top speed
	if ( (cmd->upmove < 0) &&
		 (physics->type == PHYS_GROUND) &&
		 (move_speed > max_speed * pm_duckScale) )
	{
		move_speed = max_speed * pm_duckScale;
	}

	// Wading in water lowers top speed
	if ( (water_level > 0) &&
		 (physics->type == PHYS_GROUND) )
	{
		// Compute the percentage of maximum speed lost from wading in water
		wade_drag = (1.0 - pm_swimScale) * (water_level / 3.0);

		// Compute the maximum speed allowed due to water drag
		max_wade_speed = max_speed * (1.0 - wade_drag);

		// Lower the top speed if it exceeds this new maximum speed
		if (move_speed > max_wade_speed)
			move_speed = max_wade_speed;
	}

	// Return the computed movement speed
	return move_speed;
}
예제 #20
0
void PM_StepSlideMove( qboolean gravity ) { 
	vec3_t		start_o, start_v;
	vec3_t		down_o, down_v;
	trace_t		trace;
//	float		down_dist, up_dist;
//	vec3_t		delta, delta2;
	vec3_t		up, down;
	float		stepSize;
	qboolean	isGiant = qfalse;
	bgEntity_t	*pEnt;
	qboolean skipStep = qfalse;
	int NEW_STEPSIZE = STEPSIZE;
	const int moveStyle = PM_GetMovePhysics();

	if (moveStyle == MV_CPM || moveStyle == MV_Q3 || moveStyle == MV_WSW || moveStyle == MV_RJQ3 || moveStyle == MV_RJCPM || moveStyle == MV_SLICK || moveStyle == MV_BOTCPM) {
		if (pm->ps->velocity[2] > 0 && pm->cmd.upmove > 0) {
			int jumpHeight = pm->ps->origin[2] - pm->ps->fd.forceJumpZStart;

			if (jumpHeight > 48)
				jumpHeight = 48;
			else if (jumpHeight < 22)
				jumpHeight = 22;

			NEW_STEPSIZE = 48 - jumpHeight + 22;

			//trap->SendServerCommand(-1, va("print \"new stepsize: %i, expected max end height: %i\n\"", NEW_STEPSIZE, NEW_STEPSIZE + (int)(pm->ps->origin[2] - pm->ps->fd.forceJumpZStart)));
			
			//This means that we can always clip things up to 48 units tall, if we are moving up when we hit it and from a bhop..
			//It means we can sometimes clip things up to 70 units tall, if we hit it in right part of jump
			//Should it be higher..? some of the things in q3 are 56 units tall..

			//NEW_STEPSIZE = 46;
			//Make stepsize equal to.. our current 48 - our current jumpheight ?
		}
		else 
			NEW_STEPSIZE = 22;
	}

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

	if ( BG_InReboundHold( pm->ps->legsAnim ) )
	{
		gravity = qfalse;
	}

	if ( PM_SlideMove( gravity ) == 0 ) {
		return;		// we got exactly where we wanted to go first try, nospeed ramp returns here maybe	
	}

	pEnt = pm_entSelf;

	if (pm->ps->clientNum >= MAX_CLIENTS)
	{
		if (pEnt && pEnt->s.NPC_class == CLASS_VEHICLE &&
			pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->hoverHeight > 0)
		{
			return;
		}
	}

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

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

	VectorCopy (start_o, up);

	if (pm->ps->clientNum >= MAX_CLIENTS)
	{
		// apply ground friction, even if on ladder
		if (pEnt &&
			(pEnt->s.NPC_class == CLASS_ATST ||
			(pEnt->s.NPC_class == CLASS_VEHICLE && pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->type == VH_WALKER) ) )
		{//AT-STs can step high
			up[2] += 66.0f;
			isGiant = qtrue;
		}
		else if ( pEnt && pEnt->s.NPC_class == CLASS_RANCOR )
		{//also can step up high
			up[2] += 64.0f;
			isGiant = qtrue;
		}
		else
		{
			up[2] += NEW_STEPSIZE;
		}
	}
	else
	{
		up[2] += NEW_STEPSIZE;
	}

	// test the player position if they were a stepheight higher
	pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
	if ( trace.allsolid ) {
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend can't step\n", c_pmove);
		}
		return;		// can't step up, nospeed ramp returns here maybe
	}

	stepSize = trace.endpos[2] - start_o[2];
	// try slidemove from this position
	VectorCopy (trace.endpos, pm->ps->origin);
	VectorCopy (start_v, pm->ps->velocity);

	PM_SlideMove( gravity );

	pml.clipped = qtrue; //nospeed ramp fix, if we made it to this point there wont be a nospeed ramp

	// push down the final amount
	VectorCopy (pm->ps->origin, down);
	down[2] -= stepSize;
	pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);

	if ( pm->stepSlideFix )
	{
		if ( pm->ps->clientNum < MAX_CLIENTS
			&& trace.plane.normal[2] < MIN_WALK_NORMAL )
		{//normal players cannot step up slopes that are too steep to walk on!
			vec3_t stepVec;
			//okay, the step up ends on a slope that it too steep to step up onto,
			//BUT:
			//If the step looks like this:
			//  (B)\__
			//        \_____(A)
			//Then it might still be okay, so we figure out the slope of the entire move
			//from (A) to (B) and if that slope is walk-upabble, then it's okay
			VectorSubtract( trace.endpos, down_o, stepVec );
			VectorNormalize( stepVec ); 
			if ( stepVec[2] > (1.0f-MIN_WALK_NORMAL) )
			{
				skipStep = qtrue;
			}
		}
	}

	if ( !trace.allsolid 
		&& !skipStep ) //normal players cannot step up slopes that are too steep to walk on!
	{ 
		if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
			&& isGiant 
			&& trace.entityNum < MAX_CLIENTS
			&& pEnt 
			&& pEnt->s.NPC_class == CLASS_RANCOR )
		{//Rancor don't step on clients
			if ( pm->stepSlideFix )
			{
				VectorCopy (down_o, pm->ps->origin);
				VectorCopy (down_v, pm->ps->velocity);
			}
			else
			{
				VectorCopy (start_o, pm->ps->origin);
				VectorCopy (start_v, pm->ps->velocity);
			}
		}
		/*
		else if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
			&& isGiant 
			&& trace.entityNum < MAX_CLIENTS
			&& pEnt 
			&& pEnt->s.NPC_class == CLASS_ATST 
			&& OnSameTeam( pEnt, traceEnt) )
		{//NPC AT-ST's don't step up on allies
			VectorCopy (start_o, pm->ps->origin);
			VectorCopy (start_v, pm->ps->velocity);
		}
		*/
		else
		{
			VectorCopy (trace.endpos, pm->ps->origin);
			if (pm->stepSlideFix)
			{
				if (trace.fraction < 1.0) {
					if (moveStyle == MV_WSW || moveStyle == MV_SLICK) { //Make Warsow Rampjump not slow down your XY speed
						vec3_t oldVel, clipped_velocity, newVel;
						float oldSpeed, newSpeed;

						VectorCopy(pm->ps->velocity, oldVel);
						oldSpeed = oldVel[0] * oldVel[0] + oldVel[1] * oldVel[1]; 

						PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, clipped_velocity, OVERCLIP ); //WSW RAMPJUMP 3

						VectorCopy(clipped_velocity, newVel);
						newVel[2] = 0;
						newSpeed = newVel[0] * newVel[0] + newVel[1] * newVel[1]; 

						if (newSpeed > oldSpeed)
							VectorCopy(clipped_velocity, pm->ps->velocity);
					}
					else {
						PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
					}
				}
			}
		}
	}
	else
	{
		if ( pm->stepSlideFix )
		{
			VectorCopy (down_o, pm->ps->origin);
			VectorCopy (down_v, pm->ps->velocity);
		}
	}
	if ( !pm->stepSlideFix )
	{
		if ( trace.fraction < 1.0 ) {
			if (moveStyle == MV_WSW || moveStyle == MV_SLICK) {
				vec3_t oldVel, clipped_velocity, newVel;
				float oldSpeed, newSpeed;

				VectorCopy(pm->ps->velocity, oldVel);
				oldSpeed = oldVel[0] * oldVel[0] + oldVel[1] * oldVel[1]; 

				PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, clipped_velocity, OVERCLIP ); //WSW RAMPJUMP 2

				VectorCopy(clipped_velocity, newVel);
				newVel[2] = 0;
				newSpeed = newVel[0] * newVel[0] + newVel[1] * newVel[1]; 

				if (newSpeed > oldSpeed)
					VectorCopy(clipped_velocity, pm->ps->velocity);
			}
			else {
				PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
			}
		}
	}

#if 0
	// if the down trace can trace back to the original position directly, don't step
	pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
	if ( trace.fraction == 1.0 ) {
		// use the original move
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend\n", c_pmove);
		}
	} else 
#endif
	{
		// use the step move
		float	delta;

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
예제 #21
0
/*
==================
PM_StepSlideMove

==================
*/
void PM_StepSlideMove(qboolean gravity) {
    vec3_t      start_o, start_v;
    //  vec3_t      down_o, down_v;
    trace_t     trace;
    //  float       down_dist, up_dist;
    //  vec3_t      delta, delta2;
    vec3_t      up, down;
    float       stepSize;

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

    if (PM_SlideMove(gravity) == 0) {
        return;     // we got exactly where we wanted to go first try
    }

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

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

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

    // test the player position if they were a stepheight higher
    pm->trace(&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
    if (trace.allsolid) {
        if (pm->debugLevel) {
            Com_Printf("%i:bend can't step\n", c_pmove);
        }
        return;     // can't step up
    }

    stepSize = trace.endpos[2] - start_o[2];
    // try slidemove from this position
    VectorCopy(trace.endpos, pm->ps->origin);
    VectorCopy(start_v, pm->ps->velocity);

    PM_SlideMove(gravity);

    // push down the final amount
    VectorCopy(pm->ps->origin, down);
    down[2] -= stepSize;
    pm->trace(&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
    if (!trace.allsolid) {
        VectorCopy(trace.endpos, pm->ps->origin);
    }
    if (trace.fraction < 1.0) {
        PM_ClipVelocity(pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP);
    }

#if 0
    // if the down trace can trace back to the original position directly, don't step
    pm->trace(&trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
    if (trace.fraction == 1.0) {
        // use the original move
        VectorCopy(down_o, pm->ps->origin);
        VectorCopy(down_v, pm->ps->velocity);
        if (pm->debugLevel) {
            Com_Printf("%i:bend\n", c_pmove);
        }
    } else
#endif
    {
        // use the step move
        float   delta;

        delta = pm->ps->origin[2] - start_o[2];
        if (delta > 2) {
            if (delta < 7) {
                PM_AddEvent(EV_STEP_4);
            } else if (delta < 11) {
                PM_AddEvent(EV_STEP_8);
            } else if (delta < 15) {
                PM_AddEvent(EV_STEP_12);
            } else {
                PM_AddEvent(EV_STEP_16);
            }
        }
        if (pm->debugLevel) {
            Com_Printf("%i:stepped\n", c_pmove);
        }
    }
}
예제 #22
0
/*
==================
PM_StepSlideMove

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

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

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

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

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

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

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

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

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

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

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

	cantStepUpFwd = PM_SlideMove( gravMod );

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

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

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
예제 #23
0
qboolean  PM_SlideMove( qboolean gravity )
{
	int     bumpcount, numbumps;
	vec3_t  dir;
	float   d;
	int     numplanes;
	vec3_t  planes[ MAX_CLIP_PLANES ];
	vec3_t  primal_velocity;
	vec3_t  clipVelocity;
	int     i, j, k;
	trace_t trace;
	vec3_t  end;
	float   time_left;
	float   into;
	vec3_t  endVelocity;
	vec3_t  endClipVelocity;

	numbumps = 4;

	VectorCopy( pm->ps->velocity, primal_velocity );
	VectorCopy( pm->ps->velocity, endVelocity );

	if ( gravity )
	{
		endVelocity[ 2 ] -= pm->ps->gravity * pml.frametime;
		pm->ps->velocity[ 2 ] = ( pm->ps->velocity[ 2 ] + endVelocity[ 2 ] ) * 0.5;
		primal_velocity[ 2 ] = endVelocity[ 2 ];

		if ( pml.groundPlane )
		{
			// slide along the ground plane
			PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
		}
	}

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane )
	{
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[ 0 ] );
	}
	else
	{
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[ numplanes ] );
	numplanes++;

	for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ )
	{
		// calculate position we are trying to move to
		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

		// see if we can make it there
		pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask );

		if ( trace.allsolid )
		{
			// entity is completely trapped in another solid
			pm->ps->velocity[ 2 ] = 0; // don't build up falling damage, but allow sideways acceleration
			return qtrue;
		}

		if ( trace.fraction > 0 )
		{
			// actually covered some distance
			VectorCopy( trace.endpos, pm->ps->origin );
		}

		if ( trace.fraction == 1 )
		{
			break; // moved the entire distance
		}

		// save entity for contact
		PM_AddTouchEnt( trace.entityNum );

		time_left -= time_left * trace.fraction;

		if ( numplanes >= MAX_CLIP_PLANES )
		{
			// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return qtrue;
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		for ( i = 0; i < numplanes; i++ )
		{
			if ( DotProduct( trace.plane.normal, planes[ i ] ) > 0.99 )
			{
				VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
				break;
			}
		}

		if ( i < numplanes )
		{
			continue;
		}

		VectorCopy( trace.plane.normal, planes[ numplanes ] );
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0; i < numplanes; i++ )
		{
			into = DotProduct( pm->ps->velocity, planes[ i ] );

			if ( into >= 0.1 )
			{
				continue; // move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed )
			{
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity );

			// slide along the plane
			PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity );

			// see if there is a second plane that the new move enters
			for ( j = 0; j < numplanes; j++ )
			{
				if ( j == i )
				{
					continue;
				}

				if ( DotProduct( clipVelocity, planes[ j ] ) >= 0.1 )
				{
					continue; // move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity );
				PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[ i ] ) >= 0 )
				{
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct( planes[ i ], planes[ j ], dir );
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

				CrossProduct( planes[ i ], planes[ j ], dir );
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the new move enters
				for ( k = 0; k < numplanes; k++ )
				{
					if ( k == i || k == j )
					{
						continue;
					}

					if ( DotProduct( clipVelocity, planes[ k ] ) >= 0.1 )
					{
						continue; // move doesn't interact with the plane
					}

					// stop dead at a tripple plane interaction
					VectorClear( pm->ps->velocity );
					return qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
	}

	if ( gravity )
	{
		VectorCopy( endVelocity, pm->ps->velocity );
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time )
	{
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

	return ( bumpcount != 0 );
}
예제 #24
0
bool  PM_SlideMove( bool gravity )
#endif
{
	int     bumpcount, numbumps;
#ifdef UNREALARENA
	int     fallingcount = 0;
#endif
	vec3_t  dir;
	float   d;
	int     numplanes;
	vec3_t  planes[ MAX_CLIP_PLANES ];
	vec3_t  primal_velocity;
	vec3_t  clipVelocity;
	int     i, j, k;
	trace_t trace;
	vec3_t  end;
	float   time_left;
	float   into;
	vec3_t  endVelocity;
	vec3_t  endClipVelocity;

	numbumps = 4;

	VectorCopy( pm->ps->velocity, primal_velocity );
#ifndef UNREALARENA
	VectorCopy( pm->ps->velocity, endVelocity );
#endif

	if ( gravity )
	{
#ifdef UNREALARENA
		VectorCopy( pm->ps->velocity, endVelocity );
#endif
		endVelocity[ 2 ] -= pm->ps->gravity * pml.frametime;
		pm->ps->velocity[ 2 ] = ( pm->ps->velocity[ 2 ] + endVelocity[ 2 ] ) * 0.5;
		primal_velocity[ 2 ] = endVelocity[ 2 ];

		if ( pml.groundPlane )
		{
			// slide along the ground plane
			PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity );
		}
	}

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane )
	{
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[ 0 ] );
	}
	else
	{
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[ numplanes ] );
	numplanes++;

	for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ )
	{
		// calculate position we are trying to move to
		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

		// see if we can make it there
		// spectators ignore movers, so that they can noclip through doors
		pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum,
		           pm->tracemask, ( pm->ps->pm_type == PM_SPECTATOR ) ? CONTENTS_MOVER : 0 );

		if ( trace.allsolid )
		{
			// entity is completely trapped in another solid
			pm->ps->velocity[ 2 ] = 0; // don't build up falling damage, but allow sideways acceleration
			return true;
		}

		if ( trace.fraction > 0 )
		{
#ifdef UNREALARENA
			vec3_t pos;

			VectorCopy( trace.endpos, pos );

			pos[ 2 ] -= stepsize;

			if ( PM_CheckFallingFromLedge( pos ) )
			{
				vec3_t normal;

				// using pos in place of trace.endpos as it should give better results
				PM_FindLedgeNormal( pm->ps->origin, pos, normal );

				// if we can't determine the ledge plane then stop everything
				if ( normal[ 0 ] == 0.0f &&
				     normal[ 1 ] == 0.0f &&
				     normal[ 2 ] == 0.0f )
				{
					VectorClear( pm->ps->velocity );
					fallingcount++;

					break;
				}

				// slide along the ledge plane
				PM_ClipVelocity( pm->ps->velocity, normal, pm->ps->velocity );
				fallingcount++;

				continue;
			}
#endif
			// actually covered some distance
			VectorCopy( trace.endpos, pm->ps->origin );
		}

		if ( trace.fraction == 1 )
		{
			break; // moved the entire distance
		}

		// save entity for contact
		PM_AddTouchEnt( trace.entityNum );

		time_left -= time_left * trace.fraction;

		if ( numplanes >= MAX_CLIP_PLANES )
		{
			// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return true;
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		for ( i = 0; i < numplanes; i++ )
		{
			if ( DotProduct( trace.plane.normal, planes[ i ] ) > 0.99 )
			{
				VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
				break;
			}
		}

		if ( i < numplanes )
		{
			continue;
		}

		VectorCopy( trace.plane.normal, planes[ numplanes ] );
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0; i < numplanes; i++ )
		{
			into = DotProduct( pm->ps->velocity, planes[ i ] );

			if ( into >= 0.1 )
			{
				continue; // move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed )
			{
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity );

#ifdef UNREALARENA
			if ( gravity )
			{
				// slide along the plane
				PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity );
			}
#else
			// slide along the plane
			PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity );
#endif

			// see if there is a second plane that the new move enters
			for ( j = 0; j < numplanes; j++ )
			{
				if ( j == i )
				{
					continue;
				}

				if ( DotProduct( clipVelocity, planes[ j ] ) >= 0.1 )
				{
					continue; // move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity );
#ifdef UNREALARENA
				if ( gravity )
				{
					PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity );
				}
#else
				PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity );
#endif

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[ i ] ) >= 0 )
				{
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct( planes[ i ], planes[ j ], dir );
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

#ifdef UNREALARENA
				if ( gravity )
				{
					CrossProduct( planes[ i ], planes[ j ], dir );
					VectorNormalize( dir );
					d = DotProduct( dir, endVelocity );
					VectorScale( dir, d, endClipVelocity );
				}
#else
				CrossProduct( planes[ i ], planes[ j ], dir );
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );
#endif

				// see if there is a third plane the new move enters
				for ( k = 0; k < numplanes; k++ )
				{
					if ( k == i || k == j )
					{
						continue;
					}

					if ( DotProduct( clipVelocity, planes[ k ] ) >= 0.1 )
					{
						continue; // move doesn't interact with the plane
					}

					// stop dead at a tripple plane interaction
					VectorClear( pm->ps->velocity );
					return true;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
#ifdef UNREALARENA
			if ( gravity )
			{
				VectorCopy( endClipVelocity, endVelocity );
			}
#else
			VectorCopy( endClipVelocity, endVelocity );
#endif
			break;
		}
	}

	if ( gravity )
	{
		VectorCopy( endVelocity, pm->ps->velocity );
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time )
	{
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

#ifdef UNREALARENA
	bumpcount -= fallingcount;
#endif
	return ( bumpcount != 0 );
}