00001 #include "g_local.h"
00002 #include "q_shared.h"
00003 #include "botlib.h"
00004 #include "ai_main.h"
00005
00006 float gWPRenderTime = 0;
00007 float gDeactivated = 0;
00008 float gBotEdit = 0;
00009 int gWPRenderedFrame = 0;
00010
00011 #include "../namespace_begin.h"
00012 wpobject_t *gWPArray[MAX_WPARRAY_SIZE];
00013 int gWPNum = 0;
00014 #include "../namespace_end.h"
00015
00016 int gLastPrintedIndex = -1;
00017
00018 #ifndef _XBOX
00019 nodeobject_t nodetable[MAX_NODETABLE_SIZE];
00020 int nodenum;
00021 #endif
00022
00023 int gLevelFlags = 0;
00024
00025 char *GetFlagStr( int flags )
00026 {
00027 char *flagstr;
00028 int i;
00029
00030 flagstr = (char *)B_TempAlloc(128);
00031 i = 0;
00032
00033 if (!flags)
00034 {
00035 strcpy(flagstr, "none\0");
00036 goto fend;
00037 }
00038
00039 if (flags & WPFLAG_JUMP)
00040 {
00041 flagstr[i] = 'j';
00042 i++;
00043 }
00044
00045 if (flags & WPFLAG_DUCK)
00046 {
00047 flagstr[i] = 'd';
00048 i++;
00049 }
00050
00051 if (flags & WPFLAG_SNIPEORCAMPSTAND)
00052 {
00053 flagstr[i] = 'c';
00054 i++;
00055 }
00056
00057 if (flags & WPFLAG_WAITFORFUNC)
00058 {
00059 flagstr[i] = 'f';
00060 i++;
00061 }
00062
00063 if (flags & WPFLAG_SNIPEORCAMP)
00064 {
00065 flagstr[i] = 's';
00066 i++;
00067 }
00068
00069 if (flags & WPFLAG_ONEWAY_FWD)
00070 {
00071 flagstr[i] = 'x';
00072 i++;
00073 }
00074
00075 if (flags & WPFLAG_ONEWAY_BACK)
00076 {
00077 flagstr[i] = 'y';
00078 i++;
00079 }
00080
00081 if (flags & WPFLAG_GOALPOINT)
00082 {
00083 flagstr[i] = 'g';
00084 i++;
00085 }
00086
00087 if (flags & WPFLAG_NOVIS)
00088 {
00089 flagstr[i] = 'n';
00090 i++;
00091 }
00092
00093 if (flags & WPFLAG_NOMOVEFUNC)
00094 {
00095 flagstr[i] = 'm';
00096 i++;
00097 }
00098
00099 if (flags & WPFLAG_RED_FLAG)
00100 {
00101 if (i)
00102 {
00103 flagstr[i] = ' ';
00104 i++;
00105 }
00106 flagstr[i] = 'r';
00107 i++;
00108 flagstr[i] = 'e';
00109 i++;
00110 flagstr[i] = 'd';
00111 i++;
00112 flagstr[i] = ' ';
00113 i++;
00114 flagstr[i] = 'f';
00115 i++;
00116 flagstr[i] = 'l';
00117 i++;
00118 flagstr[i] = 'a';
00119 i++;
00120 flagstr[i] = 'g';
00121 i++;
00122 }
00123
00124 if (flags & WPFLAG_BLUE_FLAG)
00125 {
00126 if (i)
00127 {
00128 flagstr[i] = ' ';
00129 i++;
00130 }
00131 flagstr[i] = 'b';
00132 i++;
00133 flagstr[i] = 'l';
00134 i++;
00135 flagstr[i] = 'u';
00136 i++;
00137 flagstr[i] = 'e';
00138 i++;
00139 flagstr[i] = ' ';
00140 i++;
00141 flagstr[i] = 'f';
00142 i++;
00143 flagstr[i] = 'l';
00144 i++;
00145 flagstr[i] = 'a';
00146 i++;
00147 flagstr[i] = 'g';
00148 i++;
00149 }
00150
00151 if (flags & WPFLAG_SIEGE_IMPERIALOBJ)
00152 {
00153 if (i)
00154 {
00155 flagstr[i] = ' ';
00156 i++;
00157 }
00158 flagstr[i] = 's';
00159 i++;
00160 flagstr[i] = 'a';
00161 i++;
00162 flagstr[i] = 'g';
00163 i++;
00164 flagstr[i] = 'a';
00165 i++;
00166 flagstr[i] = '_';
00167 i++;
00168 flagstr[i] = 'i';
00169 i++;
00170 flagstr[i] = 'm';
00171 i++;
00172 flagstr[i] = 'p';
00173 i++;
00174 }
00175
00176 if (flags & WPFLAG_SIEGE_REBELOBJ)
00177 {
00178 if (i)
00179 {
00180 flagstr[i] = ' ';
00181 i++;
00182 }
00183 flagstr[i] = 's';
00184 i++;
00185 flagstr[i] = 'a';
00186 i++;
00187 flagstr[i] = 'g';
00188 i++;
00189 flagstr[i] = 'a';
00190 i++;
00191 flagstr[i] = '_';
00192 i++;
00193 flagstr[i] = 'r';
00194 i++;
00195 flagstr[i] = 'e';
00196 i++;
00197 flagstr[i] = 'b';
00198 i++;
00199 }
00200
00201 flagstr[i] = '\0';
00202
00203 if (i == 0)
00204 {
00205 strcpy(flagstr, "unknown\0");
00206 }
00207
00208 fend:
00209 return flagstr;
00210 }
00211
00212 void G_TestLine(vec3_t start, vec3_t end, int color, int time)
00213 {
00214 gentity_t *te;
00215
00216 te = G_TempEntity( start, EV_TESTLINE );
00217 VectorCopy(start, te->s.origin);
00218 VectorCopy(end, te->s.origin2);
00219 te->s.time2 = time;
00220 te->s.weapon = color;
00221 te->r.svFlags |= SVF_BROADCAST;
00222 }
00223
00224 void BotWaypointRender(void)
00225 {
00226 int i, n;
00227 int inc_checker;
00228 int bestindex;
00229 int gotbestindex;
00230 float bestdist;
00231 float checkdist;
00232 gentity_t *plum;
00233 gentity_t *viewent;
00234 char *flagstr;
00235 vec3_t a;
00236
00237 if (!gBotEdit)
00238 {
00239 return;
00240 }
00241
00242 bestindex = 0;
00243
00244 if (gWPRenderTime > level.time)
00245 {
00246 goto checkprint;
00247 }
00248
00249 gWPRenderTime = level.time + 100;
00250
00251 i = gWPRenderedFrame;
00252 inc_checker = gWPRenderedFrame;
00253
00254 while (i < gWPNum)
00255 {
00256 if (gWPArray[i] && gWPArray[i]->inuse)
00257 {
00258 plum = G_TempEntity( gWPArray[i]->origin, EV_SCOREPLUM );
00259 plum->r.svFlags |= SVF_BROADCAST;
00260 plum->s.time = i;
00261
00262 n = 0;
00263
00264 while (n < gWPArray[i]->neighbornum)
00265 {
00266 if (gWPArray[i]->neighbors[n].forceJumpTo && gWPArray[gWPArray[i]->neighbors[n].num])
00267 {
00268 G_TestLine(gWPArray[i]->origin, gWPArray[gWPArray[i]->neighbors[n].num]->origin, 0x0000ff, 5000);
00269 }
00270 n++;
00271 }
00272
00273 gWPRenderedFrame++;
00274 }
00275 else
00276 {
00277 gWPRenderedFrame = 0;
00278 break;
00279 }
00280
00281 if ((i - inc_checker) > 4)
00282 {
00283 break;
00284 }
00285 i++;
00286 }
00287
00288 if (i >= gWPNum)
00289 {
00290 gWPRenderTime = level.time + 1500;
00291 gWPRenderedFrame = 0;
00292 }
00293
00294 checkprint:
00295
00296 if (!bot_wp_info.value)
00297 {
00298 return;
00299 }
00300
00301 viewent = &g_entities[0];
00302
00303 if (!viewent || !viewent->client)
00304 {
00305 return;
00306 }
00307
00308 bestdist = 256;
00309 gotbestindex = 0;
00310
00311 i = 0;
00312
00313 while (i < gWPNum)
00314 {
00315 if (gWPArray[i] && gWPArray[i]->inuse)
00316 {
00317 VectorSubtract(viewent->client->ps.origin, gWPArray[i]->origin, a);
00318
00319 checkdist = VectorLength(a);
00320
00321 if (checkdist < bestdist)
00322 {
00323 bestdist = checkdist;
00324 bestindex = i;
00325 gotbestindex = 1;
00326 }
00327 }
00328 i++;
00329 }
00330
00331 if (gotbestindex && bestindex != gLastPrintedIndex)
00332 {
00333 flagstr = GetFlagStr(gWPArray[bestindex]->flags);
00334 gLastPrintedIndex = bestindex;
00335 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]));
00336
00337 B_TempFree(128);
00338
00339 plum = G_TempEntity( gWPArray[bestindex]->origin, EV_SCOREPLUM );
00340 plum->r.svFlags |= SVF_BROADCAST;
00341 plum->s.time = bestindex;
00342 }
00343 else if (!gotbestindex)
00344 {
00345 gLastPrintedIndex = -1;
00346 }
00347 }
00348
00349 void TransferWPData(int from, int to)
00350 {
00351 if (!gWPArray[to])
00352 {
00353 gWPArray[to] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
00354 }
00355
00356 if (!gWPArray[to])
00357 {
00358 G_Printf(S_COLOR_RED "FATAL ERROR: Could not allocated memory for waypoint\n");
00359 }
00360
00361 gWPArray[to]->flags = gWPArray[from]->flags;
00362 gWPArray[to]->weight = gWPArray[from]->weight;
00363 gWPArray[to]->associated_entity = gWPArray[from]->associated_entity;
00364 gWPArray[to]->disttonext = gWPArray[from]->disttonext;
00365 gWPArray[to]->forceJumpTo = gWPArray[from]->forceJumpTo;
00366 gWPArray[to]->index = to;
00367 gWPArray[to]->inuse = gWPArray[from]->inuse;
00368 VectorCopy(gWPArray[from]->origin, gWPArray[to]->origin);
00369 }
00370
00371 void CreateNewWP(vec3_t origin, int flags)
00372 {
00373 if (gWPNum >= MAX_WPARRAY_SIZE)
00374 {
00375 if (!g_RMG.integer)
00376 {
00377 G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE);
00378 }
00379 return;
00380 }
00381
00382 if (!gWPArray[gWPNum])
00383 {
00384 gWPArray[gWPNum] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
00385 }
00386
00387 if (!gWPArray[gWPNum])
00388 {
00389 G_Printf(S_COLOR_RED "ERROR: Could not allocated memory for waypoint\n");
00390 }
00391
00392 gWPArray[gWPNum]->flags = flags;
00393 gWPArray[gWPNum]->weight = 0;
00394 gWPArray[gWPNum]->associated_entity = ENTITYNUM_NONE;
00395 gWPArray[gWPNum]->forceJumpTo = 0;
00396 gWPArray[gWPNum]->disttonext = 0;
00397 gWPArray[gWPNum]->index = gWPNum;
00398 gWPArray[gWPNum]->inuse = 1;
00399 VectorCopy(origin, gWPArray[gWPNum]->origin);
00400 gWPNum++;
00401 }
00402
00403 void CreateNewWP_FromObject(wpobject_t *wp)
00404 {
00405 int i;
00406
00407 if (gWPNum >= MAX_WPARRAY_SIZE)
00408 {
00409 return;
00410 }
00411
00412 if (!gWPArray[gWPNum])
00413 {
00414 gWPArray[gWPNum] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
00415 }
00416
00417 if (!gWPArray[gWPNum])
00418 {
00419 G_Printf(S_COLOR_RED "ERROR: Could not allocated memory for waypoint\n");
00420 }
00421
00422 gWPArray[gWPNum]->flags = wp->flags;
00423 gWPArray[gWPNum]->weight = wp->weight;
00424 gWPArray[gWPNum]->associated_entity = wp->associated_entity;
00425 gWPArray[gWPNum]->disttonext = wp->disttonext;
00426 gWPArray[gWPNum]->forceJumpTo = wp->forceJumpTo;
00427 gWPArray[gWPNum]->index = gWPNum;
00428 gWPArray[gWPNum]->inuse = 1;
00429 VectorCopy(wp->origin, gWPArray[gWPNum]->origin);
00430 gWPArray[gWPNum]->neighbornum = wp->neighbornum;
00431
00432 i = wp->neighbornum;
00433
00434 while (i >= 0)
00435 {
00436 gWPArray[gWPNum]->neighbors[i].num = wp->neighbors[i].num;
00437 gWPArray[gWPNum]->neighbors[i].forceJumpTo = wp->neighbors[i].forceJumpTo;
00438
00439 i--;
00440 }
00441
00442 if (gWPArray[gWPNum]->flags & WPFLAG_RED_FLAG)
00443 {
00444 flagRed = gWPArray[gWPNum];
00445 oFlagRed = flagRed;
00446 }
00447 else if (gWPArray[gWPNum]->flags & WPFLAG_BLUE_FLAG)
00448 {
00449 flagBlue = gWPArray[gWPNum];
00450 oFlagBlue = flagBlue;
00451 }
00452
00453 gWPNum++;
00454 }
00455
00456 void RemoveWP(void)
00457 {
00458 if (gWPNum <= 0)
00459 {
00460 return;
00461 }
00462
00463 gWPNum--;
00464
00465 if (!gWPArray[gWPNum] || !gWPArray[gWPNum]->inuse)
00466 {
00467 return;
00468 }
00469
00470
00471 if (gWPArray[gWPNum])
00472 {
00473 memset( gWPArray[gWPNum], 0, sizeof(gWPArray[gWPNum]) );
00474 }
00475
00476
00477
00478 if (gWPArray[gWPNum])
00479 {
00480 gWPArray[gWPNum]->inuse = 0;
00481 }
00482 }
00483
00484 void RemoveAllWP(void)
00485 {
00486 while(gWPNum) {
00487 RemoveWP();
00488 }
00489 }
00490
00491 void RemoveWP_InTrail(int afterindex)
00492 {
00493 int foundindex;
00494 int foundanindex;
00495 int didchange;
00496 int i;
00497
00498 foundindex = 0;
00499 foundanindex = 0;
00500 didchange = 0;
00501 i = 0;
00502
00503 if (afterindex < 0 || afterindex >= gWPNum)
00504 {
00505 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
00506 return;
00507 }
00508
00509 while (i < gWPNum)
00510 {
00511 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
00512 {
00513 foundindex = i;
00514 foundanindex = 1;
00515 break;
00516 }
00517
00518 i++;
00519 }
00520
00521 if (!foundanindex)
00522 {
00523 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
00524 return;
00525 }
00526
00527 i = 0;
00528
00529 while (i <= gWPNum)
00530 {
00531 if (gWPArray[i] && gWPArray[i]->index == foundindex)
00532 {
00533
00534
00535
00536 memset( gWPArray[i], 0, sizeof(gWPArray[i]) );
00537
00538
00539 gWPArray[i]->inuse = 0;
00540 didchange = 1;
00541 }
00542 else if (gWPArray[i] && didchange)
00543 {
00544 TransferWPData(i, i-1);
00545
00546
00547
00548 memset( gWPArray[i], 0, sizeof(gWPArray[i]) );
00549
00550
00551 gWPArray[i]->inuse = 0;
00552 }
00553
00554 i++;
00555 }
00556 gWPNum--;
00557 }
00558
00559 int CreateNewWP_InTrail(vec3_t origin, int flags, int afterindex)
00560 {
00561 int foundindex;
00562 int foundanindex;
00563 int i;
00564
00565 foundindex = 0;
00566 foundanindex = 0;
00567 i = 0;
00568
00569 if (gWPNum >= MAX_WPARRAY_SIZE)
00570 {
00571 if (!g_RMG.integer)
00572 {
00573 G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE);
00574 }
00575 return 0;
00576 }
00577
00578 if (afterindex < 0 || afterindex >= gWPNum)
00579 {
00580 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
00581 return 0;
00582 }
00583
00584 while (i < gWPNum)
00585 {
00586 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
00587 {
00588 foundindex = i;
00589 foundanindex = 1;
00590 break;
00591 }
00592
00593 i++;
00594 }
00595
00596 if (!foundanindex)
00597 {
00598 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
00599 return 0;
00600 }
00601
00602 i = gWPNum;
00603
00604 while (i >= 0)
00605 {
00606 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index != foundindex)
00607 {
00608 TransferWPData(i, i+1);
00609 }
00610 else if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == foundindex)
00611 {
00612 i++;
00613
00614 if (!gWPArray[i])
00615 {
00616 gWPArray[i] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
00617 }
00618
00619 gWPArray[i]->flags = flags;
00620 gWPArray[i]->weight = 0;
00621 gWPArray[i]->associated_entity = ENTITYNUM_NONE;
00622 gWPArray[i]->disttonext = 0;
00623 gWPArray[i]->forceJumpTo = 0;
00624 gWPArray[i]->index = i;
00625 gWPArray[i]->inuse = 1;
00626 VectorCopy(origin, gWPArray[i]->origin);
00627 gWPNum++;
00628 break;
00629 }
00630
00631 i--;
00632 }
00633
00634 return 1;
00635 }
00636
00637 int CreateNewWP_InsertUnder(vec3_t origin, int flags, int afterindex)
00638 {
00639 int foundindex;
00640 int foundanindex;
00641 int i;
00642
00643 foundindex = 0;
00644 foundanindex = 0;
00645 i = 0;
00646
00647 if (gWPNum >= MAX_WPARRAY_SIZE)
00648 {
00649 if (!g_RMG.integer)
00650 {
00651 G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE);
00652 }
00653 return 0;
00654 }
00655
00656 if (afterindex < 0 || afterindex >= gWPNum)
00657 {
00658 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
00659 return 0;
00660 }
00661
00662 while (i < gWPNum)
00663 {
00664 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
00665 {
00666 foundindex = i;
00667 foundanindex = 1;
00668 break;
00669 }
00670
00671 i++;
00672 }
00673
00674 if (!foundanindex)
00675 {
00676 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
00677 return 0;
00678 }
00679
00680 i = gWPNum;
00681
00682 while (i >= 0)
00683 {
00684 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index != foundindex)
00685 {
00686 TransferWPData(i, i+1);
00687 }
00688 else if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == foundindex)
00689 {
00690
00691 TransferWPData(i, i+1);
00692
00693 if (!gWPArray[i])
00694 {
00695 gWPArray[i] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
00696 }
00697
00698 gWPArray[i]->flags = flags;
00699 gWPArray[i]->weight = 0;
00700 gWPArray[i]->associated_entity = ENTITYNUM_NONE;
00701 gWPArray[i]->disttonext = 0;
00702 gWPArray[i]->forceJumpTo = 0;
00703 gWPArray[i]->index = i;
00704 gWPArray[i]->inuse = 1;
00705 VectorCopy(origin, gWPArray[i]->origin);
00706 gWPNum++;
00707 break;
00708 }
00709
00710 i--;
00711 }
00712
00713 return 1;
00714 }
00715
00716 void TeleportToWP(gentity_t *pl, int afterindex)
00717 {
00718 int foundindex;
00719 int foundanindex;
00720 int i;
00721
00722 if (!pl || !pl->client)
00723 {
00724 return;
00725 }
00726
00727 foundindex = 0;
00728 foundanindex = 0;
00729 i = 0;
00730
00731 if (afterindex < 0 || afterindex >= gWPNum)
00732 {
00733 G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
00734 return;
00735 }
00736
00737 while (i < gWPNum)
00738 {
00739 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
00740 {
00741 foundindex = i;
00742 foundanindex = 1;
00743 break;
00744 }
00745
00746 i++;
00747 }
00748
00749 if (!foundanindex)
00750 {
00751 G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
00752 return;
00753 }
00754
00755 VectorCopy(gWPArray[foundindex]->origin, pl->client->ps.origin);
00756
00757 return;
00758 }
00759
00760 void WPFlagsModify(int wpnum, int flags)
00761 {
00762 if (wpnum < 0 || wpnum >= gWPNum || !gWPArray[wpnum] || !gWPArray[wpnum]->inuse)
00763 {
00764 G_Printf(S_COLOR_YELLOW "WPFlagsModify: Waypoint %i does not exist\n", wpnum);
00765 return;
00766 }
00767
00768 gWPArray[wpnum]->flags = flags;
00769 }
00770
00771 static int NotWithinRange(int base, int extent)
00772 {
00773 if (extent > base && base+5 >= extent)
00774 {
00775 return 0;
00776 }
00777
00778 if (extent < base && base-5 <= extent)
00779 {
00780 return 0;
00781 }
00782
00783 return 1;
00784 }
00785
00786 #ifndef _XBOX
00787 int NodeHere(vec3_t spot)
00788 {
00789 int i;
00790
00791 i = 0;
00792
00793 while (i < nodenum)
00794 {
00795 if ((int)nodetable[i].origin[0] == (int)spot[0] &&
00796 (int)nodetable[i].origin[1] == (int)spot[1])
00797 {
00798 if ((int)nodetable[i].origin[2] == (int)spot[2] ||
00799 ((int)nodetable[i].origin[2] < (int)spot[2] && (int)nodetable[i].origin[2]+5 > (int)spot[2]) ||
00800 ((int)nodetable[i].origin[2] > (int)spot[2] && (int)nodetable[i].origin[2]-5 < (int)spot[2]))
00801 {
00802 return 1;
00803 }
00804 }
00805 i++;
00806 }
00807
00808 return 0;
00809 }
00810 #endif
00811
00812 int CanGetToVector(vec3_t org1, vec3_t org2, vec3_t mins, vec3_t maxs)
00813 {
00814 trace_t tr;
00815
00816 trap_Trace(&tr, org1, mins, maxs, org2, ENTITYNUM_NONE, MASK_SOLID);
00817
00818 if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
00819 {
00820 return 1;
00821 }
00822
00823 return 0;
00824 }
00825
00826 #if 0
00827 int CanGetToVectorTravel(vec3_t org1, vec3_t org2, vec3_t mins, vec3_t maxs)
00828 {
00829 trace_t tr;
00830 vec3_t a, ang, fwd;
00831 vec3_t midpos, dmid;
00832 float startheight, midheight, fLen;
00833
00834 mins[2] = -13;
00835 maxs[2] = 13;
00836
00837 trap_Trace(&tr, org1, mins, maxs, org2, ENTITYNUM_NONE, MASK_SOLID);
00838
00839 if (tr.fraction != 1 || tr.startsolid || tr.allsolid)
00840 {
00841 return 0;
00842 }
00843
00844 VectorSubtract(org2, org1, a);
00845
00846 vectoangles(a, ang);
00847
00848 AngleVectors(ang, fwd, NULL, NULL);
00849
00850 fLen = VectorLength(a)/2;
00851
00852 midpos[0] = org1[0] + fwd[0]*fLen;
00853 midpos[1] = org1[1] + fwd[1]*fLen;
00854 midpos[2] = org1[2] + fwd[2]*fLen;
00855
00856 VectorCopy(org1, dmid);
00857 dmid[2] -= 1024;
00858
00859 trap_Trace(&tr, midpos, NULL, NULL, dmid, ENTITYNUM_NONE, MASK_SOLID);
00860
00861 startheight = org1[2] - tr.endpos[2];
00862
00863 VectorCopy(midpos, dmid);
00864 dmid[2] -= 1024;
00865
00866 trap_Trace(&tr, midpos, NULL, NULL, dmid, ENTITYNUM_NONE, MASK_SOLID);
00867
00868 if (tr.startsolid || tr.allsolid)
00869 {
00870 return 1;
00871 }
00872
00873 midheight = midpos[2] - tr.endpos[2];
00874
00875 if (midheight > startheight*2)
00876 {
00877 return 0;
00878 }
00879
00880 return 1;
00881 }
00882 #else
00883 int CanGetToVectorTravel(vec3_t org1, vec3_t moveTo, vec3_t mins, vec3_t maxs)
00884
00885 {
00886 trace_t tr;
00887 vec3_t stepTo;
00888 vec3_t stepSub;
00889 vec3_t stepGoal;
00890 vec3_t workingOrg;
00891 vec3_t lastIncrement;
00892 vec3_t finalMeasure;
00893 float stepSize = 0;
00894 float measureLength = 0;
00895 int didMove = 0;
00896 int traceMask = MASK_PLAYERSOLID;
00897 qboolean initialDone = qfalse;
00898
00899 VectorCopy(org1, workingOrg);
00900 VectorCopy(org1, lastIncrement);
00901
00902 VectorCopy(moveTo, stepTo);
00903 stepTo[2] = workingOrg[2];
00904
00905 VectorSubtract(stepTo, workingOrg, stepSub);
00906 stepSize = VectorLength(stepSub);
00907
00908 VectorNormalize(stepSub);
00909
00910 while (!initialDone || didMove)
00911 {
00912 initialDone = qtrue;
00913 didMove = 0;
00914
00915 stepGoal[0] = workingOrg[0] + stepSub[0]*stepSize;
00916 stepGoal[1] = workingOrg[1] + stepSub[1]*stepSize;
00917 stepGoal[2] = workingOrg[2] + stepSub[2]*stepSize;
00918
00919 trap_Trace(&tr, workingOrg, mins, maxs, stepGoal, ENTITYNUM_NONE, traceMask);
00920
00921 if (!tr.startsolid && !tr.allsolid && tr.fraction)
00922 {
00923 vec3_t vecSub;
00924 VectorSubtract(workingOrg, tr.endpos, vecSub);
00925
00926 if (VectorLength(vecSub) > (stepSize/2))
00927 {
00928 workingOrg[0] = tr.endpos[0];
00929 workingOrg[1] = tr.endpos[1];
00930
00931 didMove = 1;
00932 }
00933 }
00934
00935 if (didMove != 1)
00936 {
00937 vec3_t trFrom;
00938 vec3_t trTo;
00939 vec3_t trDir;
00940 vec3_t vecMeasure;
00941
00942 VectorCopy(tr.endpos, trFrom);
00943 trFrom[2] += 16;
00944
00945 VectorSubtract(stepGoal, workingOrg, trDir);
00946 VectorNormalize(trDir);
00947 trTo[0] = tr.endpos[0] + trDir[0]*2;
00948 trTo[1] = tr.endpos[1] + trDir[1]*2;
00949 trTo[2] = tr.endpos[2] + trDir[2]*2;
00950 trTo[2] += 16;
00951
00952 VectorSubtract(trFrom, trTo, vecMeasure);
00953
00954 if (VectorLength(vecMeasure) > 1)
00955 {
00956 trap_Trace(&tr, trFrom, mins, maxs, trTo, ENTITYNUM_NONE, traceMask);
00957
00958 if (!tr.startsolid && !tr.allsolid && tr.fraction == 1)
00959 {
00960 vec3_t trDown;
00961 vec3_t trUp;
00962 VectorCopy(tr.endpos, trUp);
00963 VectorCopy(tr.endpos, trDown);
00964 trDown[2] -= 16;
00965
00966 trap_Trace(&tr, trFrom, mins, maxs, trTo, ENTITYNUM_NONE, traceMask);
00967
00968 if (!tr.startsolid && !tr.allsolid)
00969 {
00970 VectorCopy(tr.endpos, workingOrg);
00971
00972 didMove = 1;
00973 }
00974 }
00975 }
00976 }
00977
00978 VectorSubtract(lastIncrement, workingOrg, finalMeasure);
00979 measureLength = VectorLength(finalMeasure);
00980
00981 if (!measureLength)
00982 {
00983 break;
00984 }
00985
00986 stepSize -= measureLength;
00987 if (stepSize <= 0)
00988 {
00989 break;
00990 }
00991
00992 VectorCopy(workingOrg, lastIncrement);
00993 }
00994
00995 return didMove;
00996 }
00997 #endif
00998
00999 #ifndef _XBOX
01000 int ConnectTrail(int startindex, int endindex, qboolean behindTheScenes)
01001 {
01002 int foundit;
01003 int cancontinue;
01004 int i;
01005 int failsafe;
01006 int successnodeindex;
01007 int insertindex;
01008 int prenodestart;
01009 byte extendednodes[MAX_NODETABLE_SIZE];
01010 float fvecmeas;
01011 float baseheight;
01012 float branchDistance;
01013 float maxDistFactor = 256;
01014 vec3_t a;
01015 vec3_t startplace, starttrace;
01016 vec3_t mins, maxs;
01017 vec3_t testspot;
01018 vec3_t validspotpos;
01019 trace_t tr;
01020
01021 if (g_RMG.integer)
01022 {
01023 if (!(gWPArray[startindex]->flags & WPFLAG_NEVERONEWAY) &&
01024 !(gWPArray[endindex]->flags & WPFLAG_NEVERONEWAY))
01025 {
01026 gWPArray[startindex]->flags |= WPFLAG_ONEWAY_FWD;
01027 gWPArray[endindex]->flags |= WPFLAG_ONEWAY_BACK;
01028 }
01029 return 0;
01030 }
01031
01032 if (!g_RMG.integer)
01033 {
01034 branchDistance = TABLE_BRANCH_DISTANCE;
01035 }
01036 else
01037 {
01038 branchDistance = 512;
01039 }
01040
01041 if (g_RMG.integer)
01042 {
01043 maxDistFactor = 700;
01044 }
01045
01046 mins[0] = -15;
01047 mins[1] = -15;
01048 mins[2] = 0;
01049 maxs[0] = 15;
01050 maxs[1] = 15;
01051 maxs[2] = 0;
01052
01053 nodenum = 0;
01054 foundit = 0;
01055
01056 i = 0;
01057
01058 successnodeindex = 0;
01059
01060 while (i < MAX_NODETABLE_SIZE)
01061 {
01062 nodetable[i].flags = 0;
01063
01064 nodetable[i].inuse = 0;
01065 nodetable[i].neighbornum = 0;
01066 nodetable[i].origin[0] = 0;
01067 nodetable[i].origin[1] = 0;
01068 nodetable[i].origin[2] = 0;
01069 nodetable[i].weight = 0;
01070
01071 extendednodes[i] = 0;
01072
01073 i++;
01074 }
01075
01076 i = 0;
01077
01078 if (!behindTheScenes)
01079 {
01080 G_Printf(S_COLOR_YELLOW "Point %i is not connected to %i - Repairing...\n", startindex, endindex);
01081 }
01082
01083 VectorCopy(gWPArray[startindex]->origin, startplace);
01084
01085 VectorCopy(startplace, starttrace);
01086
01087 starttrace[2] -= 4096;
01088
01089 trap_Trace(&tr, startplace, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
01090
01091 baseheight = startplace[2] - tr.endpos[2];
01092
01093 cancontinue = 1;
01094
01095 VectorCopy(startplace, nodetable[nodenum].origin);
01096 nodetable[nodenum].weight = 1;
01097 nodetable[nodenum].inuse = 1;
01098
01099 nodenum++;
01100
01101 while (nodenum < MAX_NODETABLE_SIZE && !foundit && cancontinue)
01102 {
01103 if (g_RMG.integer)
01104 {
01105 vec3_t startDist;
01106 vec3_t endDist;
01107 float startDistf;
01108 float endDistf;
01109
01110 VectorSubtract(nodetable[nodenum-1].origin, gWPArray[startindex]->origin, startDist);
01111 VectorSubtract(nodetable[nodenum-1].origin, gWPArray[endindex]->origin, endDist);
01112
01113 startDistf = VectorLength(startDist);
01114 endDistf = VectorLength(endDist);
01115
01116 if (startDistf < 64 || endDistf < 64)
01117 {
01118 branchDistance = 64;
01119 }
01120 else if (startDistf < 128 || endDistf < 128)
01121 {
01122 branchDistance = 128;
01123 }
01124 else if (startDistf < 256 || endDistf < 256)
01125 {
01126 branchDistance = 256;
01127 }
01128 else if (startDistf < 512 || endDistf < 512)
01129 {
01130 branchDistance = 512;
01131 }
01132 else
01133 {
01134 branchDistance = 800;
01135 }
01136 }
01137 cancontinue = 0;
01138 i = 0;
01139 prenodestart = nodenum;
01140
01141 while (i < prenodestart)
01142 {
01143 if (extendednodes[i] != 1)
01144 {
01145 VectorSubtract(gWPArray[endindex]->origin, nodetable[i].origin, a);
01146 fvecmeas = VectorLength(a);
01147
01148 if (fvecmeas < 128 && CanGetToVector(gWPArray[endindex]->origin, nodetable[i].origin, mins, maxs))
01149 {
01150 foundit = 1;
01151 successnodeindex = i;
01152 break;
01153 }
01154
01155 VectorCopy(nodetable[i].origin, testspot);
01156 testspot[0] += branchDistance;
01157
01158 VectorCopy(testspot, starttrace);
01159
01160 starttrace[2] -= 4096;
01161
01162 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
01163
01164 testspot[2] = tr.endpos[2]+baseheight;
01165
01166 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
01167 {
01168 VectorCopy(testspot, nodetable[nodenum].origin);
01169 nodetable[nodenum].inuse = 1;
01170
01171 nodetable[nodenum].weight = nodetable[i].weight+1;
01172 nodetable[nodenum].neighbornum = i;
01173 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
01174 {
01175 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01176 }
01177 nodenum++;
01178 cancontinue = 1;
01179 }
01180
01181 if (nodenum >= MAX_NODETABLE_SIZE)
01182 {
01183 break;
01184 }
01185
01186 VectorCopy(nodetable[i].origin, testspot);
01187 testspot[0] -= branchDistance;
01188
01189 VectorCopy(testspot, starttrace);
01190
01191 starttrace[2] -= 4096;
01192
01193 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
01194
01195 testspot[2] = tr.endpos[2]+baseheight;
01196
01197 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
01198 {
01199 VectorCopy(testspot, nodetable[nodenum].origin);
01200 nodetable[nodenum].inuse = 1;
01201
01202 nodetable[nodenum].weight = nodetable[i].weight+1;
01203 nodetable[nodenum].neighbornum = i;
01204 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
01205 {
01206 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01207 }
01208 nodenum++;
01209 cancontinue = 1;
01210 }
01211
01212 if (nodenum >= MAX_NODETABLE_SIZE)
01213 {
01214 break;
01215 }
01216
01217 VectorCopy(nodetable[i].origin, testspot);
01218 testspot[1] += branchDistance;
01219
01220 VectorCopy(testspot, starttrace);
01221
01222 starttrace[2] -= 4096;
01223
01224 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
01225
01226 testspot[2] = tr.endpos[2]+baseheight;
01227
01228 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
01229 {
01230 VectorCopy(testspot, nodetable[nodenum].origin);
01231 nodetable[nodenum].inuse = 1;
01232
01233 nodetable[nodenum].weight = nodetable[i].weight+1;
01234 nodetable[nodenum].neighbornum = i;
01235 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
01236 {
01237 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01238 }
01239 nodenum++;
01240 cancontinue = 1;
01241 }
01242
01243 if (nodenum >= MAX_NODETABLE_SIZE)
01244 {
01245 break;
01246 }
01247
01248 VectorCopy(nodetable[i].origin, testspot);
01249 testspot[1] -= branchDistance;
01250
01251 VectorCopy(testspot, starttrace);
01252
01253 starttrace[2] -= 4096;
01254
01255 trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
01256
01257 testspot[2] = tr.endpos[2]+baseheight;
01258
01259 if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
01260 {
01261 VectorCopy(testspot, nodetable[nodenum].origin);
01262 nodetable[nodenum].inuse = 1;
01263
01264 nodetable[nodenum].weight = nodetable[i].weight+1;
01265 nodetable[nodenum].neighbornum = i;
01266 if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
01267 {
01268 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01269 }
01270 nodenum++;
01271 cancontinue = 1;
01272 }
01273
01274 if (nodenum >= MAX_NODETABLE_SIZE)
01275 {
01276 break;
01277 }
01278
01279 extendednodes[i] = 1;
01280 }
01281
01282 i++;
01283 }
01284 }
01285
01286 if (!foundit)
01287 {
01288 #ifndef _DEBUG //if debug just always print this.
01289 if (!behindTheScenes)
01290 #endif
01291 {
01292 G_Printf(S_COLOR_RED "Could not link %i to %i, unreachable by node branching.\n", startindex, endindex);
01293 }
01294 gWPArray[startindex]->flags |= WPFLAG_ONEWAY_FWD;
01295 gWPArray[endindex]->flags |= WPFLAG_ONEWAY_BACK;
01296 if (!behindTheScenes)
01297 {
01298 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);
01299 }
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312 if (!behindTheScenes)
01313 {
01314 return 0;
01315 }
01316 else
01317 {
01318 vec3_t endDist;
01319 int nCount = 0;
01320 int idealNode = -1;
01321 float bestDist = 0;
01322 float testDist;
01323
01324 if (nodenum <= 10)
01325 {
01326 return 0;
01327 }
01328
01329
01330 while (nCount < nodenum)
01331 {
01332 VectorSubtract(nodetable[nCount].origin, gWPArray[endindex]->origin, endDist);
01333 testDist = VectorLength(endDist);
01334 if (idealNode == -1)
01335 {
01336 idealNode = nCount;
01337 bestDist = testDist;
01338 nCount++;
01339 continue;
01340 }
01341
01342 if (testDist < bestDist)
01343 {
01344 idealNode = nCount;
01345 bestDist = testDist;
01346 }
01347
01348 nCount++;
01349 }
01350
01351 if (idealNode == -1)
01352 {
01353 return 0;
01354 }
01355
01356 successnodeindex = idealNode;
01357 }
01358 }
01359
01360 i = successnodeindex;
01361 insertindex = startindex;
01362 failsafe = 0;
01363 VectorCopy(gWPArray[startindex]->origin, validspotpos);
01364
01365 while (failsafe < MAX_NODETABLE_SIZE && i < MAX_NODETABLE_SIZE && i >= 0)
01366 {
01367 VectorSubtract(validspotpos, nodetable[i].origin, a);
01368 if (!nodetable[nodetable[i].neighbornum].inuse || !CanGetToVectorTravel(validspotpos, nodetable[i].origin, mins, maxs) || VectorLength(a) > maxDistFactor || (!CanGetToVectorTravel(validspotpos, gWPArray[endindex]->origin, mins, maxs) && CanGetToVectorTravel(nodetable[i].origin, gWPArray[endindex]->origin, mins, maxs)) )
01369 {
01370 nodetable[i].flags |= WPFLAG_CALCULATED;
01371 if (!CreateNewWP_InTrail(nodetable[i].origin, nodetable[i].flags, insertindex))
01372 {
01373 if (!behindTheScenes)
01374 {
01375 G_Printf(S_COLOR_RED "Could not link %i to %i, waypoint limit hit.\n", startindex, endindex);
01376 }
01377 return 0;
01378 }
01379
01380 VectorCopy(nodetable[i].origin, validspotpos);
01381 }
01382
01383 if (i == 0)
01384 {
01385 break;
01386 }
01387
01388 i = nodetable[i].neighbornum;
01389
01390 failsafe++;
01391 }
01392
01393 if (!behindTheScenes)
01394 {
01395 G_Printf(S_COLOR_YELLOW "Finished connecting %i to %i.\n", startindex, endindex);
01396 }
01397
01398 return 1;
01399 }
01400 #endif
01401
01402 int OpposingEnds(int start, int end)
01403 {
01404 if (!gWPArray[start] || !gWPArray[start]->inuse || !gWPArray[end] || !gWPArray[end]->inuse)
01405 {
01406 return 0;
01407 }
01408
01409 if ((gWPArray[start]->flags & WPFLAG_ONEWAY_FWD) &&
01410 (gWPArray[end]->flags & WPFLAG_ONEWAY_BACK))
01411 {
01412 return 1;
01413 }
01414
01415 return 0;
01416 }
01417
01418 int DoorBlockingSection(int start, int end)
01419 {
01420 trace_t tr;
01421 gentity_t *testdoor;
01422 int start_trace_index;
01423
01424 if (!gWPArray[start] || !gWPArray[start]->inuse || !gWPArray[end] || !gWPArray[end]->inuse)
01425 {
01426 return 0;
01427 }
01428
01429 trap_Trace(&tr, gWPArray[start]->origin, NULL, NULL, gWPArray[end]->origin, ENTITYNUM_NONE, MASK_SOLID);
01430
01431 if (tr.fraction == 1)
01432 {
01433 return 0;
01434 }
01435
01436 testdoor = &g_entities[tr.entityNum];
01437
01438 if (!testdoor)
01439 {
01440 return 0;
01441 }
01442
01443 if (!strstr(testdoor->classname, "func_"))
01444 {
01445 return 0;
01446 }
01447
01448 start_trace_index = tr.entityNum;
01449
01450 trap_Trace(&tr, gWPArray[end]->origin, NULL, NULL, gWPArray[start]->origin, ENTITYNUM_NONE, MASK_SOLID);
01451
01452 if (tr.fraction == 1)
01453 {
01454 return 0;
01455 }
01456
01457 if (start_trace_index == tr.entityNum)
01458 {
01459 return 1;
01460 }
01461
01462 return 0;
01463 }
01464
01465 #ifndef _XBOX
01466 int RepairPaths(qboolean behindTheScenes)
01467 {
01468 int i;
01469 int preAmount = 0;
01470 int ctRet;
01471 vec3_t a;
01472 float maxDistFactor = 400;
01473
01474 if (!gWPNum)
01475 {
01476 return 0;
01477 }
01478
01479 if (g_RMG.integer)
01480 {
01481 maxDistFactor = 800;
01482 }
01483
01484 i = 0;
01485
01486 preAmount = gWPNum;
01487
01488 trap_Cvar_Update(&bot_wp_distconnect);
01489 trap_Cvar_Update(&bot_wp_visconnect);
01490
01491 while (i < gWPNum)
01492 {
01493 if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i+1] && gWPArray[i+1]->inuse)
01494 {
01495 VectorSubtract(gWPArray[i]->origin, gWPArray[i+1]->origin, a);
01496
01497 if (!(gWPArray[i+1]->flags & WPFLAG_NOVIS) &&
01498 !(gWPArray[i+1]->flags & WPFLAG_JUMP) &&
01499 !(gWPArray[i]->flags & WPFLAG_CALCULATED) &&
01500 !OpposingEnds(i, i+1) &&
01501 ((bot_wp_distconnect.value && VectorLength(a) > maxDistFactor) || (!OrgVisible(gWPArray[i]->origin, gWPArray[i+1]->origin, ENTITYNUM_NONE) && bot_wp_visconnect.value) ) &&
01502 !DoorBlockingSection(i, i+1))
01503 {
01504 ctRet = ConnectTrail(i, i+1, behindTheScenes);
01505
01506 if (gWPNum >= MAX_WPARRAY_SIZE)
01507 {
01508 gWPNum = MAX_WPARRAY_SIZE;
01509 break;
01510 }
01511
01512
01513
01514
01515
01516 }
01517 }
01518
01519 i++;
01520 }
01521
01522 return 1;
01523 }
01524 #endif
01525
01526 int OrgVisibleCurve(vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore)
01527 {
01528 trace_t tr;
01529 vec3_t evenorg1;
01530
01531 VectorCopy(org1, evenorg1);
01532 evenorg1[2] = org2[2];
01533
01534 trap_Trace(&tr, evenorg1, mins, maxs, org2, ignore, MASK_SOLID);
01535
01536 if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
01537 {
01538 trap_Trace(&tr, evenorg1, mins, maxs, org1, ignore, MASK_SOLID);
01539
01540 if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
01541 {
01542 return 1;
01543 }
01544 }
01545
01546 return 0;
01547 }
01548
01549 int CanForceJumpTo(int baseindex, int testingindex, float distance)
01550 {
01551 float heightdif;
01552 vec3_t xy_base, xy_test, v, mins, maxs;
01553 wpobject_t *wpBase = gWPArray[baseindex];
01554 wpobject_t *wpTest = gWPArray[testingindex];
01555
01556 mins[0] = -15;
01557 mins[1] = -15;
01558 mins[2] = -15;
01559 maxs[0] = 15;
01560 maxs[1] = 15;
01561 maxs[2] = 15;
01562
01563 if (!wpBase || !wpBase->inuse || !wpTest || !wpTest->inuse)
01564 {
01565 return 0;
01566 }
01567
01568 if (distance > 400)
01569 {
01570 return 0;
01571 }
01572
01573 VectorCopy(wpBase->origin, xy_base);
01574 VectorCopy(wpTest->origin, xy_test);
01575
01576 xy_base[2] = xy_test[2];
01577
01578 VectorSubtract(xy_base, xy_test, v);
01579
01580 if (VectorLength(v) > MAX_NEIGHBOR_LINK_DISTANCE)
01581 {
01582 return 0;
01583 }
01584
01585 if ((