Example #1
0
// predicts the movement
//	assumes regular bounding box sizes
//	NOTE: out of water jumping is not included
//	NOTE: grappling hook is not included
//	origin			origin to start with
//	presencetype	presence type to start with
//	velocity		velocity to start with
//	cmdmove			client command movement
//	cmdframes		number of frame cmdmove is valid
//	maxframes		maximum number of predicted frames
//	frametime		duration of one predicted frame
//	stopevent		events that stop the prediction
//	stopareanum		stop as soon as entered this area
int AAS_ClientMovementPrediction(struct aas_clientmove_s *move,
								int entnum, vector3 *origin,
								int presencetype, int onground,
								vector3 *velocity, vector3 *cmdmove,
								int cmdframes,
								int maxframes, float frametime,
								int stopevent, int stopareanum,
								vector3 *mins, vector3 *maxs, int visualize)
{
	float phys_friction, phys_stopspeed, phys_gravity, phys_waterfriction;
	float phys_watergravity;
	float phys_walkaccelerate, phys_airaccelerate, phys_swimaccelerate;
	float phys_maxwalkvelocity, phys_maxcrouchvelocity, phys_maxswimvelocity;
	float phys_maxstep, phys_maxsteepness, phys_jumpvel, friction;
	float gravity, delta, maxvel, wishspeed, accelerate;
	//float velchange, newvel;
	//int ax;
	int n, i, j, pc, step, swimming, crouch, event, jump_frame, areanum;
	int areas[20], numareas;
	vector3 points[20];
	vector3 org, end, feet, start, stepend, lastorg, wishdir;
	vector3 frame_test_vel, old_frame_test_vel, left_test_vel;
	vector3 up = {0, 0, 1};
	aas_plane_t *plane, *plane2;
	aas_trace_t trace, steptrace;
	
	if (frametime <= 0) frametime = 0.1f;
	//
	phys_friction = aassettings.phys_friction;
	phys_stopspeed = aassettings.phys_stopspeed;
	phys_gravity = aassettings.phys_gravity;
	phys_waterfriction = aassettings.phys_waterfriction;
	phys_watergravity = aassettings.phys_watergravity;
	phys_maxwalkvelocity = aassettings.phys_maxwalkvelocity;// * frametime;
	phys_maxcrouchvelocity = aassettings.phys_maxcrouchvelocity;// * frametime;
	phys_maxswimvelocity = aassettings.phys_maxswimvelocity;// * frametime;
	phys_walkaccelerate = aassettings.phys_walkaccelerate;
	phys_airaccelerate = aassettings.phys_airaccelerate;
	phys_swimaccelerate = aassettings.phys_swimaccelerate;
	phys_maxstep = aassettings.phys_maxstep;
	phys_maxsteepness = aassettings.phys_maxsteepness;
	phys_jumpvel = aassettings.phys_jumpvel * frametime;
	//
	memset(move, 0, sizeof(aas_clientmove_t));
	memset(&trace, 0, sizeof(aas_trace_t));
	//start at the current origin
	VectorCopy(origin, &org);
	org.z += 0.25f;
	//velocity to test for the first frame
	VectorScale(velocity, frametime, &frame_test_vel);
	//
	jump_frame = -1;
	//predict a maximum of 'maxframes' ahead
	for (n = 0; n < maxframes; n++)
	{
		swimming = AAS_Swimming(&org);
		//get gravity depending on swimming or not
		gravity = swimming ? phys_watergravity : phys_gravity;
		//apply gravity at the START of the frame
		frame_test_vel.z = frame_test_vel.z - (gravity * 0.1f * frametime);
		//if on the ground or swimming
		if (onground || swimming)
		{
			friction = swimming ? phys_friction : phys_waterfriction;
			//apply friction
			VectorScale(&frame_test_vel, 1/frametime, &frame_test_vel);
			AAS_ApplyFriction(&frame_test_vel, friction, phys_stopspeed, frametime);
			VectorScale(&frame_test_vel, frametime, &frame_test_vel);
		}
		crouch = qfalse;
		//apply command movement
		if (n < cmdframes)
		{
			//ax = 0;
			maxvel = phys_maxwalkvelocity;
			accelerate = phys_airaccelerate;
			VectorCopy(cmdmove, &wishdir);
			if (onground)
			{
				if (cmdmove->z < -300)
				{
					crouch = qtrue;
					maxvel = phys_maxcrouchvelocity;
				}
				//if not swimming and upmove is positive then jump
				if (!swimming && cmdmove->z > 1)
				{
					//jump velocity minus the gravity for one frame + 5 for safety
					frame_test_vel.z = phys_jumpvel - (gravity * 0.1f * frametime) + 5;
					jump_frame = n;
					//jumping so air accelerate
					accelerate = phys_airaccelerate;
				}
				else
				{
					accelerate = phys_walkaccelerate;
				}
				//ax = 2;
			}
			if (swimming)
			{
				maxvel = phys_maxswimvelocity;
				accelerate = phys_swimaccelerate;
				//ax = 3;
			}
			else
			{
				wishdir.z = 0;
			}
			//
			wishspeed = VectorNormalize(&wishdir);
			if (wishspeed > maxvel) wishspeed = maxvel;
			VectorScale(&frame_test_vel, 1/frametime, &frame_test_vel);
			AAS_Accelerate(&frame_test_vel, frametime, &wishdir, wishspeed, accelerate);
			VectorScale(&frame_test_vel, frametime, &frame_test_vel);
			/*
			for (i = 0; i < ax; i++)
			{
				velchange = (cmdmove[i] * frametime) - frame_test_vel[i];
				if (velchange > phys_maxacceleration) velchange = phys_maxacceleration;
				else if (velchange < -phys_maxacceleration) velchange = -phys_maxacceleration;
				newvel = frame_test_vel[i] + velchange;
				//
				if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel;
				else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel;
				else frame_test_vel[i] = newvel;
			}
			*/
		}
		if (crouch)
		{
			presencetype = PRESENCE_CROUCH;
		}
		else if (presencetype == PRESENCE_CROUCH)
		{
			if (AAS_PointPresenceType(&org) & PRESENCE_NORMAL)
			{
				presencetype = PRESENCE_NORMAL;
			}
		}
		//save the current origin
		VectorCopy(&org, &lastorg);
		//move linear during one frame
		VectorCopy(&frame_test_vel, &left_test_vel);
		j = 0;
		do
		{
			VectorAdd(&org, &left_test_vel, &end);
			//trace a bounding box
			trace = AAS_TraceClientBBox(&org, &end, presencetype, entnum);
			//
//#ifdef AAS_MOVE_DEBUG
			if (visualize)
			{
				if (trace.startsolid) botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n");
				AAS_DebugLine(&org, &trace.endpos, LINECOLOR_RED);
			}
//#endif //AAS_MOVE_DEBUG
			//
			if (stopevent & (SE_ENTERAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_TOUCHCLUSTERPORTAL))
			{
				numareas = AAS_TraceAreas(&org, &trace.endpos, areas, points, 20);
				for (i = 0; i < numareas; i++)
				{
					if (stopevent & SE_ENTERAREA)
					{
						if (areas[i] == stopareanum)
						{
							VectorCopy(&points[i], &move->endpos);
							VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
							move->endarea = areas[i];
							move->trace = trace;
							move->stopevent = SE_ENTERAREA;
							move->presencetype = presencetype;
							move->endcontents = 0;
							move->time = n * frametime;
							move->frames = n;
							return qtrue;
						}
					}
					//NOTE: if not the first frame
					if ((stopevent & SE_TOUCHJUMPPAD) && n)
					{
						if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_JUMPPAD)
						{
							VectorCopy(&points[i], &move->endpos);
							VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
							move->endarea = areas[i];
							move->trace = trace;
							move->stopevent = SE_TOUCHJUMPPAD;
							move->presencetype = presencetype;
							move->endcontents = 0;
							move->time = n * frametime;
							move->frames = n;
							return qtrue;
						}
					}
					if (stopevent & SE_TOUCHTELEPORTER)
					{
						if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_TELEPORTER)
						{
							VectorCopy(&points[i], &move->endpos);
							move->endarea = areas[i];
							VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
							move->trace = trace;
							move->stopevent = SE_TOUCHTELEPORTER;
							move->presencetype = presencetype;
							move->endcontents = 0;
							move->time = n * frametime;
							move->frames = n;
							return qtrue;
						}
					}
					if (stopevent & SE_TOUCHCLUSTERPORTAL)
					{
						if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_CLUSTERPORTAL)
						{
							VectorCopy(&points[i], &move->endpos);
							move->endarea = areas[i];
							VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
							move->trace = trace;
							move->stopevent = SE_TOUCHCLUSTERPORTAL;
							move->presencetype = presencetype;
							move->endcontents = 0;
							move->time = n * frametime;
							move->frames = n;
							return qtrue;
						}
					}
				}
			}
			//
			if (stopevent & SE_HITBOUNDINGBOX)
			{
				if (AAS_ClipToBBox(&trace, &org, &trace.endpos, presencetype, mins, maxs))
				{
					VectorCopy(&trace.endpos, &move->endpos);
					move->endarea = AAS_PointAreaNum(&move->endpos);
					VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
					move->trace = trace;
					move->stopevent = SE_HITBOUNDINGBOX;
					move->presencetype = presencetype;
					move->endcontents = 0;
					move->time = n * frametime;
					move->frames = n;
					return qtrue;
				}
			}
			//move the entity to the trace end point
			VectorCopy(&trace.endpos, &org);
			//if there was a collision
			if (trace.fraction < 1.0f)
			{
				//get the plane the bounding box collided with
				plane = AAS_PlaneFromNum(trace.planenum);
				//
				if (stopevent & SE_HITGROUNDAREA)
				{
					if (DotProduct(&plane->normal, &up) > phys_maxsteepness)
					{
						VectorCopy(&org, &start);
						start.z += 0.5f;
						if (AAS_PointAreaNum(&start) == stopareanum)
						{
							VectorCopy(&start, &move->endpos);
							move->endarea = stopareanum;
							VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
							move->trace = trace;
							move->stopevent = SE_HITGROUNDAREA;
							move->presencetype = presencetype;
							move->endcontents = 0;
							move->time = n * frametime;
							move->frames = n;
							return qtrue;
						}
					}
				}
				//assume there's no step
				step = qfalse;
				//if it is a vertical plane and the bot didn't jump recently
				if (plane->normal.z == 0 && (jump_frame < 0 || n - jump_frame > 2))
				{
					//check for a step
					VectorMA(&org, -0.25f, &plane->normal, &start);
					VectorCopy(&start, &stepend);
					start.z += phys_maxstep;
					steptrace = AAS_TraceClientBBox(&start, &stepend, presencetype, entnum);
					//
					if (!steptrace.startsolid)
					{
						plane2 = AAS_PlaneFromNum(steptrace.planenum);
						if (DotProduct(&plane2->normal, &up) > phys_maxsteepness)
						{
							VectorSubtract(&end, &steptrace.endpos, &left_test_vel);
							left_test_vel.z = 0;
							frame_test_vel.z = 0;
//#ifdef AAS_MOVE_DEBUG
							if (visualize)
							{
								if (steptrace.endpos.z - org.z > 0.125f)
								{
									VectorCopy(&org, &start);
									start.z = steptrace.endpos.z;
									AAS_DebugLine(&org, &start, LINECOLOR_BLUE);
								}
							}
//#endif //AAS_MOVE_DEBUG
							org.z = steptrace.endpos.z;
							step = qtrue;
						}
					}
				}
				//
				if (!step)
				{
					//velocity left to test for this frame is the projection
					//of the current test velocity into the hit plane 
					VectorMA(&left_test_vel, -DotProduct(&left_test_vel, &plane->normal), &plane->normal, &left_test_vel);
					//store the old velocity for landing check
					VectorCopy(&frame_test_vel, &old_frame_test_vel);
					//test velocity for the next frame is the projection
					//of the velocity of the current frame into the hit plane 
					VectorMA(&frame_test_vel, -DotProduct(&frame_test_vel, &plane->normal), &plane->normal, &frame_test_vel);
					//check for a landing on an almost horizontal floor
					if (DotProduct(&plane->normal, &up) > phys_maxsteepness)
					{
						onground = qtrue;
					}
					if (stopevent & SE_HITGROUNDDAMAGE)
					{
						delta = 0;
						if (old_frame_test_vel.z < 0 &&
								frame_test_vel.z > old_frame_test_vel.z &&
								!onground)
						{
							delta = old_frame_test_vel.z;
						}
						else if (onground)
						{
							delta = frame_test_vel.z - old_frame_test_vel.z;
						}
						if (delta)
						{
							delta = delta * 10;
							delta = delta * delta * 0.0001f;
							if (swimming) delta = 0;
							// never take falling damage if completely underwater
							/*
							if (ent->waterlevel == 3) return;
							if (ent->waterlevel == 2) delta *= 0.25f;
							if (ent->waterlevel == 1) delta *= 0.5f;
							*/
							if (delta > 40)
							{
								VectorCopy(&org, &move->endpos);
								move->endarea = AAS_PointAreaNum(&org);
								VectorCopy(&frame_test_vel, &move->velocity);
								move->trace = trace;
								move->stopevent = SE_HITGROUNDDAMAGE;
								move->presencetype = presencetype;
								move->endcontents = 0;
								move->time = n * frametime;
								move->frames = n;
								return qtrue;
							}
						}
					}
				}
			}
			//extra check to prevent endless loop
			if (++j > 20) return qfalse;
		//while there is a plane hit
		} while(trace.fraction < 1.0f);
		//if going down
		if (frame_test_vel.z <= 10)
		{
			//check for a liquid at the feet of the bot
			VectorCopy(&org, &feet);
			feet.z -= 22;
			pc = AAS_PointContents(&feet);
			//get event from pc
			event = SE_NONE;
			if (pc & CONTENTS_LAVA) event |= SE_ENTERLAVA;
			if (pc & CONTENTS_SLIME) event |= SE_ENTERSLIME;
			if (pc & CONTENTS_WATER) event |= SE_ENTERWATER;
			//
			areanum = AAS_PointAreaNum(&org);
			if (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA)
				event |= SE_ENTERLAVA;
			if (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME)
				event |= SE_ENTERSLIME;
			if (aasworld.areasettings[areanum].contents & AREACONTENTS_WATER)
				event |= SE_ENTERWATER;
			//if in lava or slime
			if (event & stopevent)
			{
				VectorCopy(&org, &move->endpos);
				move->endarea = areanum;
				VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
				move->stopevent = event & stopevent;
				move->presencetype = presencetype;
				move->endcontents = pc;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			}
		}
		//
		onground = AAS_OnGround(&org, presencetype, entnum);
		//if onground and on the ground for at least one whole frame
		if (onground)
		{
			if (stopevent & SE_HITGROUND)
			{
				VectorCopy(&org, &move->endpos);
				move->endarea = AAS_PointAreaNum(&org);
				VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
				move->trace = trace;
				move->stopevent = SE_HITGROUND;
				move->presencetype = presencetype;
				move->endcontents = 0;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			}
		}
		else if (stopevent & SE_LEAVEGROUND)
		{
			VectorCopy(&org, &move->endpos);
			move->endarea = AAS_PointAreaNum(&org);
			VectorScale(&frame_test_vel, 1/frametime, &move->velocity);
			move->trace = trace;
			move->stopevent = SE_LEAVEGROUND;
			move->presencetype = presencetype;
			move->endcontents = 0;
			move->time = n * frametime;
			move->frames = n;
			return qtrue;
		}
		else if (stopevent & SE_GAP)
		{
			aas_trace_t gaptrace;

			VectorCopy(&org, &start);
			VectorCopy(&start, &end);
			end.z -= 48 + aassettings.phys_maxbarrier;
			gaptrace = AAS_TraceClientBBox(&start, &end, PRESENCE_CROUCH, -1);
			//if solid is found the bot cannot walk any further and will not fall into a gap
			if (!gaptrace.startsolid)
			{
				//if it is a gap (lower than one step height)
				if (gaptrace.endpos.z < org.z - aassettings.phys_maxstep - 1)
				{
					if (!(AAS_PointContents(&end) & CONTENTS_WATER))
					{
						VectorCopy(&lastorg, &move->endpos);
						move->endarea = AAS_PointAreaNum(&lastorg);
						VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
						move->trace = trace;
						move->stopevent = SE_GAP;
						move->presencetype = presencetype;
						move->endcontents = 0;
						move->time = n * frametime;
						move->frames = n;
						return qtrue;
					}
				}
			}
		}
	}
	//
	VectorCopy(&org, &move->endpos);
	move->endarea = AAS_PointAreaNum(&org);
	VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity);
	move->stopevent = SE_NONE;
	move->presencetype = presencetype;
	move->endcontents = 0;
	move->time = n * frametime;
	move->frames = n;
	//
	return qtrue;
}
Example #2
0
//===========================================================================
// predicts the movement
// assumes regular bounding box sizes
// NOTE: out of water jumping is not included
// NOTE: grappling hook is not included
//
// Parameter:				origin			: origin to start with
//								presencetype	: presence type to start with
//								velocity			: velocity to start with
//								cmdmove			: client command movement
//								cmdframes		: number of frame cmdmove is valid
//								maxframes		: maximum number of predicted frames
//								frametime		: duration of one predicted frame
//								stopevent		: events that stop the prediction
//						stopareanum		: stop as soon as entered this area
// Returns:					aas_clientmove_t
// Changes Globals:		-
//===========================================================================
int AAS_PredictClientMovement( struct aas_clientmove_s *move,
							   int entnum, vec3_t origin,

#if !defined RTCW_ET
							   int presencetype, int onground,
#else
							   int hitent, int onground,
#endif // RTCW_XX

							   vec3_t velocity, vec3_t cmdmove,
							   int cmdframes,
							   int maxframes, float frametime,
							   int stopevent, int stopareanum, int visualize ) {
	float sv_friction, sv_stopspeed, sv_gravity, sv_waterfriction;
	float sv_watergravity;
	float sv_walkaccelerate, sv_airaccelerate, sv_swimaccelerate;
	float sv_maxwalkvelocity, sv_maxcrouchvelocity, sv_maxswimvelocity;
	float sv_maxstep, sv_maxsteepness, sv_jumpvel, friction;
	float gravity, delta, maxvel, wishspeed, accelerate;
	//float velchange, newvel;
	int n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum;
	int areas[20], numareas;

#if !defined RTCW_ET
	vec3_t points[20];
	vec3_t org, end, feet, start, stepend, lastorg, wishdir;
	vec3_t frame_test_vel, old_frame_test_vel, left_test_vel;
	vec3_t up = {0, 0, 1};
	aas_plane_t *plane, *plane2;
	aas_trace_t trace, steptrace;
#else
	vec3_t points[20], mins, maxs;
	vec3_t org, end, feet, start, stepend, lastorg, wishdir;
	vec3_t frame_test_vel, old_frame_test_vel, left_test_vel, savevel;
	vec3_t up = {0, 0, 1};
	cplane_t *plane, *plane2, *lplane;
	//aas_trace_t trace, steptrace;
	bsp_trace_t trace, steptrace;

	if ( visualize ) {

// These debugging tools are not currently available in bspc. Mad Doctor I, 1/27/2003.
#ifndef BSPC
		AAS_ClearShownPolygons();
		AAS_ClearShownDebugLines();
#endif

	}

	// don't let us succeed on interaction with area 0
	if ( stopareanum == 0 ) {
		stopevent &= ~( SE_ENTERAREA | SE_HITGROUNDAREA );
	}
#endif // RTCW_XX


	if ( frametime <= 0 ) {
		frametime = 0.1;
	}
	//
	sv_friction = aassettings.sv_friction;
	sv_stopspeed = aassettings.sv_stopspeed;
	sv_gravity = aassettings.sv_gravity;
	sv_waterfriction = aassettings.sv_waterfriction;
	sv_watergravity = aassettings.sv_watergravity;
	sv_maxwalkvelocity = aassettings.sv_maxwalkvelocity; // * frametime;
	sv_maxcrouchvelocity = aassettings.sv_maxcrouchvelocity; // * frametime;
	sv_maxswimvelocity = aassettings.sv_maxswimvelocity; // * frametime;
	sv_walkaccelerate = aassettings.sv_walkaccelerate;
	sv_airaccelerate = aassettings.sv_airaccelerate;
	sv_swimaccelerate = aassettings.sv_swimaccelerate;
	sv_maxstep = aassettings.sv_maxstep;
	sv_maxsteepness = aassettings.sv_maxsteepness;
	sv_jumpvel = aassettings.sv_jumpvel * frametime;
	//
	memset( move, 0, sizeof( aas_clientmove_t ) );

#if !defined RTCW_ET
	memset( &trace, 0, sizeof( aas_trace_t ) );
#else
	memset( &trace, 0, sizeof( bsp_trace_t ) );
	AAS_PresenceTypeBoundingBox( PRESENCE_NORMAL, mins, maxs );
#endif // RTCW_XX

	//start at the current origin
	VectorCopy( origin, org );
	org[2] += 0.25;

#if defined RTCW_ET
	// test this position, if it's in solid, move it up to adjust for capsules
	//trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum);
	trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
	while ( trace.startsolid ) {
		org[2] += 8;
		//trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum);
		trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
		if ( trace.startsolid && ( org[2] - origin[2] > 16 ) ) {
			move->stopevent = SE_NONE;
			return qfalse;
		}
	}
#endif // RTCW_XX

	//velocity to test for the first frame
	VectorScale( velocity, frametime, frame_test_vel );
	//
	jump_frame = -1;

#if defined RTCW_ET
	lplane = NULL;
#endif // RTCW_XX

	//predict a maximum of 'maxframes' ahead
	for ( n = 0; n < maxframes; n++ )
	{
		swimming = AAS_Swimming( org );
		//get gravity depending on swimming or not
		gravity = swimming ? sv_watergravity : sv_gravity;
		//apply gravity at the START of the frame
		frame_test_vel[2] = frame_test_vel[2] - ( gravity * 0.1 * frametime );
		//if on the ground or swimming
		if ( onground || swimming ) {
			friction = swimming ? sv_friction : sv_waterfriction;
			//apply friction
			VectorScale( frame_test_vel, 1 / frametime, frame_test_vel );
			AAS_ApplyFriction( frame_test_vel, friction, sv_stopspeed, frametime );
			VectorScale( frame_test_vel, frametime, frame_test_vel );
		} //end if
		crouch = qfalse;
		//apply command movement

#if !defined RTCW_ET
		if ( n < cmdframes ) {
#else
		if ( cmdframes < 0 ) {
			// cmdmove is the destination, we should keep moving towards it
			VectorSubtract( cmdmove, org, wishdir );
			VectorNormalize( wishdir );
			VectorScale( wishdir, sv_maxwalkvelocity, wishdir );
			VectorCopy( frame_test_vel, savevel );
			VectorScale( wishdir, frametime, frame_test_vel );
			if ( !swimming ) {
				frame_test_vel[2] = savevel[2];
			}
		} else if ( n < cmdframes ) {
#endif // RTCW_XX

			ax = 0;
			maxvel = sv_maxwalkvelocity;
			accelerate = sv_airaccelerate;
			VectorCopy( cmdmove, wishdir );
			if ( onground ) {
				if ( cmdmove[2] < -300 ) {
					crouch = qtrue;
					maxvel = sv_maxcrouchvelocity;
				} //end if
				  //if not swimming and upmove is positive then jump
				if ( !swimming && cmdmove[2] > 1 ) {
					//jump velocity minus the gravity for one frame + 5 for safety
					frame_test_vel[2] = sv_jumpvel - ( gravity * 0.1 * frametime ) + 5;
					jump_frame = n;
					//jumping so air accelerate
					accelerate = sv_airaccelerate;
				} //end if
				else
				{
					accelerate = sv_walkaccelerate;
				} //end else
				ax = 2;
			} //end if
			if ( swimming ) {
				maxvel = sv_maxswimvelocity;
				accelerate = sv_swimaccelerate;
				ax = 3;
			} //end if
			else
			{
				wishdir[2] = 0;
			} //end else
			  //
			wishspeed = VectorNormalize( wishdir );
			if ( wishspeed > maxvel ) {
				wishspeed = maxvel;
			}
			VectorScale( frame_test_vel, 1 / frametime, frame_test_vel );
			AAS_Accelerate( frame_test_vel, frametime, wishdir, wishspeed, accelerate );
			VectorScale( frame_test_vel, frametime, frame_test_vel );
			/*
			for (i = 0; i < ax; i++)
			{
				velchange = (cmdmove[i] * frametime) - frame_test_vel[i];
				if (velchange > sv_maxacceleration) velchange = sv_maxacceleration;
				else if (velchange < -sv_maxacceleration) velchange = -sv_maxacceleration;
				newvel = frame_test_vel[i] + velchange;
				//
				if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel;
				else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel;
				else frame_test_vel[i] = newvel;
			} //end for
			*/
		} //end if

#if !defined RTCW_ET
		if ( crouch ) {
			presencetype = PRESENCE_CROUCH;
		} //end if
		else if ( presencetype == PRESENCE_CROUCH ) {
			if ( AAS_PointPresenceType( org ) & PRESENCE_NORMAL ) {
				presencetype = PRESENCE_NORMAL;
			} //end if
		} //end else
#else
		  //if (crouch)
		  //{
		  //	presencetype = PRESENCE_CROUCH;
		  //} //end if
		  //else if (presencetype == PRESENCE_CROUCH)
		  //{
		  //	if (AAS_PointPresenceType(org) & PRESENCE_NORMAL)
		  //	{
		  //		presencetype = PRESENCE_NORMAL;
		  //	} //end if
		  //} //end else
#endif // RTCW_XX

		  //save the current origin
		VectorCopy( org, lastorg );
		//move linear during one frame
		VectorCopy( frame_test_vel, left_test_vel );
		j = 0;
		do
		{
			VectorAdd( org, left_test_vel, end );
			//trace a bounding box

#if !defined RTCW_ET
			trace = AAS_TraceClientBBox( org, end, presencetype, entnum );
#else
			//trace = AAS_TraceClientBBox(org, end, PRESENCE_NORMAL, entnum);
			trace = AAS_Trace( org, mins, maxs, end, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
#endif // RTCW_XX

			//
//#ifdef AAS_MOVE_DEBUG
			if ( visualize ) {

#if !defined RTCW_ET
				if ( trace.startsolid ) {
					botimport.Print( PRT_MESSAGE, "PredictMovement: start solid\n" );
				}
#else
				//if (trace.startsolid)
				//botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n");
#endif // RTCW_XX

				AAS_DebugLine( org, trace.endpos, LINECOLOR_RED );
			} //end if
//#endif //AAS_MOVE_DEBUG
			//

#if defined RTCW_ET
			if ( stopevent & SE_HITENT ) {
				if ( trace.fraction < 1.0 && trace.ent == hitent ) {
					areanum = AAS_PointAreaNum( org );
					VectorCopy( org, move->endpos );
					VectorScale( frame_test_vel, 1 / frametime, move->velocity );
					move->trace = trace;
					move->stopevent = SE_HITENT;
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
					move->endcontents = 0;
					move->time = n * frametime;
					move->frames = n;
					return qtrue;
				}
			}
#endif // RTCW_XX

			if ( stopevent & SE_ENTERAREA ) {
				numareas = AAS_TraceAreas( org, trace.endpos, areas, points, 20 );
				for ( i = 0; i < numareas; i++ )
				{
					if ( areas[i] == stopareanum ) {
						VectorCopy( points[i], move->endpos );
						VectorScale( frame_test_vel, 1 / frametime, move->velocity );
						move->trace = trace;
						move->stopevent = SE_ENTERAREA;

#if !defined RTCW_ET
						move->presencetype = presencetype;
#else
						move->presencetype = ( *aasworld ).areasettings[areas[i]].presencetype;
#endif // RTCW_XX

						move->endcontents = 0;
						move->time = n * frametime;
						move->frames = n;
						return qtrue;
					} //end if
				} //end for
			} //end if

#if defined RTCW_ET
			if ( stopevent & SE_STUCK ) {
				if ( trace.fraction < 1.0 ) {
					plane = &trace.plane;
					//if (Q_fabs(plane->normal[2]) <= sv_maxsteepness) {
					VectorNormalize2( frame_test_vel, wishdir );
					if ( DotProduct( plane->normal, wishdir ) < -0.8 ) {
						areanum = AAS_PointAreaNum( org );
						VectorCopy( org, move->endpos );
						VectorScale( frame_test_vel, 1 / frametime, move->velocity );
						move->trace = trace;
						move->stopevent = SE_STUCK;
						move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
						move->endcontents = 0;
						move->time = n * frametime;
						move->frames = n;
						return qtrue;
					}
				}
			}
#endif // RTCW_XX

			  //move the entity to the trace end point
			VectorCopy( trace.endpos, org );
			//if there was a collision
			if ( trace.fraction < 1.0 ) {
				//get the plane the bounding box collided with

#if !defined RTCW_ET
				plane = AAS_PlaneFromNum( trace.planenum );
#else
				plane = &trace.plane;
#endif // RTCW_XX

				//
				if ( stopevent & SE_HITGROUNDAREA ) {
					if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) {
						VectorCopy( org, start );
						start[2] += 0.5;

#if !defined RTCW_ET
						if ( AAS_PointAreaNum( start ) == stopareanum ) {
#else
						if ( ( stopareanum < 0 && AAS_PointAreaNum( start ) ) || ( AAS_PointAreaNum( start ) == stopareanum ) ) {
#endif // RTCW_XX

							VectorCopy( start, move->endpos );
							VectorScale( frame_test_vel, 1 / frametime, move->velocity );
							move->trace = trace;
							move->stopevent = SE_HITGROUNDAREA;

#if !defined RTCW_ET
							move->presencetype = presencetype;
#else
							move->presencetype = ( *aasworld ).areasettings[stopareanum].presencetype;
#endif // RTCW_XX

							move->endcontents = 0;
							move->time = n * frametime;
							move->frames = n;
							return qtrue;
						} //end if
					} //end if
				} //end if
				  //assume there's no step
				step = qfalse;
				//if it is a vertical plane and the bot didn't jump recently
				if ( plane->normal[2] == 0 && ( jump_frame < 0 || n - jump_frame > 2 ) ) {
					//check for a step
					VectorMA( org, -0.25, plane->normal, start );
					VectorCopy( start, stepend );
					start[2] += sv_maxstep;

#if !defined RTCW_ET
					steptrace = AAS_TraceClientBBox( start, stepend, presencetype, entnum );
#else
					//steptrace = AAS_TraceClientBBox(start, stepend, PRESENCE_NORMAL, entnum);
					steptrace = AAS_Trace( start, mins, maxs, stepend, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
#endif // RTCW_XX

					//
					if ( !steptrace.startsolid ) {

#if !defined RTCW_ET
						plane2 = AAS_PlaneFromNum( steptrace.planenum );
#else
						plane2 = &steptrace.plane;
#endif // RTCW_XX

						if ( DotProduct( plane2->normal, up ) > sv_maxsteepness ) {
							VectorSubtract( end, steptrace.endpos, left_test_vel );
							left_test_vel[2] = 0;
							frame_test_vel[2] = 0;
//#ifdef AAS_MOVE_DEBUG
							if ( visualize ) {
								if ( steptrace.endpos[2] - org[2] > 0.125 ) {
									VectorCopy( org, start );
									start[2] = steptrace.endpos[2];
									AAS_DebugLine( org, start, LINECOLOR_BLUE );
								} //end if
							} //end if
//#endif //AAS_MOVE_DEBUG
							org[2] = steptrace.endpos[2];
							step = qtrue;
						} //end if
					} //end if
				} //end if
				  //
				if ( !step ) {
					//velocity left to test for this frame is the projection
					//of the current test velocity into the hit plane
					VectorMA( left_test_vel, -DotProduct( left_test_vel, plane->normal ),
							  plane->normal, left_test_vel );

#if defined RTCW_ET
					// RF: from PM_SlideMove()
					// if this is the same plane we hit before, nudge velocity
					// out along it, which fixes some epsilon issues with
					// non-axial planes
					if ( lplane && DotProduct( lplane->normal, plane->normal ) > 0.99 ) {
						VectorAdd( plane->normal, left_test_vel, left_test_vel );
					}
					lplane = plane;
#endif // RTCW_XX

					//store the old velocity for landing check
					VectorCopy( frame_test_vel, old_frame_test_vel );
					//test velocity for the next frame is the projection
					//of the velocity of the current frame into the hit plane
					VectorMA( frame_test_vel, -DotProduct( frame_test_vel, plane->normal ),
							  plane->normal, frame_test_vel );
					//check for a landing on an almost horizontal floor
					if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) {
						onground = qtrue;
					} //end if
					if ( stopevent & SE_HITGROUNDDAMAGE ) {
						delta = 0;
						if ( old_frame_test_vel[2] < 0 &&
							 frame_test_vel[2] > old_frame_test_vel[2] &&
							 !onground ) {
							delta = old_frame_test_vel[2];
						} //end if
						else if ( onground ) {
							delta = frame_test_vel[2] - old_frame_test_vel[2];
						} //end else
						if ( delta ) {
							delta = delta * 10;
							delta = delta * delta * 0.0001;
							if ( swimming ) {
								delta = 0;
							}
							// never take falling damage if completely underwater
							/*
							if (ent->waterlevel == 3) return;
							if (ent->waterlevel == 2) delta *= 0.25;
							if (ent->waterlevel == 1) delta *= 0.5;
							*/
							if ( delta > 40 ) {
								VectorCopy( org, move->endpos );
								VectorCopy( frame_test_vel, move->velocity );
								move->trace = trace;
								move->stopevent = SE_HITGROUNDDAMAGE;

#if !defined RTCW_ET
								move->presencetype = presencetype;
#else
								areanum = AAS_PointAreaNum( org );
								if ( areanum ) {
									move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
								}
#endif // RTCW_XX

								move->endcontents = 0;
								move->time = n * frametime;
								move->frames = n;
								return qtrue;
							} //end if
						} //end if
					} //end if
				} //end if
			} //end if
			  //extra check to prevent endless loop
			if ( ++j > 20 ) {
				return qfalse;
			}
			//while there is a plane hit
		} while ( trace.fraction < 1.0 );
		//if going down
		if ( frame_test_vel[2] <= 10 ) {
			//check for a liquid at the feet of the bot
			VectorCopy( org, feet );
			feet[2] -= 22;
			pc = AAS_PointContents( feet );
			//get event from pc
			event = SE_NONE;
			if ( pc & CONTENTS_LAVA ) {
				event |= SE_ENTERLAVA;
			}
			if ( pc & CONTENTS_SLIME ) {
				event |= SE_ENTERSLIME;
			}
			if ( pc & CONTENTS_WATER ) {
				event |= SE_ENTERWATER;
			}
			//
			areanum = AAS_PointAreaNum( org );
			if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_LAVA ) {
				event |= SE_ENTERLAVA;
			}
			if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_SLIME ) {
				event |= SE_ENTERSLIME;
			}
			if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_WATER ) {
				event |= SE_ENTERWATER;
			}
			//if in lava or slime
			if ( event & stopevent ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->stopevent = event & stopevent;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
#endif // RTCW_XX

				move->endcontents = pc;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
		  //

#if !defined RTCW_ET
		onground = AAS_OnGround( org, presencetype, entnum );
#else
		onground = AAS_OnGround( org, PRESENCE_NORMAL, entnum );
#endif // RTCW_XX

		//if onground and on the ground for at least one whole frame
		if ( onground ) {
			if ( stopevent & SE_HITGROUND ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->trace = trace;
				move->stopevent = SE_HITGROUND;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				areanum = AAS_PointAreaNum( org );
				if ( areanum ) {
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
				}
#endif // RTCW_XX

				move->endcontents = 0;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
		else if ( stopevent & SE_LEAVEGROUND ) {
			VectorCopy( org, move->endpos );
			VectorScale( frame_test_vel, 1 / frametime, move->velocity );
			move->trace = trace;
			move->stopevent = SE_LEAVEGROUND;

#if !defined RTCW_ET
			move->presencetype = presencetype;
#else
			areanum = AAS_PointAreaNum( org );
			if ( areanum ) {
				move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
			}
#endif // RTCW_XX

			move->endcontents = 0;
			move->time = n * frametime;
			move->frames = n;
			return qtrue;
		} //end else if
		else if ( stopevent & SE_GAP ) {

#if !defined RTCW_ET
			aas_trace_t gaptrace;
#else
			bsp_trace_t gaptrace;
#endif // RTCW_XX

			VectorCopy( org, start );
			VectorCopy( start, end );
			end[2] -= 48 + aassettings.sv_maxbarrier;

#if !defined RTCW_ET
			gaptrace = AAS_TraceClientBBox( start, end, PRESENCE_CROUCH, -1 );
#else
			//gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
			gaptrace = AAS_Trace( start, mins, maxs, end, -1, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
#endif // RTCW_XX

			//if solid is found the bot cannot walk any further and will not fall into a gap
			if ( !gaptrace.startsolid ) {
				//if it is a gap (lower than one step height)
				if ( gaptrace.endpos[2] < org[2] - aassettings.sv_maxstep - 1 ) {
					if ( !( AAS_PointContents( end ) & ( CONTENTS_WATER | CONTENTS_SLIME ) ) ) { //----(SA)	modified since slime is no longer deadly
//					if (!(AAS_PointContents(end) & CONTENTS_WATER))
						VectorCopy( lastorg, move->endpos );
						VectorScale( frame_test_vel, 1 / frametime, move->velocity );
						move->trace = trace;
						move->stopevent = SE_GAP;

#if !defined RTCW_ET
						move->presencetype = presencetype;
#else
						areanum = AAS_PointAreaNum( org );
						if ( areanum ) {
							move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
						}
#endif // RTCW_XX

						move->endcontents = 0;
						move->time = n * frametime;
						move->frames = n;
						return qtrue;
					} //end if
				} //end if
			} //end if
		} //end else if
		if ( stopevent & SE_TOUCHJUMPPAD ) {
			if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_JUMPPAD ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->trace = trace;
				move->stopevent = SE_TOUCHJUMPPAD;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				areanum = AAS_PointAreaNum( org );
				if ( areanum ) {
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
				}
#endif // RTCW_XX

				move->endcontents = 0;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
		if ( stopevent & SE_TOUCHTELEPORTER ) {
			if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_TELEPORTER ) {
				VectorCopy( org, move->endpos );
				VectorScale( frame_test_vel, 1 / frametime, move->velocity );
				move->trace = trace;
				move->stopevent = SE_TOUCHTELEPORTER;

#if !defined RTCW_ET
				move->presencetype = presencetype;
#else
				areanum = AAS_PointAreaNum( org );
				if ( areanum ) {
					move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
				}
#endif // RTCW_XX

				move->endcontents = 0;
				move->time = n * frametime;
				move->frames = n;
				return qtrue;
			} //end if
		} //end if
	} //end for
	  //

#if defined RTCW_ET
	areanum = AAS_PointAreaNum( org );
#endif // RTCW_XX

	VectorCopy( org, move->endpos );
	VectorScale( frame_test_vel, 1 / frametime, move->velocity );
	move->stopevent = SE_NONE;

#if !defined RTCW_ET
	move->presencetype = presencetype;
#else
	move->presencetype = aasworld->areasettings ? aasworld->areasettings[areanum].presencetype : 0;
#endif // RTCW_XX

	move->endcontents = 0;
	move->time = n * frametime;
	move->frames = n;
	//
	return qtrue;
} //end of the function AAS_PredictClientMovement
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_TestMovementPrediction( int entnum, vec3_t origin, vec3_t dir ) {
	vec3_t velocity, cmdmove;
	aas_clientmove_t move;

	VectorClear( velocity );
	if ( !AAS_Swimming( origin ) ) {
		dir[2] = 0;
	}
	VectorNormalize( dir );
	VectorScale( dir, 400, cmdmove );
	cmdmove[2] = 224;
	AAS_ClearShownDebugLines();
	AAS_PredictClientMovement( &move, entnum, origin, PRESENCE_NORMAL, qtrue,
							   velocity, cmdmove, 13, 13, 0.1, SE_HITGROUND, 0, qtrue );    //SE_LEAVEGROUND);
	if ( move.stopevent & SE_LEAVEGROUND ) {
		botimport.Print( PRT_MESSAGE, "leave ground\n" );
	} //end if
} //end of the function TestMovementPrediction
//===========================================================================
// calculates the horizontal velocity needed to perform a jump from start
// to end
//
// Parameter:				zvel		: z velocity for jump
//								start		: start position of jump
//								end		: end position of jump
//								*speed	: returned speed for jump
// Returns:					qfalse if too high or too far from start to end
// Changes Globals:		-
//===========================================================================
int AAS_HorizontalVelocityForJump( float zvel, vec3_t start, vec3_t end, float *velocity ) {
	float sv_gravity, sv_maxvelocity;
	float maxjump, height2fall, t, top;
	vec3_t dir;

	sv_gravity = aassettings.sv_gravity;
	sv_maxvelocity = aassettings.sv_maxvelocity;

	//maximum height a player can jump with the given initial z velocity
	maxjump = 0.5 * sv_gravity * ( zvel / sv_gravity ) * ( zvel / sv_gravity );
	//top of the parabolic jump
	top = start[2] + maxjump;
	//height the bot will fall from the top
	height2fall = top - end[2];
	//if the goal is to high to jump to
	if ( height2fall < 0 ) {
		*velocity = sv_maxvelocity;
		return 0;
	} //end if
	  //time a player takes to fall the height
	t = c::sqrt( height2fall / ( 0.5 * sv_gravity ) );
	//direction from start to end
	VectorSubtract( end, start, dir );
	//calculate horizontal speed
	*velocity = c::sqrt( dir[0] * dir[0] + dir[1] * dir[1] ) / ( t + zvel / sv_gravity );
	//the horizontal speed must be lower than the max speed
	if ( *velocity > sv_maxvelocity ) {
		*velocity = sv_maxvelocity;
		return 0;
	} //end if
	return 1;
} //end of the function AAS_HorizontalVelocityForJump