codemp/game/ai_wpnav.c

Go to the documentation of this file.
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; //so we can connect broken trails
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; //don't render too many at once
00284                 }
00285                 i++;
00286         }
00287 
00288         if (i >= gWPNum)
00289         {
00290                 gWPRenderTime = level.time + 1500; //wait a bit after we finish doing the whole trail
00291                 gWPRenderedFrame = 0;
00292         }
00293 
00294 checkprint:
00295 
00296         if (!bot_wp_info.value)
00297         {
00298                 return;
00299         }
00300 
00301         viewent = &g_entities[0]; //only show info to the first client
00302 
00303         if (!viewent || !viewent->client)
00304         { //client isn't in the game yet?
00305                 return;
00306         }
00307 
00308         bestdist = 256; //max distance for showing point info
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                 //GetFlagStr allocates 128 bytes for this, if it's changed then obviously this must be as well
00337                 B_TempFree(128); //flagstr
00338 
00339                 plum = G_TempEntity( gWPArray[bestindex]->origin, EV_SCOREPLUM );
00340                 plum->r.svFlags |= SVF_BROADCAST;
00341                 plum->s.time = bestindex; //render it once
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; //calculated elsewhere
00394         gWPArray[gWPNum]->associated_entity = ENTITYNUM_NONE; //set elsewhere
00395         gWPArray[gWPNum]->forceJumpTo = 0;
00396         gWPArray[gWPNum]->disttonext = 0; //calculated elsewhere
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         //B_Free((wpobject_t *)gWPArray[gWPNum]);
00471         if (gWPArray[gWPNum])
00472         {
00473                 memset( gWPArray[gWPNum], 0, sizeof(gWPArray[gWPNum]) );
00474         }
00475 
00476         //gWPArray[gWPNum] = NULL;
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                         //B_Free(gWPArray[i]);
00534 
00535                         //Keep reusing the memory
00536                         memset( gWPArray[i], 0, sizeof(gWPArray[i]) );
00537 
00538                         //gWPArray[i] = NULL;
00539                         gWPArray[i]->inuse = 0;
00540                         didchange = 1;
00541                 }
00542                 else if (gWPArray[i] && didchange)
00543                 {
00544                         TransferWPData(i, i-1);
00545                         //B_Free(gWPArray[i]);
00546 
00547                         //Keep reusing the memory
00548                         memset( gWPArray[i], 0, sizeof(gWPArray[i]) );
00549 
00550                         //gWPArray[i] = NULL;
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; //calculated elsewhere
00621                         gWPArray[i]->associated_entity = ENTITYNUM_NONE; //set elsewhere
00622                         gWPArray[i]->disttonext = 0; //calculated elsewhere
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                         //i++;
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; //calculated elsewhere
00700                         gWPArray[i]->associated_entity = ENTITYNUM_NONE; //set elsewhere
00701                         gWPArray[i]->disttonext = 0; //calculated elsewhere
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; //too steep of a drop.. can't go on
00878         }
00879 
00880         return 1;
00881 }
00882 #else
00883 int CanGetToVectorTravel(vec3_t org1, vec3_t moveTo, vec3_t mins, vec3_t maxs)
00884 //int ExampleAnimEntMove(gentity_t *self, vec3_t moveTo, float stepSize)
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); //make the step size the length of the original positions without Z
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                                 //trap_LinkEntity(self);
00931                                 didMove = 1;
00932                         }
00933                 }
00934                 
00935                 if (didMove != 1)
00936                 { //stair check
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(/*tr.endpos*/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                                 { //clear trace here, probably up a step
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                                         { //plop us down on the step after moving up
00970                                                 VectorCopy(tr.endpos, workingOrg);
00971                                                 //trap_LinkEntity(self);
00972                                                 didMove = 1;
00973                                         }
00974                                 }
00975                         }
00976                 }
00977 
00978                 VectorSubtract(lastIncrement, workingOrg, finalMeasure);
00979                 measureLength = VectorLength(finalMeasure);
00980 
00981                 if (!measureLength)
00982                 { //no progress, break out. If last movement was a sucess didMove will equal 1.
00983                         break;
00984                 }
00985 
00986                 stepSize -= measureLength; //subtract the progress distance from the step size so we don't overshoot the mark.
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]; //for storing checked nodes and not trying to extend them each a bazillion times
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         { //this might be temporary. Or not.
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; //be less precise here, terrain is fairly broad, and we don't want to take an hour precalculating
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) //clear it out before using it
01061         {
01062                 nodetable[i].flags = 0;
01063 //              nodetable[i].index = 0;
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 //      nodetable[nodenum].index = nodenum;
01099         nodenum++;
01100 
01101         while (nodenum < MAX_NODETABLE_SIZE && !foundit && cancontinue)
01102         {
01103                 if (g_RMG.integer)
01104                 { //adjust the branch distance dynamically depending on the distance from the start and end points.
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 //                                      nodetable[nodenum].index = nodenum;
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                                         { //if there's a big drop, make sure we know we can't just magically fly back up
01175                                                 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01176                                         }
01177                                         nodenum++;
01178                                         cancontinue = 1;
01179                                 }
01180 
01181                                 if (nodenum >= MAX_NODETABLE_SIZE)
01182                                 {
01183                                         break; //failure
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 //                                      nodetable[nodenum].index = nodenum;
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                                         { //if there's a big drop, make sure we know we can't just magically fly back up
01206                                                 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01207                                         }
01208                                         nodenum++;
01209                                         cancontinue = 1;
01210                                 }
01211 
01212                                 if (nodenum >= MAX_NODETABLE_SIZE)
01213                                 {
01214                                         break; //failure
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 //                                      nodetable[nodenum].index = nodenum;
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                                         { //if there's a big drop, make sure we know we can't just magically fly back up
01237                                                 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01238                                         }
01239                                         nodenum++;
01240                                         cancontinue = 1;
01241                                 }
01242 
01243                                 if (nodenum >= MAX_NODETABLE_SIZE)
01244                                 {
01245                                         break; //failure
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 //                                      nodetable[nodenum].index = nodenum;
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                                         { //if there's a big drop, make sure we know we can't just magically fly back up
01268                                                 nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
01269                                         }
01270                                         nodenum++;
01271                                         cancontinue = 1;
01272                                 }
01273 
01274                                 if (nodenum >= MAX_NODETABLE_SIZE)
01275                                 {
01276                                         break; //failure
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                 /*while (nodenum >= 0)
01302                 {
01303                         if (nodetable[nodenum].origin[0] || nodetable[nodenum].origin[1] || nodetable[nodenum].origin[2])
01304                         {
01305                                 CreateNewWP(nodetable[nodenum].origin, nodetable[nodenum].flags);
01306                         }
01307 
01308                         nodenum--;
01309                 }*/
01310                 //The above code transfers nodes into the "rendered" waypoint array. Strictly for debugging.
01311 
01312                 if (!behindTheScenes)
01313                 { //just use what we have if we're auto-pathing the level
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                         { //not enough to even really bother.
01326                                 return 0;
01327                         }
01328 
01329                         //Since it failed, find whichever node is closest to the desired end.
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[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)) )
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 { //if a door blocks the trail, we'll just have to assume the points on each side are in visibility when it's open
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; //higher tolerance here.
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) && //don't calculate on jump points because they might not always want to be visible (in cases of force jumping)
01499                                 !(gWPArray[i]->flags & WPFLAG_CALCULATED) && //don't calculate it again
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                                 { //Bad!
01508                                         gWPNum = MAX_WPARRAY_SIZE;
01509                                         break;
01510                                 }
01511 
01512                                 /*if (!ctRet)
01513                                 {
01514                                         return 0;
01515                                 }*/ //we still want to write it..
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; //-1
01559         maxs[0] = 15;
01560         maxs[1] = 15;
01561         maxs[2] = 15; //1
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 ((