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