Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

be_aas_move.c (37579B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 /*****************************************************************************
     24  * name:		be_aas_move.c
     25  *
     26  * desc:		AAS
     27  *
     28  * $Archive: /MissionPack/code/botlib/be_aas_move.c $
     29  *
     30  *****************************************************************************/
     31 
     32 #include "../game/q_shared.h"
     33 #include "l_memory.h"
     34 #include "l_script.h"
     35 #include "l_precomp.h"
     36 #include "l_struct.h"
     37 #include "l_libvar.h"
     38 #include "aasfile.h"
     39 #include "../game/botlib.h"
     40 #include "../game/be_aas.h"
     41 #include "be_aas_funcs.h"
     42 #include "be_aas_def.h"
     43 
     44 extern botlib_import_t botimport;
     45 
     46 aas_settings_t aassettings;
     47 
     48 //#define AAS_MOVE_DEBUG
     49 
     50 //===========================================================================
     51 //
     52 // Parameter:			-
     53 // Returns:				-
     54 // Changes Globals:		-
     55 //===========================================================================
     56 int AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs)
     57 {
     58 	vec3_t end;
     59 	bsp_trace_t trace;
     60 
     61 	VectorCopy(origin, end);
     62 	end[2] -= 100;
     63 	trace = AAS_Trace(origin, mins, maxs, end, 0, CONTENTS_SOLID);
     64 	if (trace.startsolid) return qfalse;
     65 	VectorCopy(trace.endpos, origin);
     66 	return qtrue;
     67 } //end of the function AAS_DropToFloor
     68 //===========================================================================
     69 //
     70 // Parameter:			-
     71 // Returns:				-
     72 // Changes Globals:		-
     73 //===========================================================================
     74 void AAS_InitSettings(void)
     75 {
     76 	aassettings.phys_gravitydirection[0]	= 0;
     77 	aassettings.phys_gravitydirection[1]	= 0;
     78 	aassettings.phys_gravitydirection[2]	= -1;
     79 	aassettings.phys_friction				= LibVarValue("phys_friction", "6");
     80 	aassettings.phys_stopspeed				= LibVarValue("phys_stopspeed", "100");
     81 	aassettings.phys_gravity				= LibVarValue("phys_gravity", "800");
     82 	aassettings.phys_waterfriction			= LibVarValue("phys_waterfriction", "1");
     83 	aassettings.phys_watergravity			= LibVarValue("phys_watergravity", "400");
     84 	aassettings.phys_maxvelocity			= LibVarValue("phys_maxvelocity", "320");
     85 	aassettings.phys_maxwalkvelocity		= LibVarValue("phys_maxwalkvelocity", "320");
     86 	aassettings.phys_maxcrouchvelocity		= LibVarValue("phys_maxcrouchvelocity", "100");
     87 	aassettings.phys_maxswimvelocity		= LibVarValue("phys_maxswimvelocity", "150");
     88 	aassettings.phys_walkaccelerate			= LibVarValue("phys_walkaccelerate", "10");
     89 	aassettings.phys_airaccelerate			= LibVarValue("phys_airaccelerate", "1");
     90 	aassettings.phys_swimaccelerate			= LibVarValue("phys_swimaccelerate", "4");
     91 	aassettings.phys_maxstep				= LibVarValue("phys_maxstep", "19");
     92 	aassettings.phys_maxsteepness			= LibVarValue("phys_maxsteepness", "0.7");
     93 	aassettings.phys_maxwaterjump			= LibVarValue("phys_maxwaterjump", "18");
     94 	aassettings.phys_maxbarrier				= LibVarValue("phys_maxbarrier", "33");
     95 	aassettings.phys_jumpvel				= LibVarValue("phys_jumpvel", "270");
     96 	aassettings.phys_falldelta5				= LibVarValue("phys_falldelta5", "40");
     97 	aassettings.phys_falldelta10			= LibVarValue("phys_falldelta10", "60");
     98 	aassettings.rs_waterjump				= LibVarValue("rs_waterjump", "400");
     99 	aassettings.rs_teleport					= LibVarValue("rs_teleport", "50");
    100 	aassettings.rs_barrierjump				= LibVarValue("rs_barrierjump", "100");
    101 	aassettings.rs_startcrouch				= LibVarValue("rs_startcrouch", "300");
    102 	aassettings.rs_startgrapple				= LibVarValue("rs_startgrapple", "500");
    103 	aassettings.rs_startwalkoffledge		= LibVarValue("rs_startwalkoffledge", "70");
    104 	aassettings.rs_startjump				= LibVarValue("rs_startjump", "300");
    105 	aassettings.rs_rocketjump				= LibVarValue("rs_rocketjump", "500");
    106 	aassettings.rs_bfgjump					= LibVarValue("rs_bfgjump", "500");
    107 	aassettings.rs_jumppad					= LibVarValue("rs_jumppad", "250");
    108 	aassettings.rs_aircontrolledjumppad		= LibVarValue("rs_aircontrolledjumppad", "300");
    109 	aassettings.rs_funcbob					= LibVarValue("rs_funcbob", "300");
    110 	aassettings.rs_startelevator			= LibVarValue("rs_startelevator", "50");
    111 	aassettings.rs_falldamage5				= LibVarValue("rs_falldamage5", "300");
    112 	aassettings.rs_falldamage10				= LibVarValue("rs_falldamage10", "500");
    113 	aassettings.rs_maxfallheight			= LibVarValue("rs_maxfallheight", "0");
    114 	aassettings.rs_maxjumpfallheight		= LibVarValue("rs_maxjumpfallheight", "450");
    115 } //end of the function AAS_InitSettings
    116 //===========================================================================
    117 // returns qtrue if the bot is against a ladder
    118 //
    119 // Parameter:			-
    120 // Returns:				-
    121 // Changes Globals:		-
    122 //===========================================================================
    123 int AAS_AgainstLadder(vec3_t origin)
    124 {
    125 	int areanum, i, facenum, side;
    126 	vec3_t org;
    127 	aas_plane_t *plane;
    128 	aas_face_t *face;
    129 	aas_area_t *area;
    130 
    131 	VectorCopy(origin, org);
    132 	areanum = AAS_PointAreaNum(org);
    133 	if (!areanum)
    134 	{
    135 		org[0] += 1;
    136 		areanum = AAS_PointAreaNum(org);
    137 		if (!areanum)
    138 		{
    139 			org[1] += 1;
    140 			areanum = AAS_PointAreaNum(org);
    141 			if (!areanum)
    142 			{
    143 				org[0] -= 2;
    144 				areanum = AAS_PointAreaNum(org);
    145 				if (!areanum)
    146 				{
    147 					org[1] -= 2;
    148 					areanum = AAS_PointAreaNum(org);
    149 				} //end if
    150 			} //end if
    151 		} //end if
    152 	} //end if
    153 	//if in solid... wrrr shouldn't happen
    154 	if (!areanum) return qfalse;
    155 	//if not in a ladder area
    156 	if (!(aasworld.areasettings[areanum].areaflags & AREA_LADDER)) return qfalse;
    157 	//if a crouch only area
    158 	if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qfalse;
    159 	//
    160 	area = &aasworld.areas[areanum];
    161 	for (i = 0; i < area->numfaces; i++)
    162 	{
    163 		facenum = aasworld.faceindex[area->firstface + i];
    164 		side = facenum < 0;
    165 		face = &aasworld.faces[abs(facenum)];
    166 		//if the face isn't a ladder face
    167 		if (!(face->faceflags & FACE_LADDER)) continue;
    168 		//get the plane the face is in
    169 		plane = &aasworld.planes[face->planenum ^ side];
    170 		//if the origin is pretty close to the plane
    171 		if (abs(DotProduct(plane->normal, origin) - plane->dist) < 3)
    172 		{
    173 			if (AAS_PointInsideFace(abs(facenum), origin, 0.1f)) return qtrue;
    174 		} //end if
    175 	} //end for
    176 	return qfalse;
    177 } //end of the function AAS_AgainstLadder
    178 //===========================================================================
    179 // returns qtrue if the bot is on the ground
    180 //
    181 // Parameter:			-
    182 // Returns:				-
    183 // Changes Globals:		-
    184 //===========================================================================
    185 int AAS_OnGround(vec3_t origin, int presencetype, int passent)
    186 {
    187 	aas_trace_t trace;
    188 	vec3_t end, up = {0, 0, 1};
    189 	aas_plane_t *plane;
    190 
    191 	VectorCopy(origin, end);
    192 	end[2] -= 10;
    193 
    194 	trace = AAS_TraceClientBBox(origin, end, presencetype, passent);
    195 
    196 	//if in solid
    197 	if (trace.startsolid) return qfalse;
    198 	//if nothing hit at all
    199 	if (trace.fraction >= 1.0) return qfalse;
    200 	//if too far from the hit plane
    201 	if (origin[2] - trace.endpos[2] > 10) return qfalse;
    202 	//check if the plane isn't too steep
    203 	plane = AAS_PlaneFromNum(trace.planenum);
    204 	if (DotProduct(plane->normal, up) < aassettings.phys_maxsteepness) return qfalse;
    205 	//the bot is on the ground
    206 	return qtrue;
    207 } //end of the function AAS_OnGround
    208 //===========================================================================
    209 // returns qtrue if a bot at the given position is swimming
    210 //
    211 // Parameter:				-
    212 // Returns:					-
    213 // Changes Globals:		-
    214 //===========================================================================
    215 int AAS_Swimming(vec3_t origin)
    216 {
    217 	vec3_t testorg;
    218 
    219 	VectorCopy(origin, testorg);
    220 	testorg[2] -= 2;
    221 	if (AAS_PointContents(testorg) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) return qtrue;
    222 	return qfalse;
    223 } //end of the function AAS_Swimming
    224 //===========================================================================
    225 //
    226 // Parameter:			-
    227 // Returns:				-
    228 // Changes Globals:		-
    229 //===========================================================================
    230 static vec3_t VEC_UP			= {0, -1,  0};
    231 static vec3_t MOVEDIR_UP		= {0,  0,  1};
    232 static vec3_t VEC_DOWN		= {0, -2,  0};
    233 static vec3_t MOVEDIR_DOWN	= {0,  0, -1};
    234 
    235 void AAS_SetMovedir(vec3_t angles, vec3_t movedir)
    236 {
    237 	if (VectorCompare(angles, VEC_UP))
    238 	{
    239 		VectorCopy(MOVEDIR_UP, movedir);
    240 	} //end if
    241 	else if (VectorCompare(angles, VEC_DOWN))
    242 	{
    243 		VectorCopy(MOVEDIR_DOWN, movedir);
    244 	} //end else if
    245 	else
    246 	{
    247 		AngleVectors(angles, movedir, NULL, NULL);
    248 	} //end else
    249 } //end of the function AAS_SetMovedir
    250 //===========================================================================
    251 //
    252 // Parameter:				-
    253 // Returns:					-
    254 // Changes Globals:		-
    255 //===========================================================================
    256 void AAS_JumpReachRunStart(aas_reachability_t *reach, vec3_t runstart)
    257 {
    258 	vec3_t hordir, start, cmdmove;
    259 	aas_clientmove_t move;
    260 
    261 	//
    262 	hordir[0] = reach->start[0] - reach->end[0];
    263 	hordir[1] = reach->start[1] - reach->end[1];
    264 	hordir[2] = 0;
    265 	VectorNormalize(hordir);
    266 	//start point
    267 	VectorCopy(reach->start, start);
    268 	start[2] += 1;
    269 	//get command movement
    270 	VectorScale(hordir, 400, cmdmove);
    271 	//
    272 	AAS_PredictClientMovement(&move, -1, start, PRESENCE_NORMAL, qtrue,
    273 								vec3_origin, cmdmove, 1, 2, 0.1f,
    274 								SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|
    275 								SE_HITGROUNDDAMAGE|SE_GAP, 0, qfalse);
    276 	VectorCopy(move.endpos, runstart);
    277 	//don't enter slime or lava and don't fall from too high
    278 	if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
    279 	{
    280 		VectorCopy(start, runstart);
    281 	} //end if
    282 } //end of the function AAS_JumpReachRunStart
    283 //===========================================================================
    284 // returns the Z velocity when rocket jumping at the origin
    285 //
    286 // Parameter:			-
    287 // Returns:				-
    288 // Changes Globals:		-
    289 //===========================================================================
    290 float AAS_WeaponJumpZVelocity(vec3_t origin, float radiusdamage)
    291 {
    292 	vec3_t kvel, v, start, end, forward, right, viewangles, dir;
    293 	float	mass, knockback, points;
    294 	vec3_t rocketoffset = {8, 8, -8};
    295 	vec3_t botmins = {-16, -16, -24};
    296 	vec3_t botmaxs = {16, 16, 32};
    297 	bsp_trace_t bsptrace;
    298 
    299 	//look down (90 degrees)
    300 	viewangles[PITCH] = 90;
    301 	viewangles[YAW] = 0;
    302 	viewangles[ROLL] = 0;
    303 	//get the start point shooting from
    304 	VectorCopy(origin, start);
    305 	start[2] += 8; //view offset Z
    306 	AngleVectors(viewangles, forward, right, NULL);
    307 	start[0] += forward[0] * rocketoffset[0] + right[0] * rocketoffset[1];
    308 	start[1] += forward[1] * rocketoffset[0] + right[1] * rocketoffset[1];
    309 	start[2] += forward[2] * rocketoffset[0] + right[2] * rocketoffset[1] + rocketoffset[2];
    310 	//end point of the trace
    311 	VectorMA(start, 500, forward, end);
    312 	//trace a line to get the impact point
    313 	bsptrace = AAS_Trace(start, NULL, NULL, end, 1, CONTENTS_SOLID);
    314 	//calculate the damage the bot will get from the rocket impact
    315 	VectorAdd(botmins, botmaxs, v);
    316 	VectorMA(origin, 0.5, v, v);
    317 	VectorSubtract(bsptrace.endpos, v, v);
    318 	//
    319 	points = radiusdamage - 0.5 * VectorLength(v);
    320 	if (points < 0) points = 0;
    321 	//the owner of the rocket gets half the damage
    322 	points *= 0.5;
    323 	//mass of the bot (p_client.c: PutClientInServer)
    324 	mass = 200;
    325 	//knockback is the same as the damage points
    326 	knockback = points;
    327 	//direction of the damage (from trace.endpos to bot origin)
    328 	VectorSubtract(origin, bsptrace.endpos, dir);
    329 	VectorNormalize(dir);
    330 	//damage velocity
    331 	VectorScale(dir, 1600.0 * (float)knockback / mass, kvel);	//the rocket jump hack...
    332 	//rocket impact velocity + jump velocity
    333 	return kvel[2] + aassettings.phys_jumpvel;
    334 } //end of the function AAS_WeaponJumpZVelocity
    335 //===========================================================================
    336 //
    337 // Parameter:			-
    338 // Returns:				-
    339 // Changes Globals:		-
    340 //===========================================================================
    341 float AAS_RocketJumpZVelocity(vec3_t origin)
    342 {
    343 	//rocket radius damage is 120 (p_weapon.c: Weapon_RocketLauncher_Fire)
    344 	return AAS_WeaponJumpZVelocity(origin, 120);
    345 } //end of the function AAS_RocketJumpZVelocity
    346 //===========================================================================
    347 //
    348 // Parameter:			-
    349 // Returns:				-
    350 // Changes Globals:		-
    351 //===========================================================================
    352 float AAS_BFGJumpZVelocity(vec3_t origin)
    353 {
    354 	//bfg radius damage is 1000 (p_weapon.c: weapon_bfg_fire)
    355 	return AAS_WeaponJumpZVelocity(origin, 120);
    356 } //end of the function AAS_BFGJumpZVelocity
    357 //===========================================================================
    358 // applies ground friction to the given velocity
    359 //
    360 // Parameter:			-
    361 // Returns:				-
    362 // Changes Globals:		-
    363 //===========================================================================
    364 void AAS_Accelerate(vec3_t velocity, float frametime, vec3_t wishdir, float wishspeed, float accel)
    365 {
    366 	// q2 style
    367 	int			i;
    368 	float		addspeed, accelspeed, currentspeed;
    369 
    370 	currentspeed = DotProduct(velocity, wishdir);
    371 	addspeed = wishspeed - currentspeed;
    372 	if (addspeed <= 0) {
    373 		return;
    374 	}
    375 	accelspeed = accel*frametime*wishspeed;
    376 	if (accelspeed > addspeed) {
    377 		accelspeed = addspeed;
    378 	}
    379 	
    380 	for (i=0 ; i<3 ; i++) {
    381 		velocity[i] += accelspeed*wishdir[i];	
    382 	}
    383 } //end of the function AAS_Accelerate
    384 //===========================================================================
    385 //
    386 // Parameter:			-
    387 // Returns:				-
    388 // Changes Globals:		-
    389 //===========================================================================
    390 void AAS_AirControl(vec3_t start, vec3_t end, vec3_t velocity, vec3_t cmdmove)
    391 {
    392 	vec3_t dir;
    393 
    394 	VectorSubtract(end, start, dir);
    395 } //end of the function AAS_AirControl
    396 //===========================================================================
    397 // applies ground friction to the given velocity
    398 //
    399 // Parameter:			-
    400 // Returns:				-
    401 // Changes Globals:		-
    402 //===========================================================================
    403 void AAS_ApplyFriction(vec3_t vel, float friction, float stopspeed,
    404 													float frametime)
    405 {
    406 	float speed, control, newspeed;
    407 
    408 	//horizontal speed
    409 	speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]);
    410 	if (speed)
    411 	{
    412 		control = speed < stopspeed ? stopspeed : speed;
    413 		newspeed = speed - frametime * control * friction;
    414 		if (newspeed < 0) newspeed = 0;
    415 		newspeed /= speed;
    416 		vel[0] *= newspeed;
    417 		vel[1] *= newspeed;
    418 	} //end if
    419 } //end of the function AAS_ApplyFriction
    420 //===========================================================================
    421 //
    422 // Parameter:			-
    423 // Returns:				-
    424 // Changes Globals:		-
    425 //===========================================================================
    426 int AAS_ClipToBBox(aas_trace_t *trace, vec3_t start, vec3_t end, int presencetype, vec3_t mins, vec3_t maxs)
    427 {
    428 	int i, j, side;
    429 	float front, back, frac, planedist;
    430 	vec3_t bboxmins, bboxmaxs, absmins, absmaxs, dir, mid;
    431 
    432 	AAS_PresenceTypeBoundingBox(presencetype, bboxmins, bboxmaxs);
    433 	VectorSubtract(mins, bboxmaxs, absmins);
    434 	VectorSubtract(maxs, bboxmins, absmaxs);
    435 	//
    436 	VectorCopy(end, trace->endpos);
    437 	trace->fraction = 1;
    438 	for (i = 0; i < 3; i++)
    439 	{
    440 		if (start[i] < absmins[i] && end[i] < absmins[i]) return qfalse;
    441 		if (start[i] > absmaxs[i] && end[i] > absmaxs[i]) return qfalse;
    442 	} //end for
    443 	//check bounding box collision
    444 	VectorSubtract(end, start, dir);
    445 	frac = 1;
    446 	for (i = 0; i < 3; i++)
    447 	{
    448 		//get plane to test collision with for the current axis direction
    449 		if (dir[i] > 0) planedist = absmins[i];
    450 		else planedist = absmaxs[i];
    451 		//calculate collision fraction
    452 		front = start[i] - planedist;
    453 		back = end[i] - planedist;
    454 		frac = front / (front-back);
    455 		//check if between bounding planes of next axis
    456 		side = i + 1;
    457 		if (side > 2) side = 0;
    458 		mid[side] = start[side] + dir[side] * frac;
    459 		if (mid[side] > absmins[side] && mid[side] < absmaxs[side])
    460 		{
    461 			//check if between bounding planes of next axis
    462 			side++;
    463 			if (side > 2) side = 0;
    464 			mid[side] = start[side] + dir[side] * frac;
    465 			if (mid[side] > absmins[side] && mid[side] < absmaxs[side])
    466 			{
    467 				mid[i] = planedist;
    468 				break;
    469 			} //end if
    470 		} //end if
    471 	} //end for
    472 	//if there was a collision
    473 	if (i != 3)
    474 	{
    475 		trace->startsolid = qfalse;
    476 		trace->fraction = frac;
    477 		trace->ent = 0;
    478 		trace->planenum = 0;
    479 		trace->area = 0;
    480 		trace->lastarea = 0;
    481 		//trace endpos
    482 		for (j = 0; j < 3; j++) trace->endpos[j] = start[j] + dir[j] * frac;
    483 		return qtrue;
    484 	} //end if
    485 	return qfalse;
    486 } //end of the function AAS_ClipToBBox
    487 //===========================================================================
    488 // predicts the movement
    489 // assumes regular bounding box sizes
    490 // NOTE: out of water jumping is not included
    491 // NOTE: grappling hook is not included
    492 //
    493 // Parameter:			origin			: origin to start with
    494 //						presencetype	: presence type to start with
    495 //						velocity		: velocity to start with
    496 //						cmdmove			: client command movement
    497 //						cmdframes		: number of frame cmdmove is valid
    498 //						maxframes		: maximum number of predicted frames
    499 //						frametime		: duration of one predicted frame
    500 //						stopevent		: events that stop the prediction
    501 //						stopareanum		: stop as soon as entered this area
    502 // Returns:				aas_clientmove_t
    503 // Changes Globals:		-
    504 //===========================================================================
    505 int AAS_ClientMovementPrediction(struct aas_clientmove_s *move,
    506 								int entnum, vec3_t origin,
    507 								int presencetype, int onground,
    508 								vec3_t velocity, vec3_t cmdmove,
    509 								int cmdframes,
    510 								int maxframes, float frametime,
    511 								int stopevent, int stopareanum,
    512 								vec3_t mins, vec3_t maxs, int visualize)
    513 {
    514 	float phys_friction, phys_stopspeed, phys_gravity, phys_waterfriction;
    515 	float phys_watergravity;
    516 	float phys_walkaccelerate, phys_airaccelerate, phys_swimaccelerate;
    517 	float phys_maxwalkvelocity, phys_maxcrouchvelocity, phys_maxswimvelocity;
    518 	float phys_maxstep, phys_maxsteepness, phys_jumpvel, friction;
    519 	float gravity, delta, maxvel, wishspeed, accelerate;
    520 	//float velchange, newvel;
    521 	int n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum;
    522 	int areas[20], numareas;
    523 	vec3_t points[20];
    524 	vec3_t org, end, feet, start, stepend, lastorg, wishdir;
    525 	vec3_t frame_test_vel, old_frame_test_vel, left_test_vel;
    526 	vec3_t up = {0, 0, 1};
    527 	aas_plane_t *plane, *plane2;
    528 	aas_trace_t trace, steptrace;
    529 	
    530 	if (frametime <= 0) frametime = 0.1f;
    531 	//
    532 	phys_friction = aassettings.phys_friction;
    533 	phys_stopspeed = aassettings.phys_stopspeed;
    534 	phys_gravity = aassettings.phys_gravity;
    535 	phys_waterfriction = aassettings.phys_waterfriction;
    536 	phys_watergravity = aassettings.phys_watergravity;
    537 	phys_maxwalkvelocity = aassettings.phys_maxwalkvelocity;// * frametime;
    538 	phys_maxcrouchvelocity = aassettings.phys_maxcrouchvelocity;// * frametime;
    539 	phys_maxswimvelocity = aassettings.phys_maxswimvelocity;// * frametime;
    540 	phys_walkaccelerate = aassettings.phys_walkaccelerate;
    541 	phys_airaccelerate = aassettings.phys_airaccelerate;
    542 	phys_swimaccelerate = aassettings.phys_swimaccelerate;
    543 	phys_maxstep = aassettings.phys_maxstep;
    544 	phys_maxsteepness = aassettings.phys_maxsteepness;
    545 	phys_jumpvel = aassettings.phys_jumpvel * frametime;
    546 	//
    547 	Com_Memset(move, 0, sizeof(aas_clientmove_t));
    548 	Com_Memset(&trace, 0, sizeof(aas_trace_t));
    549 	//start at the current origin
    550 	VectorCopy(origin, org);
    551 	org[2] += 0.25;
    552 	//velocity to test for the first frame
    553 	VectorScale(velocity, frametime, frame_test_vel);
    554 	//
    555 	jump_frame = -1;
    556 	//predict a maximum of 'maxframes' ahead
    557 	for (n = 0; n < maxframes; n++)
    558 	{
    559 		swimming = AAS_Swimming(org);
    560 		//get gravity depending on swimming or not
    561 		gravity = swimming ? phys_watergravity : phys_gravity;
    562 		//apply gravity at the START of the frame
    563 		frame_test_vel[2] = frame_test_vel[2] - (gravity * 0.1 * frametime);
    564 		//if on the ground or swimming
    565 		if (onground || swimming)
    566 		{
    567 			friction = swimming ? phys_friction : phys_waterfriction;
    568 			//apply friction
    569 			VectorScale(frame_test_vel, 1/frametime, frame_test_vel);
    570 			AAS_ApplyFriction(frame_test_vel, friction, phys_stopspeed, frametime);
    571 			VectorScale(frame_test_vel, frametime, frame_test_vel);
    572 		} //end if
    573 		crouch = qfalse;
    574 		//apply command movement
    575 		if (n < cmdframes)
    576 		{
    577 			ax = 0;
    578 			maxvel = phys_maxwalkvelocity;
    579 			accelerate = phys_airaccelerate;
    580 			VectorCopy(cmdmove, wishdir);
    581 			if (onground)
    582 			{
    583 				if (cmdmove[2] < -300)
    584 				{
    585 					crouch = qtrue;
    586 					maxvel = phys_maxcrouchvelocity;
    587 				} //end if
    588 				//if not swimming and upmove is positive then jump
    589 				if (!swimming && cmdmove[2] > 1)
    590 				{
    591 					//jump velocity minus the gravity for one frame + 5 for safety
    592 					frame_test_vel[2] = phys_jumpvel - (gravity * 0.1 * frametime) + 5;
    593 					jump_frame = n;
    594 					//jumping so air accelerate
    595 					accelerate = phys_airaccelerate;
    596 				} //end if
    597 				else
    598 				{
    599 					accelerate = phys_walkaccelerate;
    600 				} //end else
    601 				ax = 2;
    602 			} //end if
    603 			if (swimming)
    604 			{
    605 				maxvel = phys_maxswimvelocity;
    606 				accelerate = phys_swimaccelerate;
    607 				ax = 3;
    608 			} //end if
    609 			else
    610 			{
    611 				wishdir[2] = 0;
    612 			} //end else
    613 			//
    614 			wishspeed = VectorNormalize(wishdir);
    615 			if (wishspeed > maxvel) wishspeed = maxvel;
    616 			VectorScale(frame_test_vel, 1/frametime, frame_test_vel);
    617 			AAS_Accelerate(frame_test_vel, frametime, wishdir, wishspeed, accelerate);
    618 			VectorScale(frame_test_vel, frametime, frame_test_vel);
    619 			/*
    620 			for (i = 0; i < ax; i++)
    621 			{
    622 				velchange = (cmdmove[i] * frametime) - frame_test_vel[i];
    623 				if (velchange > phys_maxacceleration) velchange = phys_maxacceleration;
    624 				else if (velchange < -phys_maxacceleration) velchange = -phys_maxacceleration;
    625 				newvel = frame_test_vel[i] + velchange;
    626 				//
    627 				if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel;
    628 				else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel;
    629 				else frame_test_vel[i] = newvel;
    630 			} //end for
    631 			*/
    632 		} //end if
    633 		if (crouch)
    634 		{
    635 			presencetype = PRESENCE_CROUCH;
    636 		} //end if
    637 		else if (presencetype == PRESENCE_CROUCH)
    638 		{
    639 			if (AAS_PointPresenceType(org) & PRESENCE_NORMAL)
    640 			{
    641 				presencetype = PRESENCE_NORMAL;
    642 			} //end if
    643 		} //end else
    644 		//save the current origin
    645 		VectorCopy(org, lastorg);
    646 		//move linear during one frame
    647 		VectorCopy(frame_test_vel, left_test_vel);
    648 		j = 0;
    649 		do
    650 		{
    651 			VectorAdd(org, left_test_vel, end);
    652 			//trace a bounding box
    653 			trace = AAS_TraceClientBBox(org, end, presencetype, entnum);
    654 			//
    655 //#ifdef AAS_MOVE_DEBUG
    656 			if (visualize)
    657 			{
    658 				if (trace.startsolid) botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n");
    659 				AAS_DebugLine(org, trace.endpos, LINECOLOR_RED);
    660 			} //end if
    661 //#endif //AAS_MOVE_DEBUG
    662 			//
    663 			if (stopevent & (SE_ENTERAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_TOUCHCLUSTERPORTAL))
    664 			{
    665 				numareas = AAS_TraceAreas(org, trace.endpos, areas, points, 20);
    666 				for (i = 0; i < numareas; i++)
    667 				{
    668 					if (stopevent & SE_ENTERAREA)
    669 					{
    670 						if (areas[i] == stopareanum)
    671 						{
    672 							VectorCopy(points[i], move->endpos);
    673 							VectorScale(frame_test_vel, 1/frametime, move->velocity);
    674 							move->endarea = areas[i];
    675 							move->trace = trace;
    676 							move->stopevent = SE_ENTERAREA;
    677 							move->presencetype = presencetype;
    678 							move->endcontents = 0;
    679 							move->time = n * frametime;
    680 							move->frames = n;
    681 							return qtrue;
    682 						} //end if
    683 					} //end if
    684 					//NOTE: if not the first frame
    685 					if ((stopevent & SE_TOUCHJUMPPAD) && n)
    686 					{
    687 						if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_JUMPPAD)
    688 						{
    689 							VectorCopy(points[i], move->endpos);
    690 							VectorScale(frame_test_vel, 1/frametime, move->velocity);
    691 							move->endarea = areas[i];
    692 							move->trace = trace;
    693 							move->stopevent = SE_TOUCHJUMPPAD;
    694 							move->presencetype = presencetype;
    695 							move->endcontents = 0;
    696 							move->time = n * frametime;
    697 							move->frames = n;
    698 							return qtrue;
    699 						} //end if
    700 					} //end if
    701 					if (stopevent & SE_TOUCHTELEPORTER)
    702 					{
    703 						if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_TELEPORTER)
    704 						{
    705 							VectorCopy(points[i], move->endpos);
    706 							move->endarea = areas[i];
    707 							VectorScale(frame_test_vel, 1/frametime, move->velocity);
    708 							move->trace = trace;
    709 							move->stopevent = SE_TOUCHTELEPORTER;
    710 							move->presencetype = presencetype;
    711 							move->endcontents = 0;
    712 							move->time = n * frametime;
    713 							move->frames = n;
    714 							return qtrue;
    715 						} //end if
    716 					} //end if
    717 					if (stopevent & SE_TOUCHCLUSTERPORTAL)
    718 					{
    719 						if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_CLUSTERPORTAL)
    720 						{
    721 							VectorCopy(points[i], move->endpos);
    722 							move->endarea = areas[i];
    723 							VectorScale(frame_test_vel, 1/frametime, move->velocity);
    724 							move->trace = trace;
    725 							move->stopevent = SE_TOUCHCLUSTERPORTAL;
    726 							move->presencetype = presencetype;
    727 							move->endcontents = 0;
    728 							move->time = n * frametime;
    729 							move->frames = n;
    730 							return qtrue;
    731 						} //end if
    732 					} //end if
    733 				} //end for
    734 			} //end if
    735 			//
    736 			if (stopevent & SE_HITBOUNDINGBOX)
    737 			{
    738 				if (AAS_ClipToBBox(&trace, org, trace.endpos, presencetype, mins, maxs))
    739 				{
    740 					VectorCopy(trace.endpos, move->endpos);
    741 					move->endarea = AAS_PointAreaNum(move->endpos);
    742 					VectorScale(frame_test_vel, 1/frametime, move->velocity);
    743 					move->trace = trace;
    744 					move->stopevent = SE_HITBOUNDINGBOX;
    745 					move->presencetype = presencetype;
    746 					move->endcontents = 0;
    747 					move->time = n * frametime;
    748 					move->frames = n;
    749 					return qtrue;
    750 				} //end if
    751 			} //end if
    752 			//move the entity to the trace end point
    753 			VectorCopy(trace.endpos, org);
    754 			//if there was a collision
    755 			if (trace.fraction < 1.0)
    756 			{
    757 				//get the plane the bounding box collided with
    758 				plane = AAS_PlaneFromNum(trace.planenum);
    759 				//
    760 				if (stopevent & SE_HITGROUNDAREA)
    761 				{
    762 					if (DotProduct(plane->normal, up) > phys_maxsteepness)
    763 					{
    764 						VectorCopy(org, start);
    765 						start[2] += 0.5;
    766 						if (AAS_PointAreaNum(start) == stopareanum)
    767 						{
    768 							VectorCopy(start, move->endpos);
    769 							move->endarea = stopareanum;
    770 							VectorScale(frame_test_vel, 1/frametime, move->velocity);
    771 							move->trace = trace;
    772 							move->stopevent = SE_HITGROUNDAREA;
    773 							move->presencetype = presencetype;
    774 							move->endcontents = 0;
    775 							move->time = n * frametime;
    776 							move->frames = n;
    777 							return qtrue;
    778 						} //end if
    779 					} //end if
    780 				} //end if
    781 				//assume there's no step
    782 				step = qfalse;
    783 				//if it is a vertical plane and the bot didn't jump recently
    784 				if (plane->normal[2] == 0 && (jump_frame < 0 || n - jump_frame > 2))
    785 				{
    786 					//check for a step
    787 					VectorMA(org, -0.25, plane->normal, start);
    788 					VectorCopy(start, stepend);
    789 					start[2] += phys_maxstep;
    790 					steptrace = AAS_TraceClientBBox(start, stepend, presencetype, entnum);
    791 					//
    792 					if (!steptrace.startsolid)
    793 					{
    794 						plane2 = AAS_PlaneFromNum(steptrace.planenum);
    795 						if (DotProduct(plane2->normal, up) > phys_maxsteepness)
    796 						{
    797 							VectorSubtract(end, steptrace.endpos, left_test_vel);
    798 							left_test_vel[2] = 0;
    799 							frame_test_vel[2] = 0;
    800 //#ifdef AAS_MOVE_DEBUG
    801 							if (visualize)
    802 							{
    803 								if (steptrace.endpos[2] - org[2] > 0.125)
    804 								{
    805 									VectorCopy(org, start);
    806 									start[2] = steptrace.endpos[2];
    807 									AAS_DebugLine(org, start, LINECOLOR_BLUE);
    808 								} //end if
    809 							} //end if
    810 //#endif //AAS_MOVE_DEBUG
    811 							org[2] = steptrace.endpos[2];
    812 							step = qtrue;
    813 						} //end if
    814 					} //end if
    815 				} //end if
    816 				//
    817 				if (!step)
    818 				{
    819 					//velocity left to test for this frame is the projection
    820 					//of the current test velocity into the hit plane 
    821 					VectorMA(left_test_vel, -DotProduct(left_test_vel, plane->normal),
    822 										plane->normal, left_test_vel);
    823 					//store the old velocity for landing check
    824 					VectorCopy(frame_test_vel, old_frame_test_vel);
    825 					//test velocity for the next frame is the projection
    826 					//of the velocity of the current frame into the hit plane 
    827 					VectorMA(frame_test_vel, -DotProduct(frame_test_vel, plane->normal),
    828 										plane->normal, frame_test_vel);
    829 					//check for a landing on an almost horizontal floor
    830 					if (DotProduct(plane->normal, up) > phys_maxsteepness)
    831 					{
    832 						onground = qtrue;
    833 					} //end if
    834 					if (stopevent & SE_HITGROUNDDAMAGE)
    835 					{
    836 						delta = 0;
    837 						if (old_frame_test_vel[2] < 0 &&
    838 								frame_test_vel[2] > old_frame_test_vel[2] &&
    839 								!onground)
    840 						{
    841 							delta = old_frame_test_vel[2];
    842 						} //end if
    843 						else if (onground)
    844 						{
    845 							delta = frame_test_vel[2] - old_frame_test_vel[2];
    846 						} //end else
    847 						if (delta)
    848 						{
    849 							delta = delta * 10;
    850 							delta = delta * delta * 0.0001;
    851 							if (swimming) delta = 0;
    852 							// never take falling damage if completely underwater
    853 							/*
    854 							if (ent->waterlevel == 3) return;
    855 							if (ent->waterlevel == 2) delta *= 0.25;
    856 							if (ent->waterlevel == 1) delta *= 0.5;
    857 							*/
    858 							if (delta > 40)
    859 							{
    860 								VectorCopy(org, move->endpos);
    861 								move->endarea = AAS_PointAreaNum(org);
    862 								VectorCopy(frame_test_vel, move->velocity);
    863 								move->trace = trace;
    864 								move->stopevent = SE_HITGROUNDDAMAGE;
    865 								move->presencetype = presencetype;
    866 								move->endcontents = 0;
    867 								move->time = n * frametime;
    868 								move->frames = n;
    869 								return qtrue;
    870 							} //end if
    871 						} //end if
    872 					} //end if
    873 				} //end if
    874 			} //end if
    875 			//extra check to prevent endless loop
    876 			if (++j > 20) return qfalse;
    877 		//while there is a plane hit
    878 		} while(trace.fraction < 1.0);
    879 		//if going down
    880 		if (frame_test_vel[2] <= 10)
    881 		{
    882 			//check for a liquid at the feet of the bot
    883 			VectorCopy(org, feet);
    884 			feet[2] -= 22;
    885 			pc = AAS_PointContents(feet);
    886 			//get event from pc
    887 			event = SE_NONE;
    888 			if (pc & CONTENTS_LAVA) event |= SE_ENTERLAVA;
    889 			if (pc & CONTENTS_SLIME) event |= SE_ENTERSLIME;
    890 			if (pc & CONTENTS_WATER) event |= SE_ENTERWATER;
    891 			//
    892 			areanum = AAS_PointAreaNum(org);
    893 			if (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA)
    894 				event |= SE_ENTERLAVA;
    895 			if (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME)
    896 				event |= SE_ENTERSLIME;
    897 			if (aasworld.areasettings[areanum].contents & AREACONTENTS_WATER)
    898 				event |= SE_ENTERWATER;
    899 			//if in lava or slime
    900 			if (event & stopevent)
    901 			{
    902 				VectorCopy(org, move->endpos);
    903 				move->endarea = areanum;
    904 				VectorScale(frame_test_vel, 1/frametime, move->velocity);
    905 				move->stopevent = event & stopevent;
    906 				move->presencetype = presencetype;
    907 				move->endcontents = pc;
    908 				move->time = n * frametime;
    909 				move->frames = n;
    910 				return qtrue;
    911 			} //end if
    912 		} //end if
    913 		//
    914 		onground = AAS_OnGround(org, presencetype, entnum);
    915 		//if onground and on the ground for at least one whole frame
    916 		if (onground)
    917 		{
    918 			if (stopevent & SE_HITGROUND)
    919 			{
    920 				VectorCopy(org, move->endpos);
    921 				move->endarea = AAS_PointAreaNum(org);
    922 				VectorScale(frame_test_vel, 1/frametime, move->velocity);
    923 				move->trace = trace;
    924 				move->stopevent = SE_HITGROUND;
    925 				move->presencetype = presencetype;
    926 				move->endcontents = 0;
    927 				move->time = n * frametime;
    928 				move->frames = n;
    929 				return qtrue;
    930 			} //end if
    931 		} //end if
    932 		else if (stopevent & SE_LEAVEGROUND)
    933 		{
    934 			VectorCopy(org, move->endpos);
    935 			move->endarea = AAS_PointAreaNum(org);
    936 			VectorScale(frame_test_vel, 1/frametime, move->velocity);
    937 			move->trace = trace;
    938 			move->stopevent = SE_LEAVEGROUND;
    939 			move->presencetype = presencetype;
    940 			move->endcontents = 0;
    941 			move->time = n * frametime;
    942 			move->frames = n;
    943 			return qtrue;
    944 		} //end else if
    945 		else if (stopevent & SE_GAP)
    946 		{
    947 			aas_trace_t gaptrace;
    948 
    949 			VectorCopy(org, start);
    950 			VectorCopy(start, end);
    951 			end[2] -= 48 + aassettings.phys_maxbarrier;
    952 			gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
    953 			//if solid is found the bot cannot walk any further and will not fall into a gap
    954 			if (!gaptrace.startsolid)
    955 			{
    956 				//if it is a gap (lower than one step height)
    957 				if (gaptrace.endpos[2] < org[2] - aassettings.phys_maxstep - 1)
    958 				{
    959 					if (!(AAS_PointContents(end) & CONTENTS_WATER))
    960 					{
    961 						VectorCopy(lastorg, move->endpos);
    962 						move->endarea = AAS_PointAreaNum(lastorg);
    963 						VectorScale(frame_test_vel, 1/frametime, move->velocity);
    964 						move->trace = trace;
    965 						move->stopevent = SE_GAP;
    966 						move->presencetype = presencetype;
    967 						move->endcontents = 0;
    968 						move->time = n * frametime;
    969 						move->frames = n;
    970 						return qtrue;
    971 					} //end if
    972 				} //end if
    973 			} //end if
    974 		} //end else if
    975 	} //end for
    976 	//
    977 	VectorCopy(org, move->endpos);
    978 	move->endarea = AAS_PointAreaNum(org);
    979 	VectorScale(frame_test_vel, 1/frametime, move->velocity);
    980 	move->stopevent = SE_NONE;
    981 	move->presencetype = presencetype;
    982 	move->endcontents = 0;
    983 	move->time = n * frametime;
    984 	move->frames = n;
    985 	//
    986 	return qtrue;
    987 } //end of the function AAS_ClientMovementPrediction
    988 //===========================================================================
    989 //
    990 // Parameter:			-
    991 // Returns:				-
    992 // Changes Globals:		-
    993 //===========================================================================
    994 int AAS_PredictClientMovement(struct aas_clientmove_s *move,
    995 								int entnum, vec3_t origin,
    996 								int presencetype, int onground,
    997 								vec3_t velocity, vec3_t cmdmove,
    998 								int cmdframes,
    999 								int maxframes, float frametime,
   1000 								int stopevent, int stopareanum, int visualize)
   1001 {
   1002 	vec3_t mins, maxs;
   1003 	return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground,
   1004 										velocity, cmdmove, cmdframes, maxframes,
   1005 										frametime, stopevent, stopareanum,
   1006 										mins, maxs, visualize);
   1007 } //end of the function AAS_PredictClientMovement
   1008 //===========================================================================
   1009 //
   1010 // Parameter:			-
   1011 // Returns:				-
   1012 // Changes Globals:		-
   1013 //===========================================================================
   1014 int AAS_ClientMovementHitBBox(struct aas_clientmove_s *move,
   1015 								int entnum, vec3_t origin,
   1016 								int presencetype, int onground,
   1017 								vec3_t velocity, vec3_t cmdmove,
   1018 								int cmdframes,
   1019 								int maxframes, float frametime,
   1020 								vec3_t mins, vec3_t maxs, int visualize)
   1021 {
   1022 	return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground,
   1023 										velocity, cmdmove, cmdframes, maxframes,
   1024 										frametime, SE_HITBOUNDINGBOX, 0,
   1025 										mins, maxs, visualize);
   1026 } //end of the function AAS_ClientMovementHitBBox
   1027 //===========================================================================
   1028 //
   1029 // Parameter:			-
   1030 // Returns:				-
   1031 // Changes Globals:		-
   1032 //===========================================================================
   1033 void AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir)
   1034 {
   1035 	vec3_t velocity, cmdmove;
   1036 	aas_clientmove_t move;
   1037 
   1038 	VectorClear(velocity);
   1039 	if (!AAS_Swimming(origin)) dir[2] = 0;
   1040 	VectorNormalize(dir);
   1041 	VectorScale(dir, 400, cmdmove);
   1042 	cmdmove[2] = 224;
   1043 	AAS_ClearShownDebugLines();
   1044 	AAS_PredictClientMovement(&move, entnum, origin, PRESENCE_NORMAL, qtrue,
   1045 									velocity, cmdmove, 13, 13, 0.1f, SE_HITGROUND, 0, qtrue);//SE_LEAVEGROUND);
   1046 	if (move.stopevent & SE_LEAVEGROUND)
   1047 	{
   1048 		botimport.Print(PRT_MESSAGE, "leave ground\n");
   1049 	} //end if
   1050 } //end of the function TestMovementPrediction
   1051 //===========================================================================
   1052 // calculates the horizontal velocity needed to perform a jump from start
   1053 // to end
   1054 //
   1055 // Parameter:			zvel	: z velocity for jump
   1056 //						start	: start position of jump
   1057 //						end		: end position of jump
   1058 //						*speed	: returned speed for jump
   1059 // Returns:				qfalse if too high or too far from start to end
   1060 // Changes Globals:		-
   1061 //===========================================================================
   1062 int AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity)
   1063 {
   1064 	float phys_gravity, phys_maxvelocity;
   1065 	float maxjump, height2fall, t, top;
   1066 	vec3_t dir;
   1067 
   1068 	phys_gravity = aassettings.phys_gravity;
   1069 	phys_maxvelocity = aassettings.phys_maxvelocity;
   1070 
   1071 	//maximum height a player can jump with the given initial z velocity
   1072 	maxjump = 0.5 * phys_gravity * (zvel / phys_gravity) * (zvel / phys_gravity);
   1073 	//top of the parabolic jump
   1074 	top = start[2] + maxjump;
   1075 	//height the bot will fall from the top
   1076 	height2fall = top - end[2];
   1077 	//if the goal is to high to jump to
   1078 	if (height2fall < 0)
   1079 	{
   1080 		*velocity = phys_maxvelocity;
   1081 		return 0;
   1082 	} //end if
   1083 	//time a player takes to fall the height
   1084 	t = sqrt(height2fall / (0.5 * phys_gravity));
   1085   	//direction from start to end
   1086 	VectorSubtract(end, start, dir);
   1087 	//
   1088 	if ( (t + zvel / phys_gravity) == 0.0f ) {
   1089 		*velocity = phys_maxvelocity;
   1090 		return 0;
   1091 	}
   1092 	//calculate horizontal speed
   1093 	*velocity = sqrt(dir[0]*dir[0] + dir[1]*dir[1]) / (t + zvel / phys_gravity);
   1094 	//the horizontal speed must be lower than the max speed
   1095 	if (*velocity > phys_maxvelocity)
   1096 	{
   1097 		*velocity = phys_maxvelocity;
   1098 		return 0;
   1099 	} //end if
   1100 	return 1;
   1101 } //end of the function AAS_HorizontalVelocityForJump