be_ai_move.c (113070B)
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_ai_move.c 25 * 26 * desc: bot movement AI 27 * 28 * $Archive: /MissionPack/code/botlib/be_ai_move.c $ 29 * 30 *****************************************************************************/ 31 32 #include "../game/q_shared.h" 33 #include "l_memory.h" 34 #include "l_libvar.h" 35 #include "l_utils.h" 36 #include "l_script.h" 37 #include "l_precomp.h" 38 #include "l_struct.h" 39 #include "aasfile.h" 40 #include "../game/botlib.h" 41 #include "../game/be_aas.h" 42 #include "be_aas_funcs.h" 43 #include "be_interface.h" 44 45 #include "../game/be_ea.h" 46 #include "../game/be_ai_goal.h" 47 #include "../game/be_ai_move.h" 48 49 50 //#define DEBUG_AI_MOVE 51 //#define DEBUG_ELEVATOR 52 //#define DEBUG_GRAPPLE 53 54 // bk001204 - redundant bot_avoidspot_t, see ../game/be_ai_move.h 55 56 //movement state 57 //NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and 58 // MFL_GRAPPLEPULL must be set outside the movement code 59 typedef struct bot_movestate_s 60 { 61 //input vars (all set outside the movement code) 62 vec3_t origin; //origin of the bot 63 vec3_t velocity; //velocity of the bot 64 vec3_t viewoffset; //view offset 65 int entitynum; //entity number of the bot 66 int client; //client number of the bot 67 float thinktime; //time the bot thinks 68 int presencetype; //presencetype of the bot 69 vec3_t viewangles; //view angles of the bot 70 //state vars 71 int areanum; //area the bot is in 72 int lastareanum; //last area the bot was in 73 int lastgoalareanum; //last goal area number 74 int lastreachnum; //last reachability number 75 vec3_t lastorigin; //origin previous cycle 76 int reachareanum; //area number of the reachabilty 77 int moveflags; //movement flags 78 int jumpreach; //set when jumped 79 float grapplevisible_time; //last time the grapple was visible 80 float lastgrappledist; //last distance to the grapple end 81 float reachability_time; //time to use current reachability 82 int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid 83 float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities 84 int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding 85 // 86 bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid 87 int numavoidspots; 88 } bot_movestate_t; 89 90 //used to avoid reachability links for some time after being used 91 #define AVOIDREACH 92 #define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use 93 #define AVOIDREACH_TRIES 4 94 //prediction times 95 #define PREDICTIONTIME_JUMP 3 //in seconds 96 #define PREDICTIONTIME_MOVE 2 //in seconds 97 //weapon indexes for weapon jumping 98 #define WEAPONINDEX_ROCKET_LAUNCHER 5 99 #define WEAPONINDEX_BFG 9 100 101 #define MODELTYPE_FUNC_PLAT 1 102 #define MODELTYPE_FUNC_BOB 2 103 #define MODELTYPE_FUNC_DOOR 3 104 #define MODELTYPE_FUNC_STATIC 4 105 106 libvar_t *sv_maxstep; 107 libvar_t *sv_maxbarrier; 108 libvar_t *sv_gravity; 109 libvar_t *weapindex_rocketlauncher; 110 libvar_t *weapindex_bfg10k; 111 libvar_t *weapindex_grapple; 112 libvar_t *entitytypemissile; 113 libvar_t *offhandgrapple; 114 libvar_t *cmd_grappleoff; 115 libvar_t *cmd_grappleon; 116 //type of model, func_plat or func_bobbing 117 int modeltypes[MAX_MODELS]; 118 119 bot_movestate_t *botmovestates[MAX_CLIENTS+1]; 120 121 //======================================================================== 122 // 123 // Parameter: - 124 // Returns: - 125 // Changes Globals: - 126 //======================================================================== 127 int BotAllocMoveState(void) 128 { 129 int i; 130 131 for (i = 1; i <= MAX_CLIENTS; i++) 132 { 133 if (!botmovestates[i]) 134 { 135 botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t)); 136 return i; 137 } //end if 138 } //end for 139 return 0; 140 } //end of the function BotAllocMoveState 141 //======================================================================== 142 // 143 // Parameter: - 144 // Returns: - 145 // Changes Globals: - 146 //======================================================================== 147 void BotFreeMoveState(int handle) 148 { 149 if (handle <= 0 || handle > MAX_CLIENTS) 150 { 151 botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); 152 return; 153 } //end if 154 if (!botmovestates[handle]) 155 { 156 botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); 157 return; 158 } //end if 159 FreeMemory(botmovestates[handle]); 160 botmovestates[handle] = NULL; 161 } //end of the function BotFreeMoveState 162 //======================================================================== 163 // 164 // Parameter: - 165 // Returns: - 166 // Changes Globals: - 167 //======================================================================== 168 bot_movestate_t *BotMoveStateFromHandle(int handle) 169 { 170 if (handle <= 0 || handle > MAX_CLIENTS) 171 { 172 botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); 173 return NULL; 174 } //end if 175 if (!botmovestates[handle]) 176 { 177 botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); 178 return NULL; 179 } //end if 180 return botmovestates[handle]; 181 } //end of the function BotMoveStateFromHandle 182 //======================================================================== 183 // 184 // Parameter: - 185 // Returns: - 186 // Changes Globals: - 187 //======================================================================== 188 void BotInitMoveState(int handle, bot_initmove_t *initmove) 189 { 190 bot_movestate_t *ms; 191 192 ms = BotMoveStateFromHandle(handle); 193 if (!ms) return; 194 VectorCopy(initmove->origin, ms->origin); 195 VectorCopy(initmove->velocity, ms->velocity); 196 VectorCopy(initmove->viewoffset, ms->viewoffset); 197 ms->entitynum = initmove->entitynum; 198 ms->client = initmove->client; 199 ms->thinktime = initmove->thinktime; 200 ms->presencetype = initmove->presencetype; 201 VectorCopy(initmove->viewangles, ms->viewangles); 202 // 203 ms->moveflags &= ~MFL_ONGROUND; 204 if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND; 205 ms->moveflags &= ~MFL_TELEPORTED; 206 if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED; 207 ms->moveflags &= ~MFL_WATERJUMP; 208 if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP; 209 ms->moveflags &= ~MFL_WALK; 210 if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK; 211 ms->moveflags &= ~MFL_GRAPPLEPULL; 212 if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL; 213 } //end of the function BotInitMoveState 214 //======================================================================== 215 // 216 // Parameter: - 217 // Returns: - 218 // Changes Globals: - 219 //======================================================================== 220 float AngleDiff(float ang1, float ang2) 221 { 222 float diff; 223 224 diff = ang1 - ang2; 225 if (ang1 > ang2) 226 { 227 if (diff > 180.0) diff -= 360.0; 228 } //end if 229 else 230 { 231 if (diff < -180.0) diff += 360.0; 232 } //end else 233 return diff; 234 } //end of the function AngleDiff 235 //=========================================================================== 236 // 237 // Parameter: - 238 // Returns: - 239 // Changes Globals: - 240 //=========================================================================== 241 int BotFuzzyPointReachabilityArea(vec3_t origin) 242 { 243 int firstareanum, j, x, y, z; 244 int areas[10], numareas, areanum, bestareanum; 245 float dist, bestdist; 246 vec3_t points[10], v, end; 247 248 firstareanum = 0; 249 areanum = AAS_PointAreaNum(origin); 250 if (areanum) 251 { 252 firstareanum = areanum; 253 if (AAS_AreaReachability(areanum)) return areanum; 254 } //end if 255 VectorCopy(origin, end); 256 end[2] += 4; 257 numareas = AAS_TraceAreas(origin, end, areas, points, 10); 258 for (j = 0; j < numareas; j++) 259 { 260 if (AAS_AreaReachability(areas[j])) return areas[j]; 261 } //end for 262 bestdist = 999999; 263 bestareanum = 0; 264 for (z = 1; z >= -1; z -= 1) 265 { 266 for (x = 1; x >= -1; x -= 1) 267 { 268 for (y = 1; y >= -1; y -= 1) 269 { 270 VectorCopy(origin, end); 271 end[0] += x * 8; 272 end[1] += y * 8; 273 end[2] += z * 12; 274 numareas = AAS_TraceAreas(origin, end, areas, points, 10); 275 for (j = 0; j < numareas; j++) 276 { 277 if (AAS_AreaReachability(areas[j])) 278 { 279 VectorSubtract(points[j], origin, v); 280 dist = VectorLength(v); 281 if (dist < bestdist) 282 { 283 bestareanum = areas[j]; 284 bestdist = dist; 285 } //end if 286 } //end if 287 if (!firstareanum) firstareanum = areas[j]; 288 } //end for 289 } //end for 290 } //end for 291 if (bestareanum) return bestareanum; 292 } //end for 293 return firstareanum; 294 } //end of the function BotFuzzyPointReachabilityArea 295 //=========================================================================== 296 // 297 // Parameter: - 298 // Returns: - 299 // Changes Globals: - 300 //=========================================================================== 301 int BotReachabilityArea(vec3_t origin, int client) 302 { 303 int modelnum, modeltype, reachnum, areanum; 304 aas_reachability_t reach; 305 vec3_t org, end, mins, maxs, up = {0, 0, 1}; 306 bsp_trace_t bsptrace; 307 aas_trace_t trace; 308 309 //check if the bot is standing on something 310 AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs); 311 VectorMA(origin, -3, up, end); 312 bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); 313 if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE) 314 { 315 //if standing on the world the bot should be in a valid area 316 if (bsptrace.ent == ENTITYNUM_WORLD) 317 { 318 return BotFuzzyPointReachabilityArea(origin); 319 } //end if 320 321 modelnum = AAS_EntityModelindex(bsptrace.ent); 322 modeltype = modeltypes[modelnum]; 323 324 //if standing on a func_plat or func_bobbing then the bot is assumed to be 325 //in the area the reachability points to 326 if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB) 327 { 328 reachnum = AAS_NextModelReachability(0, modelnum); 329 if (reachnum) 330 { 331 AAS_ReachabilityFromNum(reachnum, &reach); 332 return reach.areanum; 333 } //end if 334 } //end else if 335 336 //if the bot is swimming the bot should be in a valid area 337 if (AAS_Swimming(origin)) 338 { 339 return BotFuzzyPointReachabilityArea(origin); 340 } //end if 341 // 342 areanum = BotFuzzyPointReachabilityArea(origin); 343 //if the bot is in an area with reachabilities 344 if (areanum && AAS_AreaReachability(areanum)) return areanum; 345 //trace down till the ground is hit because the bot is standing on some other entity 346 VectorCopy(origin, org); 347 VectorCopy(org, end); 348 end[2] -= 800; 349 trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1); 350 if (!trace.startsolid) 351 { 352 VectorCopy(trace.endpos, org); 353 } //end if 354 // 355 return BotFuzzyPointReachabilityArea(org); 356 } //end if 357 // 358 return BotFuzzyPointReachabilityArea(origin); 359 } //end of the function BotReachabilityArea 360 //=========================================================================== 361 // returns the reachability area the bot is in 362 // 363 // Parameter: - 364 // Returns: - 365 // Changes Globals: - 366 //=========================================================================== 367 /* 368 int BotReachabilityArea(vec3_t origin, int testground) 369 { 370 int firstareanum, i, j, x, y, z; 371 int areas[10], numareas, areanum, bestareanum; 372 float dist, bestdist; 373 vec3_t org, end, points[10], v; 374 aas_trace_t trace; 375 376 firstareanum = 0; 377 for (i = 0; i < 2; i++) 378 { 379 VectorCopy(origin, org); 380 //if test at the ground (used when bot is standing on an entity) 381 if (i > 0) 382 { 383 VectorCopy(origin, end); 384 end[2] -= 800; 385 trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1); 386 if (!trace.startsolid) 387 { 388 VectorCopy(trace.endpos, org); 389 } //end if 390 } //end if 391 392 firstareanum = 0; 393 areanum = AAS_PointAreaNum(org); 394 if (areanum) 395 { 396 firstareanum = areanum; 397 if (AAS_AreaReachability(areanum)) return areanum; 398 } //end if 399 bestdist = 999999; 400 bestareanum = 0; 401 for (z = 1; z >= -1; z -= 1) 402 { 403 for (x = 1; x >= -1; x -= 1) 404 { 405 for (y = 1; y >= -1; y -= 1) 406 { 407 VectorCopy(org, end); 408 end[0] += x * 8; 409 end[1] += y * 8; 410 end[2] += z * 12; 411 numareas = AAS_TraceAreas(org, end, areas, points, 10); 412 for (j = 0; j < numareas; j++) 413 { 414 if (AAS_AreaReachability(areas[j])) 415 { 416 VectorSubtract(points[j], org, v); 417 dist = VectorLength(v); 418 if (dist < bestdist) 419 { 420 bestareanum = areas[j]; 421 bestdist = dist; 422 } //end if 423 } //end if 424 } //end for 425 } //end for 426 } //end for 427 if (bestareanum) return bestareanum; 428 } //end for 429 if (!testground) break; 430 } //end for 431 //#ifdef DEBUG 432 //botimport.Print(PRT_MESSAGE, "no reachability area\n"); 433 //#endif //DEBUG 434 return firstareanum; 435 } //end of the function BotReachabilityArea*/ 436 //=========================================================================== 437 // 438 // Parameter: - 439 // Returns: - 440 // Changes Globals: - 441 //=========================================================================== 442 int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach) 443 { 444 int i, modelnum; 445 vec3_t mins, maxs, modelorigin, org, end; 446 vec3_t angles = {0, 0, 0}; 447 vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8}; 448 bsp_trace_t trace; 449 450 modelnum = reach->facenum & 0x0000FFFF; 451 //get some bsp model info 452 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); 453 // 454 if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin)) 455 { 456 botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); 457 return qfalse; 458 } //end if 459 // 460 for (i = 0; i < 2; i++) 461 { 462 if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse; 463 if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse; 464 } //end for 465 // 466 VectorCopy(origin, org); 467 org[2] += 24; 468 VectorCopy(origin, end); 469 end[2] -= 48; 470 // 471 trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); 472 if (!trace.startsolid && !trace.allsolid) 473 { 474 //NOTE: the reachability face number is the model number of the elevator 475 if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum) 476 { 477 return qtrue; 478 } //end if 479 } //end if 480 return qfalse; 481 } //end of the function BotOnMover 482 //=========================================================================== 483 // 484 // Parameter: - 485 // Returns: - 486 // Changes Globals: - 487 //=========================================================================== 488 int MoverDown(aas_reachability_t *reach) 489 { 490 int modelnum; 491 vec3_t mins, maxs, origin; 492 vec3_t angles = {0, 0, 0}; 493 494 modelnum = reach->facenum & 0x0000FFFF; 495 //get some bsp model info 496 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); 497 // 498 if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) 499 { 500 botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); 501 return qfalse; 502 } //end if 503 //if the top of the plat is below the reachability start point 504 if (origin[2] + maxs[2] < reach->start[2]) return qtrue; 505 return qfalse; 506 } //end of the function MoverDown 507 //======================================================================== 508 // 509 // Parameter: - 510 // Returns: - 511 // Changes Globals: - 512 //======================================================================== 513 void BotSetBrushModelTypes(void) 514 { 515 int ent, modelnum; 516 char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; 517 518 Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int)); 519 // 520 for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) 521 { 522 if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; 523 if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue; 524 if (model[0]) modelnum = atoi(model+1); 525 else modelnum = 0; 526 527 if (modelnum < 0 || modelnum > MAX_MODELS) 528 { 529 botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname); 530 continue; 531 } //end if 532 533 if (!Q_stricmp(classname, "func_bobbing")) 534 modeltypes[modelnum] = MODELTYPE_FUNC_BOB; 535 else if (!Q_stricmp(classname, "func_plat")) 536 modeltypes[modelnum] = MODELTYPE_FUNC_PLAT; 537 else if (!Q_stricmp(classname, "func_door")) 538 modeltypes[modelnum] = MODELTYPE_FUNC_DOOR; 539 else if (!Q_stricmp(classname, "func_static")) 540 modeltypes[modelnum] = MODELTYPE_FUNC_STATIC; 541 } //end for 542 } //end of the function BotSetBrushModelTypes 543 //=========================================================================== 544 // 545 // Parameter: - 546 // Returns: - 547 // Changes Globals: - 548 //=========================================================================== 549 int BotOnTopOfEntity(bot_movestate_t *ms) 550 { 551 vec3_t mins, maxs, end, up = {0, 0, 1}; 552 bsp_trace_t trace; 553 554 AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); 555 VectorMA(ms->origin, -3, up, end); 556 trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); 557 if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) 558 { 559 return trace.ent; 560 } //end if 561 return -1; 562 } //end of the function BotOnTopOfEntity 563 //=========================================================================== 564 // 565 // Parameter: - 566 // Returns: - 567 // Changes Globals: - 568 //=========================================================================== 569 int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags) 570 { 571 //if the reachability uses an unwanted travel type 572 if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse; 573 //don't go into areas with bad travel types 574 if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse; 575 return qtrue; 576 } //end of the function BotValidTravel 577 //=========================================================================== 578 // 579 // Parameter: - 580 // Returns: - 581 // Changes Globals: - 582 //=========================================================================== 583 void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime) 584 { 585 int i; 586 587 for (i = 0; i < MAX_AVOIDREACH; i++) 588 { 589 if (ms->avoidreach[i] == number) 590 { 591 if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++; 592 else ms->avoidreachtries[i] = 1; 593 ms->avoidreachtimes[i] = AAS_Time() + avoidtime; 594 return; 595 } //end if 596 } //end for 597 //add the reachability to the reachabilities to avoid for a while 598 for (i = 0; i < MAX_AVOIDREACH; i++) 599 { 600 if (ms->avoidreachtimes[i] < AAS_Time()) 601 { 602 ms->avoidreach[i] = number; 603 ms->avoidreachtimes[i] = AAS_Time() + avoidtime; 604 ms->avoidreachtries[i] = 1; 605 return; 606 } //end if 607 } //end for 608 } //end of the function BotAddToAvoidReach 609 //=========================================================================== 610 // 611 // Parameter: - 612 // Returns: - 613 // Changes Globals: - 614 //=========================================================================== 615 float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2) 616 { 617 vec3_t proj, dir; 618 int j; 619 620 AAS_ProjectPointOntoVector(p, lp1, lp2, proj); 621 for (j = 0; j < 3; j++) 622 if ((proj[j] > lp1[j] && proj[j] > lp2[j]) || 623 (proj[j] < lp1[j] && proj[j] < lp2[j])) 624 break; 625 if (j < 3) { 626 if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j])) 627 VectorSubtract(p, lp1, dir); 628 else 629 VectorSubtract(p, lp2, dir); 630 return VectorLengthSquared(dir); 631 } 632 VectorSubtract(p, proj, dir); 633 return VectorLengthSquared(dir); 634 } //end of the function DistanceFromLineSquared 635 //=========================================================================== 636 // 637 // Parameter: - 638 // Returns: - 639 // Changes Globals: - 640 //=========================================================================== 641 float VectorDistanceSquared(vec3_t p1, vec3_t p2) 642 { 643 vec3_t dir; 644 VectorSubtract(p2, p1, dir); 645 return VectorLengthSquared(dir); 646 } //end of the function VectorDistanceSquared 647 //=========================================================================== 648 // 649 // Parameter: - 650 // Returns: - 651 // Changes Globals: - 652 //=========================================================================== 653 int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots) 654 { 655 int checkbetween, i, type; 656 float squareddist, squaredradius; 657 658 switch(reach->traveltype & TRAVELTYPE_MASK) 659 { 660 case TRAVEL_WALK: checkbetween = qtrue; break; 661 case TRAVEL_CROUCH: checkbetween = qtrue; break; 662 case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break; 663 case TRAVEL_LADDER: checkbetween = qtrue; break; 664 case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break; 665 case TRAVEL_JUMP: checkbetween = qfalse; break; 666 case TRAVEL_SWIM: checkbetween = qtrue; break; 667 case TRAVEL_WATERJUMP: checkbetween = qtrue; break; 668 case TRAVEL_TELEPORT: checkbetween = qfalse; break; 669 case TRAVEL_ELEVATOR: checkbetween = qfalse; break; 670 case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break; 671 case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break; 672 case TRAVEL_BFGJUMP: checkbetween = qfalse; break; 673 case TRAVEL_JUMPPAD: checkbetween = qfalse; break; 674 case TRAVEL_FUNCBOB: checkbetween = qfalse; break; 675 default: checkbetween = qtrue; break; 676 } //end switch 677 678 type = AVOID_CLEAR; 679 for (i = 0; i < numavoidspots; i++) 680 { 681 squaredradius = Square(avoidspots[i].radius); 682 squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start); 683 // if moving towards the avoid spot 684 if (squareddist < squaredradius && 685 VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist) 686 { 687 type = avoidspots[i].type; 688 } //end if 689 else if (checkbetween) { 690 squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end); 691 // if moving towards the avoid spot 692 if (squareddist < squaredradius && 693 VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) 694 { 695 type = avoidspots[i].type; 696 } //end if 697 } //end if 698 else 699 { 700 VectorDistanceSquared(avoidspots[i].origin, reach->end); 701 // if the reachability leads closer to the avoid spot 702 if (squareddist < squaredradius && 703 VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) 704 { 705 type = avoidspots[i].type; 706 } //end if 707 } //end else 708 if (type == AVOID_ALWAYS) 709 return type; 710 } //end for 711 return type; 712 } //end of the function BotAvoidSpots 713 //=========================================================================== 714 // 715 // Parameter: - 716 // Returns: - 717 // Changes Globals: - 718 //=========================================================================== 719 void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) 720 { 721 bot_movestate_t *ms; 722 723 ms = BotMoveStateFromHandle(movestate); 724 if (!ms) return; 725 if (type == AVOID_CLEAR) 726 { 727 ms->numavoidspots = 0; 728 return; 729 } //end if 730 731 if (ms->numavoidspots >= MAX_AVOIDSPOTS) 732 return; 733 VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin); 734 ms->avoidspots[ms->numavoidspots].radius = radius; 735 ms->avoidspots[ms->numavoidspots].type = type; 736 ms->numavoidspots++; 737 } //end of the function BotAddAvoidSpot 738 //=========================================================================== 739 // 740 // Parameter: - 741 // Returns: - 742 // Changes Globals: - 743 //=========================================================================== 744 int BotGetReachabilityToGoal(vec3_t origin, int areanum, 745 int lastgoalareanum, int lastareanum, 746 int *avoidreach, float *avoidreachtimes, int *avoidreachtries, 747 bot_goal_t *goal, int travelflags, int movetravelflags, 748 struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags) 749 { 750 int i, t, besttime, bestreachnum, reachnum; 751 aas_reachability_t reach; 752 753 //if not in a valid area 754 if (!areanum) return 0; 755 // 756 if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum)) 757 { 758 travelflags |= TFL_DONOTENTER; 759 movetravelflags |= TFL_DONOTENTER; 760 } //end if 761 //use the routing to find the next area to go to 762 besttime = 0; 763 bestreachnum = 0; 764 // 765 for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum; 766 reachnum = AAS_NextAreaReachability(areanum, reachnum)) 767 { 768 #ifdef AVOIDREACH 769 //check if it isn't an reachability to avoid 770 for (i = 0; i < MAX_AVOIDREACH; i++) 771 { 772 if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break; 773 } //end for 774 if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES) 775 { 776 #ifdef DEBUG 777 if (bot_developer) 778 { 779 botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]); 780 } //end if 781 #endif //DEBUG 782 continue; 783 } //end if 784 #endif //AVOIDREACH 785 //get the reachability from the number 786 AAS_ReachabilityFromNum(reachnum, &reach); 787 //NOTE: do not go back to the previous area if the goal didn't change 788 //NOTE: is this actually avoidance of local routing minima between two areas??? 789 if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue; 790 //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue; 791 //if the travel isn't valid 792 if (!BotValidTravel(origin, &reach, movetravelflags)) continue; 793 //get the travel time 794 t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags); 795 //if the goal area isn't reachable from the reachable area 796 if (!t) continue; 797 //if the bot should not use this reachability to avoid bad spots 798 if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) { 799 if (flags) { 800 *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT; 801 } 802 continue; 803 } 804 //add the travel time towards the area 805 t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start); 806 //if the travel time is better than the ones already found 807 if (!besttime || t < besttime) 808 { 809 besttime = t; 810 bestreachnum = reachnum; 811 } //end if 812 } //end for 813 // 814 return bestreachnum; 815 } //end of the function BotGetReachabilityToGoal 816 //=========================================================================== 817 // 818 // Parameter: - 819 // Returns: - 820 // Changes Globals: - 821 //=========================================================================== 822 int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target) 823 { 824 vec3_t dir; 825 float curdist; 826 827 VectorSubtract(end, start, dir); 828 curdist = VectorNormalize(dir); 829 if (*dist + curdist < maxdist) 830 { 831 VectorCopy(end, target); 832 *dist += curdist; 833 return qfalse; 834 } //end if 835 else 836 { 837 VectorMA(start, maxdist - *dist, dir, target); 838 *dist = maxdist; 839 return qtrue; 840 } //end else 841 } //end of the function BotAddToTarget 842 843 int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target) 844 { 845 aas_reachability_t reach; 846 int reachnum, lastareanum; 847 bot_movestate_t *ms; 848 vec3_t end; 849 float dist; 850 851 ms = BotMoveStateFromHandle(movestate); 852 if (!ms) return qfalse; 853 reachnum = 0; 854 //if the bot has no goal or no last reachability 855 if (!ms->lastreachnum || !goal) return qfalse; 856 857 reachnum = ms->lastreachnum; 858 VectorCopy(ms->origin, end); 859 lastareanum = ms->lastareanum; 860 dist = 0; 861 while(reachnum && dist < lookahead) 862 { 863 AAS_ReachabilityFromNum(reachnum, &reach); 864 if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue; 865 //never look beyond teleporters 866 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue; 867 //never look beyond the weapon jump point 868 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue; 869 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue; 870 //don't add jump pad distances 871 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD && 872 (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR && 873 (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB) 874 { 875 if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue; 876 } //end if 877 reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum, 878 ms->lastgoalareanum, lastareanum, 879 ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, 880 goal, travelflags, travelflags, NULL, 0, NULL); 881 VectorCopy(reach.end, end); 882 lastareanum = reach.areanum; 883 if (lastareanum == goal->areanum) 884 { 885 BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target); 886 return qtrue; 887 } //end if 888 } //end while 889 // 890 return qfalse; 891 } //end of the function BotMovementViewTarget 892 //=========================================================================== 893 // 894 // Parameter: - 895 // Returns: - 896 // Changes Globals: - 897 //=========================================================================== 898 int BotVisible(int ent, vec3_t eye, vec3_t target) 899 { 900 bsp_trace_t trace; 901 902 trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); 903 if (trace.fraction >= 1) return qtrue; 904 return qfalse; 905 } //end of the function BotVisible 906 //=========================================================================== 907 // 908 // Parameter: - 909 // Returns: - 910 // Changes Globals: - 911 //=========================================================================== 912 int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target) 913 { 914 aas_reachability_t reach; 915 int reachnum, lastgoalareanum, lastareanum, i; 916 int avoidreach[MAX_AVOIDREACH]; 917 float avoidreachtimes[MAX_AVOIDREACH]; 918 int avoidreachtries[MAX_AVOIDREACH]; 919 vec3_t end; 920 921 //if the bot has no goal or no last reachability 922 if (!goal) return qfalse; 923 //if the areanum is not valid 924 if (!areanum) return qfalse; 925 //if the goal areanum is not valid 926 if (!goal->areanum) return qfalse; 927 928 Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); 929 lastgoalareanum = goal->areanum; 930 lastareanum = areanum; 931 VectorCopy(origin, end); 932 //only do 20 hops 933 for (i = 0; i < 20 && (areanum != goal->areanum); i++) 934 { 935 // 936 reachnum = BotGetReachabilityToGoal(end, areanum, 937 lastgoalareanum, lastareanum, 938 avoidreach, avoidreachtimes, avoidreachtries, 939 goal, travelflags, travelflags, NULL, 0, NULL); 940 if (!reachnum) return qfalse; 941 AAS_ReachabilityFromNum(reachnum, &reach); 942 // 943 if (BotVisible(goal->entitynum, goal->origin, reach.start)) 944 { 945 VectorCopy(reach.start, target); 946 return qtrue; 947 } //end if 948 // 949 if (BotVisible(goal->entitynum, goal->origin, reach.end)) 950 { 951 VectorCopy(reach.end, target); 952 return qtrue; 953 } //end if 954 // 955 if (reach.areanum == goal->areanum) 956 { 957 VectorCopy(reach.end, target); 958 return qtrue; 959 } //end if 960 // 961 lastareanum = areanum; 962 areanum = reach.areanum; 963 VectorCopy(reach.end, end); 964 // 965 } //end while 966 // 967 return qfalse; 968 } //end of the function BotPredictVisiblePosition 969 //=========================================================================== 970 // 971 // Parameter: - 972 // Returns: - 973 // Changes Globals: - 974 //=========================================================================== 975 void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter) 976 { 977 int modelnum; 978 vec3_t mins, maxs, origin, mids; 979 vec3_t angles = {0, 0, 0}; 980 981 modelnum = reach->facenum & 0x0000FFFF; 982 //get some bsp model info 983 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); 984 // 985 if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) 986 { 987 botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); 988 } //end if 989 //get a point just above the plat in the bottom position 990 VectorAdd(mins, maxs, mids); 991 VectorMA(origin, 0.5, mids, bottomcenter); 992 bottomcenter[2] = reach->start[2]; 993 } //end of the function MoverBottomCenter 994 //=========================================================================== 995 // 996 // Parameter: - 997 // Returns: - 998 // Changes Globals: - 999 //=========================================================================== 1000 float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum) 1001 { 1002 float dist, startz; 1003 vec3_t start, end; 1004 aas_trace_t trace; 1005 1006 //do gap checking 1007 startz = origin[2]; 1008 //this enables walking down stairs more fluidly 1009 { 1010 VectorCopy(origin, start); 1011 VectorCopy(origin, end); 1012 end[2] -= 60; 1013 trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); 1014 if (trace.fraction >= 1) return 1; 1015 startz = trace.endpos[2] + 1; 1016 } 1017 // 1018 for (dist = 8; dist <= 100; dist += 8) 1019 { 1020 VectorMA(origin, dist, hordir, start); 1021 start[2] = startz + 24; 1022 VectorCopy(start, end); 1023 end[2] -= 48 + sv_maxbarrier->value; 1024 trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); 1025 //if solid is found the bot can't walk any further and fall into a gap 1026 if (!trace.startsolid) 1027 { 1028 //if it is a gap 1029 if (trace.endpos[2] < startz - sv_maxstep->value - 8) 1030 { 1031 VectorCopy(trace.endpos, end); 1032 end[2] -= 20; 1033 if (AAS_PointContents(end) & CONTENTS_WATER) break; 1034 //if a gap is found slow down 1035 //botimport.Print(PRT_MESSAGE, "gap at %f\n", dist); 1036 return dist; 1037 } //end if 1038 startz = trace.endpos[2]; 1039 } //end if 1040 } //end for 1041 return 0; 1042 } //end of the function BotGapDistance 1043 //=========================================================================== 1044 // 1045 // Parameter: - 1046 // Returns: - 1047 // Changes Globals: - 1048 //=========================================================================== 1049 int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed) 1050 { 1051 vec3_t start, hordir, end; 1052 aas_trace_t trace; 1053 1054 VectorCopy(ms->origin, end); 1055 end[2] += sv_maxbarrier->value; 1056 //trace right up 1057 trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum); 1058 //this shouldn't happen... but we check anyway 1059 if (trace.startsolid) return qfalse; 1060 //if very low ceiling it isn't possible to jump up to a barrier 1061 if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; 1062 // 1063 hordir[0] = dir[0]; 1064 hordir[1] = dir[1]; 1065 hordir[2] = 0; 1066 VectorNormalize(hordir); 1067 VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end); 1068 VectorCopy(trace.endpos, start); 1069 end[2] = trace.endpos[2]; 1070 //trace from previous trace end pos horizontally in the move direction 1071 trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); 1072 //again this shouldn't happen 1073 if (trace.startsolid) return qfalse; 1074 // 1075 VectorCopy(trace.endpos, start); 1076 VectorCopy(trace.endpos, end); 1077 end[2] = ms->origin[2]; 1078 //trace down from the previous trace end pos 1079 trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); 1080 //if solid 1081 if (trace.startsolid) return qfalse; 1082 //if no obstacle at all 1083 if (trace.fraction >= 1.0) return qfalse; 1084 //if less than the maximum step height 1085 if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; 1086 // 1087 EA_Jump(ms->client); 1088 EA_Move(ms->client, hordir, speed); 1089 ms->moveflags |= MFL_BARRIERJUMP; 1090 //there is a barrier 1091 return qtrue; 1092 } //end of the function BotCheckBarrierJump 1093 //=========================================================================== 1094 // 1095 // Parameter: - 1096 // Returns: - 1097 // Changes Globals: - 1098 //=========================================================================== 1099 int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) 1100 { 1101 vec3_t normdir; 1102 1103 VectorCopy(dir, normdir); 1104 VectorNormalize(normdir); 1105 EA_Move(ms->client, normdir, speed); 1106 return qtrue; 1107 } //end of the function BotSwimInDirection 1108 //=========================================================================== 1109 // 1110 // Parameter: - 1111 // Returns: - 1112 // Changes Globals: - 1113 //=========================================================================== 1114 int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) 1115 { 1116 vec3_t hordir, cmdmove, velocity, tmpdir, origin; 1117 int presencetype, maxframes, cmdframes, stopevent; 1118 aas_clientmove_t move; 1119 float dist; 1120 1121 if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; 1122 //if the bot is on the ground 1123 if (ms->moveflags & MFL_ONGROUND) 1124 { 1125 //if there is a barrier the bot can jump on 1126 if (BotCheckBarrierJump(ms, dir, speed)) return qtrue; 1127 //remove barrier jump flag 1128 ms->moveflags &= ~MFL_BARRIERJUMP; 1129 //get the presence type for the movement 1130 if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH; 1131 else presencetype = PRESENCE_NORMAL; 1132 //horizontal direction 1133 hordir[0] = dir[0]; 1134 hordir[1] = dir[1]; 1135 hordir[2] = 0; 1136 VectorNormalize(hordir); 1137 //if the bot is not supposed to jump 1138 if (!(type & MOVE_JUMP)) 1139 { 1140 //if there is a gap, try to jump over it 1141 if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP; 1142 } //end if 1143 //get command movement 1144 VectorScale(hordir, speed, cmdmove); 1145 VectorCopy(ms->velocity, velocity); 1146 // 1147 if (type & MOVE_JUMP) 1148 { 1149 //botimport.Print(PRT_MESSAGE, "trying jump\n"); 1150 cmdmove[2] = 400; 1151 maxframes = PREDICTIONTIME_JUMP / 0.1; 1152 cmdframes = 1; 1153 stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE| 1154 SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; 1155 } //end if 1156 else 1157 { 1158 maxframes = 2; 1159 cmdframes = 2; 1160 stopevent = SE_HITGROUNDDAMAGE| 1161 SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; 1162 } //end else 1163 //AAS_ClearShownDebugLines(); 1164 // 1165 VectorCopy(ms->origin, origin); 1166 origin[2] += 0.5; 1167 AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue, 1168 velocity, cmdmove, cmdframes, maxframes, 0.1f, 1169 stopevent, 0, qfalse);//qtrue); 1170 //if prediction time wasn't enough to fully predict the movement 1171 if (move.frames >= maxframes && (type & MOVE_JUMP)) 1172 { 1173 //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client); 1174 return qfalse; 1175 } //end if 1176 //don't enter slime or lava and don't fall from too high 1177 if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) 1178 { 1179 //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client); 1180 //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n"); 1181 //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n"); 1182 //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n"); 1183 return qfalse; 1184 } //end if 1185 //if ground was hit 1186 if (move.stopevent & SE_HITGROUND) 1187 { 1188 //check for nearby gap 1189 VectorNormalize2(move.velocity, tmpdir); 1190 dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum); 1191 if (dist > 0) return qfalse; 1192 // 1193 dist = BotGapDistance(move.endpos, hordir, ms->entitynum); 1194 if (dist > 0) return qfalse; 1195 } //end if 1196 //get horizontal movement 1197 tmpdir[0] = move.endpos[0] - ms->origin[0]; 1198 tmpdir[1] = move.endpos[1] - ms->origin[1]; 1199 tmpdir[2] = 0; 1200 // 1201 //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE); 1202 //the bot is blocked by something 1203 if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse; 1204 //perform the movement 1205 if (type & MOVE_JUMP) EA_Jump(ms->client); 1206 if (type & MOVE_CROUCH) EA_Crouch(ms->client); 1207 EA_Move(ms->client, hordir, speed); 1208 //movement was succesfull 1209 return qtrue; 1210 } //end if 1211 else 1212 { 1213 if (ms->moveflags & MFL_BARRIERJUMP) 1214 { 1215 //if near the top or going down 1216 if (ms->velocity[2] < 50) 1217 { 1218 EA_Move(ms->client, dir, speed); 1219 } //end if 1220 } //end if 1221 //FIXME: do air control to avoid hazards 1222 return qtrue; 1223 } //end else 1224 } //end of the function BotWalkInDirection 1225 //=========================================================================== 1226 // 1227 // Parameter: - 1228 // Returns: - 1229 // Changes Globals: - 1230 //=========================================================================== 1231 int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) 1232 { 1233 bot_movestate_t *ms; 1234 1235 ms = BotMoveStateFromHandle(movestate); 1236 if (!ms) return qfalse; 1237 //if swimming 1238 if (AAS_Swimming(ms->origin)) 1239 { 1240 return BotSwimInDirection(ms, dir, speed, type); 1241 } //end if 1242 else 1243 { 1244 return BotWalkInDirection(ms, dir, speed, type); 1245 } //end else 1246 } //end of the function BotMoveInDirection 1247 //=========================================================================== 1248 // 1249 // Parameter: - 1250 // Returns: - 1251 // Changes Globals: - 1252 //=========================================================================== 1253 int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out) 1254 { 1255 float x1, dx1, dy1, x2, dx2, dy2, d; 1256 1257 dx1 = p2[0] - p1[0]; 1258 dy1 = p2[1] - p1[1]; 1259 dx2 = p4[0] - p3[0]; 1260 dy2 = p4[1] - p3[1]; 1261 1262 d = dy1 * dx2 - dx1 * dy2; 1263 if (d != 0) 1264 { 1265 x1 = p1[1] * dx1 - p1[0] * dy1; 1266 x2 = p3[1] * dx2 - p3[0] * dy2; 1267 out[0] = (int) ((dx1 * x2 - dx2 * x1) / d); 1268 out[1] = (int) ((dy1 * x2 - dy2 * x1) / d); 1269 return qtrue; 1270 } //end if 1271 else 1272 { 1273 return qfalse; 1274 } //end else 1275 } //end of the function Intersection 1276 //=========================================================================== 1277 // 1278 // Parameter: - 1279 // Returns: - 1280 // Changes Globals: - 1281 //=========================================================================== 1282 void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result) 1283 { 1284 vec3_t mins, maxs, end, up = {0, 0, 1}; 1285 bsp_trace_t trace; 1286 1287 //test for entities obstructing the bot's path 1288 AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); 1289 // 1290 if (fabs(DotProduct(dir, up)) < 0.7) 1291 { 1292 mins[2] += sv_maxstep->value; //if the bot can step on 1293 maxs[2] -= 10; //a little lower to avoid low ceiling 1294 } //end if 1295 VectorMA(ms->origin, 3, dir, end); 1296 trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY); 1297 //if not started in solid and not hitting the world entity 1298 if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) 1299 { 1300 result->blocked = qtrue; 1301 result->blockentity = trace.ent; 1302 #ifdef DEBUG 1303 //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); 1304 #endif //DEBUG 1305 } //end if 1306 //if not in an area with reachability 1307 else if (checkbottom && !AAS_AreaReachability(ms->areanum)) 1308 { 1309 //check if the bot is standing on something 1310 AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); 1311 VectorMA(ms->origin, -3, up, end); 1312 trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); 1313 if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) 1314 { 1315 result->blocked = qtrue; 1316 result->blockentity = trace.ent; 1317 result->flags |= MOVERESULT_ONTOPOFOBSTACLE; 1318 #ifdef DEBUG 1319 //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); 1320 #endif //DEBUG 1321 } //end if 1322 } //end else 1323 } //end of the function BotCheckBlocked 1324 //=========================================================================== 1325 // 1326 // Parameter: - 1327 // Returns: - 1328 // Changes Globals: - 1329 //=========================================================================== 1330 void BotClearMoveResult(bot_moveresult_t *moveresult) 1331 { 1332 moveresult->failure = qfalse; 1333 moveresult->type = 0; 1334 moveresult->blocked = qfalse; 1335 moveresult->blockentity = 0; 1336 moveresult->traveltype = 0; 1337 moveresult->flags = 0; 1338 } //end of the function BotClearMoveResult 1339 //=========================================================================== 1340 // 1341 // Parameter: - 1342 // Returns: - 1343 // Changes Globals: - 1344 //=========================================================================== 1345 bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) 1346 { 1347 float dist, speed; 1348 vec3_t hordir; 1349 bot_moveresult_t result; 1350 1351 BotClearMoveResult(&result); 1352 //first walk straight to the reachability start 1353 hordir[0] = reach->start[0] - ms->origin[0]; 1354 hordir[1] = reach->start[1] - ms->origin[1]; 1355 hordir[2] = 0; 1356 dist = VectorNormalize(hordir); 1357 // 1358 BotCheckBlocked(ms, hordir, qtrue, &result); 1359 // 1360 if (dist < 10) 1361 { 1362 //walk straight to the reachability end 1363 hordir[0] = reach->end[0] - ms->origin[0]; 1364 hordir[1] = reach->end[1] - ms->origin[1]; 1365 hordir[2] = 0; 1366 dist = VectorNormalize(hordir); 1367 } //end if 1368 //if going towards a crouch area 1369 if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL)) 1370 { 1371 //if pretty close to the reachable area 1372 if (dist < 20) EA_Crouch(ms->client); 1373 } //end if 1374 // 1375 dist = BotGapDistance(ms->origin, hordir, ms->entitynum); 1376 // 1377 if (ms->moveflags & MFL_WALK) 1378 { 1379 if (dist > 0) speed = 200 - (180 - 1 * dist); 1380 else speed = 200; 1381 EA_Walk(ms->client); 1382 } //end if 1383 else 1384 { 1385 if (dist > 0) speed = 400 - (360 - 2 * dist); 1386 else speed = 400; 1387 } //end else 1388 //elemantary action move in direction 1389 EA_Move(ms->client, hordir, speed); 1390 VectorCopy(hordir, result.movedir); 1391 // 1392 return result; 1393 } //end of the function BotTravel_Walk 1394 //=========================================================================== 1395 // 1396 // Parameter: - 1397 // Returns: - 1398 // Changes Globals: - 1399 //=========================================================================== 1400 bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) 1401 { 1402 vec3_t hordir; 1403 float dist, speed; 1404 bot_moveresult_t result; 1405 1406 BotClearMoveResult(&result); 1407 //if not on the ground and changed areas... don't walk back!! 1408 //(doesn't seem to help) 1409 /* 1410 ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); 1411 if (ms->areanum == reach->areanum) 1412 { 1413 #ifdef DEBUG 1414 botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n"); 1415 #endif //DEBUG 1416 return result; 1417 } //end if*/ 1418 //go straight to the reachability end 1419 hordir[0] = reach->end[0] - ms->origin[0]; 1420 hordir[1] = reach->end[1] - ms->origin[1]; 1421 hordir[2] = 0; 1422 dist = VectorNormalize(hordir); 1423 // 1424 if (dist > 100) dist = 100; 1425 speed = 400 - (400 - 3 * dist); 1426 // 1427 EA_Move(ms->client, hordir, speed); 1428 VectorCopy(hordir, result.movedir); 1429 // 1430 return result; 1431 } //end of the function BotFinishTravel_Walk 1432 //=========================================================================== 1433 // 1434 // Parameter: - 1435 // Returns: - 1436 // Changes Globals: - 1437 //=========================================================================== 1438 bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach) 1439 { 1440 float speed; 1441 vec3_t hordir; 1442 bot_moveresult_t result; 1443 1444 BotClearMoveResult(&result); 1445 // 1446 speed = 400; 1447 //walk straight to reachability end 1448 hordir[0] = reach->end[0] - ms->origin[0]; 1449 hordir[1] = reach->end[1] - ms->origin[1]; 1450 hordir[2] = 0; 1451 VectorNormalize(hordir); 1452 // 1453 BotCheckBlocked(ms, hordir, qtrue, &result); 1454 //elemantary actions 1455 EA_Crouch(ms->client); 1456 EA_Move(ms->client, hordir, speed); 1457 // 1458 VectorCopy(hordir, result.movedir); 1459 // 1460 return result; 1461 } //end of the function BotTravel_Crouch 1462 //=========================================================================== 1463 // 1464 // Parameter: - 1465 // Returns: - 1466 // Changes Globals: - 1467 //=========================================================================== 1468 bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) 1469 { 1470 float dist, speed; 1471 vec3_t hordir; 1472 bot_moveresult_t result; 1473 1474 BotClearMoveResult(&result); 1475 //walk straight to reachability start 1476 hordir[0] = reach->start[0] - ms->origin[0]; 1477 hordir[1] = reach->start[1] - ms->origin[1]; 1478 hordir[2] = 0; 1479 dist = VectorNormalize(hordir); 1480 // 1481 BotCheckBlocked(ms, hordir, qtrue, &result); 1482 //if pretty close to the barrier 1483 if (dist < 9) 1484 { 1485 EA_Jump(ms->client); 1486 } //end if 1487 else 1488 { 1489 if (dist > 60) dist = 60; 1490 speed = 360 - (360 - 6 * dist); 1491 EA_Move(ms->client, hordir, speed); 1492 } //end else 1493 VectorCopy(hordir, result.movedir); 1494 // 1495 return result; 1496 } //end of the function BotTravel_BarrierJump 1497 //=========================================================================== 1498 // 1499 // Parameter: - 1500 // Returns: - 1501 // Changes Globals: - 1502 //=========================================================================== 1503 bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) 1504 { 1505 float dist; 1506 vec3_t hordir; 1507 bot_moveresult_t result; 1508 1509 BotClearMoveResult(&result); 1510 //if near the top or going down 1511 if (ms->velocity[2] < 250) 1512 { 1513 hordir[0] = reach->end[0] - ms->origin[0]; 1514 hordir[1] = reach->end[1] - ms->origin[1]; 1515 hordir[2] = 0; 1516 dist = VectorNormalize(hordir); 1517 // 1518 BotCheckBlocked(ms, hordir, qtrue, &result); 1519 // 1520 EA_Move(ms->client, hordir, 400); 1521 VectorCopy(hordir, result.movedir); 1522 } //end if 1523 // 1524 return result; 1525 } //end of the function BotFinishTravel_BarrierJump 1526 //=========================================================================== 1527 // 1528 // Parameter: - 1529 // Returns: - 1530 // Changes Globals: - 1531 //=========================================================================== 1532 bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach) 1533 { 1534 vec3_t dir; 1535 bot_moveresult_t result; 1536 1537 BotClearMoveResult(&result); 1538 //swim straight to reachability end 1539 VectorSubtract(reach->start, ms->origin, dir); 1540 VectorNormalize(dir); 1541 // 1542 BotCheckBlocked(ms, dir, qtrue, &result); 1543 //elemantary actions 1544 EA_Move(ms->client, dir, 400); 1545 // 1546 VectorCopy(dir, result.movedir); 1547 Vector2Angles(dir, result.ideal_viewangles); 1548 result.flags |= MOVERESULT_SWIMVIEW; 1549 // 1550 return result; 1551 } //end of the function BotTravel_Swim 1552 //=========================================================================== 1553 // 1554 // Parameter: - 1555 // Returns: - 1556 // Changes Globals: - 1557 //=========================================================================== 1558 bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) 1559 { 1560 vec3_t dir, hordir; 1561 float dist; 1562 bot_moveresult_t result; 1563 1564 BotClearMoveResult(&result); 1565 //swim straight to reachability end 1566 VectorSubtract(reach->end, ms->origin, dir); 1567 VectorCopy(dir, hordir); 1568 hordir[2] = 0; 1569 dir[2] += 15 + crandom() * 40; 1570 //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]); 1571 VectorNormalize(dir); 1572 dist = VectorNormalize(hordir); 1573 //elemantary actions 1574 //EA_Move(ms->client, dir, 400); 1575 EA_MoveForward(ms->client); 1576 //move up if close to the actual out of water jump spot 1577 if (dist < 40) EA_MoveUp(ms->client); 1578 //set the ideal view angles 1579 Vector2Angles(dir, result.ideal_viewangles); 1580 result.flags |= MOVERESULT_MOVEMENTVIEW; 1581 // 1582 VectorCopy(dir, result.movedir); 1583 // 1584 return result; 1585 } //end of the function BotTravel_WaterJump 1586 //=========================================================================== 1587 // 1588 // Parameter: - 1589 // Returns: - 1590 // Changes Globals: - 1591 //=========================================================================== 1592 bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) 1593 { 1594 vec3_t dir, pnt; 1595 float dist; 1596 bot_moveresult_t result; 1597 1598 //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n"); 1599 BotClearMoveResult(&result); 1600 //if waterjumping there's nothing to do 1601 if (ms->moveflags & MFL_WATERJUMP) return result; 1602 //if not touching any water anymore don't do anything 1603 //otherwise the bot sometimes keeps jumping? 1604 VectorCopy(ms->origin, pnt); 1605 pnt[2] -= 32; //extra for q2dm4 near red armor/mega health 1606 if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result; 1607 //swim straight to reachability end 1608 VectorSubtract(reach->end, ms->origin, dir); 1609 dir[0] += crandom() * 10; 1610 dir[1] += crandom() * 10; 1611 dir[2] += 70 + crandom() * 10; 1612 dist = VectorNormalize(dir); 1613 //elemantary actions 1614 EA_Move(ms->client, dir, 400); 1615 //set the ideal view angles 1616 Vector2Angles(dir, result.ideal_viewangles); 1617 result.flags |= MOVERESULT_MOVEMENTVIEW; 1618 // 1619 VectorCopy(dir, result.movedir); 1620 // 1621 return result; 1622 } //end of the function BotFinishTravel_WaterJump 1623 //=========================================================================== 1624 // 1625 // Parameter: - 1626 // Returns: - 1627 // Changes Globals: - 1628 //=========================================================================== 1629 bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) 1630 { 1631 vec3_t hordir, dir; 1632 float dist, speed, reachhordist; 1633 bot_moveresult_t result; 1634 1635 BotClearMoveResult(&result); 1636 //check if the bot is blocked by anything 1637 VectorSubtract(reach->start, ms->origin, dir); 1638 VectorNormalize(dir); 1639 BotCheckBlocked(ms, dir, qtrue, &result); 1640 //if the reachability start and end are practially above each other 1641 VectorSubtract(reach->end, reach->start, dir); 1642 dir[2] = 0; 1643 reachhordist = VectorLength(dir); 1644 //walk straight to the reachability start 1645 hordir[0] = reach->start[0] - ms->origin[0]; 1646 hordir[1] = reach->start[1] - ms->origin[1]; 1647 hordir[2] = 0; 1648 dist = VectorNormalize(hordir); 1649 //if pretty close to the start focus on the reachability end 1650 if (dist < 48) 1651 { 1652 hordir[0] = reach->end[0] - ms->origin[0]; 1653 hordir[1] = reach->end[1] - ms->origin[1]; 1654 hordir[2] = 0; 1655 VectorNormalize(hordir); 1656 // 1657 if (reachhordist < 20) 1658 { 1659 speed = 100; 1660 } //end if 1661 else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed)) 1662 { 1663 speed = 400; 1664 } //end if 1665 } //end if 1666 else 1667 { 1668 if (reachhordist < 20) 1669 { 1670 if (dist > 64) dist = 64; 1671 speed = 400 - (256 - 4 * dist); 1672 } //end if 1673 else 1674 { 1675 speed = 400; 1676 } //end else 1677 } //end else 1678 // 1679 BotCheckBlocked(ms, hordir, qtrue, &result); 1680 //elemantary action 1681 EA_Move(ms->client, hordir, speed); 1682 VectorCopy(hordir, result.movedir); 1683 // 1684 return result; 1685 } //end of the function BotTravel_WalkOffLedge 1686 //=========================================================================== 1687 // 1688 // Parameter: - 1689 // Returns: - 1690 // Changes Globals: - 1691 //=========================================================================== 1692 int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed) 1693 { 1694 vec3_t org, vel; 1695 float dist; 1696 int i; 1697 1698 VectorCopy(origin, org); 1699 VectorScale(velocity, 0.1, vel); 1700 for (i = 0; i < 50; i++) 1701 { 1702 vel[2] -= sv_gravity->value * 0.01; 1703 //if going down and next position would be below the goal 1704 if (vel[2] < 0 && org[2] + vel[2] < goal[2]) 1705 { 1706 VectorScale(vel, (goal[2] - org[2]) / vel[2], vel); 1707 VectorAdd(org, vel, org); 1708 VectorSubtract(goal, org, dir); 1709 dist = VectorNormalize(dir); 1710 if (dist > 32) dist = 32; 1711 *speed = 400 - (400 - 13 * dist); 1712 return qtrue; 1713 } //end if 1714 else 1715 { 1716 VectorAdd(org, vel, org); 1717 } //end else 1718 } //end for 1719 VectorSet(dir, 0, 0, 0); 1720 *speed = 400; 1721 return qfalse; 1722 } //end of the function BotAirControl 1723 //=========================================================================== 1724 // 1725 // Parameter: - 1726 // Returns: - 1727 // Changes Globals: - 1728 //=========================================================================== 1729 bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) 1730 { 1731 vec3_t dir, hordir, end, v; 1732 float dist, speed; 1733 bot_moveresult_t result; 1734 1735 BotClearMoveResult(&result); 1736 // 1737 VectorSubtract(reach->end, ms->origin, dir); 1738 BotCheckBlocked(ms, dir, qtrue, &result); 1739 // 1740 VectorSubtract(reach->end, ms->origin, v); 1741 v[2] = 0; 1742 dist = VectorNormalize(v); 1743 if (dist > 16) VectorMA(reach->end, 16, v, end); 1744 else VectorCopy(reach->end, end); 1745 // 1746 if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed)) 1747 { 1748 //go straight to the reachability end 1749 VectorCopy(dir, hordir); 1750 hordir[2] = 0; 1751 // 1752 dist = VectorNormalize(hordir); 1753 speed = 400; 1754 } //end if 1755 // 1756 EA_Move(ms->client, hordir, speed); 1757 VectorCopy(hordir, result.movedir); 1758 // 1759 return result; 1760 } //end of the function BotFinishTravel_WalkOffLedge 1761 //=========================================================================== 1762 // 1763 // Parameter: - 1764 // Returns: - 1765 // Changes Globals: - 1766 //=========================================================================== 1767 /* 1768 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) 1769 { 1770 vec3_t hordir; 1771 float dist, gapdist, speed, horspeed, sv_jumpvel; 1772 bot_moveresult_t result; 1773 1774 BotClearMoveResult(&result); 1775 // 1776 sv_jumpvel = botlibglobals.sv_jumpvel->value; 1777 //walk straight to the reachability start 1778 hordir[0] = reach->start[0] - ms->origin[0]; 1779 hordir[1] = reach->start[1] - ms->origin[1]; 1780 hordir[2] = 0; 1781 dist = VectorNormalize(hordir); 1782 // 1783 speed = 350; 1784 // 1785 gapdist = BotGapDistance(ms, hordir, ms->entitynum); 1786 //if pretty close to the start focus on the reachability end 1787 if (dist < 50 || (gapdist && gapdist < 50)) 1788 { 1789 //NOTE: using max speed (400) works best 1790 //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed)) 1791 //{ 1792 // speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; 1793 //} //end if 1794 hordir[0] = reach->end[0] - ms->origin[0]; 1795 hordir[1] = reach->end[1] - ms->origin[1]; 1796 VectorNormalize(hordir); 1797 //elemantary action jump 1798 EA_Jump(ms->client); 1799 // 1800 ms->jumpreach = ms->lastreachnum; 1801 speed = 600; 1802 } //end if 1803 else 1804 { 1805 if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed)) 1806 { 1807 speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; 1808 } //end if 1809 } //end else 1810 //elemantary action 1811 EA_Move(ms->client, hordir, speed); 1812 VectorCopy(hordir, result.movedir); 1813 // 1814 return result; 1815 } //end of the function BotTravel_Jump*/ 1816 /* 1817 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) 1818 { 1819 vec3_t hordir, dir1, dir2, mins, maxs, start, end; 1820 float dist1, dist2, speed; 1821 bot_moveresult_t result; 1822 bsp_trace_t trace; 1823 1824 BotClearMoveResult(&result); 1825 // 1826 hordir[0] = reach->start[0] - reach->end[0]; 1827 hordir[1] = reach->start[1] - reach->end[1]; 1828 hordir[2] = 0; 1829 VectorNormalize(hordir); 1830 // 1831 VectorCopy(reach->start, start); 1832 start[2] += 1; 1833 //minus back the bouding box size plus 16 1834 VectorMA(reach->start, 80, hordir, end); 1835 // 1836 AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs); 1837 //check for solids 1838 trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID); 1839 if (trace.startsolid) VectorCopy(start, trace.endpos); 1840 //check for a gap 1841 for (dist1 = 0; dist1 < 80; dist1 += 10) 1842 { 1843 VectorMA(start, dist1+10, hordir, end); 1844 end[2] += 1; 1845 if (AAS_PointAreaNum(end) != ms->reachareanum) break; 1846 } //end for 1847 if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos); 1848 // dist1 = BotGapDistance(start, hordir, ms->entitynum); 1849 // if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos); 1850 // 1851 VectorSubtract(ms->origin, reach->start, dir1); 1852 dir1[2] = 0; 1853 dist1 = VectorNormalize(dir1); 1854 VectorSubtract(ms->origin, trace.endpos, dir2); 1855 dir2[2] = 0; 1856 dist2 = VectorNormalize(dir2); 1857 //if just before the reachability start 1858 if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) 1859 { 1860 //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n"); 1861 hordir[0] = reach->end[0] - ms->origin[0]; 1862 hordir[1] = reach->end[1] - ms->origin[1]; 1863 hordir[2] = 0; 1864 VectorNormalize(hordir); 1865 //elemantary action jump 1866 if (dist1 < 24) EA_Jump(ms->client); 1867 else if (dist1 < 32) EA_DelayedJump(ms->client); 1868 EA_Move(ms->client, hordir, 600); 1869 // 1870 ms->jumpreach = ms->lastreachnum; 1871 } //end if 1872 else 1873 { 1874 //botimport.Print(PRT_MESSAGE, "going towards run to point\n"); 1875 hordir[0] = trace.endpos[0] - ms->origin[0]; 1876 hordir[1] = trace.endpos[1] - ms->origin[1]; 1877 hordir[2] = 0; 1878 VectorNormalize(hordir); 1879 // 1880 if (dist2 > 80) dist2 = 80; 1881 speed = 400 - (400 - 5 * dist2); 1882 EA_Move(ms->client, hordir, speed); 1883 } //end else 1884 VectorCopy(hordir, result.movedir); 1885 // 1886 return result; 1887 } //end of the function BotTravel_Jump*/ 1888 //* 1889 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) 1890 { 1891 vec3_t hordir, dir1, dir2, start, end, runstart; 1892 // vec3_t runstart, dir1, dir2, hordir; 1893 float dist1, dist2, speed; 1894 bot_moveresult_t result; 1895 1896 BotClearMoveResult(&result); 1897 // 1898 AAS_JumpReachRunStart(reach, runstart); 1899 //* 1900 hordir[0] = runstart[0] - reach->start[0]; 1901 hordir[1] = runstart[1] - reach->start[1]; 1902 hordir[2] = 0; 1903 VectorNormalize(hordir); 1904 // 1905 VectorCopy(reach->start, start); 1906 start[2] += 1; 1907 VectorMA(reach->start, 80, hordir, runstart); 1908 //check for a gap 1909 for (dist1 = 0; dist1 < 80; dist1 += 10) 1910 { 1911 VectorMA(start, dist1+10, hordir, end); 1912 end[2] += 1; 1913 if (AAS_PointAreaNum(end) != ms->reachareanum) break; 1914 } //end for 1915 if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart); 1916 // 1917 VectorSubtract(ms->origin, reach->start, dir1); 1918 dir1[2] = 0; 1919 dist1 = VectorNormalize(dir1); 1920 VectorSubtract(ms->origin, runstart, dir2); 1921 dir2[2] = 0; 1922 dist2 = VectorNormalize(dir2); 1923 //if just before the reachability start 1924 if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) 1925 { 1926 // botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); 1927 hordir[0] = reach->end[0] - ms->origin[0]; 1928 hordir[1] = reach->end[1] - ms->origin[1]; 1929 hordir[2] = 0; 1930 VectorNormalize(hordir); 1931 //elemantary action jump 1932 if (dist1 < 24) EA_Jump(ms->client); 1933 else if (dist1 < 32) EA_DelayedJump(ms->client); 1934 EA_Move(ms->client, hordir, 600); 1935 // 1936 ms->jumpreach = ms->lastreachnum; 1937 } //end if 1938 else 1939 { 1940 // botimport.Print(PRT_MESSAGE, "going towards run start point\n"); 1941 hordir[0] = runstart[0] - ms->origin[0]; 1942 hordir[1] = runstart[1] - ms->origin[1]; 1943 hordir[2] = 0; 1944 VectorNormalize(hordir); 1945 // 1946 if (dist2 > 80) dist2 = 80; 1947 speed = 400 - (400 - 5 * dist2); 1948 EA_Move(ms->client, hordir, speed); 1949 } //end else 1950 VectorCopy(hordir, result.movedir); 1951 // 1952 return result; 1953 } //end of the function BotTravel_Jump*/ 1954 //=========================================================================== 1955 // 1956 // Parameter: - 1957 // Returns: - 1958 // Changes Globals: - 1959 //=========================================================================== 1960 bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) 1961 { 1962 vec3_t hordir, hordir2; 1963 float speed, dist; 1964 bot_moveresult_t result; 1965 1966 BotClearMoveResult(&result); 1967 //if not jumped yet 1968 if (!ms->jumpreach) return result; 1969 //go straight to the reachability end 1970 hordir[0] = reach->end[0] - ms->origin[0]; 1971 hordir[1] = reach->end[1] - ms->origin[1]; 1972 hordir[2] = 0; 1973 dist = VectorNormalize(hordir); 1974 // 1975 hordir2[0] = reach->end[0] - reach->start[0]; 1976 hordir2[1] = reach->end[1] - reach->start[1]; 1977 hordir2[2] = 0; 1978 VectorNormalize(hordir2); 1979 // 1980 if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result; 1981 //always use max speed when traveling through the air 1982 speed = 800; 1983 // 1984 EA_Move(ms->client, hordir, speed); 1985 VectorCopy(hordir, result.movedir); 1986 // 1987 return result; 1988 } //end of the function BotFinishTravel_Jump 1989 //=========================================================================== 1990 // 1991 // Parameter: - 1992 // Returns: - 1993 // Changes Globals: - 1994 //=========================================================================== 1995 bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach) 1996 { 1997 //float dist, speed; 1998 vec3_t dir, viewdir;//, hordir; 1999 vec3_t origin = {0, 0, 0}; 2000 // vec3_t up = {0, 0, 1}; 2001 bot_moveresult_t result; 2002 2003 BotClearMoveResult(&result); 2004 // 2005 // if ((ms->moveflags & MFL_AGAINSTLADDER)) 2006 //NOTE: not a good idea for ladders starting in water 2007 // || !(ms->moveflags & MFL_ONGROUND)) 2008 { 2009 //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n"); 2010 VectorSubtract(reach->end, ms->origin, dir); 2011 VectorNormalize(dir); 2012 //set the ideal view angles, facing the ladder up or down 2013 viewdir[0] = dir[0]; 2014 viewdir[1] = dir[1]; 2015 viewdir[2] = 3 * dir[2]; 2016 Vector2Angles(viewdir, result.ideal_viewangles); 2017 //elemantary action 2018 EA_Move(ms->client, origin, 0); 2019 EA_MoveForward(ms->client); 2020 //set movement view flag so the AI can see the view is focussed 2021 result.flags |= MOVERESULT_MOVEMENTVIEW; 2022 } //end if 2023 /* else 2024 { 2025 //botimport.Print(PRT_MESSAGE, "moving towards ladder\n"); 2026 VectorSubtract(reach->end, ms->origin, dir); 2027 //make sure the horizontal movement is large anough 2028 VectorCopy(dir, hordir); 2029 hordir[2] = 0; 2030 dist = VectorNormalize(hordir); 2031 // 2032 dir[0] = hordir[0]; 2033 dir[1] = hordir[1]; 2034 if (dir[2] > 0) dir[2] = 1; 2035 else dir[2] = -1; 2036 if (dist > 50) dist = 50; 2037 speed = 400 - (200 - 4 * dist); 2038 EA_Move(ms->client, dir, speed); 2039 } //end else*/ 2040 //save the movement direction 2041 VectorCopy(dir, result.movedir); 2042 // 2043 return result; 2044 } //end of the function BotTravel_Ladder 2045 //=========================================================================== 2046 // 2047 // Parameter: - 2048 // Returns: - 2049 // Changes Globals: - 2050 //=========================================================================== 2051 bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach) 2052 { 2053 vec3_t hordir; 2054 float dist; 2055 bot_moveresult_t result; 2056 2057 BotClearMoveResult(&result); 2058 //if the bot is being teleported 2059 if (ms->moveflags & MFL_TELEPORTED) return result; 2060 2061 //walk straight to center of the teleporter 2062 VectorSubtract(reach->start, ms->origin, hordir); 2063 if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; 2064 dist = VectorNormalize(hordir); 2065 // 2066 BotCheckBlocked(ms, hordir, qtrue, &result); 2067 2068 if (dist < 30) EA_Move(ms->client, hordir, 200); 2069 else EA_Move(ms->client, hordir, 400); 2070 2071 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2072 2073 VectorCopy(hordir, result.movedir); 2074 return result; 2075 } //end of the function BotTravel_Teleport 2076 //=========================================================================== 2077 // 2078 // Parameter: - 2079 // Returns: - 2080 // Changes Globals: - 2081 //=========================================================================== 2082 bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) 2083 { 2084 vec3_t dir, dir1, dir2, hordir, bottomcenter; 2085 float dist, dist1, dist2, speed; 2086 bot_moveresult_t result; 2087 2088 BotClearMoveResult(&result); 2089 //if standing on the plat 2090 if (BotOnMover(ms->origin, ms->entitynum, reach)) 2091 { 2092 #ifdef DEBUG_ELEVATOR 2093 botimport.Print(PRT_MESSAGE, "bot on elevator\n"); 2094 #endif //DEBUG_ELEVATOR 2095 //if vertically not too far from the end point 2096 if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value) 2097 { 2098 #ifdef DEBUG_ELEVATOR 2099 botimport.Print(PRT_MESSAGE, "bot moving to end\n"); 2100 #endif //DEBUG_ELEVATOR 2101 //move to the end point 2102 VectorSubtract(reach->end, ms->origin, hordir); 2103 hordir[2] = 0; 2104 VectorNormalize(hordir); 2105 if (!BotCheckBarrierJump(ms, hordir, 100)) 2106 { 2107 EA_Move(ms->client, hordir, 400); 2108 } //end if 2109 VectorCopy(hordir, result.movedir); 2110 } //end else 2111 //if not really close to the center of the elevator 2112 else 2113 { 2114 MoverBottomCenter(reach, bottomcenter); 2115 VectorSubtract(bottomcenter, ms->origin, hordir); 2116 hordir[2] = 0; 2117 dist = VectorNormalize(hordir); 2118 // 2119 if (dist > 10) 2120 { 2121 #ifdef DEBUG_ELEVATOR 2122 botimport.Print(PRT_MESSAGE, "bot moving to center\n"); 2123 #endif //DEBUG_ELEVATOR 2124 //move to the center of the plat 2125 if (dist > 100) dist = 100; 2126 speed = 400 - (400 - 4 * dist); 2127 // 2128 EA_Move(ms->client, hordir, speed); 2129 VectorCopy(hordir, result.movedir); 2130 } //end if 2131 } //end else 2132 } //end if 2133 else 2134 { 2135 #ifdef DEBUG_ELEVATOR 2136 botimport.Print(PRT_MESSAGE, "bot not on elevator\n"); 2137 #endif //DEBUG_ELEVATOR 2138 //if very near the reachability end 2139 VectorSubtract(reach->end, ms->origin, dir); 2140 dist = VectorLength(dir); 2141 if (dist < 64) 2142 { 2143 if (dist > 60) dist = 60; 2144 speed = 360 - (360 - 6 * dist); 2145 // 2146 if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) 2147 { 2148 if (speed > 5) EA_Move(ms->client, dir, speed); 2149 } //end if 2150 VectorCopy(dir, result.movedir); 2151 // 2152 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2153 //stop using this reachability 2154 ms->reachability_time = 0; 2155 return result; 2156 } //end if 2157 //get direction and distance to reachability start 2158 VectorSubtract(reach->start, ms->origin, dir1); 2159 if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; 2160 dist1 = VectorNormalize(dir1); 2161 //if the elevator isn't down 2162 if (!MoverDown(reach)) 2163 { 2164 #ifdef DEBUG_ELEVATOR 2165 botimport.Print(PRT_MESSAGE, "elevator not down\n"); 2166 #endif //DEBUG_ELEVATOR 2167 dist = dist1; 2168 VectorCopy(dir1, dir); 2169 // 2170 BotCheckBlocked(ms, dir, qfalse, &result); 2171 // 2172 if (dist > 60) dist = 60; 2173 speed = 360 - (360 - 6 * dist); 2174 // 2175 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) 2176 { 2177 if (speed > 5) EA_Move(ms->client, dir, speed); 2178 } //end if 2179 VectorCopy(dir, result.movedir); 2180 // 2181 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2182 //this isn't a failure... just wait till the elevator comes down 2183 result.type = RESULTTYPE_ELEVATORUP; 2184 result.flags |= MOVERESULT_WAITING; 2185 return result; 2186 } //end if 2187 //get direction and distance to elevator bottom center 2188 MoverBottomCenter(reach, bottomcenter); 2189 VectorSubtract(bottomcenter, ms->origin, dir2); 2190 if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; 2191 dist2 = VectorNormalize(dir2); 2192 //if very close to the reachability start or 2193 //closer to the elevator center or 2194 //between reachability start and elevator center 2195 if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) 2196 { 2197 #ifdef DEBUG_ELEVATOR 2198 botimport.Print(PRT_MESSAGE, "bot moving to center\n"); 2199 #endif //DEBUG_ELEVATOR 2200 dist = dist2; 2201 VectorCopy(dir2, dir); 2202 } //end if 2203 else //closer to the reachability start 2204 { 2205 #ifdef DEBUG_ELEVATOR 2206 botimport.Print(PRT_MESSAGE, "bot moving to start\n"); 2207 #endif //DEBUG_ELEVATOR 2208 dist = dist1; 2209 VectorCopy(dir1, dir); 2210 } //end else 2211 // 2212 BotCheckBlocked(ms, dir, qfalse, &result); 2213 // 2214 if (dist > 60) dist = 60; 2215 speed = 400 - (400 - 6 * dist); 2216 // 2217 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) 2218 { 2219 EA_Move(ms->client, dir, speed); 2220 } //end if 2221 VectorCopy(dir, result.movedir); 2222 // 2223 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2224 } //end else 2225 return result; 2226 } //end of the function BotTravel_Elevator 2227 //=========================================================================== 2228 // 2229 // Parameter: - 2230 // Returns: - 2231 // Changes Globals: - 2232 //=========================================================================== 2233 bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) 2234 { 2235 vec3_t bottomcenter, bottomdir, topdir; 2236 bot_moveresult_t result; 2237 2238 BotClearMoveResult(&result); 2239 // 2240 MoverBottomCenter(reach, bottomcenter); 2241 VectorSubtract(bottomcenter, ms->origin, bottomdir); 2242 // 2243 VectorSubtract(reach->end, ms->origin, topdir); 2244 // 2245 if (fabs(bottomdir[2]) < fabs(topdir[2])) 2246 { 2247 VectorNormalize(bottomdir); 2248 EA_Move(ms->client, bottomdir, 300); 2249 } //end if 2250 else 2251 { 2252 VectorNormalize(topdir); 2253 EA_Move(ms->client, topdir, 300); 2254 } //end else 2255 return result; 2256 } //end of the function BotFinishTravel_Elevator 2257 //=========================================================================== 2258 // 2259 // Parameter: - 2260 // Returns: - 2261 // Changes Globals: - 2262 //=========================================================================== 2263 void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin) 2264 { 2265 int spawnflags, modelnum; 2266 vec3_t mins, maxs, mid, angles = {0, 0, 0}; 2267 int num0, num1; 2268 2269 modelnum = reach->facenum & 0x0000FFFF; 2270 if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) 2271 { 2272 botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum); 2273 VectorSet(start, 0, 0, 0); 2274 VectorSet(end, 0, 0, 0); 2275 return; 2276 } //end if 2277 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); 2278 VectorAdd(mins, maxs, mid); 2279 VectorScale(mid, 0.5, mid); 2280 VectorCopy(mid, start); 2281 VectorCopy(mid, end); 2282 spawnflags = reach->facenum >> 16; 2283 num0 = reach->edgenum >> 16; 2284 if (num0 > 0x00007FFF) num0 |= 0xFFFF0000; 2285 num1 = reach->edgenum & 0x0000FFFF; 2286 if (num1 > 0x00007FFF) num1 |= 0xFFFF0000; 2287 if (spawnflags & 1) 2288 { 2289 start[0] = num0; 2290 end[0] = num1; 2291 // 2292 origin[0] += mid[0]; 2293 origin[1] = mid[1]; 2294 origin[2] = mid[2]; 2295 } //end if 2296 else if (spawnflags & 2) 2297 { 2298 start[1] = num0; 2299 end[1] = num1; 2300 // 2301 origin[0] = mid[0]; 2302 origin[1] += mid[1]; 2303 origin[2] = mid[2]; 2304 } //end else if 2305 else 2306 { 2307 start[2] = num0; 2308 end[2] = num1; 2309 // 2310 origin[0] = mid[0]; 2311 origin[1] = mid[1]; 2312 origin[2] += mid[2]; 2313 } //end else 2314 } //end of the function BotFuncBobStartEnd 2315 //=========================================================================== 2316 // 2317 // Parameter: - 2318 // Returns: - 2319 // Changes Globals: - 2320 //=========================================================================== 2321 bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) 2322 { 2323 vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin; 2324 float dist, dist1, dist2, speed; 2325 bot_moveresult_t result; 2326 2327 BotClearMoveResult(&result); 2328 // 2329 BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); 2330 //if standing ontop of the func_bobbing 2331 if (BotOnMover(ms->origin, ms->entitynum, reach)) 2332 { 2333 #ifdef DEBUG_FUNCBOB 2334 botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n"); 2335 #endif 2336 //if near end point of reachability 2337 VectorSubtract(bob_origin, bob_end, dir); 2338 if (VectorLength(dir) < 24) 2339 { 2340 #ifdef DEBUG_FUNCBOB 2341 botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n"); 2342 #endif 2343 //move to the end point 2344 VectorSubtract(reach->end, ms->origin, hordir); 2345 hordir[2] = 0; 2346 VectorNormalize(hordir); 2347 if (!BotCheckBarrierJump(ms, hordir, 100)) 2348 { 2349 EA_Move(ms->client, hordir, 400); 2350 } //end if 2351 VectorCopy(hordir, result.movedir); 2352 } //end else 2353 //if not really close to the center of the elevator 2354 else 2355 { 2356 MoverBottomCenter(reach, bottomcenter); 2357 VectorSubtract(bottomcenter, ms->origin, hordir); 2358 hordir[2] = 0; 2359 dist = VectorNormalize(hordir); 2360 // 2361 if (dist > 10) 2362 { 2363 #ifdef DEBUG_FUNCBOB 2364 botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); 2365 #endif 2366 //move to the center of the plat 2367 if (dist > 100) dist = 100; 2368 speed = 400 - (400 - 4 * dist); 2369 // 2370 EA_Move(ms->client, hordir, speed); 2371 VectorCopy(hordir, result.movedir); 2372 } //end if 2373 } //end else 2374 } //end if 2375 else 2376 { 2377 #ifdef DEBUG_FUNCBOB 2378 botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n"); 2379 #endif 2380 //if very near the reachability end 2381 VectorSubtract(reach->end, ms->origin, dir); 2382 dist = VectorLength(dir); 2383 if (dist < 64) 2384 { 2385 #ifdef DEBUG_FUNCBOB 2386 botimport.Print(PRT_MESSAGE, "bot moving to end\n"); 2387 #endif 2388 if (dist > 60) dist = 60; 2389 speed = 360 - (360 - 6 * dist); 2390 //if swimming or no barrier jump 2391 if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) 2392 { 2393 if (speed > 5) EA_Move(ms->client, dir, speed); 2394 } //end if 2395 VectorCopy(dir, result.movedir); 2396 // 2397 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2398 //stop using this reachability 2399 ms->reachability_time = 0; 2400 return result; 2401 } //end if 2402 //get direction and distance to reachability start 2403 VectorSubtract(reach->start, ms->origin, dir1); 2404 if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; 2405 dist1 = VectorNormalize(dir1); 2406 //if func_bobbing is Not it's start position 2407 VectorSubtract(bob_origin, bob_start, dir); 2408 if (VectorLength(dir) > 16) 2409 { 2410 #ifdef DEBUG_FUNCBOB 2411 botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n"); 2412 #endif 2413 dist = dist1; 2414 VectorCopy(dir1, dir); 2415 // 2416 BotCheckBlocked(ms, dir, qfalse, &result); 2417 // 2418 if (dist > 60) dist = 60; 2419 speed = 360 - (360 - 6 * dist); 2420 // 2421 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) 2422 { 2423 if (speed > 5) EA_Move(ms->client, dir, speed); 2424 } //end if 2425 VectorCopy(dir, result.movedir); 2426 // 2427 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2428 //this isn't a failure... just wait till the func_bobbing arrives 2429 result.type = RESULTTYPE_WAITFORFUNCBOBBING; 2430 result.flags |= MOVERESULT_WAITING; 2431 return result; 2432 } //end if 2433 //get direction and distance to func_bob bottom center 2434 MoverBottomCenter(reach, bottomcenter); 2435 VectorSubtract(bottomcenter, ms->origin, dir2); 2436 if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; 2437 dist2 = VectorNormalize(dir2); 2438 //if very close to the reachability start or 2439 //closer to the elevator center or 2440 //between reachability start and func_bobbing center 2441 if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) 2442 { 2443 #ifdef DEBUG_FUNCBOB 2444 botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); 2445 #endif 2446 dist = dist2; 2447 VectorCopy(dir2, dir); 2448 } //end if 2449 else //closer to the reachability start 2450 { 2451 #ifdef DEBUG_FUNCBOB 2452 botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n"); 2453 #endif 2454 dist = dist1; 2455 VectorCopy(dir1, dir); 2456 } //end else 2457 // 2458 BotCheckBlocked(ms, dir, qfalse, &result); 2459 // 2460 if (dist > 60) dist = 60; 2461 speed = 400 - (400 - 6 * dist); 2462 // 2463 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) 2464 { 2465 EA_Move(ms->client, dir, speed); 2466 } //end if 2467 VectorCopy(dir, result.movedir); 2468 // 2469 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2470 } //end else 2471 return result; 2472 } //end of the function BotTravel_FuncBobbing 2473 //=========================================================================== 2474 // 2475 // Parameter: - 2476 // Returns: - 2477 // Changes Globals: - 2478 //=========================================================================== 2479 bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) 2480 { 2481 vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter; 2482 bot_moveresult_t result; 2483 float dist, speed; 2484 2485 BotClearMoveResult(&result); 2486 // 2487 BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); 2488 // 2489 VectorSubtract(bob_origin, bob_end, dir); 2490 dist = VectorLength(dir); 2491 //if the func_bobbing is near the end 2492 if (dist < 16) 2493 { 2494 VectorSubtract(reach->end, ms->origin, hordir); 2495 if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; 2496 dist = VectorNormalize(hordir); 2497 // 2498 if (dist > 60) dist = 60; 2499 speed = 360 - (360 - 6 * dist); 2500 // 2501 if (speed > 5) EA_Move(ms->client, dir, speed); 2502 VectorCopy(dir, result.movedir); 2503 // 2504 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; 2505 } //end if 2506 else 2507 { 2508 MoverBottomCenter(reach, bottomcenter); 2509 VectorSubtract(bottomcenter, ms->origin, hordir); 2510 if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; 2511 dist = VectorNormalize(hordir); 2512 // 2513 if (dist > 5) 2514 { 2515 //move to the center of the plat 2516 if (dist > 100) dist = 100; 2517 speed = 400 - (400 - 4 * dist); 2518 // 2519 EA_Move(ms->client, hordir, speed); 2520 VectorCopy(hordir, result.movedir); 2521 } //end if 2522 } //end else 2523 return result; 2524 } //end of the function BotFinishTravel_FuncBobbing 2525 //=========================================================================== 2526 // 0 no valid grapple hook visible 2527 // 1 the grapple hook is still flying 2528 // 2 the grapple hooked into a wall 2529 // 2530 // Parameter: - 2531 // Returns: - 2532 // Changes Globals: - 2533 //=========================================================================== 2534 int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach) 2535 { 2536 int i; 2537 aas_entityinfo_t entinfo; 2538 2539 //if the grapple hook is pulling 2540 if (ms->moveflags & MFL_GRAPPLEPULL) 2541 return 2; 2542 //check for a visible grapple missile entity 2543 //or visible grapple entity 2544 for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i)) 2545 { 2546 if (AAS_EntityType(i) == (int) entitytypemissile->value) 2547 { 2548 AAS_EntityInfo(i, &entinfo); 2549 if (entinfo.weapon == (int) weapindex_grapple->value) 2550 { 2551 return 1; 2552 } //end if 2553 } //end if 2554 } //end for 2555 //no valid grapple at all 2556 return 0; 2557 } //end of the function GrappleState 2558 //=========================================================================== 2559 // 2560 // Parameter: - 2561 // Returns: - 2562 // Changes Globals: - 2563 //=========================================================================== 2564 void BotResetGrapple(bot_movestate_t *ms) 2565 { 2566 aas_reachability_t reach; 2567 2568 AAS_ReachabilityFromNum(ms->lastreachnum, &reach); 2569 //if not using the grapple hook reachability anymore 2570 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK) 2571 { 2572 if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time) 2573 { 2574 if (offhandgrapple->value) 2575 EA_Command(ms->client, cmd_grappleoff->string); 2576 ms->moveflags &= ~MFL_ACTIVEGRAPPLE; 2577 ms->grapplevisible_time = 0; 2578 #ifdef DEBUG_GRAPPLE 2579 botimport.Print(PRT_MESSAGE, "reset grapple\n"); 2580 #endif //DEBUG_GRAPPLE 2581 } //end if 2582 } //end if 2583 } //end of the function BotResetGrapple 2584 //=========================================================================== 2585 // 2586 // Parameter: - 2587 // Returns: - 2588 // Changes Globals: - 2589 //=========================================================================== 2590 bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach) 2591 { 2592 bot_moveresult_t result; 2593 float dist, speed; 2594 vec3_t dir, viewdir, org; 2595 int state, areanum; 2596 bsp_trace_t trace; 2597 2598 #ifdef DEBUG_GRAPPLE 2599 static int debugline; 2600 if (!debugline) debugline = botimport.DebugLineCreate(); 2601 botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE); 2602 #endif //DEBUG_GRAPPLE 2603 2604 BotClearMoveResult(&result); 2605 // 2606 if (ms->moveflags & MFL_GRAPPLERESET) 2607 { 2608 if (offhandgrapple->value) 2609 EA_Command(ms->client, cmd_grappleoff->string); 2610 ms->moveflags &= ~MFL_ACTIVEGRAPPLE; 2611 return result; 2612 } //end if 2613 // 2614 if (!(int) offhandgrapple->value) 2615 { 2616 result.weapon = weapindex_grapple->value; 2617 result.flags |= MOVERESULT_MOVEMENTWEAPON; 2618 } //end if 2619 // 2620 if (ms->moveflags & MFL_ACTIVEGRAPPLE) 2621 { 2622 #ifdef DEBUG_GRAPPLE 2623 botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n"); 2624 #endif //DEBUG_GRAPPLE 2625 // 2626 state = GrappleState(ms, reach); 2627 // 2628 VectorSubtract(reach->end, ms->origin, dir); 2629 dir[2] = 0; 2630 dist = VectorLength(dir); 2631 //if very close to the grapple end or the grappled is hooked and 2632 //the bot doesn't get any closer 2633 if (state && dist < 48) 2634 { 2635 if (ms->lastgrappledist - dist < 1) 2636 { 2637 #ifdef DEBUG_GRAPPLE 2638 botimport.Print(PRT_ERROR, "grapple normal end\n"); 2639 #endif //DEBUG_GRAPPLE 2640 if (offhandgrapple->value) 2641 EA_Command(ms->client, cmd_grappleoff->string); 2642 ms->moveflags &= ~MFL_ACTIVEGRAPPLE; 2643 ms->moveflags |= MFL_GRAPPLERESET; 2644 ms->reachability_time = 0; //end the reachability 2645 return result; 2646 } //end if 2647 } //end if 2648 //if no valid grapple at all, or the grapple hooked and the bot 2649 //isn't moving anymore 2650 else if (!state || (state == 2 && dist > ms->lastgrappledist - 2)) 2651 { 2652 if (ms->grapplevisible_time < AAS_Time() - 0.4) 2653 { 2654 #ifdef DEBUG_GRAPPLE 2655 botimport.Print(PRT_ERROR, "grapple not visible\n"); 2656 #endif //DEBUG_GRAPPLE 2657 if (offhandgrapple->value) 2658 EA_Command(ms->client, cmd_grappleoff->string); 2659 ms->moveflags &= ~MFL_ACTIVEGRAPPLE; 2660 ms->moveflags |= MFL_GRAPPLERESET; 2661 ms->reachability_time = 0; //end the reachability 2662 return result; 2663 } //end if 2664 } //end if 2665 else 2666 { 2667 ms->grapplevisible_time = AAS_Time(); 2668 } //end else 2669 // 2670 if (!(int) offhandgrapple->value) 2671 { 2672 EA_Attack(ms->client); 2673 } //end if 2674 //remember the current grapple distance 2675 ms->lastgrappledist = dist; 2676 } //end if 2677 else 2678 { 2679 #ifdef DEBUG_GRAPPLE 2680 botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n"); 2681 #endif //DEBUG_GRAPPLE 2682 // 2683 ms->grapplevisible_time = AAS_Time(); 2684 // 2685 VectorSubtract(reach->start, ms->origin, dir); 2686 if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0; 2687 VectorAdd(ms->origin, ms->viewoffset, org); 2688 VectorSubtract(reach->end, org, viewdir); 2689 // 2690 dist = VectorNormalize(dir); 2691 Vector2Angles(viewdir, result.ideal_viewangles); 2692 result.flags |= MOVERESULT_MOVEMENTVIEW; 2693 // 2694 if (dist < 5 && 2695 fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 && 2696 fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2) 2697 { 2698 #ifdef DEBUG_GRAPPLE 2699 botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n"); 2700 #endif //DEBUG_GRAPPLE 2701 //check if the grapple missile path is clear 2702 VectorAdd(ms->origin, ms->viewoffset, org); 2703 trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID); 2704 VectorSubtract(reach->end, trace.endpos, dir); 2705 if (VectorLength(dir) > 16) 2706 { 2707 result.failure = qtrue; 2708 return result; 2709 } //end if 2710 //activate the grapple 2711 if (offhandgrapple->value) 2712 { 2713 EA_Command(ms->client, cmd_grappleon->string); 2714 } //end if 2715 else 2716 { 2717 EA_Attack(ms->client); 2718 } //end else 2719 ms->moveflags |= MFL_ACTIVEGRAPPLE; 2720 ms->lastgrappledist = 999999; 2721 } //end if 2722 else 2723 { 2724 if (dist < 70) speed = 300 - (300 - 4 * dist); 2725 else speed = 400; 2726 // 2727 BotCheckBlocked(ms, dir, qtrue, &result); 2728 //elemantary action move in direction 2729 EA_Move(ms->client, dir, speed); 2730 VectorCopy(dir, result.movedir); 2731 } //end else 2732 //if in another area before actually grappling 2733 areanum = AAS_PointAreaNum(ms->origin); 2734 if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0; 2735 } //end else 2736 return result; 2737 } //end of the function BotTravel_Grapple 2738 //=========================================================================== 2739 // 2740 // Parameter: - 2741 // Returns: - 2742 // Changes Globals: - 2743 //=========================================================================== 2744 bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach) 2745 { 2746 vec3_t hordir; 2747 float dist, speed; 2748 bot_moveresult_t result; 2749 2750 //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n"); 2751 BotClearMoveResult(&result); 2752 // 2753 hordir[0] = reach->start[0] - ms->origin[0]; 2754 hordir[1] = reach->start[1] - ms->origin[1]; 2755 hordir[2] = 0; 2756 // 2757 dist = VectorNormalize(hordir); 2758 //look in the movement direction 2759 Vector2Angles(hordir, result.ideal_viewangles); 2760 //look straight down 2761 result.ideal_viewangles[PITCH] = 90; 2762 // 2763 if (dist < 5 && 2764 fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && 2765 fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) 2766 { 2767 //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); 2768 hordir[0] = reach->end[0] - ms->origin[0]; 2769 hordir[1] = reach->end[1] - ms->origin[1]; 2770 hordir[2] = 0; 2771 VectorNormalize(hordir); 2772 //elemantary action jump 2773 EA_Jump(ms->client); 2774 EA_Attack(ms->client); 2775 EA_Move(ms->client, hordir, 800); 2776 // 2777 ms->jumpreach = ms->lastreachnum; 2778 } //end if 2779 else 2780 { 2781 if (dist > 80) dist = 80; 2782 speed = 400 - (400 - 5 * dist); 2783 EA_Move(ms->client, hordir, speed); 2784 } //end else 2785 //look in the movement direction 2786 Vector2Angles(hordir, result.ideal_viewangles); 2787 //look straight down 2788 result.ideal_viewangles[PITCH] = 90; 2789 //set the view angles directly 2790 EA_View(ms->client, result.ideal_viewangles); 2791 //view is important for the movment 2792 result.flags |= MOVERESULT_MOVEMENTVIEWSET; 2793 //select the rocket launcher 2794 EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value); 2795 //weapon is used for movement 2796 result.weapon = (int) weapindex_rocketlauncher->value; 2797 result.flags |= MOVERESULT_MOVEMENTWEAPON; 2798 // 2799 VectorCopy(hordir, result.movedir); 2800 // 2801 return result; 2802 } //end of the function BotTravel_RocketJump 2803 //=========================================================================== 2804 // 2805 // Parameter: - 2806 // Returns: - 2807 // Changes Globals: - 2808 //=========================================================================== 2809 bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach) 2810 { 2811 vec3_t hordir; 2812 float dist, speed; 2813 bot_moveresult_t result; 2814 2815 //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n"); 2816 BotClearMoveResult(&result); 2817 // 2818 hordir[0] = reach->start[0] - ms->origin[0]; 2819 hordir[1] = reach->start[1] - ms->origin[1]; 2820 hordir[2] = 0; 2821 // 2822 dist = VectorNormalize(hordir); 2823 // 2824 if (dist < 5 && 2825 fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && 2826 fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) 2827 { 2828 //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); 2829 hordir[0] = reach->end[0] - ms->origin[0]; 2830 hordir[1] = reach->end[1] - ms->origin[1]; 2831 hordir[2] = 0; 2832 VectorNormalize(hordir); 2833 //elemantary action jump 2834 EA_Jump(ms->client); 2835 EA_Attack(ms->client); 2836 EA_Move(ms->client, hordir, 800); 2837 // 2838 ms->jumpreach = ms->lastreachnum; 2839 } //end if 2840 else 2841 { 2842 if (dist > 80) dist = 80; 2843 speed = 400 - (400 - 5 * dist); 2844 EA_Move(ms->client, hordir, speed); 2845 } //end else 2846 //look in the movement direction 2847 Vector2Angles(hordir, result.ideal_viewangles); 2848 //look straight down 2849 result.ideal_viewangles[PITCH] = 90; 2850 //set the view angles directly 2851 EA_View(ms->client, result.ideal_viewangles); 2852 //view is important for the movment 2853 result.flags |= MOVERESULT_MOVEMENTVIEWSET; 2854 //select the rocket launcher 2855 EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value); 2856 //weapon is used for movement 2857 result.weapon = (int) weapindex_bfg10k->value; 2858 result.flags |= MOVERESULT_MOVEMENTWEAPON; 2859 // 2860 VectorCopy(hordir, result.movedir); 2861 // 2862 return result; 2863 } //end of the function BotTravel_BFGJump 2864 //=========================================================================== 2865 // 2866 // Parameter: - 2867 // Returns: - 2868 // Changes Globals: - 2869 //=========================================================================== 2870 bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach) 2871 { 2872 vec3_t hordir; 2873 float speed; 2874 bot_moveresult_t result; 2875 2876 BotClearMoveResult(&result); 2877 //if not jumped yet 2878 if (!ms->jumpreach) return result; 2879 /* 2880 //go straight to the reachability end 2881 hordir[0] = reach->end[0] - ms->origin[0]; 2882 hordir[1] = reach->end[1] - ms->origin[1]; 2883 hordir[2] = 0; 2884 VectorNormalize(hordir); 2885 //always use max speed when traveling through the air 2886 EA_Move(ms->client, hordir, 800); 2887 VectorCopy(hordir, result.movedir); 2888 */ 2889 // 2890 if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) 2891 { 2892 //go straight to the reachability end 2893 VectorSubtract(reach->end, ms->origin, hordir); 2894 hordir[2] = 0; 2895 VectorNormalize(hordir); 2896 speed = 400; 2897 } //end if 2898 // 2899 EA_Move(ms->client, hordir, speed); 2900 VectorCopy(hordir, result.movedir); 2901 // 2902 return result; 2903 } //end of the function BotFinishTravel_WeaponJump 2904 //=========================================================================== 2905 // 2906 // Parameter: - 2907 // Returns: - 2908 // Changes Globals: - 2909 //=========================================================================== 2910 bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) 2911 { 2912 float dist, speed; 2913 vec3_t hordir; 2914 bot_moveresult_t result; 2915 2916 BotClearMoveResult(&result); 2917 //first walk straight to the reachability start 2918 hordir[0] = reach->start[0] - ms->origin[0]; 2919 hordir[1] = reach->start[1] - ms->origin[1]; 2920 hordir[2] = 0; 2921 dist = VectorNormalize(hordir); 2922 // 2923 BotCheckBlocked(ms, hordir, qtrue, &result); 2924 speed = 400; 2925 //elemantary action move in direction 2926 EA_Move(ms->client, hordir, speed); 2927 VectorCopy(hordir, result.movedir); 2928 // 2929 return result; 2930 } //end of the function BotTravel_JumpPad 2931 //=========================================================================== 2932 // 2933 // Parameter: - 2934 // Returns: - 2935 // Changes Globals: - 2936 //=========================================================================== 2937 bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) 2938 { 2939 float speed; 2940 vec3_t hordir; 2941 bot_moveresult_t result; 2942 2943 BotClearMoveResult(&result); 2944 if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) 2945 { 2946 hordir[0] = reach->end[0] - ms->origin[0]; 2947 hordir[1] = reach->end[1] - ms->origin[1]; 2948 hordir[2] = 0; 2949 VectorNormalize(hordir); 2950 speed = 400; 2951 } //end if 2952 BotCheckBlocked(ms, hordir, qtrue, &result); 2953 //elemantary action move in direction 2954 EA_Move(ms->client, hordir, speed); 2955 VectorCopy(hordir, result.movedir); 2956 // 2957 return result; 2958 } //end of the function BotFinishTravel_JumpPad 2959 //=========================================================================== 2960 // time before the reachability times out 2961 // 2962 // Parameter: - 2963 // Returns: - 2964 // Changes Globals: - 2965 //=========================================================================== 2966 int BotReachabilityTime(aas_reachability_t *reach) 2967 { 2968 switch(reach->traveltype & TRAVELTYPE_MASK) 2969 { 2970 case TRAVEL_WALK: return 5; 2971 case TRAVEL_CROUCH: return 5; 2972 case TRAVEL_BARRIERJUMP: return 5; 2973 case TRAVEL_LADDER: return 6; 2974 case TRAVEL_WALKOFFLEDGE: return 5; 2975 case TRAVEL_JUMP: return 5; 2976 case TRAVEL_SWIM: return 5; 2977 case TRAVEL_WATERJUMP: return 5; 2978 case TRAVEL_TELEPORT: return 5; 2979 case TRAVEL_ELEVATOR: return 10; 2980 case TRAVEL_GRAPPLEHOOK: return 8; 2981 case TRAVEL_ROCKETJUMP: return 6; 2982 case TRAVEL_BFGJUMP: return 6; 2983 case TRAVEL_JUMPPAD: return 10; 2984 case TRAVEL_FUNCBOB: return 10; 2985 default: 2986 { 2987 botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype); 2988 return 8; 2989 } //end case 2990 } //end switch 2991 } //end of the function BotReachabilityTime 2992 //=========================================================================== 2993 // 2994 // Parameter: - 2995 // Returns: - 2996 // Changes Globals: - 2997 //=========================================================================== 2998 bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal) 2999 { 3000 bot_moveresult_t result; 3001 vec3_t dir; 3002 float dist, speed; 3003 3004 #ifdef DEBUG 3005 //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1)); 3006 //AAS_ClearShownDebugLines(); 3007 //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED); 3008 #endif //DEBUG 3009 BotClearMoveResult(&result); 3010 //walk straight to the goal origin 3011 dir[0] = goal->origin[0] - ms->origin[0]; 3012 dir[1] = goal->origin[1] - ms->origin[1]; 3013 if (ms->moveflags & MFL_SWIMMING) 3014 { 3015 dir[2] = goal->origin[2] - ms->origin[2]; 3016 result.traveltype = TRAVEL_SWIM; 3017 } //end if 3018 else 3019 { 3020 dir[2] = 0; 3021 result.traveltype = TRAVEL_WALK; 3022 } //endif 3023 // 3024 dist = VectorNormalize(dir); 3025 if (dist > 100) dist = 100; 3026 speed = 400 - (400 - 4 * dist); 3027 if (speed < 10) speed = 0; 3028 // 3029 BotCheckBlocked(ms, dir, qtrue, &result); 3030 //elemantary action move in direction 3031 EA_Move(ms->client, dir, speed); 3032 VectorCopy(dir, result.movedir); 3033 // 3034 if (ms->moveflags & MFL_SWIMMING) 3035 { 3036 Vector2Angles(dir, result.ideal_viewangles); 3037 result.flags |= MOVERESULT_SWIMVIEW; 3038 } //end if 3039 //if (!debugline) debugline = botimport.DebugLineCreate(); 3040 //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE); 3041 // 3042 ms->lastreachnum = 0; 3043 ms->lastareanum = 0; 3044 ms->lastgoalareanum = goal->areanum; 3045 VectorCopy(ms->origin, ms->lastorigin); 3046 // 3047 return result; 3048 } //end of the function BotMoveInGoalArea 3049 //=========================================================================== 3050 // 3051 // Parameter: - 3052 // Returns: - 3053 // Changes Globals: - 3054 //=========================================================================== 3055 void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags) 3056 { 3057 int reachnum, lastreachnum, foundjumppad, ent, resultflags; 3058 aas_reachability_t reach, lastreach; 3059 bot_movestate_t *ms; 3060 //vec3_t mins, maxs, up = {0, 0, 1}; 3061 //bsp_trace_t trace; 3062 //static int debugline; 3063 3064 3065 BotClearMoveResult(result); 3066 // 3067 ms = BotMoveStateFromHandle(movestate); 3068 if (!ms) return; 3069 //reset the grapple before testing if the bot has a valid goal 3070 //because the bot could loose all it's goals when stuck to a wall 3071 BotResetGrapple(ms); 3072 // 3073 if (!goal) 3074 { 3075 #ifdef DEBUG 3076 botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client); 3077 #endif //DEBUG 3078 result->failure = qtrue; 3079 return; 3080 } //end if 3081 //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach); 3082 //remove some of the move flags 3083 ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER); 3084 //set some of the move flags 3085 //NOTE: the MFL_ONGROUND flag is also set in the higher AI 3086 if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; 3087 // 3088 if (ms->moveflags & MFL_ONGROUND) 3089 { 3090 int modeltype, modelnum; 3091 3092 ent = BotOnTopOfEntity(ms); 3093 3094 if (ent != -1) 3095 { 3096 modelnum = AAS_EntityModelindex(ent); 3097 if (modelnum >= 0 && modelnum < MAX_MODELS) 3098 { 3099 modeltype = modeltypes[modelnum]; 3100 3101 if (modeltype == MODELTYPE_FUNC_PLAT) 3102 { 3103 AAS_ReachabilityFromNum(ms->lastreachnum, &reach); 3104 //if the bot is Not using the elevator 3105 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR || 3106 //NOTE: the face number is the plat model number 3107 (reach.facenum & 0x0000FFFF) != modelnum) 3108 { 3109 reachnum = AAS_NextModelReachability(0, modelnum); 3110 if (reachnum) 3111 { 3112 //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client); 3113 AAS_ReachabilityFromNum(reachnum, &reach); 3114 ms->lastreachnum = reachnum; 3115 ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); 3116 } //end if 3117 else 3118 { 3119 if (bot_developer) 3120 { 3121 botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client); 3122 } //end if 3123 result->blocked = qtrue; 3124 result->blockentity = ent; 3125 result->flags |= MOVERESULT_ONTOPOFOBSTACLE; 3126 return; 3127 } //end else 3128 } //end if 3129 result->flags |= MOVERESULT_ONTOPOF_ELEVATOR; 3130 } //end if 3131 else if (modeltype == MODELTYPE_FUNC_BOB) 3132 { 3133 AAS_ReachabilityFromNum(ms->lastreachnum, &reach); 3134 //if the bot is Not using the func bobbing 3135 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB || 3136 //NOTE: the face number is the func_bobbing model number 3137 (reach.facenum & 0x0000FFFF) != modelnum) 3138 { 3139 reachnum = AAS_NextModelReachability(0, modelnum); 3140 if (reachnum) 3141 { 3142 //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client); 3143 AAS_ReachabilityFromNum(reachnum, &reach); 3144 ms->lastreachnum = reachnum; 3145 ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); 3146 } //end if 3147 else 3148 { 3149 if (bot_developer) 3150 { 3151 botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client); 3152 } //end if 3153 result->blocked = qtrue; 3154 result->blockentity = ent; 3155 result->flags |= MOVERESULT_ONTOPOFOBSTACLE; 3156 return; 3157 } //end else 3158 } //end if 3159 result->flags |= MOVERESULT_ONTOPOF_FUNCBOB; 3160 } //end if 3161 else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR) 3162 { 3163 // check if ontop of a door bridge ? 3164 ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); 3165 // if not in a reachability area 3166 if (!AAS_AreaReachability(ms->areanum)) 3167 { 3168 result->blocked = qtrue; 3169 result->blockentity = ent; 3170 result->flags |= MOVERESULT_ONTOPOFOBSTACLE; 3171 return; 3172 } //end if 3173 } //end else if 3174 else 3175 { 3176 result->blocked = qtrue; 3177 result->blockentity = ent; 3178 result->flags |= MOVERESULT_ONTOPOFOBSTACLE; 3179 return; 3180 } //end else 3181 } //end if 3182 } //end if 3183 } //end if 3184 //if swimming 3185 if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING; 3186 //if against a ladder 3187 if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER; 3188 //if the bot is on the ground, swimming or against a ladder 3189 if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER)) 3190 { 3191 //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); 3192 // 3193 AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach); 3194 //reachability area the bot is in 3195 //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR)); 3196 ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); 3197 // 3198 if ( !ms->areanum ) 3199 { 3200 result->failure = qtrue; 3201 result->blocked = qtrue; 3202 result->blockentity = 0; 3203 result->type = RESULTTYPE_INSOLIDAREA; 3204 return; 3205 } //end if 3206 //if the bot is in the goal area 3207 if (ms->areanum == goal->areanum) 3208 { 3209 *result = BotMoveInGoalArea(ms, goal); 3210 return; 3211 } //end if 3212 //assume we can use the reachability from the last frame 3213 reachnum = ms->lastreachnum; 3214 //if there is a last reachability 3215 if (reachnum) 3216 { 3217 AAS_ReachabilityFromNum(reachnum, &reach); 3218 //check if the reachability is still valid 3219 if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags)) 3220 { 3221 reachnum = 0; 3222 } //end if 3223 //special grapple hook case 3224 else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK) 3225 { 3226 if (ms->reachability_time < AAS_Time() || 3227 (ms->moveflags & MFL_GRAPPLERESET)) 3228 { 3229 reachnum = 0; 3230 } //end if 3231 } //end if 3232 //special elevator case 3233 else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR || 3234 (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) 3235 { 3236 if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) || 3237 (result->flags & MOVERESULT_ONTOPOF_FUNCBOB)) 3238 { 3239 ms->reachability_time = AAS_Time() + 5; 3240 } //end if 3241 //if the bot was going for an elevator and reached the reachability area 3242 if (ms->areanum == reach.areanum || 3243 ms->reachability_time < AAS_Time()) 3244 { 3245 reachnum = 0; 3246 } //end if 3247 } //end if 3248 else 3249 { 3250 #ifdef DEBUG 3251 if (bot_developer) 3252 { 3253 if (ms->reachability_time < AAS_Time()) 3254 { 3255 botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client); 3256 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); 3257 botimport.Print(PRT_MESSAGE, "\n"); 3258 } //end if 3259 /* 3260 if (ms->lastareanum != ms->areanum) 3261 { 3262 botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum); 3263 } //end if*/ 3264 } //end if 3265 #endif //DEBUG 3266 //if the goal area changed or the reachability timed out 3267 //or the area changed 3268 if (ms->lastgoalareanum != goal->areanum || 3269 ms->reachability_time < AAS_Time() || 3270 ms->lastareanum != ms->areanum) 3271 { 3272 reachnum = 0; 3273 //botimport.Print(PRT_MESSAGE, "area change or timeout\n"); 3274 } //end else if 3275 } //end else 3276 } //end if 3277 resultflags = 0; 3278 //if the bot needs a new reachability 3279 if (!reachnum) 3280 { 3281 //if the area has no reachability links 3282 if (!AAS_AreaReachability(ms->areanum)) 3283 { 3284 #ifdef DEBUG 3285 if (bot_developer) 3286 { 3287 botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum); 3288 } //end if 3289 #endif //DEBUG 3290 } //end if 3291 //get a new reachability leading towards the goal 3292 reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum, 3293 ms->lastgoalareanum, ms->lastareanum, 3294 ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, 3295 goal, travelflags, travelflags, 3296 ms->avoidspots, ms->numavoidspots, &resultflags); 3297 //the area number the reachability starts in 3298 ms->reachareanum = ms->areanum; 3299 //reset some state variables 3300 ms->jumpreach = 0; //for TRAVEL_JUMP 3301 ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK 3302 //if there is a reachability to the goal 3303 if (reachnum) 3304 { 3305 AAS_ReachabilityFromNum(reachnum, &reach); 3306 //set a timeout for this reachability 3307 ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); 3308 // 3309 #ifdef AVOIDREACH 3310 //add the reachability to the reachabilities to avoid for a while 3311 BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME); 3312 #endif //AVOIDREACH 3313 } //end if 3314 #ifdef DEBUG 3315 3316 else if (bot_developer) 3317 { 3318 botimport.Print(PRT_MESSAGE, "goal not reachable\n"); 3319 Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy 3320 } //end else 3321 if (bot_developer) 3322 { 3323 //if still going for the same goal 3324 if (ms->lastgoalareanum == goal->areanum) 3325 { 3326 if (ms->lastareanum == reach.areanum) 3327 { 3328 botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n"); 3329 } //end if 3330 } //end if 3331 } //end if 3332 #endif //DEBUG 3333 } //end else 3334 // 3335 ms->lastreachnum = reachnum; 3336 ms->lastgoalareanum = goal->areanum; 3337 ms->lastareanum = ms->areanum; 3338 //if the bot has a reachability 3339 if (reachnum) 3340 { 3341 //get the reachability from the number 3342 AAS_ReachabilityFromNum(reachnum, &reach); 3343 result->traveltype = reach.traveltype; 3344 // 3345 #ifdef DEBUG_AI_MOVE 3346 AAS_ClearShownDebugLines(); 3347 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); 3348 AAS_ShowReachability(&reach); 3349 #endif //DEBUG_AI_MOVE 3350 // 3351 #ifdef DEBUG 3352 //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client); 3353 //AAS_PrintTravelType(reach.traveltype); 3354 //botimport.Print(PRT_MESSAGE, "\n"); 3355 #endif //DEBUG 3356 switch(reach.traveltype & TRAVELTYPE_MASK) 3357 { 3358 case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break; 3359 case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break; 3360 case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break; 3361 case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; 3362 case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break; 3363 case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break; 3364 case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; 3365 case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break; 3366 case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break; 3367 case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break; 3368 case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; 3369 case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break; 3370 case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break; 3371 case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break; 3372 case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break; 3373 default: 3374 { 3375 botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); 3376 break; 3377 } //end case 3378 } //end switch 3379 result->traveltype = reach.traveltype; 3380 result->flags |= resultflags; 3381 } //end if 3382 else 3383 { 3384 result->failure = qtrue; 3385 result->flags |= resultflags; 3386 Com_Memset(&reach, 0, sizeof(aas_reachability_t)); 3387 } //end else 3388 #ifdef DEBUG 3389 if (bot_developer) 3390 { 3391 if (result->failure) 3392 { 3393 botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client); 3394 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); 3395 botimport.Print(PRT_MESSAGE, "\n"); 3396 } //end if 3397 } //end if 3398 #endif //DEBUG 3399 } //end if 3400 else 3401 { 3402 int i, numareas, areas[16]; 3403 vec3_t end; 3404 3405 //special handling of jump pads when the bot uses a jump pad without knowing it 3406 foundjumppad = qfalse; 3407 VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end); 3408 numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16); 3409 for (i = numareas-1; i >= 0; i--) 3410 { 3411 if (AAS_AreaJumpPad(areas[i])) 3412 { 3413 //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]); 3414 foundjumppad = qtrue; 3415 lastreachnum = BotGetReachabilityToGoal(end, areas[i], 3416 ms->lastgoalareanum, ms->lastareanum, 3417 ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, 3418 goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL); 3419 if (lastreachnum) 3420 { 3421 ms->lastreachnum = lastreachnum; 3422 ms->lastareanum = areas[i]; 3423 //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n"); 3424 break; 3425 } //end if 3426 else 3427 { 3428 for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum; 3429 lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum)) 3430 { 3431 //get the reachability from the number 3432 AAS_ReachabilityFromNum(lastreachnum, &reach); 3433 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) 3434 { 3435 ms->lastreachnum = lastreachnum; 3436 ms->lastareanum = areas[i]; 3437 //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n"); 3438 break; 3439 } //end if 3440 } //end for 3441 if (lastreachnum) break; 3442 } //end else 3443 } //end if 3444 } //end for 3445 if (bot_developer) 3446 { 3447 //if a jumppad is found with the trace but no reachability is found 3448 if (foundjumppad && !ms->lastreachnum) 3449 { 3450 botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client); 3451 } //end if 3452 } //end if 3453 // 3454 if (ms->lastreachnum) 3455 { 3456 //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); 3457 AAS_ReachabilityFromNum(ms->lastreachnum, &reach); 3458 result->traveltype = reach.traveltype; 3459 #ifdef DEBUG 3460 //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client); 3461 //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); 3462 //botimport.Print(PRT_MESSAGE, "\n"); 3463 #endif //DEBUG 3464 // 3465 switch(reach.traveltype & TRAVELTYPE_MASK) 3466 { 3467 case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break; 3468 case TRAVEL_CROUCH: /*do nothing*/ break; 3469 case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break; 3470 case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; 3471 case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break; 3472 case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break; 3473 case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; 3474 case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break; 3475 case TRAVEL_TELEPORT: /*do nothing*/ break; 3476 case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break; 3477 case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; 3478 case TRAVEL_ROCKETJUMP: 3479 case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break; 3480 case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break; 3481 case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break; 3482 default: 3483 { 3484 botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); 3485 break; 3486 } //end case 3487 } //end switch 3488 result->traveltype = reach.traveltype; 3489 #ifdef DEBUG 3490 if (bot_developer) 3491 { 3492 if (result->failure) 3493 { 3494 botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client); 3495 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); 3496 botimport.Print(PRT_MESSAGE, "\n"); 3497 } //end if 3498 } //end if 3499 #endif //DEBUG 3500 } //end if 3501 } //end else 3502 //FIXME: is it right to do this here? 3503 if (result->blocked) ms->reachability_time -= 10 * ms->thinktime; 3504 //copy the last origin 3505 VectorCopy(ms->origin, ms->lastorigin); 3506 //return the movement result 3507 return; 3508 } //end of the function BotMoveToGoal 3509 //=========================================================================== 3510 // 3511 // Parameter: - 3512 // Returns: - 3513 // Changes Globals: - 3514 //=========================================================================== 3515 void BotResetAvoidReach(int movestate) 3516 { 3517 bot_movestate_t *ms; 3518 3519 ms = BotMoveStateFromHandle(movestate); 3520 if (!ms) return; 3521 Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); 3522 Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float)); 3523 Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int)); 3524 } //end of the function BotResetAvoidReach 3525 //=========================================================================== 3526 // 3527 // Parameter: - 3528 // Returns: - 3529 // Changes Globals: - 3530 //=========================================================================== 3531 void BotResetLastAvoidReach(int movestate) 3532 { 3533 int i, latest; 3534 float latesttime; 3535 bot_movestate_t *ms; 3536 3537 ms = BotMoveStateFromHandle(movestate); 3538 if (!ms) return; 3539 latesttime = 0; 3540 latest = 0; 3541 for (i = 0; i < MAX_AVOIDREACH; i++) 3542 { 3543 if (ms->avoidreachtimes[i] > latesttime) 3544 { 3545 latesttime = ms->avoidreachtimes[i]; 3546 latest = i; 3547 } //end if 3548 } //end for 3549 if (latesttime) 3550 { 3551 ms->avoidreachtimes[latest] = 0; 3552 if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--; 3553 } //end if 3554 } //end of the function BotResetLastAvoidReach 3555 //=========================================================================== 3556 // 3557 // Parameter: - 3558 // Returns: - 3559 // Changes Globals: - 3560 //=========================================================================== 3561 void BotResetMoveState(int movestate) 3562 { 3563 bot_movestate_t *ms; 3564 3565 ms = BotMoveStateFromHandle(movestate); 3566 if (!ms) return; 3567 Com_Memset(ms, 0, sizeof(bot_movestate_t)); 3568 } //end of the function BotResetMoveState 3569 //=========================================================================== 3570 // 3571 // Parameter: - 3572 // Returns: - 3573 // Changes Globals: - 3574 //=========================================================================== 3575 int BotSetupMoveAI(void) 3576 { 3577 BotSetBrushModelTypes(); 3578 sv_maxstep = LibVar("sv_step", "18"); 3579 sv_maxbarrier = LibVar("sv_maxbarrier", "32"); 3580 sv_gravity = LibVar("sv_gravity", "800"); 3581 weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5"); 3582 weapindex_bfg10k = LibVar("weapindex_bfg10k", "9"); 3583 weapindex_grapple = LibVar("weapindex_grapple", "10"); 3584 entitytypemissile = LibVar("entitytypemissile", "3"); 3585 offhandgrapple = LibVar("offhandgrapple", "0"); 3586 cmd_grappleon = LibVar("cmd_grappleon", "grappleon"); 3587 cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff"); 3588 return BLERR_NOERROR; 3589 } //end of the function BotSetupMoveAI 3590 //=========================================================================== 3591 // 3592 // Parameter: - 3593 // Returns: - 3594 // Changes Globals: - 3595 //=========================================================================== 3596 void BotShutdownMoveAI(void) 3597 { 3598 int i; 3599 3600 for (i = 1; i <= MAX_CLIENTS; i++) 3601 { 3602 if (botmovestates[i]) 3603 { 3604 FreeMemory(botmovestates[i]); 3605 botmovestates[i] = NULL; 3606 } //end if 3607 } //end for 3608 } //end of the function BotShutdownMoveAI 3609 3610