grid.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1997-2001 Id Software, Inc.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "common.h"
00027 #include "grid.h"
00028 #include "tracing.h"
00029 #include "routing.h"
00030 #include "../shared/parse.h"
00031 
00033 static const int TUsUsed[] = {
00034     TU_MOVE_STRAIGHT, /* E  */
00035     TU_MOVE_STRAIGHT, /* W  */
00036     TU_MOVE_STRAIGHT, /* N  */
00037     TU_MOVE_STRAIGHT, /* S  */
00038     TU_MOVE_DIAGONAL, /* NE */
00039     TU_MOVE_DIAGONAL, /* SW */
00040     TU_MOVE_DIAGONAL, /* NW */
00041     TU_MOVE_DIAGONAL, /* SE */
00042     TU_MOVE_CLIMB,    /* UP     */
00043     TU_MOVE_CLIMB,    /* DOWN   */
00044     TU_CROUCH,        /* STAND  */
00045     TU_CROUCH,        /* CROUCH */
00046     0,                /* ???    */
00047     TU_MOVE_FALL,     /* FALL   */
00048     0,                /* ???    */
00049     0,                /* ???    */
00050     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & E  */
00051     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & W  */
00052     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & N  */
00053     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & S  */
00054     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & NE */
00055     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & SW */
00056     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & NW */
00057     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & SE */
00058     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & E  */
00059     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & W  */
00060     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & N  */
00061     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & S  */
00062     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & NE */
00063     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & SW */
00064     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & NW */
00065     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & SE */
00066     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & E  */
00067     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & W  */
00068     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & N  */
00069     TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & S  */
00070     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & NE */
00071     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & SW */
00072     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & NW */
00073     TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR  /* FLY DOWN & SE */
00074 };
00075 CASSERT(lengthof(TUsUsed) == PATHFINDING_DIRECTIONS);
00076 
00092 static qboolean Grid_CheckForbidden (const pos3_t exclude, const actorSizeEnum_t actorSize, pathing_t *path, int x, int y, int z)
00093 {
00094     pos_t **p;
00095     int i;
00096     actorSizeEnum_t size;
00097     int fx, fy, fz; 
00098     byte *forbiddenSize;
00099 
00100     for (i = 0, p = path->fblist; i < path->fblength / 2; i++, p += 2) {
00101         /* Skip initial position. */
00102         if (VectorCompare((*p), exclude)) {
00103             /* Com_DPrintf(DEBUG_PATHING, "Grid_CheckForbidden: skipping %i|%i|%i\n", (*p)[0], (*p)[1], (*p)[2]); */
00104             continue;
00105         }
00106 
00107         forbiddenSize = *(p + 1);
00108         memcpy(&size, forbiddenSize, sizeof(size));
00109         fx = (*p)[0];
00110         fy = (*p)[1];
00111         fz = (*p)[2];
00112 
00113         /* Com_DPrintf(DEBUG_PATHING, "Grid_CheckForbidden: comparing (%i, %i, %i) * %i to (%i, %i, %i) * %i \n", x, y, z, actorSize, fx, fy, fz, size); */
00114 
00115         if (fx + size <= x || x + actorSize <= fx)
00116             continue; /* x bounds do not intersect */
00117         if (fy + size <= y || y + actorSize <= fy)
00118             continue; /* y bounds do not intersect */
00119         if (z == fz) {
00120             Com_DPrintf(DEBUG_PATHING, "Grid_CheckForbidden: Collision (%i, %i, %i) * %i and (%i, %i, %i) * %i \n", x, y, z, actorSize, fx, fy, fz, size);
00121             return qtrue; /* confirmed intersection */
00122         }
00123     }
00124     return qfalse;
00125 }
00126 
00127 static void Grid_SetMoveData (pathing_t *path, const int x, const int y, const int z, const int c, const byte length, const int dir, const int ox, const int oy, const int oz, const int oc, priorityQueue_t *pqueue)
00128 {
00129     pos4_t dummy;
00130 
00131     RT_AREA_TEST(path, x, y, z, c);
00132     RT_AREA(path, x, y, z, c) = length; 
00133     RT_AREA_FROM(path, x, y, z, c) = makeDV(dir, oz); 
00134     {
00135         pos3_t pos, test;
00136         int crouch = c;
00137         VectorSet(pos, ox, oy, oz);
00138         VectorSet(test, x, y, z);
00139         PosSubDV(test, crouch, RT_AREA_FROM(path, x, y, z, c));
00140         if (!VectorCompare(test, pos) || crouch != oc) {
00141             Com_Printf("Grid_SetMoveData: Created faulty DV table.\nx:%i y:%i z:%i c:%i\ndir:%i\nnx:%i ny:%i nz:%i nc:%i\ntx:%i ty:%i tz:%i tc:%i\n",
00142                 ox, oy, oz, oc, dir, x, y, z, c, test[0], test[1], test[2], crouch);
00143 
00144             Com_Error(ERR_DROP, "Grid_SetMoveData: Created faulty DV table.");
00145         }
00146     }
00147     Vector4Set(dummy, x, y, z, c);
00149     PQueuePush(pqueue, dummy, length);
00150 }
00151 
00163 static void Grid_MoveMark (const routing_t *map, const pos3_t exclude, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t pos, byte crouchingState, const int dir, priorityQueue_t *pqueue)
00164 {
00165     int x, y, z;
00166     int nx, ny, nz;
00167     int dx, dy, dz;
00168     byte l, ol;
00169     int passageHeight;
00170 
00172     const qboolean flier = qfalse; 
00177     const qboolean hasLadderSupport = qfalse; 
00181     const qboolean hasLadderClimb = qfalse; 
00184     const int fallingHeight = PATHFINDING_MAX_FALL;
00190     const int coreDir = dir % CORE_DIRECTIONS;
00193     const int actorHeight = ModelCeilingToQuant((float)(crouchingState ? PLAYER_CROUCHING_HEIGHT : PLAYER_STANDING_HEIGHT)); 
00195     /* Ensure that dir is in bounds. */
00196     if (dir < 0 || dir >= PATHFINDING_DIRECTIONS)
00197         return;
00198 
00199     /* Directions 12, 14, and 15 are currently undefined. */
00200     if (dir == 12 || dir == 14 || dir == 15)
00201         return;
00202 
00203     /* IMPORTANT: only fliers can use directions higher than NON_FLYING_DIRECTIONS. */
00204     if (!flier && dir >= FLYING_DIRECTIONS) {
00205         Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Non-fliers can't fly.\n");
00206         return;
00207     }
00208 
00209     x = pos[0];
00210     y = pos[1];
00211     z = pos[2];
00212 
00213     RT_AREA_TEST(path, x, y, z, crouchingState);
00214     ol = RT_AREA(path, x, y, z, crouchingState);
00215 
00216     Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: (%i %i %i) s:%i dir:%i c:%i ol:%i\n", x, y, z, actorSize, dir, crouchingState, ol);
00217 
00218     /* We cannot fly and crouch at the same time. This will also cause an actor to stand to fly. */
00219     if (crouchingState && dir >= FLYING_DIRECTIONS) {
00220         Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't fly while crouching.\n");
00221         return;
00222     }
00223 
00224     if (ol >= MAX_MOVELENGTH && ol != ROUTING_NOT_REACHABLE) {
00225         Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Exiting because the TUS needed to move here are already too large. %i %i\n", ol , MAX_MOVELENGTH);
00226         return;
00227     }
00228 
00229 #ifdef PARANOID
00230     if (z >= PATHFINDING_HEIGHT) {
00231         Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: WARNING z = %i(>= HEIGHT %i)\n", z, PATHFINDING_HEIGHT);
00232         return;
00233     }
00234 #endif
00235 
00236     /* Find the number of TUs used to move in this direction. */
00237     l = Grid_GetTUsForDirection(dir);
00238 
00239     /* If crouching then multiply by the crouching factor. */
00240     if (crouchingState == 1)
00241         l *= TU_CROUCH_MOVING_FACTOR;
00242 
00243     /* Now add the TUs needed to get to the originating cell. */
00244     l += ol;
00245 
00246     /* If this is a crouching or crouching move, then process that motion. */
00247     if (dir == DIRECTION_STAND_UP || dir == DIRECTION_CROUCH) {
00248         /* Can't stand up if standing. */
00249         if (dir == DIRECTION_STAND_UP && crouchingState == 0) {
00250             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't stand while standing.\n");
00251             return;
00252         }
00253         /* Can't stand up if there's not enough head room. */
00254         if (dir == DIRECTION_STAND_UP && QuantToModel(Grid_Height(map, actorSize, pos)) >= PLAYER_STANDING_HEIGHT) {
00255             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't stand under a short ceiling.\n");
00256             return;
00257         }
00258         /* Can't get down if crouching. */
00259         if (dir == DIRECTION_CROUCH && crouchingState == 1) {
00260             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't crouch while crouching.\n");
00261             return;
00262         }
00263 
00264         /* Since we can toggle crouching, then do so. */
00265         crouchingState ^= 1;
00266 
00267         /* Is this a better move into this cell? */
00268         RT_AREA_TEST(path, x, y, z, crouchingState);
00269         if (RT_AREA(path, x, y, z, crouchingState) <= l) {
00270             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Toggling crouch is not optimum. %i %i\n", RT_AREA(path, x, y, z, crouchingState), l);
00271             return;
00272         }
00273 
00274         /* Store move. */
00275         if (pqueue)
00276             Grid_SetMoveData(path, x, y, z, crouchingState, l, dir, x, y, z, crouchingState ^ 1, pqueue);
00277 
00278         Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Set move to (%i %i %i) c:%i to %i.\n", x, y, z, crouchingState, l);
00279         /* We are done, exit now. */
00280         return;
00281     }
00282 
00283     dx = dvecs[dir][0]; 
00284     dy = dvecs[dir][1]; 
00285     dz = dvecs[dir][2]; 
00286     nx = x + dx;        
00287     ny = y + dy;        
00288     nz = z + dz;        
00290     /* Connection checks.  If we cannot move in the desired direction, then bail. */
00291     /* Range check of new values (all sizes) */
00292     if (nx < 0 || nx > PATHFINDING_WIDTH - actorSize
00293      || ny < 0 || ny > PATHFINDING_WIDTH - actorSize
00294      || nz < 0 || nz > PATHFINDING_HEIGHT) {
00295         return;
00296     }
00297 
00298     Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: (%i %i %i) s:%i to (%i %i %i)\n", x, y, z, actorSize, nx, ny, nz);
00299 
00300     /* If there is no passageway (or rather lack of a wall) to the desired cell, then return. */
00303     /* If the flier is moving up or down diagonally, then passage height will also adjust */
00304     if (dir >= FLYING_DIRECTIONS) {
00305         int neededHeight;
00306         if (dz > 0) {
00307             /* If the actor is moving up, check the passage at the current cell.
00308              * The minimum height is the actor's height plus the distance from the current floor to the top of the cell. */
00309             neededHeight = actorHeight + CELL_HEIGHT - max(0, RT_FLOOR(map, actorSize, x, y, z));
00310             RT_CONN_TEST(map, actorSize, x, y, z, coreDir);
00311             passageHeight = RT_CONN(map, actorSize, x, y, z, coreDir);
00312         } else if (dz < 0) {
00313             /* If the actor is moving down, check from the destination cell back. *
00314              * The minimum height is the actor's height plus the distance from the destination floor to the top of the cell. */
00315             neededHeight = actorHeight + CELL_HEIGHT - max(0, RT_FLOOR(map, actorSize, nx, ny, nz));
00316             RT_CONN_TEST(map, actorSize, nx, ny, nz, coreDir ^ 1);
00317             passageHeight = RT_CONN(map, actorSize, nx, ny, nz, coreDir ^ 1);
00318         } else {
00319             neededHeight = actorHeight;
00320             RT_CONN_TEST(map, actorSize, x, y, z, coreDir);
00321             passageHeight = RT_CONN(map, actorSize, x, y, z, coreDir);
00322         }
00323         if (passageHeight < neededHeight) {
00324             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Passage is not tall enough. passage:%i actor:%i\n", passageHeight, actorHeight);
00325             return;
00326         }
00327     } else if (dir < CORE_DIRECTIONS) {
00334         const int stepup = RT_STEPUP(map, actorSize, x, y, z, dir); 
00335         const int stepupHeight = stepup & ~(PATHFINDING_BIG_STEPDOWN | PATHFINDING_BIG_STEPUP); 
00336         int heightChange;
00337 
00339         int actorStepupHeight = PATHFINDING_MAX_STEPUP;
00340 
00341         /* This is the standard passage height for all units trying to move horizontally. */
00342         RT_CONN_TEST(map, actorSize, x, y, z, coreDir);
00343         passageHeight = RT_CONN(map, actorSize, x, y, z, coreDir);
00344         if (passageHeight < actorHeight) {
00345             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Passage is not tall enough. passage:%i actor:%i\n", passageHeight, actorHeight);
00346             return;
00347         }
00348 
00349         /* If we are moving horizontally, use the stepup requirement of the floors.
00350          * The new z coordinate may need to be adjusted from stepup.
00351          * Also, actor_stepup_height must be at least the cell's positive stepup value to move that direction. */
00352         /* If the actor cannot reach stepup, then we can't go this way. */
00353         if (actorStepupHeight < stepupHeight) {
00354             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Actor cannot stepup high enough. passage:%i actor:%i\n", stepupHeight, actorStepupHeight);
00355             return;
00356         }
00357         if ((stepup & PATHFINDING_BIG_STEPUP) && nz < PATHFINDING_HEIGHT - 1) {
00358             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Stepping up into higher cell.\n");
00359             nz++;
00385         } else if ((stepup & PATHFINDING_BIG_STEPDOWN) && nz > 0
00386             && actorStepupHeight >= (RT_STEPUP(map, actorSize, nx, ny, nz - 1, dir ^ 1) & ~(PATHFINDING_BIG_STEPDOWN | PATHFINDING_BIG_STEPUP))) {
00387             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Not stepping down into lower cell.\n");
00388             nz--;
00389         } else {
00390             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Not stepping up or down.\n");
00391         }
00392         heightChange = RT_FLOOR(map, actorSize, nx, ny, nz) - RT_FLOOR(map, actorSize, x, y, z) + (nz - z) * CELL_HEIGHT;
00393 
00394         /* If the actor tries to fall more than falling_height, then prohibit the move. */
00395         if (heightChange < -fallingHeight && !hasLadderSupport) {
00396             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Too far a drop without a ladder. change:%i maxfall:%i\n", heightChange, -fallingHeight);
00397             return;
00398         }
00399 
00400         /* If we are walking normally, we can fall if we move into a cell that does not
00401          * have its STEPDOWN flag set and has a negative floor:
00402          * Set heightChange to 0.
00403          * The actor enters the cell.
00404          * The actor will be forced to fall (dir 13) from the destination cell to the cell below. */
00405         if (RT_FLOOR(map, actorSize, nx, ny, nz) < 0) {
00406             /* We cannot fall if STEPDOWN is defined. */
00407             if (stepup & PATHFINDING_BIG_STEPDOWN) {
00408                 Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: There is stepdown from here.\n");
00409                 return;
00410             }
00411             /* We cannot fall if there is an entity below the cell we want to move to. */
00412             if (Grid_CheckForbidden(exclude, actorSize, path, nx, ny, nz - 1)) {
00413                 Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: The fall destination is occupied.\n");
00414                 return;
00415             }
00416             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Preparing for a fall. change:%i fall:%i\n", heightChange, -actorStepupHeight);
00417             heightChange = 0;
00418             nz--;
00419         }
00420 
00421     }
00422     /* else there is no movement that uses passages. */
00423     /* If we are falling, the height difference is the floor value. */
00424     else if (dir == DIRECTION_FALL) {
00425         if (flier) {
00426             /* Fliers cannot fall intentionally. */
00427             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Fliers can't fall.\n");
00428             return;
00429         } else if (RT_FLOOR(map, actorSize, x, y, z) >= 0) {
00430             /* We cannot fall if there is a floor in this cell. */
00431             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't fall while supported. floor:%i\n", RT_FLOOR(map, actorSize, x, y, z));
00432             return;
00433         } else if (hasLadderSupport) {
00434             /* The actor can't fall if there is ladder support. */
00435             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't fall because of ladder.\n");
00436             return;
00437         }
00438     } else if (dir == DIRECTION_CLIMB_UP) {
00439         if (flier && QuantToModel(RT_CEILING(map, actorSize, x, y, z)) < UNIT_HEIGHT * 2 - PLAYER_HEIGHT) { /* up */
00440             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Not enough headroom to fly up. passage:%i actor:%i\n", QuantToModel(RT_CEILING(map, actorSize, x, y, z)), UNIT_HEIGHT * 2 - PLAYER_HEIGHT);
00441             return;
00442         }
00443         /* If the actor is not a flyer and tries to move up, there must be a ladder. */
00444         if (dir == DIRECTION_CLIMB_UP && !hasLadderClimb) {
00445             Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't climb up without a ladder.\n");
00446             return;
00447         }
00448     } else if (dir == DIRECTION_CLIMB_DOWN) {
00449         if (flier) {
00450             if (RT_FLOOR(map, actorSize, x, y, z) >= 0 ) { /* down */
00451                 Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't fly down through a floor. floor:%i\n", RT_FLOOR(map, actorSize, x, y, z));
00452                 return;
00453             }
00454         } else {
00455             /* If the actor is not a flyer and tries to move down, there must be a ladder. */
00456             if (!hasLadderClimb) {
00457                 Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Can't climb down without a ladder.\n");
00458                 return;
00459             }
00460         }
00461     }
00462 
00463     /* OK, at this point we are certain of a few things:
00464      * There is not a wall obstructing access to the destination cell.
00465      * If the actor is not a flier, the actor will not rise more than actor_stepup_height or fall more than
00466      *    falling_height, unless climbing.
00467      *
00468      * If the actor is a flier, as long as there is a passage, it can be moved through.
00469      * There are no floor difference restrictions for fliers, only obstructions. */
00470 
00471     /* nz can't move out of bounds */
00472     if (nz < 0)
00473         nz = 0;
00474     if (nz >= PATHFINDING_HEIGHT)
00475         nz = PATHFINDING_HEIGHT - 1;
00476 
00477     /* Is this a better move into this cell? */
00478     RT_AREA_TEST(path, nx, ny, nz, crouchingState);
00479     if (RT_AREA(path, nx, ny, nz, crouchingState) <= l) {
00480         Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: This move is not optimum. %i %i\n", RT_AREA(path, nx, ny, nz, crouchingState), l);
00481         return;
00482     }
00483 
00484     /* Test for forbidden (by other entities) areas. */
00485     if (Grid_CheckForbidden(exclude, actorSize, path, nx, ny, nz)) {
00486         Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: That spot is occupied.\n");
00487         return;
00488     }
00489 
00490     /* Store move. */
00491     if (pqueue) {
00492         Grid_SetMoveData(path, nx, ny, nz, crouchingState, l, dir, x, y, z, crouchingState, pqueue);
00493     }
00494     Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: Set move to (%i %i %i) c:%i to %i. srcfloor:%i\n", nx, ny, nz, crouchingState, l, RT_FLOOR(map, actorSize, x, y, z));
00495 }
00496 
00497 
00513 void Grid_MoveCalc (const routing_t *map, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t from, byte crouchingState, int distance, byte ** fb_list, int fb_length)
00514 {
00515     int dir;
00516     int count;
00517     priorityQueue_t pqueue;
00518     pos4_t epos; 
00519     pos3_t pos;
00520     /* this is the position of the current actor- so the actor can stand in the cell it is in when pathfinding */
00521     pos3_t excludeFromForbiddenList;
00522 
00523     /* reset move data */
00524     memset(path->area, ROUTING_NOT_REACHABLE, PATHFINDING_WIDTH * PATHFINDING_WIDTH * PATHFINDING_HEIGHT * ACTOR_MAX_STATES);
00525     memset(path->areaFrom, ROUTING_NOT_REACHABLE, PATHFINDING_WIDTH * PATHFINDING_WIDTH * PATHFINDING_HEIGHT * ACTOR_MAX_STATES);
00526     path->fblist = fb_list;
00527     path->fblength = fb_length;
00528 
00529     if (distance > MAX_ROUTE + 3)   /* +3 is added to calc at least one square (diagonal) more */
00530         distance = MAX_ROUTE + 3;   /* and later show one step beyond the walkable path in red */
00531 
00532     /* Prepare exclusion of starting-location (i.e. this should be ent-pos or le-pos) in Grid_CheckForbidden */
00533     VectorCopy(from, excludeFromForbiddenList);
00534 
00535     PQueueInitialise(&pqueue, 1024);
00536     Vector4Set(epos, from[0], from[1], from[2], crouchingState);
00537     PQueuePush(&pqueue, epos, 0);
00538 
00539     /* Confirm bounds */
00540     assert((from[2]) < PATHFINDING_HEIGHT);
00541     assert(crouchingState == 0 || crouchingState == 1); /* s.a. ACTOR_MAX_STATES */
00542 
00543     RT_AREA(path, from[0], from[1], from[2], crouchingState) = 0;
00544 
00545     Com_DPrintf(DEBUG_PATHING, "Grid_MoveCalc: Start at (%i %i %i) c:%i\n", from[0], from[1], from[2], crouchingState);
00546 
00547     count = 0;
00548     while (!PQueueIsEmpty(&pqueue)) {
00549         PQueuePop(&pqueue, epos);
00550         VectorCopy(epos, pos);
00551         count++;
00552 
00553         /* for A*
00554         if pos = goal
00555             return pos
00556         */
00559         if (RT_AREA(path, pos[0], pos[1], pos[2], crouchingState) >= distance)
00560             continue;
00561 
00562         for (dir = 0; dir < PATHFINDING_DIRECTIONS; dir++) {
00563             Grid_MoveMark(map, excludeFromForbiddenList, actorSize, path, pos, epos[3], dir, &pqueue);
00564         }
00565     }
00566     /* Com_Printf("Loop: %i", count); */
00567     PQueueFree(&pqueue);
00568 
00569     Com_DPrintf(DEBUG_PATHING, "Grid_MoveCalc: Done\n\n");
00570 }
00571 
00577 void Grid_MoveStore (pathing_t *path)
00578 {
00579     memcpy(path->areaStored, path->area, sizeof(path->areaStored));
00580 }
00581 
00582 
00592 pos_t Grid_MoveLength (const pathing_t *path, const pos3_t to, byte crouchingState, qboolean stored)
00593 {
00594 #ifdef PARANOID
00595     if (to[2] >= PATHFINDING_HEIGHT) {
00596         Com_DPrintf(DEBUG_PATHING, "Grid_MoveLength: WARNING to[2] = %i(>= HEIGHT)\n", to[2]);
00597         return ROUTING_NOT_REACHABLE;
00598     }
00599 #endif
00600     /* Confirm bounds */
00601     assert(to[2] < PATHFINDING_HEIGHT);
00602     assert(crouchingState == 0 || crouchingState == 1); /* s.a. ACTOR_MAX_STATES */
00603 
00604     if (!stored)
00605         return RT_AREA(path, to[0], to[1], to[2], crouchingState);
00606     else
00607         return RT_SAREA(path, to[0], to[1], to[2], crouchingState);
00608 }
00609 
00610 
00619 int Grid_MoveNext (const pathing_t *path, const pos3_t toPos, byte crouchingState)
00620 {
00621     const pos_t l = RT_AREA(path, toPos[0], toPos[1], toPos[2], crouchingState); 
00623     /* Check to see if the TUs needed to move here are greater than 0 and less then ROUTING_NOT_REACHABLE */
00624     if (!l || l == ROUTING_NOT_REACHABLE) {
00625         /* ROUTING_UNREACHABLE means, not possible/reachable */
00626         return ROUTING_UNREACHABLE;
00627     }
00628 
00629     /* Return the information indicating how the actor got to this cell */
00630     return RT_AREA_FROM(path, toPos[0], toPos[1], toPos[2], crouchingState);
00631 }
00632 
00633 
00641 unsigned int Grid_Ceiling (const routing_t *map, const actorSizeEnum_t actorSize, const pos3_t pos)
00642 {
00643     /* max 8 levels */
00644     if (pos[2] >= PATHFINDING_HEIGHT) {
00645         Com_Printf("Grid_Height: Warning: z level is bigger than %i: %i\n",
00646             (PATHFINDING_HEIGHT - 1), pos[2]);
00647     }
00648     return QuantToModel(RT_CEILING(map, actorSize, pos[0], pos[1], pos[2] & 7));
00649 }
00650 
00651 
00659 int Grid_Height (const routing_t *map, const actorSizeEnum_t actorSize, const pos3_t pos)
00660 {
00661     /* max 8 levels */
00662     if (pos[2] >= PATHFINDING_HEIGHT) {
00663         Com_Printf("Grid_Height: Warning: z level is bigger than %i: %i\n",
00664             (PATHFINDING_HEIGHT - 1), pos[2]);
00665     }
00666     return QuantToModel(RT_CEILING(map, actorSize, pos[0], pos[1], pos[2] & (PATHFINDING_HEIGHT - 1))
00667         - RT_FLOOR(map, actorSize, pos[0], pos[1], pos[2] & (PATHFINDING_HEIGHT - 1)));
00668 }
00669 
00670 
00678 int Grid_Floor (const routing_t *map, const actorSizeEnum_t actorSize, const pos3_t pos)
00679 {
00680     /* max 8 levels */
00681     if (pos[2] >= PATHFINDING_HEIGHT) {
00682         Com_Printf("Grid_Floor: Warning: z level is bigger than %i: %i\n",
00683             (PATHFINDING_HEIGHT - 1), pos[2]);
00684     }
00685     return QuantToModel(RT_FLOOR(map, actorSize, pos[0], pos[1], pos[2] & (PATHFINDING_HEIGHT - 1)));
00686 }
00687 
00688 
00697 pos_t Grid_StepUp (const routing_t *map, const actorSizeEnum_t actorSize, const pos3_t pos, const int dir)
00698 {
00699     /* max 8 levels */
00700     if (pos[2] >= PATHFINDING_HEIGHT) {
00701         Com_Printf("Grid_StepUp: Warning: z level is bigger than 7: %i\n", pos[2]);
00702     }
00703     return QuantToModel(RT_STEPUP(map, actorSize, pos[0], pos[1], pos[2] & (PATHFINDING_HEIGHT - 1), dir));
00704 }
00705 
00706 
00712 int Grid_GetTUsForDirection (int dir)
00713 {
00714     assert(dir >= 0 && dir < PATHFINDING_DIRECTIONS);
00715     return TUsUsed[dir];
00716 }
00717 
00718 
00726 int Grid_Filled (const routing_t *map, const actorSizeEnum_t actorSize, const pos3_t pos)
00727 {
00728     /* max 8 levels */
00729     assert(pos[2] < PATHFINDING_HEIGHT);
00730     return RT_FILLED(map, pos[0], pos[1], pos[2], actorSize);
00731 }
00732 
00733 
00742 pos_t Grid_Fall (const routing_t *map, const actorSizeEnum_t actorSize, const pos3_t pos)
00743 {
00744     int z = pos[2], base, diff;
00745     qboolean flier = qfalse; 
00747     /* Is z off the map? */
00748     if (z >= PATHFINDING_HEIGHT) {
00749         Com_DPrintf(DEBUG_PATHING, "Grid_Fall: z (height) out of bounds): z=%i max=%i\n", z, PATHFINDING_HEIGHT);
00750         return 0xFF;
00751     }
00752 
00753     /* If we can fly, then obviously we won't fall. */
00754     if (flier)
00755         return z;
00756 
00757     /* Easy math- get the floor, integer divide by CELL_HEIGHT, add to z.
00758      * If z < 0, we are going down.
00759      * If z >= CELL_HEIGHT, we are going up.
00760      * If 0 <= z <= CELL_HEIGHT, then z / 16 = 0, no change. */
00761     base = RT_FLOOR(map, actorSize, pos[0], pos[1], z);
00762     /* Hack to deal with negative numbers- otherwise rounds toward 0 instead of down. */
00763     diff = base < 0 ? (base - (CELL_HEIGHT - 1)) / CELL_HEIGHT : base / CELL_HEIGHT;
00764     z += diff;
00765     /* The tracing code will set locations without a floor to -1.  Compensate for that. */
00766     if (z < 0)
00767         z = 0;
00768     else if (z >= PATHFINDING_HEIGHT)
00769         z = PATHFINDING_HEIGHT - 1;
00770     return z;
00771 }
00772 
00781 void Grid_PosToVec (const routing_t *map, const actorSizeEnum_t actorSize, const pos3_t pos, vec3_t vec)
00782 {
00783     SizedPosToVec(pos, actorSize, vec);
00784 #ifdef PARANOID
00785     if (pos[2] >= PATHFINDING_HEIGHT)
00786         Com_Printf("Grid_PosToVec: Warning - z level bigger than 7 (%i - source: %.02f)\n", pos[2], vec[2]);
00787 #endif
00788     /* Clamp the floor value between 0 and UNIT_HEIGHT */
00789     vec[2] += max(0, min(UNIT_HEIGHT, Grid_Floor(map, actorSize, pos)));
00790 }
00791 
00792 
00801 void Grid_RecalcBoxRouting (mapTiles_t *mapTiles, routing_t *map, const pos3_t min, const pos3_t max, const char **list)
00802 {
00803     int x, y, z, actorSize, dir;
00804 
00805     Com_DPrintf(DEBUG_PATHING, "rerouting (%i %i %i) (%i %i %i)\n",
00806         (int)min[0], (int)min[1], (int)min[2],
00807         (int)max[0], (int)max[1], (int)max[2]);
00808 
00809     /* check unit heights */
00810     for (actorSize = 1; actorSize <= ACTOR_MAX_SIZE; actorSize++) {
00811         const int maxY = max[1] + actorSize;
00812         const int maxX = max[0] + actorSize;
00813         /* Offset the initial X and Y to compensate for larger actors when needed. */
00814         for (y = max(min[1] - actorSize + 1, 0); y < maxY; y++) {
00815             for (x = max(min[0] - actorSize + 1, 0); x < maxX; x++) {
00817                 for (z = max[2]; z >= 0; z--) {
00818                     const int newZ = RT_CheckCell(mapTiles, map, actorSize, x, y, z, list);
00819                     assert(newZ <= z);
00820                     z = newZ;
00821                 }
00822             }
00823         }
00824     }
00825 
00826     /* check connections */
00827     for (actorSize = 1; actorSize <= ACTOR_MAX_SIZE; actorSize++) {
00828         const int minX = max(min[0] - actorSize, 0);
00829         const int minY = max(min[1] - actorSize, 0);
00830         const int maxX = min(max[0] + actorSize, PATHFINDING_WIDTH - 1);
00831         const int maxY = min(max[1] + actorSize, PATHFINDING_WIDTH - 1);
00832         /* Offset the initial X and Y to compensate for larger actors when needed.
00833          * Also sweep further out to catch the walls back into our box. */
00834         for (y = minY; y <= maxY; y++) {
00835             for (x = minX; x <= maxX; x++) {
00836                 for (dir = 0; dir < CORE_DIRECTIONS; dir++) {
00839 #if RT_IS_BIDIRECTIONAL == 1
00840                     if ((dir & 1) && x != minX && x != maxX && y != minY && y != maxY)
00841                         continue;
00842 #endif
00843                     RT_UpdateConnectionColumn(mapTiles, map, actorSize, x, y, dir, list);
00844                 }
00845             }
00846         }
00847     }
00848 }
00849 
00850 
00861 void Grid_RecalcRouting (mapTiles_t *mapTiles, routing_t *map, const char *name, const char **list)
00862 {
00863     const cBspModel_t *model;
00864     pos3_t min, max;
00865     unsigned int i;
00866     double start, end;
00867 
00868     start = time(NULL);
00869 
00870     /* get inline model, if it is one */
00871     if (*name != '*') {
00872         Com_Printf("Called Grid_RecalcRouting with no inline model\n");
00873         return;
00874     }
00875     model = CM_InlineModel(mapTiles, name);
00876     if (!model) {
00877         Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name);
00878         return;
00879     }
00880 
00881     Com_DPrintf(DEBUG_PATHING, "Model:%s origin(%f,%f,%f) angles(%f,%f,%f) mins(%f,%f,%f) maxs(%f,%f,%f)\n", name,
00882         model->origin[0], model->origin[1], model->origin[2],
00883         model->angles[0], model->angles[1], model->angles[2],
00884         model->mins[0], model->mins[1], model->mins[2],
00885         model->maxs[0], model->maxs[1], model->maxs[2]);
00886 
00887     /* get the target model's dimensions */
00888     if (VectorNotEmpty(model->angles)) {
00889         vec3_t minVec, maxVec;
00890         vec3_t centerVec, halfVec, newCenterVec;
00891         vec3_t m[3];
00892 
00893         /* Find the center of the extents. */
00894         VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec);
00895 
00896         /* Find the half height and half width of the extents. */
00897         VectorSubtract(model->maxs, centerVec, halfVec);
00898 
00899         /* Rotate the center about the origin. */
00900         VectorCreateRotationMatrix(model->angles, m);
00901         VectorRotate(m, centerVec, newCenterVec);
00902 
00903         /* Set minVec and maxVec to bound around newCenterVec at halfVec size. */
00904         VectorSubtract(newCenterVec, halfVec, minVec);
00905         VectorAdd(newCenterVec, halfVec, maxVec);
00906 
00907         /* Now offset by origin then convert to position (Doors do not have 0 origins) */
00908         VectorAdd(minVec, model->origin, minVec);
00909         VecToPos(minVec, min);
00910         VectorAdd(maxVec, model->origin, maxVec);
00911         VecToPos(maxVec, max);
00912     } else {  /* normal */
00913         vec3_t temp;
00914         /* Now offset by origin then convert to position (Doors do not have 0 origins) */
00915         VectorAdd(model->mins, model->origin, temp);
00916         VecToPos(temp, min);
00917         VectorAdd(model->maxs, model->origin, temp);
00918         VecToPos(temp, max);
00919     }
00920 
00921     /* fit min/max into the world size */
00922     max[0] = min(max[0] + 1, PATHFINDING_WIDTH - 1);
00923     max[1] = min(max[1] + 1, PATHFINDING_WIDTH - 1);
00924     max[2] = min(max[2] + 1, PATHFINDING_HEIGHT - 1);
00925     for (i = 0; i < 3; i++)
00926         min[i] = max(min[i] - 1, 0);
00927 
00928     /* We now have the dimensions, call the generic rerouting function. */
00929     Grid_RecalcBoxRouting(mapTiles, map, min, max, list);
00930 
00931     end = time(NULL);
00932     Com_DPrintf(DEBUG_ROUTING, "Retracing for model %s between (%i, %i, %i) and (%i, %i %i) in %5.1fs\n",
00933             name, min[0], min[1], min[2], max[0], max[1], max[2], end - start);
00934 }

Generated by  doxygen 1.6.2