/game/ai_wpnav.c
C | 3813 lines | 3083 code | 670 blank | 60 comment | 777 complexity | 87627928173391e4577879087fa43f7e MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1#include "g_local.h" 2#include "q_shared.h" 3#include "botlib.h" 4#include "ai_main.h" 5 6float gWPRenderTime = 0; 7float gDeactivated = 0; 8float gBotEdit = 0; 9int gWPRenderedFrame = 0; 10 11#include "../namespace_begin.h" 12wpobject_t *gWPArray[MAX_WPARRAY_SIZE]; 13int gWPNum = 0; 14#include "../namespace_end.h" 15 16int gLastPrintedIndex = -1; 17 18#ifndef _XBOX 19nodeobject_t nodetable[MAX_NODETABLE_SIZE]; 20int nodenum; //so we can connect broken trails 21#endif 22 23int gLevelFlags = 0; 24 25char *GetFlagStr( int flags ) 26{ 27 char *flagstr; 28 int i; 29 30 flagstr = (char *)B_TempAlloc(128); 31 i = 0; 32 33 if (!flags) 34 { 35 strcpy(flagstr, "none\0"); 36 goto fend; 37 } 38 39 if (flags & WPFLAG_JUMP) 40 { 41 flagstr[i] = 'j'; 42 i++; 43 } 44 45 if (flags & WPFLAG_DUCK) 46 { 47 flagstr[i] = 'd'; 48 i++; 49 } 50 51 if (flags & WPFLAG_SNIPEORCAMPSTAND) 52 { 53 flagstr[i] = 'c'; 54 i++; 55 } 56 57 if (flags & WPFLAG_WAITFORFUNC) 58 { 59 flagstr[i] = 'f'; 60 i++; 61 } 62 63 if (flags & WPFLAG_SNIPEORCAMP) 64 { 65 flagstr[i] = 's'; 66 i++; 67 } 68 69 if (flags & WPFLAG_ONEWAY_FWD) 70 { 71 flagstr[i] = 'x'; 72 i++; 73 } 74 75 if (flags & WPFLAG_ONEWAY_BACK) 76 { 77 flagstr[i] = 'y'; 78 i++; 79 } 80 81 if (flags & WPFLAG_GOALPOINT) 82 { 83 flagstr[i] = 'g'; 84 i++; 85 } 86 87 if (flags & WPFLAG_NOVIS) 88 { 89 flagstr[i] = 'n'; 90 i++; 91 } 92 93 if (flags & WPFLAG_NOMOVEFUNC) 94 { 95 flagstr[i] = 'm'; 96 i++; 97 } 98 99 if (flags & WPFLAG_RED_FLAG) 100 { 101 if (i) 102 { 103 flagstr[i] = ' '; 104 i++; 105 } 106 flagstr[i] = 'r'; 107 i++; 108 flagstr[i] = 'e'; 109 i++; 110 flagstr[i] = 'd'; 111 i++; 112 flagstr[i] = ' '; 113 i++; 114 flagstr[i] = 'f'; 115 i++; 116 flagstr[i] = 'l'; 117 i++; 118 flagstr[i] = 'a'; 119 i++; 120 flagstr[i] = 'g'; 121 i++; 122 } 123 124 if (flags & WPFLAG_BLUE_FLAG) 125 { 126 if (i) 127 { 128 flagstr[i] = ' '; 129 i++; 130 } 131 flagstr[i] = 'b'; 132 i++; 133 flagstr[i] = 'l'; 134 i++; 135 flagstr[i] = 'u'; 136 i++; 137 flagstr[i] = 'e'; 138 i++; 139 flagstr[i] = ' '; 140 i++; 141 flagstr[i] = 'f'; 142 i++; 143 flagstr[i] = 'l'; 144 i++; 145 flagstr[i] = 'a'; 146 i++; 147 flagstr[i] = 'g'; 148 i++; 149 } 150 151 if (flags & WPFLAG_SIEGE_IMPERIALOBJ) 152 { 153 if (i) 154 { 155 flagstr[i] = ' '; 156 i++; 157 } 158 flagstr[i] = 's'; 159 i++; 160 flagstr[i] = 'a'; 161 i++; 162 flagstr[i] = 'g'; 163 i++; 164 flagstr[i] = 'a'; 165 i++; 166 flagstr[i] = '_'; 167 i++; 168 flagstr[i] = 'i'; 169 i++; 170 flagstr[i] = 'm'; 171 i++; 172 flagstr[i] = 'p'; 173 i++; 174 } 175 176 if (flags & WPFLAG_SIEGE_REBELOBJ) 177 { 178 if (i) 179 { 180 flagstr[i] = ' '; 181 i++; 182 } 183 flagstr[i] = 's'; 184 i++; 185 flagstr[i] = 'a'; 186 i++; 187 flagstr[i] = 'g'; 188 i++; 189 flagstr[i] = 'a'; 190 i++; 191 flagstr[i] = '_'; 192 i++; 193 flagstr[i] = 'r'; 194 i++; 195 flagstr[i] = 'e'; 196 i++; 197 flagstr[i] = 'b'; 198 i++; 199 } 200 201 flagstr[i] = '\0'; 202 203 if (i == 0) 204 { 205 strcpy(flagstr, "unknown\0"); 206 } 207 208fend: 209 return flagstr; 210} 211 212void G_TestLine(vec3_t start, vec3_t end, int color, int time) 213{ 214 gentity_t *te; 215 216 te = G_TempEntity( start, EV_TESTLINE ); 217 VectorCopy(start, te->s.origin); 218 VectorCopy(end, te->s.origin2); 219 te->s.time2 = time; 220 te->s.weapon = color; 221 te->r.svFlags |= SVF_BROADCAST; 222} 223 224void BotWaypointRender(void) 225{ 226 int i, n; 227 int inc_checker; 228 int bestindex; 229 int gotbestindex; 230 float bestdist; 231 float checkdist; 232 gentity_t *plum; 233 gentity_t *viewent; 234 char *flagstr; 235 vec3_t a; 236 237 if (!gBotEdit) 238 { 239 return; 240 } 241 242 bestindex = 0; 243 244 if (gWPRenderTime > level.time) 245 { 246 goto checkprint; 247 } 248 249 gWPRenderTime = level.time + 100; 250 251 i = gWPRenderedFrame; 252 inc_checker = gWPRenderedFrame; 253 254 while (i < gWPNum) 255 { 256 if (gWPArray[i] && gWPArray[i]->inuse) 257 { 258 plum = G_TempEntity( gWPArray[i]->origin, EV_SCOREPLUM ); 259 plum->r.svFlags |= SVF_BROADCAST; 260 plum->s.time = i; 261 262 n = 0; 263 264 while (n < gWPArray[i]->neighbornum) 265 { 266 if (gWPArray[i]->neighbors[n].forceJumpTo && gWPArray[gWPArray[i]->neighbors[n].num]) 267 { 268 G_TestLine(gWPArray[i]->origin, gWPArray[gWPArray[i]->neighbors[n].num]->origin, 0x0000ff, 5000); 269 } 270 n++; 271 } 272 273 gWPRenderedFrame++; 274 } 275 else 276 { 277 gWPRenderedFrame = 0; 278 break; 279 } 280 281 if ((i - inc_checker) > 4) 282 { 283 break; //don't render too many at once 284 } 285 i++; 286 } 287 288 if (i >= gWPNum) 289 { 290 gWPRenderTime = level.time + 1500; //wait a bit after we finish doing the whole trail 291 gWPRenderedFrame = 0; 292 } 293 294checkprint: 295 296 if (!bot_wp_info.value) 297 { 298 return; 299 } 300 301 viewent = &g_entities[0]; //only show info to the first client 302 303 if (!viewent || !viewent->client) 304 { //client isn't in the game yet? 305 return; 306 } 307 308 bestdist = 256; //max distance for showing point info 309 gotbestindex = 0; 310 311 i = 0; 312 313 while (i < gWPNum) 314 { 315 if (gWPArray[i] && gWPArray[i]->inuse) 316 { 317 VectorSubtract(viewent->client->ps.origin, gWPArray[i]->origin, a); 318 319 checkdist = VectorLength(a); 320 321 if (checkdist < bestdist) 322 { 323 bestdist = checkdist; 324 bestindex = i; 325 gotbestindex = 1; 326 } 327 } 328 i++; 329 } 330 331 if (gotbestindex && bestindex != gLastPrintedIndex) 332 { 333 flagstr = GetFlagStr(gWPArray[bestindex]->flags); 334 gLastPrintedIndex = bestindex; 335 G_Printf(S_COLOR_YELLOW "Waypoint %i\nFlags - %i (%s) (w%f)\nOrigin - (%i %i %i)\n", (int)(gWPArray[bestindex]->index), (int)(gWPArray[bestindex]->flags), flagstr, gWPArray[bestindex]->weight, (int)(gWPArray[bestindex]->origin[0]), (int)(gWPArray[bestindex]->origin[1]), (int)(gWPArray[bestindex]->origin[2])); 336 //GetFlagStr allocates 128 bytes for this, if it's changed then obviously this must be as well 337 B_TempFree(128); //flagstr 338 339 plum = G_TempEntity( gWPArray[bestindex]->origin, EV_SCOREPLUM ); 340 plum->r.svFlags |= SVF_BROADCAST; 341 plum->s.time = bestindex; //render it once 342 } 343 else if (!gotbestindex) 344 { 345 gLastPrintedIndex = -1; 346 } 347} 348 349void TransferWPData(int from, int to) 350{ 351 if (!gWPArray[to]) 352 { 353 gWPArray[to] = (wpobject_t *)B_Alloc(sizeof(wpobject_t)); 354 } 355 356 if (!gWPArray[to]) 357 { 358 G_Printf(S_COLOR_RED "FATAL ERROR: Could not allocated memory for waypoint\n"); 359 } 360 361 gWPArray[to]->flags = gWPArray[from]->flags; 362 gWPArray[to]->weight = gWPArray[from]->weight; 363 gWPArray[to]->associated_entity = gWPArray[from]->associated_entity; 364 gWPArray[to]->disttonext = gWPArray[from]->disttonext; 365 gWPArray[to]->forceJumpTo = gWPArray[from]->forceJumpTo; 366 gWPArray[to]->index = to; 367 gWPArray[to]->inuse = gWPArray[from]->inuse; 368 VectorCopy(gWPArray[from]->origin, gWPArray[to]->origin); 369} 370 371void CreateNewWP(vec3_t origin, int flags) 372{ 373 if (gWPNum >= MAX_WPARRAY_SIZE) 374 { 375 if (!g_RMG.integer) 376 { 377 G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE); 378 } 379 return; 380 } 381 382 if (!gWPArray[gWPNum]) 383 { 384 gWPArray[gWPNum] = (wpobject_t *)B_Alloc(sizeof(wpobject_t)); 385 } 386 387 if (!gWPArray[gWPNum]) 388 { 389 G_Printf(S_COLOR_RED "ERROR: Could not allocated memory for waypoint\n"); 390 } 391 392 gWPArray[gWPNum]->flags = flags; 393 gWPArray[gWPNum]->weight = 0; //calculated elsewhere 394 gWPArray[gWPNum]->associated_entity = ENTITYNUM_NONE; //set elsewhere 395 gWPArray[gWPNum]->forceJumpTo = 0; 396 gWPArray[gWPNum]->disttonext = 0; //calculated elsewhere 397 gWPArray[gWPNum]->index = gWPNum; 398 gWPArray[gWPNum]->inuse = 1; 399 VectorCopy(origin, gWPArray[gWPNum]->origin); 400 gWPNum++; 401} 402 403void CreateNewWP_FromObject(wpobject_t *wp) 404{ 405 int i; 406 407 if (gWPNum >= MAX_WPARRAY_SIZE) 408 { 409 return; 410 } 411 412 if (!gWPArray[gWPNum]) 413 { 414 gWPArray[gWPNum] = (wpobject_t *)B_Alloc(sizeof(wpobject_t)); 415 } 416 417 if (!gWPArray[gWPNum]) 418 { 419 G_Printf(S_COLOR_RED "ERROR: Could not allocated memory for waypoint\n"); 420 } 421 422 gWPArray[gWPNum]->flags = wp->flags; 423 gWPArray[gWPNum]->weight = wp->weight; 424 gWPArray[gWPNum]->associated_entity = wp->associated_entity; 425 gWPArray[gWPNum]->disttonext = wp->disttonext; 426 gWPArray[gWPNum]->forceJumpTo = wp->forceJumpTo; 427 gWPArray[gWPNum]->index = gWPNum; 428 gWPArray[gWPNum]->inuse = 1; 429 VectorCopy(wp->origin, gWPArray[gWPNum]->origin); 430 gWPArray[gWPNum]->neighbornum = wp->neighbornum; 431 432 i = wp->neighbornum; 433 434 while (i >= 0) 435 { 436 gWPArray[gWPNum]->neighbors[i].num = wp->neighbors[i].num; 437 gWPArray[gWPNum]->neighbors[i].forceJumpTo = wp->neighbors[i].forceJumpTo; 438 439 i--; 440 } 441 442 if (gWPArray[gWPNum]->flags & WPFLAG_RED_FLAG) 443 { 444 flagRed = gWPArray[gWPNum]; 445 oFlagRed = flagRed; 446 } 447 else if (gWPArray[gWPNum]->flags & WPFLAG_BLUE_FLAG) 448 { 449 flagBlue = gWPArray[gWPNum]; 450 oFlagBlue = flagBlue; 451 } 452 453 gWPNum++; 454} 455 456void RemoveWP(void) 457{ 458 if (gWPNum <= 0) 459 { 460 return; 461 } 462 463 gWPNum--; 464 465 if (!gWPArray[gWPNum] || !gWPArray[gWPNum]->inuse) 466 { 467 return; 468 } 469 470 //B_Free((wpobject_t *)gWPArray[gWPNum]); 471 if (gWPArray[gWPNum]) 472 { 473 memset( gWPArray[gWPNum], 0, sizeof(gWPArray[gWPNum]) ); 474 } 475 476 //gWPArray[gWPNum] = NULL; 477 478 if (gWPArray[gWPNum]) 479 { 480 gWPArray[gWPNum]->inuse = 0; 481 } 482} 483 484void RemoveAllWP(void) 485{ 486 while(gWPNum) { 487 RemoveWP(); 488 } 489} 490 491void RemoveWP_InTrail(int afterindex) 492{ 493 int foundindex; 494 int foundanindex; 495 int didchange; 496 int i; 497 498 foundindex = 0; 499 foundanindex = 0; 500 didchange = 0; 501 i = 0; 502 503 if (afterindex < 0 || afterindex >= gWPNum) 504 { 505 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex); 506 return; 507 } 508 509 while (i < gWPNum) 510 { 511 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex) 512 { 513 foundindex = i; 514 foundanindex = 1; 515 break; 516 } 517 518 i++; 519 } 520 521 if (!foundanindex) 522 { 523 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex); 524 return; 525 } 526 527 i = 0; 528 529 while (i <= gWPNum) 530 { 531 if (gWPArray[i] && gWPArray[i]->index == foundindex) 532 { 533 //B_Free(gWPArray[i]); 534 535 //Keep reusing the memory 536 memset( gWPArray[i], 0, sizeof(gWPArray[i]) ); 537 538 //gWPArray[i] = NULL; 539 gWPArray[i]->inuse = 0; 540 didchange = 1; 541 } 542 else if (gWPArray[i] && didchange) 543 { 544 TransferWPData(i, i-1); 545 //B_Free(gWPArray[i]); 546 547 //Keep reusing the memory 548 memset( gWPArray[i], 0, sizeof(gWPArray[i]) ); 549 550 //gWPArray[i] = NULL; 551 gWPArray[i]->inuse = 0; 552 } 553 554 i++; 555 } 556 gWPNum--; 557} 558 559int CreateNewWP_InTrail(vec3_t origin, int flags, int afterindex) 560{ 561 int foundindex; 562 int foundanindex; 563 int i; 564 565 foundindex = 0; 566 foundanindex = 0; 567 i = 0; 568 569 if (gWPNum >= MAX_WPARRAY_SIZE) 570 { 571 if (!g_RMG.integer) 572 { 573 G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE); 574 } 575 return 0; 576 } 577 578 if (afterindex < 0 || afterindex >= gWPNum) 579 { 580 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex); 581 return 0; 582 } 583 584 while (i < gWPNum) 585 { 586 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex) 587 { 588 foundindex = i; 589 foundanindex = 1; 590 break; 591 } 592 593 i++; 594 } 595 596 if (!foundanindex) 597 { 598 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex); 599 return 0; 600 } 601 602 i = gWPNum; 603 604 while (i >= 0) 605 { 606 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index != foundindex) 607 { 608 TransferWPData(i, i+1); 609 } 610 else if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == foundindex) 611 { 612 i++; 613 614 if (!gWPArray[i]) 615 { 616 gWPArray[i] = (wpobject_t *)B_Alloc(sizeof(wpobject_t)); 617 } 618 619 gWPArray[i]->flags = flags; 620 gWPArray[i]->weight = 0; //calculated elsewhere 621 gWPArray[i]->associated_entity = ENTITYNUM_NONE; //set elsewhere 622 gWPArray[i]->disttonext = 0; //calculated elsewhere 623 gWPArray[i]->forceJumpTo = 0; 624 gWPArray[i]->index = i; 625 gWPArray[i]->inuse = 1; 626 VectorCopy(origin, gWPArray[i]->origin); 627 gWPNum++; 628 break; 629 } 630 631 i--; 632 } 633 634 return 1; 635} 636 637int CreateNewWP_InsertUnder(vec3_t origin, int flags, int afterindex) 638{ 639 int foundindex; 640 int foundanindex; 641 int i; 642 643 foundindex = 0; 644 foundanindex = 0; 645 i = 0; 646 647 if (gWPNum >= MAX_WPARRAY_SIZE) 648 { 649 if (!g_RMG.integer) 650 { 651 G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE); 652 } 653 return 0; 654 } 655 656 if (afterindex < 0 || afterindex >= gWPNum) 657 { 658 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex); 659 return 0; 660 } 661 662 while (i < gWPNum) 663 { 664 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex) 665 { 666 foundindex = i; 667 foundanindex = 1; 668 break; 669 } 670 671 i++; 672 } 673 674 if (!foundanindex) 675 { 676 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex); 677 return 0; 678 } 679 680 i = gWPNum; 681 682 while (i >= 0) 683 { 684 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index != foundindex) 685 { 686 TransferWPData(i, i+1); 687 } 688 else if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == foundindex) 689 { 690 //i++; 691 TransferWPData(i, i+1); 692 693 if (!gWPArray[i]) 694 { 695 gWPArray[i] = (wpobject_t *)B_Alloc(sizeof(wpobject_t)); 696 } 697 698 gWPArray[i]->flags = flags; 699 gWPArray[i]->weight = 0; //calculated elsewhere 700 gWPArray[i]->associated_entity = ENTITYNUM_NONE; //set elsewhere 701 gWPArray[i]->disttonext = 0; //calculated elsewhere 702 gWPArray[i]->forceJumpTo = 0; 703 gWPArray[i]->index = i; 704 gWPArray[i]->inuse = 1; 705 VectorCopy(origin, gWPArray[i]->origin); 706 gWPNum++; 707 break; 708 } 709 710 i--; 711 } 712 713 return 1; 714} 715 716void TeleportToWP(gentity_t *pl, int afterindex) 717{ 718 int foundindex; 719 int foundanindex; 720 int i; 721 722 if (!pl || !pl->client) 723 { 724 return; 725 } 726 727 foundindex = 0; 728 foundanindex = 0; 729 i = 0; 730 731 if (afterindex < 0 || afterindex >= gWPNum) 732 { 733 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex); 734 return; 735 } 736 737 while (i < gWPNum) 738 { 739 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex) 740 { 741 foundindex = i; 742 foundanindex = 1; 743 break; 744 } 745 746 i++; 747 } 748 749 if (!foundanindex) 750 { 751 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex); 752 return; 753 } 754 755 VectorCopy(gWPArray[foundindex]->origin, pl->client->ps.origin); 756 757 return; 758} 759 760void WPFlagsModify(int wpnum, int flags) 761{ 762 if (wpnum < 0 || wpnum >= gWPNum || !gWPArray[wpnum] || !gWPArray[wpnum]->inuse) 763 { 764 G_Printf(S_COLOR_YELLOW "WPFlagsModify: Waypoint %i does not exist\n", wpnum); 765 return; 766 } 767 768 gWPArray[wpnum]->flags = flags; 769} 770 771static int NotWithinRange(int base, int extent) 772{ 773 if (extent > base && base+5 >= extent) 774 { 775 return 0; 776 } 777 778 if (extent < base && base-5 <= extent) 779 { 780 return 0; 781 } 782 783 return 1; 784} 785 786#ifndef _XBOX 787int NodeHere(vec3_t spot) 788{ 789 int i; 790 791 i = 0; 792 793 while (i < nodenum) 794 { 795 if ((int)nodetable[i].origin[0] == (int)spot[0] && 796 (int)nodetable[i].origin[1] == (int)spot[1]) 797 { 798 if ((int)nodetable[i].origin[2] == (int)spot[2] || 799 ((int)nodetable[i].origin[2] < (int)spot[2] && (int)nodetable[i].origin[2]+5 > (int)spot[2]) || 800 ((int)nodetable[i].origin[2] > (int)spot[2] && (int)nodetable[i].origin[2]-5 < (int)spot[2])) 801 { 802 return 1; 803 } 804 } 805 i++; 806 } 807 808 return 0; 809} 810#endif 811 812int CanGetToVector(vec3_t org1, vec3_t org2, vec3_t mins, vec3_t maxs) 813{ 814 trace_t tr; 815 816 trap_Trace(&tr, org1, mins, maxs, org2, ENTITYNUM_NONE, MASK_SOLID); 817 818 if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid) 819 { 820 return 1; 821 } 822 823 return 0; 824} 825 826#if 0 827int CanGetToVectorTravel(vec3_t org1, vec3_t org2, vec3_t mins, vec3_t maxs) 828{ 829 trace_t tr; 830 vec3_t a, ang, fwd; 831 vec3_t midpos, dmid; 832 float startheight, midheight, fLen; 833 834 mins[2] = -13; 835 maxs[2] = 13; 836 837 trap_Trace(&tr, org1, mins, maxs, org2, ENTITYNUM_NONE, MASK_SOLID); 838 839 if (tr.fraction != 1 || tr.startsolid || tr.allsolid) 840 { 841 return 0; 842 } 843 844 VectorSubtract(org2, org1, a); 845 846 vectoangles(a, ang); 847 848 AngleVectors(ang, fwd, NULL, NULL); 849 850 fLen = VectorLength(a)/2; 851 852 midpos[0] = org1[0] + fwd[0]*fLen; 853 midpos[1] = org1[1] + fwd[1]*fLen; 854 midpos[2] = org1[2] + fwd[2]*fLen; 855 856 VectorCopy(org1, dmid); 857 dmid[2] -= 1024; 858 859 trap_Trace(&tr, midpos, NULL, NULL, dmid, ENTITYNUM_NONE, MASK_SOLID); 860 861 startheight = org1[2] - tr.endpos[2]; 862 863 VectorCopy(midpos, dmid); 864 dmid[2] -= 1024; 865 866 trap_Trace(&tr, midpos, NULL, NULL, dmid, ENTITYNUM_NONE, MASK_SOLID); 867 868 if (tr.startsolid || tr.allsolid) 869 { 870 return 1; 871 } 872 873 midheight = midpos[2] - tr.endpos[2]; 874 875 if (midheight > startheight*2) 876 { 877 return 0; //too steep of a drop.. can't go on 878 } 879 880 return 1; 881} 882#else 883int CanGetToVectorTravel(vec3_t org1, vec3_t moveTo, vec3_t mins, vec3_t maxs) 884//int ExampleAnimEntMove(gentity_t *self, vec3_t moveTo, float stepSize) 885{ 886 trace_t tr; 887 vec3_t stepTo; 888 vec3_t stepSub; 889 vec3_t stepGoal; 890 vec3_t workingOrg; 891 vec3_t lastIncrement; 892 vec3_t finalMeasure; 893 float stepSize = 0; 894 float measureLength = 0; 895 int didMove = 0; 896 int traceMask = MASK_PLAYERSOLID; 897 qboolean initialDone = qfalse; 898 899 VectorCopy(org1, workingOrg); 900 VectorCopy(org1, lastIncrement); 901 902 VectorCopy(moveTo, stepTo); 903 stepTo[2] = workingOrg[2]; 904 905 VectorSubtract(stepTo, workingOrg, stepSub); 906 stepSize = VectorLength(stepSub); //make the step size the length of the original positions without Z 907 908 VectorNormalize(stepSub); 909 910 while (!initialDone || didMove) 911 { 912 initialDone = qtrue; 913 didMove = 0; 914 915 stepGoal[0] = workingOrg[0] + stepSub[0]*stepSize; 916 stepGoal[1] = workingOrg[1] + stepSub[1]*stepSize; 917 stepGoal[2] = workingOrg[2] + stepSub[2]*stepSize; 918 919 trap_Trace(&tr, workingOrg, mins, maxs, stepGoal, ENTITYNUM_NONE, traceMask); 920 921 if (!tr.startsolid && !tr.allsolid && tr.fraction) 922 { 923 vec3_t vecSub; 924 VectorSubtract(workingOrg, tr.endpos, vecSub); 925 926 if (VectorLength(vecSub) > (stepSize/2)) 927 { 928 workingOrg[0] = tr.endpos[0]; 929 workingOrg[1] = tr.endpos[1]; 930 //trap_LinkEntity(self); 931 didMove = 1; 932 } 933 } 934 935 if (didMove != 1) 936 { //stair check 937 vec3_t trFrom; 938 vec3_t trTo; 939 vec3_t trDir; 940 vec3_t vecMeasure; 941 942 VectorCopy(tr.endpos, trFrom); 943 trFrom[2] += 16; 944 945 VectorSubtract(/*tr.endpos*/stepGoal, workingOrg, trDir); 946 VectorNormalize(trDir); 947 trTo[0] = tr.endpos[0] + trDir[0]*2; 948 trTo[1] = tr.endpos[1] + trDir[1]*2; 949 trTo[2] = tr.endpos[2] + trDir[2]*2; 950 trTo[2] += 16; 951 952 VectorSubtract(trFrom, trTo, vecMeasure); 953 954 if (VectorLength(vecMeasure) > 1) 955 { 956 trap_Trace(&tr, trFrom, mins, maxs, trTo, ENTITYNUM_NONE, traceMask); 957 958 if (!tr.startsolid && !tr.allsolid && tr.fraction == 1) 959 { //clear trace here, probably up a step 960 vec3_t trDown; 961 vec3_t trUp; 962 VectorCopy(tr.endpos, trUp); 963 VectorCopy(tr.endpos, trDown); 964 trDown[2] -= 16; 965 966 trap_Trace(&tr, trFrom, mins, maxs, trTo, ENTITYNUM_NONE, traceMask); 967 968 if (!tr.startsolid && !tr.allsolid) 969 { //plop us down on the step after moving up 970 VectorCopy(tr.endpos, workingOrg); 971 //trap_LinkEntity(self); 972 didMove = 1; 973 } 974 } 975 } 976 } 977 978 VectorSubtract(lastIncrement, workingOrg, finalMeasure); 979 measureLength = VectorLength(finalMeasure); 980 981 if (!measureLength) 982 { //no progress, break out. If last movement was a sucess didMove will equal 1. 983 break; 984 } 985 986 stepSize -= measureLength; //subtract the progress distance from the step size so we don't overshoot the mark. 987 if (stepSize <= 0) 988 { 989 break; 990 } 991 992 VectorCopy(workingOrg, lastIncrement); 993 } 994 995 return didMove; 996} 997#endif 998 999#ifndef _XBOX 1000int ConnectTrail(int startindex, int endindex, qboolean behindTheScenes) 1001{ 1002 int foundit; 1003 int cancontinue; 1004 int i; 1005 int failsafe; 1006 int successnodeindex; 1007 int insertindex; 1008 int prenodestart; 1009 byte extendednodes[MAX_NODETABLE_SIZE]; //for storing checked nodes and not trying to extend them each a bazillion times 1010 float fvecmeas; 1011 float baseheight; 1012 float branchDistance; 1013 float maxDistFactor = 256; 1014 vec3_t a; 1015 vec3_t startplace, starttrace; 1016 vec3_t mins, maxs; 1017 vec3_t testspot; 1018 vec3_t validspotpos; 1019 trace_t tr; 1020 1021 if (g_RMG.integer) 1022 { //this might be temporary. Or not. 1023 if (!(gWPArray[startindex]->flags & WPFLAG_NEVERONEWAY) && 1024 !(gWPArray[endindex]->flags & WPFLAG_NEVERONEWAY)) 1025 { 1026 gWPArray[startindex]->flags |= WPFLAG_ONEWAY_FWD; 1027 gWPArray[endindex]->flags |= WPFLAG_ONEWAY_BACK; 1028 } 1029 return 0; 1030 } 1031 1032 if (!g_RMG.integer) 1033 { 1034 branchDistance = TABLE_BRANCH_DISTANCE; 1035 } 1036 else 1037 { 1038 branchDistance = 512; //be less precise here, terrain is fairly broad, and we don't want to take an hour precalculating 1039 } 1040 1041 if (g_RMG.integer) 1042 { 1043 maxDistFactor = 700; 1044 } 1045 1046 mins[0] = -15; 1047 mins[1] = -15; 1048 mins[2] = 0; 1049 maxs[0] = 15; 1050 maxs[1] = 15; 1051 maxs[2] = 0; 1052 1053 nodenum = 0; 1054 foundit = 0; 1055 1056 i = 0; 1057 1058 successnodeindex = 0; 1059 1060 while (i < MAX_NODETABLE_SIZE) //clear it out before using it 1061 { 1062 nodetable[i].flags = 0; 1063// nodetable[i].index = 0; 1064 nodetable[i].inuse = 0; 1065 nodetable[i].neighbornum = 0; 1066 nodetable[i].origin[0] = 0; 1067 nodetable[i].origin[1] = 0; 1068 nodetable[i].origin[2] = 0; 1069 nodetable[i].weight = 0; 1070 1071 extendednodes[i] = 0; 1072 1073 i++; 1074 } 1075 1076 i = 0; 1077 1078 if (!behindTheScenes) 1079 { 1080 G_Printf(S_COLOR_YELLOW "Point %i is not connected to %i - Repairing...\n", startindex, endindex); 1081 } 1082 1083 VectorCopy(gWPArray[startindex]->origin, startplace); 1084 1085 VectorCopy(startplace, starttrace); 1086 1087 starttrace[2] -= 4096; 1088 1089 trap_Trace(&tr, startplace, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID); 1090 1091 baseheight = startplace[2] - tr.endpos[2]; 1092 1093 cancontinue = 1; 1094 1095 VectorCopy(startplace, nodetable[nodenum].origin); 1096 nodetable[nodenum].weight = 1; 1097 nodetable[nodenum].inuse = 1; 1098// nodetable[nodenum].index = nodenum; 1099 nodenum++; 1100 1101 while (nodenum < MAX_NODETABLE_SIZE && !foundit && cancontinue) 1102 { 1103 if (g_RMG.integer) 1104 { //adjust the branch distance dynamically depending on the distance from the start and end points. 1105 vec3_t startDist; 1106 vec3_t endDist; 1107 float startDistf; 1108 float endDistf; 1109 1110 VectorSubtract(nodetable[nodenum-1].origin, gWPArray[startindex]->origin, startDist); 1111 VectorSubtract(nodetable[nodenum-1].origin, gWPArray[endindex]->origin, endDist); 1112 1113 startDistf = VectorLength(startDist); 1114 endDistf = VectorLength(endDist); 1115 1116 if (startDistf < 64 || endDistf < 64) 1117 { 1118 branchDistance = 64; 1119 } 1120 else if (startDistf < 128 || endDistf < 128) 1121 { 1122 branchDistance = 128; 1123 } 1124 else if (startDistf < 256 || endDistf < 256) 1125 { 1126 branchDistance = 256; 1127 } 1128 else if (startDistf < 512 || endDistf < 512) 1129 { 1130 branchDistance = 512; 1131 } 1132 else 1133 { 1134 branchDistance = 800; 1135 } 1136 } 1137 cancontinue = 0; 1138 i = 0; 1139 prenodestart = nodenum; 1140 1141 while (i < prenodestart) 1142 { 1143 if (extendednodes[i] != 1) 1144 { 1145 VectorSubtract(gWPArray[endindex]->origin, nodetable[i].origin, a); 1146 fvecmeas = VectorLength(a); 1147 1148 if (fvecmeas < 128 && CanGetToVector(gWPArray[endindex]->origin, nodetable[i].origin, mins, maxs)) 1149 { 1150 foundit = 1; 1151 successnodeindex = i; 1152 break; 1153 } 1154 1155 VectorCopy(nodetable[i].origin, testspot); 1156 testspot[0] += branchDistance; 1157 1158 VectorCopy(testspot, starttrace); 1159 1160 starttrace[2] -= 4096; 1161 1162 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID); 1163 1164 testspot[2] = tr.endpos[2]+baseheight; 1165 1166 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs)) 1167 { 1168 VectorCopy(testspot, nodetable[nodenum].origin); 1169 nodetable[nodenum].inuse = 1; 1170// nodetable[nodenum].index = nodenum; 1171 nodetable[nodenum].weight = nodetable[i].weight+1; 1172 nodetable[nodenum].neighbornum = i; 1173 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50) 1174 { //if there's a big drop, make sure we know we can't just magically fly back up 1175 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD; 1176 } 1177 nodenum++; 1178 cancontinue = 1; 1179 } 1180 1181 if (nodenum >= MAX_NODETABLE_SIZE) 1182 { 1183 break; //failure 1184 } 1185 1186 VectorCopy(nodetable[i].origin, testspot); 1187 testspot[0] -= branchDistance; 1188 1189 VectorCopy(testspot, starttrace); 1190 1191 starttrace[2] -= 4096; 1192 1193 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID); 1194 1195 testspot[2] = tr.endpos[2]+baseheight; 1196 1197 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs)) 1198 { 1199 VectorCopy(testspot, nodetable[nodenum].origin); 1200 nodetable[nodenum].inuse = 1; 1201// nodetable[nodenum].index = nodenum; 1202 nodetable[nodenum].weight = nodetable[i].weight+1; 1203 nodetable[nodenum].neighbornum = i; 1204 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50) 1205 { //if there's a big drop, make sure we know we can't just magically fly back up 1206 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD; 1207 } 1208 nodenum++; 1209 cancontinue = 1; 1210 } 1211 1212 if (nodenum >= MAX_NODETABLE_SIZE) 1213 { 1214 break; //failure 1215 } 1216 1217 VectorCopy(nodetable[i].origin, testspot); 1218 testspot[1] += branchDistance; 1219 1220 VectorCopy(testspot, starttrace); 1221 1222 starttrace[2] -= 4096; 1223 1224 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID); 1225 1226 testspot[2] = tr.endpos[2]+baseheight; 1227 1228 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs)) 1229 { 1230 VectorCopy(testspot, nodetable[nodenum].origin); 1231 nodetable[nodenum].inuse = 1; 1232// nodetable[nodenum].index = nodenum; 1233 nodetable[nodenum].weight = nodetable[i].weight+1; 1234 nodetable[nodenum].neighbornum = i; 1235 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50) 1236 { //if there's a big drop, make sure we know we can't just magically fly back up 1237 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD; 1238 } 1239 nodenum++; 1240 cancontinue = 1; 1241 } 1242 1243 if (nodenum >= MAX_NODETABLE_SIZE) 1244 { 1245 break; //failure 1246 } 1247 1248 VectorCopy(nodetable[i].origin, testspot); 1249 testspot[1] -= branchDistance; 1250 1251 VectorCopy(testspot, starttrace); 1252 1253 starttrace[2] -= 4096; 1254 1255 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID); 1256 1257 testspot[2] = tr.endpos[2]+baseheight; 1258 1259 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs)) 1260 { 1261 VectorCopy(testspot, nodetable[nodenum].origin); 1262 nodetable[nodenum].inuse = 1; 1263// nodetable[nodenum].index = nodenum; 1264 nodetable[nodenum].weight = nodetable[i].weight+1; 1265 nodetable[nodenum].neighbornum = i; 1266 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50) 1267 { //if there's a big drop, make sure we know we can't just magically fly back up 1268 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD; 1269 } 1270 nodenum++; 1271 cancontinue = 1; 1272 } 1273 1274 if (nodenum >= MAX_NODETABLE_SIZE) 1275 { 1276 break; //failure 1277 } 1278 1279 extendednodes[i] = 1; 1280 } 1281 1282 i++; 1283 } 1284 } 1285 1286 if (!foundit) 1287 { 1288#ifndef _DEBUG //if debug just always print this. 1289 if (!behindTheScenes) 1290#endif 1291 { 1292 G_Printf(S_COLOR_RED "Could not link %i to %i, unreachable by node branching.\n", startindex, endindex); 1293 } 1294 gWPArray[startindex]->flags |= WPFLAG_ONEWAY_FWD; 1295 gWPArray[endindex]->flags |= WPFLAG_ONEWAY_BACK; 1296 if (!behindTheScenes) 1297 { 1298 G_Printf(S_COLOR_YELLOW "Since points cannot be connected, point %i has been flagged as only-forward and point %i has been flagged as only-backward.\n", startindex, endindex); 1299 } 1300 1301 /*while (nodenum >= 0) 1302 { 1303 if (nodetable[nodenum].origin[0] || nodetable[nodenum].origin[1] || nodetable[nodenum].origin[2]) 1304 { 1305 CreateNewWP(nodetable[nodenum].origin, nodetable[nodenum].flags); 1306 } 1307 1308 nodenum--; 1309 }*/ 1310 //The above code transfers nodes into the "rendered" waypoint array. Strictly for debugging. 1311 1312 if (!behindTheScenes) 1313 { //just use what we have if we're auto-pathing the level 1314 return 0; 1315 } 1316 else 1317 { 1318 vec3_t endDist; 1319 int nCount = 0; 1320 int idealNode = -1; 1321 float bestDist = 0; 1322 float testDist; 1323 1324 if (nodenum <= 10) 1325 { //not enough to even really bother. 1326 return 0; 1327 } 1328 1329 //Since it failed, find whichever node is closest to the desired end. 1330 while (nCount < nodenum) 1331 { 1332 VectorSubtract(nodetable[nCount].origin, gWPArray[endindex]->origin, endDist); 1333 testDist = VectorLength(endDist); 1334 if (idealNode == -1) 1335 { 1336 idealNode = nCount; 1337 bestDist = testDist; 1338 nCount++; 1339 continue; 1340 } 1341 1342 if (testDist < bestDist) 1343 { 1344 idealNode = nCount; 1345 bestDist = testDist; 1346 } 1347 1348 nCount++; 1349 } 1350 1351 if (idealNode == -1) 1352 { 1353 return 0; 1354 } 1355 1356 successnodeindex = idealNode; 1357 } 1358 } 1359 1360 i = successnodeindex; 1361 insertindex = startindex; 1362 failsafe = 0; 1363 VectorCopy(gWPArray[startindex]->origin, validspotpos); 1364 1365 while (failsafe < MAX_NODETABLE_SIZE && i < MAX_NODETABLE_SIZE && i >= 0) 1366 { 1367 VectorSubtract(validspotpos, nodetable[i].origin, a); 1368 if (!nodetable[nodetable[i].neighbornum].inuse || !CanGetToVectorTravel(validspotpos, /*nodetable[nodetable[i].neighbornum].origin*/nodetable[i].origin, mins, maxs) || VectorLength(a) > maxDistFactor || (!CanGetToVectorTravel(validspotpos, gWPArray[endindex]->origin, mins, maxs) && CanGetToVectorTravel(nodetable[i].origin, gWPArray[endindex]->origin, mins, maxs)) ) 1369 { 1370 nodetable[i].flags |= WPFLAG_CALCULATED; 1371 if (!CreateNewWP_InTrail(nodetable[i].origin, nodetable[i].flags, insertindex)) 1372 { 1373 if (!behindTheScenes) 1374 { 1375 G_Printf(S_COLOR_RED "Could not link %i to %i, waypoint limit hit.\n", startindex, endindex); 1376 } 1377 return 0; 1378 } 1379 1380 VectorCopy(nodetable[i].origin, validspotpos); 1381 } 1382 1383 if (i == 0) 1384 { 1385 break; 1386 } 1387 1388 i = nodetable[i].neighbornum; 1389 1390 failsafe++; 1391 } 1392 1393 if (!behindTheScenes) 1394 { 1395 G_Printf(S_COLOR_YELLOW "Finished connecting %i to %i.\n", startindex, endindex); 1396 } 1397 1398 return 1; 1399} 1400#endif 1401 1402int OpposingEnds(int start, int end) 1403{ 1404 if (!gWPArray[start] || !gWPArray[start]->inuse || !gWPArray[end] || !gWPArray[end]->inuse) 1405 { 1406 return 0; 1407 } 1408 1409 if ((gWPArray[start]->flags & WPFLAG_ONEWAY_FWD) && 1410 (gWPArray[end]->flags & WPFLAG_ONEWAY_BACK)) 1411 { 1412 return 1; 1413 } 1414 1415 return 0; 1416} 1417 1418int DoorBlockingSection(int start, int end) 1419{ //if a door blocks the trail, we'll just have to assume the points on each side are in visibility when it's open 1420 trace_t tr; 1421 gentity_t *testdoor; 1422 int start_trace_index; 1423 1424 if (!gWPArray[start] || !gWPArray[start]->inuse || !gWPArray[end] || !gWPArray[end]->inuse) 1425 { 1426 return 0; 1427 } 1428 1429 trap_Trace(&tr, gWPArray[start]->origin, NULL, NULL, gWPArray[end]->origin, ENTITYNUM_NONE, MASK_SOLID); 1430 1431 if (tr.fraction == 1) 1432 { 1433 return 0; 1434 } 1435 1436 testdoor = &g_entities[tr.entityNum]; 1437 1438 if (!testdoor) 1439 { 1440 return 0; 1441 } 1442 1443 if (!strstr(testdoor->classname, "func_")) 1444 { 1445 return 0; 1446 } 1447 1448 start_trace_index = tr.entityNum; 1449 1450 trap_Trace(&tr, gWPArray[end]->origin, NULL, NULL, gWPArray[start]->origin, ENTITYNUM_NONE, MASK_SOLID); 1451 1452 if (tr.fraction == 1) 1453 { 1454 return 0; 1455 } 1456 1457 if (start_trace_index == tr.entityNum) 1458 { 1459 return 1; 1460 } 1461 1462 return 0; 1463} 1464 1465#ifndef _XBOX 1466int RepairPaths(qboolean behindTheScenes) 1467{ 1468 int i; 1469 int preAmount = 0; 1470 int ctRet; 1471 vec3_t a; 1472 float maxDistFactor = 400; 1473 1474 if (!gWPNum) 1475 { 1476 return 0; 1477 } 1478 1479 if (g_RMG.integer) 1480 { 1481 maxDistFactor = 800; //higher tolerance here. 1482 } 1483 1484 i = 0; 1485 1486 preAmount = gWPNum; 1487 1488 trap_Cvar_Update(&bot_wp_distconnect); 1489 trap_Cvar_Update(&bot_wp_visconnect); 1490 1491 while (i < gWPNum) 1492 { 1493 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i+1] && gWPArray[i+1]->inuse) 1494 { 1495 VectorSubtract(gWPArray[i]->origin, gWPArray[i+1]->origin, a); 1496 1497 if (!(gWPArray[i+1]->flags & WPFLAG_NOVIS) && 1498 !(gWPArray[i+1]->flags & WPFLAG_JUMP) && //don't calculate on jump points because they might not always want to be visible (in cases of force jumping) 1499 !(gWPArray[i]->flags & WPFLAG_CALCULATED) && //don't calculate it again 1500 !OpposingEnds(i, i+1) && 1501 ((bot_wp_distconnect.value && VectorLength(a) > maxDistFactor) || (!OrgVisible(gWPArray[i]->origin, gWPArray[i+1]->origin, ENTITYNUM_NONE) && bot_wp_visconnect.value) ) && 1502 !DoorBlockingSection(i, i+1)) 1503 { 1504 ctRet = ConnectTrail(i, i+1, behindTheScenes); 1505 1506 if (gWPNum >= MAX_WPARRAY_SIZE) 1507 { //Bad! 1508 gWPNum = MAX_WPARRAY_SIZE; 1509 break; 1510 } 1511 1512 /*if (!ctRet) 1513 { 1514 return 0; 1515 }*/ //we still want to write it.. 1516 } 1517 } 1518 1519 i++; 1520 } 1521 1522 return 1; 1523} 1524#endif 1525 1526int OrgVisibleCurve(vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore) 1527{ 1528 trace_t tr; 1529 vec3_t evenorg1; 1530 1531 VectorCopy(org1, evenorg1); 1532 evenorg1[2] = org2[2]; 1533 1534 trap_Trace(&tr, evenorg1, mins, maxs, org2, ignore, MASK_SOLID); 1535 1536 if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid) 1537 { 1538 trap_Trace(&tr, evenorg1, mins, maxs, org1, ignore, MASK_SOLID); 1539 1540 if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid) 1541 { 1542 return 1; 1543 } 1544 } 1545 1546 return 0; 1547} 1548 1549int CanForceJumpTo(int baseindex, int testingindex, float distance) 1550{ 1551 float heightdif; 1552 vec3_t xy_base, xy_test, v, mins, maxs; 1553 wpobject_t *wpBase = gWPArray[baseindex]; 1554 wpobject_t *wpTest = gWPArray[testingindex]; 1555 1556 mins[0] = -15; 1557 mins[1] = -15; 1558 mins[2] = -15; //-1 1559 maxs[0] = 15; 1560 maxs[1] = 15; 1561 maxs[2] = 15; //1 1562 1563 if (!wpBase || !wpBase->inuse || !wpTest || !wpTest->inuse) 1564 { 1565 return 0; 1566 } 1567 1568 if (distance > 400) 1569 { 1570 return 0; 1571 } 1572 1573 VectorCopy(wpBase->origin, xy_base); 1574 VectorCopy(wpTest->origin, xy_test); 1575 1576 xy_base[2] = xy_test[2]; 1577 1578 VectorSubtract(xy_base, xy_test, v); 1579 1580 if (VectorLength(v) > MAX_NEIGHBOR_LINK_DISTANCE) 1581 { 1582 return 0; 1583 } 1584 1585 if ((int)wpBase->origin[2] < (int)wpTest->origin[2]) 1586 { 1587 heightdif = wpTest->origin[2] - wpBase->origin[2]; 1588 } 1589 else 1590 { 1591 return 0; //err.. 1592 } 1593 1594 if (heightdif < 128) 1595 { //don't bother.. 1596 return 0; 1597 } 1598 1599 if (heightdif > 512) 1600 { //too high 1601 return 0; 1602 } 1603 1604 if (!OrgVisibleCurve(wpBase->origin, mins, maxs, wpTest->origin, ENTITYNUM_NONE)) 1605 { 1606 return 0; 1607 } 1608 1609 if (heightdif > 400) 1610 { 1611 return 3; 1612 } 1613 else if (heightdif > 256) 1614 { 1615 return 2; 1616 } 1617 else 1618 { 1619 return 1; 1620 } 1621} 1622 1623void CalculatePaths(void) 1624{ 1625 int i; 1626 int c; 1627 int forceJumpable; 1628 int maxNeighborDist = MAX_NEIGHBOR_LINK_DISTANCE; 1629 float nLDist; 1630 vec3_t a; 1631 vec3_t mins, maxs; 1632 1633 if (!gWPNum) 1634 { 1635 return; 1636 } 1637 1638 if (g_RMG.integer) 1639 { 1640 maxNeighborDist = DEFAULT_GRID_SPACING + (DEFAULT_GRID_SPACING*0.5); 1641 } 1642 1643 mins[0] = -15; 1644 mins[1] = -15; 1645 mins[2] = -15; //-1 1646 maxs[0] = 15; 1647 maxs[1] = 15; 1648 maxs[2] = 15; //1 1649 1650 //now clear out all the neighbor data before we recalculate 1651 i = 0; 1652 1653 while (i < gWPNum) 1654 { 1655 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->neighbornum) 1656 { 1657 while (gWPArray[i]->neighbornum >= 0) 1658 { 1659 gWPArray[i]->neighbors[gWPArray[i]->neighbornum].num = 0; 1660 gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 0; 1661 gWPArray[i]->neighbornum--; 1662 } 1663 gWPArray[i]->neighbornum = 0; 1664 } 1665 1666 i++; 1667 } 1668 1669 i = 0; 1670 1671 while (i < gWPNum) 1672 { 1673 if (gWPArray[i] && gWPArray[i]->inuse) 1674 { 1675 c = 0; 1676 1677 while (c < gWPNum) 1678 { 1679 if (gWPArray[c] && gWPArray[c]->inuse && i != c && 1680 NotWithinRange(i, c)) 1681 { 1682 VectorSubtract(gWPArray[i]->origin, gWPArray[c]->origin, a); 1683 1684 nLDist = VectorLength(a); 1685 forceJumpable = CanForceJumpTo(i, c, nLDist); 1686 1687 if ((nLDist < maxNeighborDist || forceJumpable) && 1688 ((int)gWPArray[i]->origin[2] == (int)gWPArray[c]->origin[2] || forceJumpable) && 1689 (OrgVisibleBox(gWPArray[i]->origin, mins, maxs, gWPArray[c]->origin, ENTITYNUM_NONE) || forceJumpable)) 1690 { 1691 gWPArray[i]->neighbors[gWPArray[i]->neighbornum].num = c; 1692 if (forceJumpable && ((int)gWPArray[i]->origin[2] != (int)gWPArray[c]->origin[2] || nLDist < maxNeighborDist)) 1693 { 1694 gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 999;//forceJumpable; //FJSR 1695 } 1696 else 1697 { 1698 gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 0; 1699 } 1700 gWPArray[i]->neighbornum++; 1701 } 1702 1703 if (gWPArray[i]->neighbornum >= MAX_NEIGHBOR_SIZE) 1704 { 1705 break; 1706 } 1707 } 1708 c++; 1709 } 1710 } 1711 i++; 1712 } 1713} 1714 1715gentity_t *GetObjectThatTargets(gentity_t *ent) 1716{ 1717 gentity_t *next = NULL; 1718 1719 if (!ent->targetname) 1720 { 1721 return NULL; 1722 } 1723 1724 next = G_Find( next, FOFS(target), ent->targetname ); 1725 1726 if (next) 1727 { 1728 return next; 1729 } 1730 1731 return NULL; 1732} 1733 1734void CalculateSiegeGoals(void) 1735{ 1736 int i = 0; 1737 int looptracker = 0; 1738 int wpindex = 0; 1739 vec3_t dif; 1740 gentity_t *ent; 1741 gentity_t *tent = NULL, *t2ent = NULL; 1742 1743 while (i < level.num_entities) 1744 { 1745 ent = &g_entities[i]; 1746 1747 tent = NULL; 1748 1749 if (ent && ent->classname && strcmp(ent->classname, "info_siege_objective") == 0) 1750 { 1751 tent = ent; 1752 t2ent = GetObjectThatTargets(tent); 1753 looptracker = 0; 1754 1755 while (t2ent && looptracker < 2048) 1756 { //looptracker keeps us from getting stuck in case something is set up weird on this map 1757 tent = t2ent; 1758 t2ent = GetObjectThatTargets(tent); 1759 looptracker++; 1760 } 1761 1762 if (looptracker >= 2048) 1763 { //something unpleasent has happened 1764 tent = NULL; 1765 break; 1766 } 1767 } 1768 1769 if (tent && ent && tent != ent) 1770 { //tent should now be the object attached to the mission objective 1771 dif[0] = (tent->r.absmax[0]+tent->r.absmin[0])/2; 1772 dif[1] = (tent->r.absmax[1]+tent->r.absmin[1])/2; 1773 dif[2] = (tent->r.absmax[2]+tent->r.absmin[2])/2; 1774 1775 wpindex = GetNearestVisibleWP(dif, tent->s.number); 1776 1777 if (wpindex != -1 && gWPArray[wpindex] && gWPArray[wpindex]->inuse) 1778 { //found the waypoint nearest the center of this objective-related object 1779 if (ent->side == SIEGETEAM_TEAM1) 1780 { 1781 gWPArray[wpindex]->flags |= WPFLAG_SIEGE_IMPERIALOBJ; 1782 } 1783 else 1784 { 1785 gWPArray[wpindex]->flags |= WPFLAG_SIEGE_REBELOBJ; 1786 } 1787 1788 gWPArray[wpindex]->associated_entity = tent->s.number; 1789 } 1790 } 1791 1792 i++; 1793 } 1794} 1795 1796float botGlobalNavWeaponWeights[WP_NUM_WEAPONS] = 1797{ 1798 0,//WP_NONE, 1799 1800 0,//WP_STUN_BATON, 1801 0,//WP_MELEE 1802 0,//WP_SABER, // NOTE: lots of code assumes this is the first weapon (... which is crap) so be careful -Ste. 1803 0,//WP_BRYAR_PISTOL, 1804 3,//WP_BLASTER, 1805 5,//WP_DISRUPTOR, 1806 4,//WP_BOWCASTER, 1807 6,//WP_REPEATER, 1808 7,//WP_DEMP2, 1809 8,//WP_FLECHETTE, 1810 9,//WP_ROCKET_LAUNCHER, 1811 3,//WP_THERMAL, 1812 3,//WP_TRIP_MINE, 1813 3,//WP_DET_PACK, 1814 0//WP_EMPLACED_GUN, 1815}; 1816 1817int GetNearestVisibleWPToItem(vec3_t org, int ignore) 1818{ 1819 int i; 1820 float bestdist; 1821 float flLen; 1822 int bestindex; 1823 vec3_t a, mins, maxs; 1824 1825 i = 0; 1826 bestdist = 64; //has to be less than 64 units to the item or it isn't safe enough 1827 bestindex = -1; 1828 1829 mins[0] = -15; 1830 mins[1] = -15; 1831 mins[2] = 0; 1832 maxs[0] = 15; 1833 maxs[1] = 15; 1834 maxs[2] = 0; 1835 1836 while (i < gWPNum) 1837 { 1838 if (gWPArray[i] && gWPArray[i]->inuse && 1839 gWPArray[i]->origin[2]-15 < org[2] && 1840 gWPArray[i]->origin[2]+15 > org[2]) 1841 { 1842 VectorSubtract(org, gWPArray[i]->origin, a); 1843 flLen = VectorLength(a); 1844 1845 if (flLen < bestdist && trap_InPVS(org, gWPArray[i]->origin) && OrgVisibleBox(org, mins, maxs, gWPArray[i]->origin, ignore)) 1846 { 1847 bestdist = flLen; 1848 bestindex = i; 1849 } 1850 } 1851 1852 i++; 1853 } 1854 1855 return bestindex; 1856} 1857 1858void CalculateWeightGoals(void) 1859{ //set waypoint weights depending on weapon and item placement 1860 int i = 0; 1861 int wpindex = 0; 1862 gentity_t *ent; 1863 float weight; 1864 1865 trap_Cvar_Update(&bot_wp_clearweight); 1866 1867 if (bot_wp_clearweight.integer) 1868 { //if set then flush out all weight/goal values before calculating them again 1869 while (i < gWPNum) 1870 { 1871 if (gWPArray[i] && gWPArray[i]->inuse) 1872 { 1873 gWPArray[i]->weight = 0; 1874 1875 if (gWPArray[i]->flags & WPFLAG_GOALPOINT) 1876 { 1877 gWPArray[i]->flags -= WPFLAG_GOALPOINT; 1878 } 1879 } 1880 1881 i++; 1882 } 1883 } 1884 1885 i = 0; 1886 1887 while (i < level.num_entities) 1888 { 1889 ent = &g_entities[i]; 1890 1891 weight = 0; 1892 1893 if (ent && ent->classname) 1894 { 1895 if (strcmp(ent->classname, "item_seeker") == 0) 1896 { 1897 weight = 2; 1898 } 1899 else if (strcmp(ent->classname, "item_shield") == 0) 1900 { 1901 weight = 2; 1902 } 1903 else if (strcmp(ent->classname, "item_medpac") == 0) 1904 { 1905 weight = 2; 1906 } 1907 else if (strcmp(ent->classname, "item_sentry_gun") == 0) 1908 { 1909 weight = 2; 1910 } 1911 else if (strcmp(ent->classname, "item_force_enlighten_dark") == 0) 1912 { 1913 weight = 5; 1914 } 1915 else if (strcmp(ent->classname, "item_force_enlighten_light") == 0) 1916 { 1917 weight = 5; 1918 } 1919 else if (strcmp(ent->classname, "item_force_boon") == 0) 1920 { 1921 weight = 5; 1922 } 1923 else if (strcmp(ent->classname, "item_ysalimari") == 0) 1924 { 1925 weight = 2; 1926 } 1927 else if (strstr(ent->classname, "weapon_") && ent->item) 1928 { 1929 weight = botGlobalNavWeaponWeights[ent->item->giTag]; 1930 } 1931 else if (ent->item && ent->item->giType == IT_AMMO) 1932 { 1933 weight = 3; 1934 } 1935 } 1936 1937 if (ent && weight) 1938 { 1939 wpindex = GetNearestVisibleWPToItem(ent->s.pos.trBase, ent->s.number); 1940 1941 if (wpindex != -1 && gWPArray[wpindex] && gWPArray[wpindex]->inuse) 1942 { //found the waypoint nearest the center of this object 1943 gWPArray[wpindex]->weight = weight; 1944 gWPArray[wpindex]->flags |= WPFLAG_GOALPOINT; 1945 gWPArray[wpindex]->associated_entity = ent->s.number; 1946 } 1947 } 1948 1949 i++; 1950 } 1951} 1952 1953void CalculateJumpRoutes(void) 1954{ 1955 int i = 0; 1956 float nheightdif = 0; 1957 float pheightdif = 0; 1958 1959 while (i < gWPNum) 1960 { 1961 if (gWPArray[i] && gWPArray[i]->inuse) 1962 { 1963 if (gWPArray[i]->flags & WPFLAG_JUMP) 1964 { 1965 nheightdif = 0; 1966 pheightdif = 0; 1967 1968 gWPArray[i]->forceJumpTo = 0; 1969 1970 if (gWPArray[i-1] && gWPArray[i-1]->inuse && (gWPArray[i-1]->origin[2]+16) < gWPArray[i]->origin[2]) 1971 { 1972 nheightdif = (gWPArray[i]->origin[2] - gWPArray[i-1]->origin[2]); 1973 } 1974 1975 if (gWPArray[i+1] && gWPArray[i+1]->inuse && (gWPArray[i+1]->origin[2]+16) < gWPArray[i]->origin[2]) 1976 { 1977 pheightdif = (gWPArray[i]->origin[2] - gWPArray[i+1]->origin[2]); 1978 } 1979 1980 if (nheightdif > pheightdif) 1981 { 1982 pheightdif = nheightdif; 1983 } 1984 1985 if (pheightdif) 1986 { 1987 if (pheightdif > 500) 1988 { 1989 gWPArray[i]->forceJumpTo = 999; //FORCE_LEVEL_3; //FJSR 1990 } 1991 else if (pheightdif > 256) 1992 { 1993 gWPArray[i]->forceJumpTo = 999; //FORCE_LEVEL_2; //FJSR 1994 } 1995 else if (pheightdif > 128) 1996 { 1997 gWPArray[i]->forceJumpTo = 999; //FORCE_LEVEL_1; //FJSR 1998 } 1999 } 2000 } 2001 } 2002 2003 i++; 2004 } 2005} 2006 2007int LoadPathData(const char *filename) 2008{ 2009 fileHandle_t f; 2010 char *fileString; 2011 char *currentVar; 2012 char *routePath; 2013 wpobject_t thiswp; 2014 int len; 2015 int i, i_cv; 2016 int nei_num; 2017 2018 i = 0; 2019 i_cv = 0; 2020 2021 routePath = (char *)B_TempAlloc(1024); 2022 2023 Com_sprintf(routePath, 1024, "botroutes/%s.wnt\0", filename); 2024 2025 len = trap_FS_FOpenFile(routePath, &f, FS_READ); 2026 2027 B_TempFree(1024); //routePath 2028 2029 if (!f) 2030 { 2031 G_Printf(S_COLOR_YELLOW "Bot route data not found for %s\n", filename); 2032 return 2; 2033 } 2034 2035 if (len >= 524288) 2036 { 2037 G_Printf(S_COLOR_RED "Route file exceeds maximum length\n"); 2038 return 0; 2039 } 2040 2041 fileString = (char *)B_TempAlloc(524288); 2042 currentVar = (char *)B_TempAlloc(2048); 2043 2044 trap_FS_Read(fileString, len, f); 2045 2046 if (fileString[i] == 'l') 2047 { //contains a "levelflags" entry.. 2048 char readLFlags[64]; 2049 i_cv = 0; 2050 2051 while (fileString[i] != ' ') 2052 { 2053 i++; 2054 } 2055 i++; 2056 while (fileString[i] != '\n') 2057 { 2058 readLFlags[i_cv] = fileString[i]; 2059 i_cv++; 2060 i++; 2061 } 2062 readLFlags[i_cv] = 0; 2063 i++; 2064 2065 gLevelFlags = atoi(readLFlags); 2066 } 2067 else 2068 { 2069 gLevelFlags = 0; 2070 } 2071 2072 while (i < len) 2073 { 2074 i_cv = 0; 2075 2076 thiswp.index = 0; 2077 thiswp.flags = 0; 2078 thiswp.inuse = 0; 2079 thiswp.neighbornum = 0; 2080 thiswp.origin[0] = 0; 2081 thiswp.origin[1] = 0; 2082 thiswp.origin[2] = 0; 2083 thiswp.weight = 0; 2084 thiswp.associated_entity = ENTITYNUM_NONE; 2085 thiswp.forceJumpTo = 0; 2086 thiswp.disttonext = 0; 2087 nei_num = 0; 2088 2089 while (nei_num < MAX_NEIGHBOR_SIZE) 2090 { 2091 thiswp.neighbors[nei_num].num = 0; 2092 thiswp.neighbors[nei_num].forceJumpTo = 0; 2093 2094 nei_num++; 2095 } 2096 2097 while (fileString[i] != ' ') 2098 { 2099 currentVar[i_cv] = fileString[i]; 2100 i_cv++; 2101 i++; 2102 } 2103 currentVar[i_cv] = '\0'; 2104 2105 thiswp.index = atoi(currentVar); 2106 2107 i_cv = 0; 2108 i++; 2109 2110 while (fileString[i] != ' ') 2111 { 2112 currentVar[i_cv] = fileString[i]; 2113 i_cv++; 2114 i++; 2115 } 2116 currentVar[i_cv] = '\0'; 2117 2118 thiswp.flags = atoi(currentVar); 2119 2120 i_cv = 0; 2121 i++; 2122 2123 while (fileString[i] != ' ') 2124 { 2125 currentVar[i_cv] = fileString[i]; 2126 i_cv++; 2127 i++; 2128 } 2129 currentVar[i_cv] = '\0'; 2130 2131 thiswp.weight = atof(currentVar); 2132 2133 i_cv = 0; 2134 i++; 2135 i++; 2136 2137 while (fileString[i] != ' ') 2138 { 2139 currentVar[i_cv] = fileString[i]; 2140 i_cv++; 2141 i++; 2142 } 2143 currentVar[i_cv] = '\0'; 2144 2145 thiswp.origin[0] = atof(currentVar); 2146 2147 i_cv = 0; 2148 i++; 2149 2150 while (fileString[i] != ' ') 2151 { 2152 currentVar[i_cv] = fileString[i]; 2153 i_cv++; 2154 i++; 2155 } 2156 currentVar[i_cv] = '\0'; 2157 2158 thiswp.origin[1] = atof(currentVar); 2159 2160 i_cv = 0; 2161 i++; 2162 2163 while (fileString[i] != ')') 2164 { 2165 currentVar[i_cv] = fileString[i]; 2166 i_cv++; 2167 i++; 2168 } 2169 currentVar[i_cv] = '\0'; 2170 2171 thiswp.origin[2] = atof(currentVar); 2172 2173 i += 4; 2174 2175 while (fileString[i] != '}') 2176 { 2177 i_cv = 0; 2178 while (fileString[i] != ' ' && fileString[i] != '-') 2179 { 2180 currentVar[i_cv] = fileString[i]; 2181 i_cv++; 2182 i++; 2183 } 2184 currentVar[i_cv] = '\0'; 2185 2186 thiswp.neighbors[thiswp.neighbornum].num = atoi(currentVar); 2187 2188 if (fileString[i] == '-') 2189 { 2190 i_cv = 0; 2191 i++; 2192 2193 while (fileString[i] != ' ') 2194 { 2195 currentVar[i_cv] = fileString[i]; 2196 i_cv++; 2197 i++; 2198 } 2199 currentVar[i_cv] = '\0'; 2200 2201 thiswp.neighbors[thiswp.neighbornum].forceJumpTo = 999; //atoi(currentVar); //FJSR 2202 } 2203 else 2204 { 2205 thiswp.neighbors[thiswp.neighbornum].forceJumpTo = 0; 2206 } 2207 2208 thiswp.neighbornum++; 2209 2210 i++; 2211 } 2212 2213 i_cv = 0; 2214 i++; 2215 i++; 2216 2217 while (fileString[i] != '\n') 2218 { 2219 currentVar[i_cv] = fileString[i]; 2220 i_cv++; 2221 i++; 2222 } 2223 currentVar[i_cv] = '\0'; 2224 2225 thiswp.disttonext = atof(currentVar); 2226 2227 CreateNewWP_FromObject(&thiswp); 2228 i++; 2229 } 2230 2231 B_TempFree(524288); //fileString 2232 B_TempFree(2048); //currentVar 2233 2234 trap_FS_FCloseFile(f); 2235 2236 if (g_gametype.integer == GT_SIEGE) 2237 { 2238 CalculateSiegeGoals(); 2239 } 2240 2241 CalculateWeightGoals(); 2242 //calculate weights for idle activity goals when 2243 //the bot has absolutely nothing else to do 2244 2245 CalculateJumpRoutes(); 2246 //Look at jump points and mark them as requiring 2247 //force jumping as needed 2248 2249 return 1; 2250} 2251 2252void FlagObjects(void) 2253{ 2254 int i = 0, bestindex = 0, found = 0; 2255 float bestdist = 999999, tlen = 0; 2256 gentity_t *flag_red, *flag_blue, *ent; 2257 vec3_t a, mins, maxs; 2258 trace_t tr; 2259 2260 flag_red = NULL; 2261 flag_blue = NULL; 2262 2263 mins[0] = -15; 2264 mins[1] = -15; 2265 mins[2] = -5; 2266 maxs[0] = 15; 2267 maxs[1] = 15; 2268 maxs[2] = 5; 2269 2270 while (i < level.num_entities) 2271 { 2272 ent = &g_entities[i]; 2273 2274 if (ent && ent->inuse && ent->classname) 2275 { 2276 if (!flag_red && strcmp(ent->classname, "team_CTF_redflag") == 0) 2277 { 2278 flag_red = ent; 2279 } 2280 else if (!flag_blue && strcmp(ent->classname, "team_CTF_blueflag") == 0) 2281 { 2282 flag_blue = ent; 2283 } 2284 2285 if (flag_red && flag_blue) 2286 { 2287 break; 2288 } 2289 } 2290 2291 i++; 2292 } 2293 2294 i = 0; 2295 2296 if (!flag_red || !flag_blue) 2297 { 2298 return; 2299 } 2300 2301 while (i < gWPNum) 2302 { 2303 if (gWPArray[i] && gWPArray[i]->inuse) 2304 { 2305 VectorSubtract(flag_red->s.pos.trBase, gWPArray[i]->origin, a); 2306 tlen = VectorLength(a); 2307 2308 if (tlen < bestdist) 2309 { 2310 trap_Trace(&tr, flag_red->s.pos.trBase, mins, maxs, gWPArray[i]->origin, flag_red->s.number, MASK_SOLID); 2311 2312 if (tr.fraction == 1 || tr.entityNum == flag_red->s.number) 2313 { 2314 bestdist = tlen; 2315 bestindex = i; 2316 found = 1; 2317 } 2318 } 2319 2320 } 2321 2322 i++; 2323 } 2324 2325 if (found) 2326 { 2327 gWPArray[bestindex]->flags |= WPFLAG_RED_FLAG; 2328 flagRed = gWPArray[bestindex]; 2329 oFlagRed = flagRed; 2330 eFlagRed = flag_red; 2331 } 2332 2333 bestdist = 999999; 2334 bestindex = 0; 2335 found = 0; 2336 i = 0; 2337 2338 while (i < gWPNum) 2339 { 2340 if (gWPArray[i] && gWPArray[i]->inuse) 2341 { 2342 VectorSubtract(flag_blue->s.pos.trBase, gWPArray[i]->origin, a); 2343 tlen = VectorLength(a); 2344 2345 if (tlen < bestdist) 2346 { 2347 trap_Trace(&tr, flag_blue->s.pos.trBase, mins, maxs, gWPArray[i]->origin, flag_blue->s.number, MASK_SOLID); 2348 2349 if (tr.fraction == 1 || tr.entityNum == flag_blue->s.number) 2350 { 2351 bestdist = tlen; 2352 bestindex = i; 2353 found = 1; 2354 } 2355 } 2356 2357 } 2358 2359 i++; 2360 } 2361 2362 if (found) 2363 { 2364 gWPArray[bestindex]->flags |= WPFLAG_BLUE_FLAG; 2365 flagBlue = gWPArray[bestindex]; 2366 oFlagBlue = flagBlue; 2367 eFlagBlue = flag_blue; 2368 } 2369} 2370 2371#ifndef _XBOX 2372int SavePathData(const char *filename) 2373{ 2374 fileHandle_t f; 2375 char *fileString; 2376 char *storeString; 2377 char *routePath; 2378 vec3_t a; 2379 float flLen; 2380 int i, s, n; 2381 2382 fileString = NULL; 2383 i = 0; 2384 s = 0; 2385 2386 if (!gWPNum) 2387 { 2388 return 0; 2389 } 2390 2391 routePath = (char *)B_TempAlloc(1024); 2392 2393 Com_sprintf(routePath, 1024, "botroutes/%s.wnt\0", filename); 2394 2395 trap_FS_FOpenFile(routePath, &f, FS_WRITE); 2396 2397 B_TempFree(1024); //routePath 2398 2399 if (!f) 2400 { 2401 G_Printf(S_COLOR_RED "ERROR: Could not open file to write path data\n"); 2402 return 0; 2403 } 2404 2405 if (!RepairPaths(qfalse)) //check if we can see all waypoints from the last. If not, try to branch over. 2406 { 2407 trap_FS_FCloseFile(f); 2408 return 0; 2409 } 2410 2411 CalculatePaths(); //make everything nice and connected before saving 2412 2413 FlagObjects(); //currently only used for flagging waypoints nearest CTF flags 2414 2415 fileString = (char *)B_TempAlloc(524288); 2416 storeString = (char *)B_TempAlloc(4096); 2417 2418 Com_sprintf(fileString, 524288, "%i %i %f (%f %f %f) { ", gWPArray[i]->index, gWPArray[i]->flags, gWPArray[i]->weight, gWPArray[i]->origin[0], gWPArray[i]->origin[1], gWPArray[i]->origin[2]); 2419 2420 n = 0; 2421 2422 while (n < gWPArray[i]->neighbornum) 2423 { 2424 if (gWPArray[i]->neighbors[n].forceJumpTo) 2425 { 2426 Com_sprintf(storeString, 4096, "%s%i-%i ", storeString, gWPArray[i]->neighbors[n].num, gWPArray[i]->neighbors[n].forceJumpTo); 2427 } 2428 else 2429 { 2430 Com_sprintf(storeString, 4096, "%s%i ", storeString, gWPArray[i]->neighbors[n].num); 2431 } 2432 n++; 2433 } 2434 2435 if (gWPArray[i+1] && gWPArray[i+1]->inuse && gWPArray[i+1]->index) 2436 { 2437 VectorSubtract(gWPArray[i]->origin, gWPArray[i+1]->origin, a); 2438 flLen = VectorLength(a); 2439 } 2440 else 2441 { 2442 flLen = 0; 2443 } 2444 2445 gWPArray[i]->disttonext = flLen; 2446 2447 Com_sprintf(fileString, 524288, "%s} %f\n", fileString, flLen); 2448 2449 i++; 2450 2451 while (i < gWPNum) 2452 { 2453 //sprintf(fileString, "%s%i %i %f (%f %f %f) { ", fileString, gWPArray[i]->index, gWPArray[i]->flags, gWPArray[i]->weight, gWPArray[i]->origin[0], gWPArray[i]->origin[1], gWPArray[i]->origin[2]); 2454 Com_sprintf(storeString, 4096, "%i %i %f (%f %f %f) { ", gWPArray[i]->index, gWPArray[i]->flags, gWPArray[i]->weight, gWPArray[i]->origin[0], gWPArray[i]->origin[1], gWPArray[i]->origin[2]); 2455 2456 n = 0; 2457 2458 while (n < gWPArray[i]->neighbornum) 2459 { 2460 if (gWPArray[i]->neighbors[n].forceJumpTo) 2461 { 2462 Com_sprintf(storeString, 4096, "%s%i-%i ", storeString, gWPArray[i]->neighbors[n].num, gWPArray[i]->neighbors[n].forceJumpTo); 2463 } 2464 else 2465 { 2466 Com_sprintf(storeString, 4096, "%s%i ", storeString, gWPArray[i]->neighbors[n].num); 2467 } 2468 n++; 2469 } 2470 2471 if (gWPArray[i+1] && gWPArray[i+1]->inuse && gWPArray[i+1]->index) 2472 { 2473 VectorSubtract(gWPArray[i]->origin, gWPArray[i+1]->origin, a); 2474 flLen = VectorLength(a); 2475 } 2476 else 2477 { 2478 flLen = 0; 2479 } 2480 2481 gWPArray[i]->disttonext = flLen; 2482 2483 Com_sprintf(storeString, 4096, "%s} %f\n", storeString, flLen); 2484 2485 strcat(fileString, storeString); 2486 2487 i++; 2488 } 2489 2490 trap_FS_Write(fileString, strlen(fileString), f); 2491 2492 B_TempFree(524288); //fileString 2493 B_TempFree(4096); //storeString 2494 2495 trap_FS_FCloseFile(f); 2496 2497 G_Printf("Path data has been saved and updated. You may need to restart the level for some things to be properly calculated.\n"); 2498 2499 return 1; 2500} 2501#endif 2502 2503//#define PAINFULLY_DEBUGGING_THROUGH_VM 2504 2505#define MAX_SPAWNPOINT_ARRAY 64 2506int gSpawnPointNum = 0; 2507gentity_t *gSpawnPoints[MAX_SPAWNPOINT_ARRAY]; 2508 2509#ifn…
Large files files are truncated, but you can click here to view the full file