00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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,
00035 TU_MOVE_STRAIGHT,
00036 TU_MOVE_STRAIGHT,
00037 TU_MOVE_STRAIGHT,
00038 TU_MOVE_DIAGONAL,
00039 TU_MOVE_DIAGONAL,
00040 TU_MOVE_DIAGONAL,
00041 TU_MOVE_DIAGONAL,
00042 TU_MOVE_CLIMB,
00043 TU_MOVE_CLIMB,
00044 TU_CROUCH,
00045 TU_CROUCH,
00046 0,
00047 TU_MOVE_FALL,
00048 0,
00049 0,
00050 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00051 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00052 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00053 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00054 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00055 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00056 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00057 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00058 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00059 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00060 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00061 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00062 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00063 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00064 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00065 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00066 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00067 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00068 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00069 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR,
00070 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00071 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00072 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR,
00073 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR
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
00102 if (VectorCompare((*p), exclude)) {
00103
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
00114
00115 if (fx + size <= x || x + actorSize <= fx)
00116 continue;
00117 if (fy + size <= y || y + actorSize <= fy)
00118 continue;
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;
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
00196 if (dir < 0 || dir >= PATHFINDING_DIRECTIONS)
00197 return;
00198
00199
00200 if (dir == 12 || dir == 14 || dir == 15)
00201 return;
00202
00203
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
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
00237 l = Grid_GetTUsForDirection(dir);
00238
00239
00240 if (crouchingState == 1)
00241 l *= TU_CROUCH_MOVING_FACTOR;
00242
00243
00244 l += ol;
00245
00246
00247 if (dir == DIRECTION_STAND_UP || dir == DIRECTION_CROUCH) {
00248
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
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
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
00265 crouchingState ^= 1;
00266
00267
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
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
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
00291
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
00303
00304 if (dir >= FLYING_DIRECTIONS) {
00305 int neededHeight;
00306 if (dz > 0) {
00307
00308
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
00314
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
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
00350
00351
00352
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
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
00401
00402
00403
00404
00405 if (RT_FLOOR(map, actorSize, nx, ny, nz) < 0) {
00406
00407 if (stepup & PATHFINDING_BIG_STEPDOWN) {
00408 Com_DPrintf(DEBUG_PATHING, "Grid_MoveMark: There is stepdown from here.\n");
00409 return;
00410 }
00411
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
00423
00424 else if (dir == DIRECTION_FALL) {
00425 if (flier) {
00426
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
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
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) {
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
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 ) {
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
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
00464
00465
00466
00467
00468
00469
00470
00471
00472 if (nz < 0)
00473 nz = 0;
00474 if (nz >= PATHFINDING_HEIGHT)
00475 nz = PATHFINDING_HEIGHT - 1;
00476
00477
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
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
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
00521 pos3_t excludeFromForbiddenList;
00522
00523
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)
00530 distance = MAX_ROUTE + 3;
00531
00532
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
00540 assert((from[2]) < PATHFINDING_HEIGHT);
00541 assert(crouchingState == 0 || crouchingState == 1);
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
00554
00555
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
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
00601 assert(to[2] < PATHFINDING_HEIGHT);
00602 assert(crouchingState == 0 || crouchingState == 1);
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
00624 if (!l || l == ROUTING_NOT_REACHABLE) {
00625
00626 return ROUTING_UNREACHABLE;
00627 }
00628
00629
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
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
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
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
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
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
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
00754 if (flier)
00755 return z;
00756
00757
00758
00759
00760
00761 base = RT_FLOOR(map, actorSize, pos[0], pos[1], z);
00762
00763 diff = base < 0 ? (base - (CELL_HEIGHT - 1)) / CELL_HEIGHT : base / CELL_HEIGHT;
00764 z += diff;
00765
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
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
00810 for (actorSize = 1; actorSize <= ACTOR_MAX_SIZE; actorSize++) {
00811 const int maxY = max[1] + actorSize;
00812 const int maxX = max[0] + actorSize;
00813
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
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
00833
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
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
00888 if (VectorNotEmpty(model->angles)) {
00889 vec3_t minVec, maxVec;
00890 vec3_t centerVec, halfVec, newCenterVec;
00891 vec3_t m[3];
00892
00893
00894 VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec);
00895
00896
00897 VectorSubtract(model->maxs, centerVec, halfVec);
00898
00899
00900 VectorCreateRotationMatrix(model->angles, m);
00901 VectorRotate(m, centerVec, newCenterVec);
00902
00903
00904 VectorSubtract(newCenterVec, halfVec, minVec);
00905 VectorAdd(newCenterVec, halfVec, maxVec);
00906
00907
00908 VectorAdd(minVec, model->origin, minVec);
00909 VecToPos(minVec, min);
00910 VectorAdd(maxVec, model->origin, maxVec);
00911 VecToPos(maxVec, max);
00912 } else {
00913 vec3_t temp;
00914
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
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
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 }