UFO: Alien Invasion
Loading...
Searching...
No Matches
grid.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 1997-2001 Id Software, Inc.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24*/
25
26#include "common.h"
27#include "grid.h"
28#include "tracing.h"
29#include "routing.h"
30#include "pqueue.h"
31
32#define RT_AREA_POS(path, p, state) ((path)->area[(state)][(p)[2]][(p)[1]][(p)[0]])
33#define RT_AREA_FROM_POS(path, p, state) ((path)->areaFrom[(state)][(p)[2]][(p)[1]][(p)[0]])
34#define RT_SAREA(path, x, y, z, state) ((path)->areaStored[(state)][(z)][(y)][(x)])
35#define RT_AREA_TEST_POS(path, p, state) assert((p)[2] < PATHFINDING_HEIGHT);\
36 assert((state) == 0 || (state) == 1);
37 /* assuming p is a pos3_t, we don't need to check for p[n] >= 0 here because it's unsigned.
38 * also we don't need to check against PATHFINDING_WIDTH because it's always greater than a 'byte' type. */
39
41static const int TUsUsed[] = {
42 TU_MOVE_STRAIGHT, /* E */
43 TU_MOVE_STRAIGHT, /* W */
44 TU_MOVE_STRAIGHT, /* N */
45 TU_MOVE_STRAIGHT, /* S */
46 TU_MOVE_DIAGONAL, /* NE */
47 TU_MOVE_DIAGONAL, /* SW */
48 TU_MOVE_DIAGONAL, /* NW */
49 TU_MOVE_DIAGONAL, /* SE */
50 TU_MOVE_CLIMB, /* UP */
51 TU_MOVE_CLIMB, /* DOWN */
52 TU_CROUCH, /* STAND */
53 TU_CROUCH, /* CROUCH */
54 0, /* ??? */
55 TU_MOVE_FALL, /* FALL */
56 0, /* ??? */
57 0, /* ??? */
62 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & NE */
63 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & SW */
64 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & NW */
65 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY UP & SE */
66 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & E */
67 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & W */
68 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & N */
69 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & S */
70 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & NE */
71 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & SW */
72 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & NW */
73 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY LEVEL & SE */
74 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & E */
75 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & W */
76 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & N */
77 TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & S */
78 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & NE */
79 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & SW */
80 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR, /* FLY DOWN & NW */
81 TU_MOVE_DIAGONAL * TU_FLYING_MOVING_FACTOR /* FLY DOWN & SE */
82};
84
96static bool Grid_CheckForbidden (const pos3_t exclude, const actorSizeEnum_t actorSize, pathing_t* path, pos3_t chkPos)
97{
98 if (!path->fbList)
99 return false; /* no fbList, no intersection. We're done. */
100
101 pos_t** p = nullptr;
102 while ((p = path->fbList->getNext(p))) {
103 /* Skip initial position. */
104 if (VectorCompare((*p), exclude)) {
105 continue;
106 }
107
108 /* extract the forbidden coordinates */
109 actorSizeEnum_t entSize = path->fbList->getEntSize(p);
110 const int fx = (*p)[0];
111 const int fy = (*p)[1];
112 const int fz = (*p)[2];
113
114 if (fx + entSize <= chkPos[0] || chkPos[0] + actorSize <= fx)
115 continue; /* x bounds do not intersect */
116 if (fy + entSize <= chkPos[1] || chkPos[1] + actorSize <= fy)
117 continue; /* y bounds do not intersect */
118 if (chkPos[2] == fz)
119 return true; /* confirmed intersection */
120 }
121 return false;
122}
123
124static void Grid_SetMoveData (pathing_t* path, const pos3_t toPos, const int crouch, const byte length, const int dir, const int oldZ)
125{
126 RT_AREA_TEST_POS(path, toPos, crouch);
127 RT_AREA_POS(path, toPos, crouch) = length;
128 RT_AREA_FROM_POS(path, toPos, crouch) = makeDV(dir, oldZ);
129}
130
134class Step {
135private:
137 bool flier;
138
142
147
151public:
152 const int dir;
154 pos3_t toPos; /* The position we are moving to with this step. */
156 const byte crouchingState;
158
159 Step (const Routing& r, const pos3_t fromPos, const actorSizeEnum_t actorSize, const byte crouchingState, const int dir);
160 bool init ();
161 bool calcNewPos ();
162 void calcNewTUs (const pathing_t* path);
163 bool checkWalkingDirections (const pathing_t* path);
164 bool checkFlyingDirections () const;
165 bool checkVerticalDirections () const;
166 bool isPossible (const pathing_t* path);
167};
168
177Step::Step (const Routing& r, const pos3_t _fromPos, const actorSizeEnum_t _actorSize, const byte _crouchingState, const int _dir) :
179 r), dir(_dir), actorSize(_actorSize), crouchingState(_crouchingState), TUsAfter(0)
180{
181 VectorCopy(_fromPos, fromPos);
182}
183
189{
195
196 /* Ensure that dir is in bounds. */
197 assert(dir >= 0 && dir < PATHFINDING_DIRECTIONS);
198
199 /* IMPORTANT: only fliers can use directions higher than NON_FLYING_DIRECTIONS. */
200 if (!flier && dir >= FLYING_DIRECTIONS) {
201 return false;
202 }
203
204 /* We cannot fly and crouch at the same time. This will also cause an actor to stand to fly. */
206 return false;
207 }
208
209 return true;
210}
211
212
218{
219 toPos[0] = fromPos[0] + dvecs[dir][0];
220 toPos[1] = fromPos[1] + dvecs[dir][1];
221 toPos[2] = fromPos[2] + dvecs[dir][2];
222
223 /* Connection checks. If we cannot move in the desired direction, then bail. */
224 /* Range check of new values (all sizes) */
225 /* "comparison is always false due to limited range of data type" */
226 /* Only activate this check if PATHFINDING_WIDTH or pos3_t changes */
227/* if (toPos[0] < 0 || toPos[0] > PATHFINDING_WIDTH - actorSize
228 || toPos[1] < 0 || toPos[1] > PATHFINDING_WIDTH - actorSize
229 || toPos[2] < 0 {
230 return false;
231 } */
232 if (toPos[2] > PATHFINDING_HEIGHT) {
233 return false;
234 }
235 return true;
236}
237
242void Step::calcNewTUs (const pathing_t* path)
243{
244 const byte TUsSoFar = RT_AREA_POS(path, fromPos, crouchingState);
245 /* Find the number of TUs used (normally) to move in this direction. */
246 const byte TUsForMove = Grid_GetTUsForDirection(dir, crouchingState);
247
248 /* Now add the TUs needed to get to the originating cell. */
249 TUsAfter = TUsSoFar + TUsForMove;
250}
251
260{
262 const int fallingHeight = PATHFINDING_MAX_FALL;
263 const int stepupHeight = routing.getStepupHeight(actorSize, fromPos[0], fromPos[1], fromPos[2], dir);
265 const int actorStepupHeight = PATHFINDING_MAX_STEPUP;
266
267 /* This is the standard passage height for all units trying to move horizontally. */
268 const int passageHeight = routing.getConn(actorSize, fromPos, dir);
269 if (passageHeight < actorHeight) {
270#if 0
272 int dvFlagsNew = 0;
273 if (!crouchingState /* not in std crouch mode */
274 && passageHeight >= actorCrouchedHeight) { /* and passage is tall enough for crouching ? */
275 /* we should try autocrouching */
276 int dvFlagsOld = getDVflags(RT_AREA_POS(path, fromPos, crouchingState));
277 int toHeight = routing.getCeiling(actorSize, toPos) - routing.getFloor(actorSize, toPos);
278 int tuCr = Grid_GetTUsForDirection(dir, 1); /* 1 means crouched */
279 int newTUs = 0;
280
281 if (toHeight >= actorHeight) { /* can we stand in the new cell ? */
282 if ((dvFlagsOld & DV_FLAG_AUTOCROUCH) /* already in auto-crouch mode ? */
283 || (dvFlagsOld & DV_FLAG_AUTOCROUCHED)) {
284 dvFlagsNew |= DV_FLAG_AUTOCROUCHED; /* keep that ! */
285 newTUs = tuCr + TU_CROUCH; /* TUs for crouching plus getting up */
286 }
287 else {
288 dvFlagsNew |= DV_FLAG_AUTODIVE;
289 newTUs = tuCr + 2 * TU_CROUCH; /* TUs for crouching plus getting down and up */
290 }
291 }
292 else { /* we can't stand there */
293 if (dvFlagsOld & DV_FLAG_AUTOCROUCHED) {
294 dvFlagsNew |= DV_FLAG_AUTOCROUCHED; /* keep that ! */
295 newTUs = tuCr; /* TUs just for crouching */
296 }
297 else {
298 dvFlagsNew |= DV_FLAG_AUTOCROUCH; /* get down ! */
299 newTUs = tuCr + TU_CROUCH; /* TUs for crouching plus getting down */
300 }
301 }
302 }
303 else
304#endif
305 return false; /* Passage is not tall enough. */
306 }
307
308 /* If we are moving horizontally, use the stepup requirement of the floors.
309 * The new z coordinate may need to be adjusted from stepup.
310 * Also, actor_stepup_height must be at least the cell's positive stepup value to move that direction. */
311 /* If the actor cannot reach stepup, then we can't go this way. */
312 if (actorStepupHeight < stepupHeight) {
313 return false; /* Actor cannot stepup high enough. */
314 }
315
316 const int nx = toPos[0];
317 const int ny = toPos[1];
318 const int nz = toPos[2];
319
320 if (routing.isStepUpLevel(actorSize, fromPos, dir) && toPos[2] < PATHFINDING_HEIGHT - 1) {
321 toPos[2]++;
347 } else if (routing.isStepDownLevel(actorSize, fromPos, dir) && toPos[2] > 0
348 && actorStepupHeight >= routing.getStepupHeight(actorSize, nx, ny, nz - 1, dir ^ 1)) {
349 toPos[2]--; /* Stepping down into lower cell. */
350 }
351
352 const int heightChange = routing.getFloor(actorSize, toPos) - routing.getFloor(actorSize, fromPos) + (toPos[2] - fromPos[2]) * CELL_HEIGHT;
353
354 /* If the actor tries to fall more than falling_height, then prohibit the move. */
355 if (heightChange < -fallingHeight && !hasLadderSupport) {
356 return false; /* Too far a drop without a ladder. */
357 }
358
359 /* If we are walking normally, we can fall if we move into a cell that does not
360 * have its STEPDOWN flag set and has a negative floor:
361 * Set heightChange to 0.
362 * The actor enters the cell.
363 * The actor will be forced to fall (dir 13) from the destination cell to the cell below. */
364 if (routing.getFloor(actorSize, toPos) < 0) {
365 /* We cannot fall if STEPDOWN is defined. */
366 if (routing.isStepDownLevel(actorSize, fromPos, dir)) {
367 return false; /* There is stepdown from here. */
368 }
369 toPos[2]--;
370 }
371 return true;
372}
373
379{
380 const int coreDir = dir % CORE_DIRECTIONS;
381 int neededHeight;
382 int passageHeight;
383
384 if (toPos[2] > fromPos[2]) {
385 /* If the actor is moving up, check the passage at the current cell.
386 * The minimum height is the actor's height plus the distance from the current floor to the top of the cell. */
387 neededHeight = actorHeight + CELL_HEIGHT - std::max((const signed char)0, routing.getFloor(actorSize, fromPos));
388 passageHeight = routing.getConn(actorSize, fromPos, coreDir);
389 } else if (toPos[2] < fromPos[2]) {
390 /* If the actor is moving down, check from the destination cell back. *
391 * The minimum height is the actor's height plus the distance from the destination floor to the top of the cell. */
392 neededHeight = actorHeight + CELL_HEIGHT - std::max((const signed char)0, routing.getFloor(actorSize, toPos));
393 passageHeight = routing.getConn(actorSize, toPos, coreDir ^ 1);
394 } else {
395 neededHeight = actorHeight;
396 passageHeight = routing.getConn(actorSize, fromPos, coreDir);
397 }
398 if (passageHeight < neededHeight) {
399 return false;
400 }
401 return true;
402}
403
409{
410 if (dir == DIRECTION_FALL) {
411 if (flier) {
412 /* Fliers cannot fall intentionally. */
413 return false;
414 } else if (routing.getFloor(actorSize, fromPos) >= 0) {
415 /* We cannot fall if there is a floor in this cell. */
416 return false;
417 } else if (hasLadderSupport) {
418 /* The actor can't fall if there is ladder support. */
419 return false;
420 }
421 } else if (dir == DIRECTION_CLIMB_UP) {
422 if (flier && QuantToModel(routing.getCeiling(actorSize, fromPos)) < UNIT_HEIGHT * 2 - PLAYER_HEIGHT) { /* Not enough headroom to fly up. */
423 return false;
424 } else if (!hasLadderToClimb) {
425 /* If the actor is not a flyer and tries to move up, there must be a ladder. */
426 return false;
427 }
428 } else if (dir == DIRECTION_CLIMB_DOWN) {
429 if (flier && routing.getFloor(actorSize, fromPos) >= 0) {
430 /* Can't fly down through a floor. */
431 return false;
432 } else if (!hasLadderToClimb) {
433 /* If the actor is not a flyer and tries to move down, there must be a ladder. */
434 return false;
435 }
436 }
437 return true;
438}
439
443bool Step::isPossible (const pathing_t* path)
444{
445 /* calculate the position we would normally end up if moving in the given dir. */
446 if (!calcNewPos()) {
447 return false;
448 }
449 calcNewTUs(path);
450
451 /* If there is no passageway (or rather lack of a wall) to the desired cell, then return. */
452 /* If the flier is moving up or down diagonally, then passage height will also adjust */
453 if (dir >= FLYING_DIRECTIONS) {
454 if (!checkFlyingDirections()) {
455 return false;
456 }
457 } else if (dir < CORE_DIRECTIONS) {
459 if (!checkWalkingDirections(path)) {
460 return false;
461 }
462 } else {
463 /* else there is no movement that uses passages. */
464 /* If we are falling, the height difference is the floor value. */
466 return false;
467 }
468 }
469
470 /* OK, at this point we are certain of a few things:
471 * There is not a wall obstructing access to the destination cell.
472 * If the actor is not a flier, the actor will not rise more than actor_stepup_height or fall more than
473 * falling_height, unless climbing.
474 *
475 * If the actor is a flier, as long as there is a passage, it can be moved through.
476 * There are no floor difference restrictions for fliers, only obstructions. */
477
478 return true;
479}
480
481
497void Grid_CalcPathing (const Routing& routing, const actorSizeEnum_t actorSize, pathing_t* path, const pos3_t from, int maxTUs, forbiddenList_t* fb_list)
498{
499 /* Confirm bounds */
500 assert((from[2]) < PATHFINDING_HEIGHT);
501
502 /* reset move data */
505 path->fbList = fb_list;
506
507 maxTUs = std::min(maxTUs, MAX_ROUTE_TUS);
508
509 /* this is the position of the current actor- so the actor can stand in the cell it is in when pathfinding */
510 pos3_t excludeFromForbiddenList;
511 /* Prepare exclusion of starting-location (i.e. this should be ent-pos or le-pos) in Grid_CheckForbidden */
512 VectorCopy(from, excludeFromForbiddenList);
513
514 priorityQueue_t pqueue;
515 pos4_t epos;
516 pos3_t pos;
517 /* amst is the acronym for actor movement state */
518 for (int amst = 0; amst < ACTOR_MAX_STATES; ++amst) {
519 /* set starting position to 0 TUs.*/
520 RT_AREA_POS(path, from, amst) = 0;
521
522 PQueueInitialise(&pqueue, 1024);
523 Vector4Set(epos, from[0], from[1], from[2], amst);
524 PQueuePush(&pqueue, epos, 0);
525
526 while (!PQueueIsEmpty(&pqueue)) {
527 PQueuePop(&pqueue, epos);
528 VectorCopy(epos, pos);
529
530 /* if reaching that square already took too many TUs,
531 * don't bother to reach new squares *from* there. */
532 const byte usedTUs = RT_AREA_POS(path, pos, amst);
533 if (usedTUs >= maxTUs)
534 continue;
535
536 for (int dir = 0; dir < PATHFINDING_DIRECTIONS; ++dir) {
537 /* Directions 12, 14, and 15 are currently undefined. */
538 if (dir == 12 || dir == 14 || dir == 15)
539 continue;
540 /* If this is a crouching or crouching move, forget it. */
541 if (dir == DIRECTION_STAND_UP || dir == DIRECTION_CROUCH)
542 continue;
543
544 Step step(routing, pos, actorSize, amst, dir);
545 if (!step.init())
546 continue; /* either dir is irrelevant or something worse happened */
547
548 if (step.isPossible(path)) {
549 /* Is this a better move into this cell? */
550 RT_AREA_TEST_POS(path, step.toPos, step.crouchingState);
551 if (RT_AREA_POS(path, step.toPos, step.crouchingState) <= step.TUsAfter) {
552 continue; /* This move is not optimum. */
553 }
554
555 /* Test for forbidden (by other entities) areas. */
556 if (Grid_CheckForbidden(excludeFromForbiddenList, step.actorSize, path, step.toPos)) {
557 continue; /* That spot is occupied. */
558 }
559
560 /* Store move in pathing table. */
561 Grid_SetMoveData(path, step.toPos, step.crouchingState, step.TUsAfter, step.dir, step.fromPos[2]);
562
563 pos4_t dummy;
564 Vector4Set(dummy, step.toPos[0], step.toPos[1], step.toPos[2], step.crouchingState);
565 PQueuePush(&pqueue, dummy, step.TUsAfter);
566 }
567 }
568 }
569 PQueueFree(&pqueue);
570 }
571}
572
590bool Grid_FindPath (const Routing& routing, const actorSizeEnum_t actorSize, pathing_t* path, const pos3_t from, const pos3_t targetPos, byte crouchingState, int maxTUs, forbiddenList_t* forbiddenList)
591{
592 /* Confirm bounds */
593 assert((from[2]) < PATHFINDING_HEIGHT);
594 assert(crouchingState == 0 || crouchingState == 1); /* s.a. ACTOR_MAX_STATES */
595
596 /* reset move data */
599 if (forbiddenList) {
600 path->fbList = forbiddenList;
601 }
602
603 /* this is the position of the current actor- so the actor can stand in the cell it is in when pathfinding */
604 pos3_t excludeFromForbiddenList;
605 /* Prepare exclusion of starting-location (i.e. this should be ent-pos or le-pos) in Grid_CheckForbidden */
606 VectorCopy(from, excludeFromForbiddenList);
607 /* set starting position to 0 TUs.*/
608 RT_AREA_POS(path, from, crouchingState) = 0;
609
610 bool found = false;
611 priorityQueue_t pqueue;
612 pos4_t epos;
613 pos3_t pos;
614
615 PQueueInitialise(&pqueue, 1024);
616 Vector4Set(epos, from[0], from[1], from[2], crouchingState);
617 PQueuePush(&pqueue, epos, 0);
618
619 while (!PQueueIsEmpty(&pqueue)) {
620 PQueuePop(&pqueue, epos);
621 VectorCopy(epos, pos);
622
623 /* if reaching that square already took too many TUs,
624 * don't bother to reach new squares *from* there. */
625 const byte usedTUs = RT_AREA_POS(path, pos, crouchingState);
626 if (usedTUs >= maxTUs)
627 continue;
628
629 for (int dir = 0; dir < PATHFINDING_DIRECTIONS; dir++) {
630 /* Directions 12, 14, and 15 are currently undefined. */
631 if (dir == 12 || dir == 14 || dir == 15)
632 continue;
633 /* If this is a crouching or crouching move, forget it. */
634 if (dir == DIRECTION_STAND_UP || dir == DIRECTION_CROUCH)
635 continue;
636
637 Step step(routing, pos, actorSize, crouchingState, dir);
638 if (!step.init())
639 continue; /* either dir is irrelevant or something worse happened */
640
641 if (!step.isPossible(path))
642 continue;
643
644 /* Is this a better move into this cell? */
645 RT_AREA_TEST_POS(path, step.toPos, step.crouchingState);
646 if (RT_AREA_POS(path, step.toPos, step.crouchingState) <= step.TUsAfter) {
647 continue; /* This move is not optimum. */
648 }
649
650 /* Test for forbidden (by other entities) areas. */
651 /* Optionally check the forbiddenList. We might want to find a multi-turn path. */
652 if (forbiddenList)
653 if (!VectorCompare(step.toPos, targetPos)) /* but exclude the target position */
654 if (Grid_CheckForbidden(excludeFromForbiddenList, step.actorSize, path, step.toPos)) {
655 continue; /* That spot is occupied. */
656 }
657
658 /* Store move in pathing table. */
659 Grid_SetMoveData(path, step.toPos, step.crouchingState, step.TUsAfter, step.dir, step.fromPos[2]);
660
661 pos4_t dummy;
662 const int dist = step.TUsAfter + (int) (2 * VectorDist(step.toPos, targetPos));
663 Vector4Set(dummy, step.toPos[0], step.toPos[1], step.toPos[2], step.crouchingState);
664 PQueuePush(&pqueue, dummy, dist);
665
666 if (VectorEqual(step.toPos, targetPos)) {
667 found = true;
668 break;
669 }
670 }
671 if (found)
672 break;
673 }
674 PQueueFree(&pqueue);
675 return found;
676}
677
684{
685 memcpy(path->areaStored, path->area, sizeof(path->areaStored));
686}
687
688
698pos_t Grid_MoveLength (const pathing_t* path, const pos3_t to, byte crouchingState, bool stored)
699{
700 /* Confirm bounds */
701 assert(to[2] < PATHFINDING_HEIGHT);
702 assert(crouchingState == 0 || crouchingState == 1); /* s.a. ACTOR_MAX_STATES */
703
704 if (!stored)
705 return RT_AREA_POS(path, to, crouchingState);
706 else
707 return RT_SAREA(path, to[0], to[1], to[2], crouchingState);
708}
709
710
719int Grid_MoveNext (const pathing_t* path, const pos3_t toPos, byte crouchingState)
720{
721 const pos_t moveLen = RT_AREA_POS(path, toPos, crouchingState);
722
723 /* Check to see if the TUs needed to move here are greater than 0 and less then ROUTING_NOT_REACHABLE */
724 if (!moveLen || moveLen == ROUTING_NOT_REACHABLE) {
725 /* ROUTING_UNREACHABLE means, not possible/reachable */
726 return ROUTING_UNREACHABLE;
727 }
728
729 /* Return the information indicating how the actor got to this cell */
730 return RT_AREA_FROM_POS(path, toPos, crouchingState);
731}
732
733
741unsigned int Grid_Ceiling (const Routing& routing, const actorSizeEnum_t actorSize, const pos3_t pos)
742{
743 assert(pos[2] < PATHFINDING_HEIGHT);
744 return QuantToModel(routing.getCeiling(actorSize, pos[0], pos[1], pos[2] & 7));
745}
746
754int Grid_Floor (const Routing& routing, const actorSizeEnum_t actorSize, const pos3_t pos)
755{
756 assert(pos[2] < PATHFINDING_HEIGHT);
757 return QuantToModel(routing.getFloor(actorSize, pos[0], pos[1], pos[2] & (PATHFINDING_HEIGHT - 1)));
758}
759
766int Grid_GetTUsForDirection (const int dir, bool crouched)
767{
768 assert(dir >= 0 && dir < PATHFINDING_DIRECTIONS);
769 if (crouched && dir < CORE_DIRECTIONS)
770 return TUsUsed[dir] * TU_CROUCH_MOVING_FACTOR;
771 else
772 return TUsUsed[dir];
773}
774
783pos_t Grid_Fall (const Routing& routing, const actorSizeEnum_t actorSize, const pos3_t pos)
784{
785 int z = pos[2];
786 bool flier = false;
787
788 /* Is z off the map? */
789 if (z >= PATHFINDING_HEIGHT) {
790 return 0xFF;
791 }
792
793 /* If we can fly, then obviously we won't fall. */
794 if (flier)
795 return z;
796
797 /* Easy math- get the floor, integer divide by CELL_HEIGHT, add to z.
798 * If z < 0, we are going down.
799 * If z >= CELL_HEIGHT, we are going up.
800 * If 0 <= z <= CELL_HEIGHT, then z / 16 = 0, no change. */
801 const int base = routing.getFloor(actorSize, pos[0], pos[1], z);
802 /* Hack to deal with negative numbers- otherwise rounds toward 0 instead of down. */
803 const int diff = base < 0 ? (base - (CELL_HEIGHT - 1)) / CELL_HEIGHT : base / CELL_HEIGHT;
804 z += diff;
805 /* The tracing code will set locations without a floor to -1. Compensate for that. */
806 if (z < 0)
807 z = 0;
808 else if (z >= PATHFINDING_HEIGHT)
809 z = PATHFINDING_HEIGHT - 1;
810 return z;
811}
812
818bool Grid_ShouldUseAutostand (const pathing_t* path, const pos3_t toPos)
819{
820 const int tusCrouched = RT_AREA_POS(path, toPos, 1);
821 const int tusUpright = RT_AREA_POS(path, toPos, 0);
822 return tusUpright + 2 * TU_CROUCH < tusCrouched;
823}
824
832void Grid_PosToVec (const Routing& routing, const actorSizeEnum_t actorSize, const pos3_t pos, vec3_t vec)
833{
834 SizedPosToVec(pos, actorSize, vec);
835#ifdef PARANOID
836 if (pos[2] >= PATHFINDING_HEIGHT)
837 Com_Printf("Grid_PosToVec: Warning - z level bigger than 7 (%i - source: %.02f)\n", pos[2], vec[2]);
838#endif
839 /* Clamp the floor value between 0 and UNIT_HEIGHT */
840 const int gridFloor = Grid_Floor(routing, actorSize, pos);
841 vec[2] += std::max(0, std::min(UNIT_HEIGHT, gridFloor));
842}
843
844
854void Grid_RecalcBoxRouting (mapTiles_t* mapTiles, Routing& routing, const GridBox& box, const char** list)
855{
856 /* check unit heights */
857 for (int actorSize = 1; actorSize <= ACTOR_MAX_SIZE; ++actorSize) {
858 GridBox rBox(box); /* the box we will actually reroute */
859 /* Offset the initial X and Y to compensate for larger actors when needed. */
860 rBox.expandXY(actorSize - 1);
861 /* also start one level above the box to measure high floors correctly */
862 rBox.addOneZ();
863 for (int y = rBox.getMinY(); y <= rBox.getMaxY(); ++y) {
864 for (int x = rBox.getMinX(); x <= rBox.getMaxX(); ++x) {
866 for (int z = rBox.getMaxZ(); z >= 0; --z) {
867 const int newZ = RT_CheckCell(mapTiles, routing, actorSize, x, y, z, list);
868 assert(newZ <= z);
869 z = newZ;
870 }
871 }
872 }
873 }
874
875 /* check connections */
876 for (int actorSize = 1; actorSize <= ACTOR_MAX_SIZE; actorSize++) {
877 GridBox rBox(box); /* the box we will actually reroute */
878 rBox.expandXY(actorSize); /* for connections, expand by the full size of the actor */
879 rBox.addOneZ();
880 for (int y = rBox.getMinY(); y <= rBox.getMaxY(); ++y) {
881 for (int x = rBox.getMinX(); x <= rBox.getMaxX(); ++x) {
882 for (int dir = 0; dir < CORE_DIRECTIONS; ++dir) {
883 /* for places outside the model box, skip dirs that can not be affected by the model */
884 if (x > box.getMaxX() && dir != 1 && dir != 5 && dir != 6)
885 continue;
886 if (y > box.getMaxY() && dir != 3 && dir != 5 && dir != 7)
887 continue;
888 if (actorSize == ACTOR_SIZE_NORMAL) {
889 if (x < box.getMinX() && dir != 0 && dir != 4 && dir != 7)
890 continue;
891 if (y < box.getMinY() && dir != 2 && dir != 4 && dir != 6)
892 continue;
893 } else {
894 /* the position of 2x2 actors is their lower left cell */
895 if (x < box.getMinX() - 1 && dir != 0 && dir != 4 && dir != 7)
896 continue;
897 if (y < box.getMinY() - 1 && dir != 2 && dir != 4 && dir != 6)
898 continue;
899 }
900 // RT_UpdateConnectionColumn(mapTiles, routing, actorSize, x, y, dir, list);
901 RT_UpdateConnectionColumn(mapTiles, routing, actorSize, x, y, dir, list, rBox.getMinZ(), rBox.getMaxZ());
902 }
903 }
904 }
905 }
906}
907
908
922void Grid_RecalcRouting (mapTiles_t* mapTiles, Routing& routing, const char* name, const GridBox& box, const char** list)
923{
924 if (box.isZero()) {
925 /* get inline model, if it is one */
926 if (*name != '*') {
927 Com_Printf("Called Grid_RecalcRouting with no inline model\n");
928 return;
929 }
930 const cBspModel_t* model = CM_InlineModel(mapTiles, name);
931 if (!model) {
932 Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name);
933 return;
934 }
935
936 AABB absbox;
937#if 1
938 /* An attempt to fix the 'doors starting opened' bug (# 3456).
939 * The main difference is the (missing) rotation of the halfVec.
940 * The results are better, but do not fix the problem. */
941 CalculateMinsMaxs(model->angles, model->cbmBox, model->origin, absbox);
942#else
943 /* get the target model's dimensions */
944 if (VectorNotEmpty(model->angles)) {
945 vec3_t minVec, maxVec;
946 vec3_t centerVec, halfVec, newCenterVec;
947 vec3_t m[3];
948
949 /* Find the center of the extents. */
950 model->cbmBox.getCenter(centerVec);
951
952 /* Find the half height and half width of the extents. */
953 VectorSubtract(model->cbmBox.maxs, centerVec, halfVec);
954
955 /* Rotate the center about the origin. */
957 VectorRotate(m, centerVec, newCenterVec);
958
959 /* Set minVec and maxVec to bound around newCenterVec at halfVec size. */
960 VectorSubtract(newCenterVec, halfVec, minVec);
961 VectorAdd(newCenterVec, halfVec, maxVec);
962
963 /* Now offset by origin then convert to position (Doors do not have 0 origins) */
964 absbox.set(minVec, maxVec);
965 absbox.shift(model->origin);
966 } else { /* normal */
967 /* Now offset by origin then convert to position (Doors do not have 0 origins) */
968 absbox.set(model->cbmBox);
969 absbox.shift(model->origin);
970 }
971#endif
972 GridBox rerouteBox;
973 rerouteBox.set(absbox);
974
975 /* fit min/max into the world size */
976 rerouteBox.clipToMaxBoundaries();
977
978 /* We now have the dimensions, call the generic rerouting function. */
979 Grid_RecalcBoxRouting(mapTiles, routing, rerouteBox, list);
980 } else {
981 /* use the passed box */
982 Grid_RecalcBoxRouting(mapTiles, routing, box, list);
983 }
984}
static forbiddenList_t forbiddenList
A list of locations that cannot be moved to.
Definition cl_actor.cpp:602
Definition aabb.h:42
vec3_t maxs
Definition aabb.h:258
void getCenter(vec3_t center) const
Calculates the center of the bounding box.
Definition aabb.h:155
void set(const AABB &other)
Copies the values from the given aabb.
Definition aabb.h:60
void shift(const vec3_t shiftVec)
shove the whole box by the given vector
Definition aabb.h:246
pos_t getMinY() const
Definition mathlib.h:177
void set(const pos3_t mini, const pos3_t maxi)
Definition mathlib.h:148
void clipToMaxBoundaries()
Definition mathlib.h:215
void addOneZ()
Definition mathlib.h:212
pos_t getMinZ() const
Definition mathlib.h:180
pos_t getMaxY() const
Definition mathlib.h:186
bool isZero() const
Definition mathlib.h:196
void expandXY(const int byVal)
expand the box in four directions, but clip them to the maximum boundaries
Definition mathlib.h:206
pos_t getMinX() const
Definition mathlib.h:174
pos_t getMaxX() const
Definition mathlib.h:183
pos_t getMaxZ() const
Definition mathlib.h:189
signed char getFloor(const actorSizeEnum_t actorSize, const pos3_t pos) const
Definition typedefs.h:262
byte getCeiling(const int actorSize, const pos3_t pos) const
Definition typedefs.h:272
a struct holding the relevant data to check if we can move between two adjacent cells
Definition grid.cpp:134
int actorCrouchedHeight
Definition grid.cpp:149
const Routing & routing
Definition grid.cpp:150
pos3_t fromPos
Definition grid.cpp:153
bool hasLadderSupport
Definition grid.cpp:146
Step(const Routing &r, const pos3_t fromPos, const actorSizeEnum_t actorSize, const byte crouchingState, const int dir)
Constructor.
Definition grid.cpp:177
bool flier
Definition grid.cpp:137
bool init()
Initialize the other Step data.
Definition grid.cpp:188
bool checkFlyingDirections() const
Checks if we can move in the given flying direction.
Definition grid.cpp:378
pos3_t toPos
Definition grid.cpp:154
byte TUsAfter
Definition grid.cpp:157
bool isPossible(const pathing_t *path)
Definition grid.cpp:443
bool checkVerticalDirections() const
Checks if we can move in the given vertical direction.
Definition grid.cpp:408
const byte crouchingState
Definition grid.cpp:156
bool checkWalkingDirections(const pathing_t *path)
Checks if we can walk in the given direction First test for opening height availability....
Definition grid.cpp:259
const int dir
Definition grid.cpp:152
actorSizeEnum_t actorSize
Definition grid.cpp:155
bool calcNewPos()
Calculate the cell the we end up in if moving in the give dir.
Definition grid.cpp:217
int actorHeight
Definition grid.cpp:148
bool hasLadderToClimb
Definition grid.cpp:141
void calcNewTUs(const pathing_t *path)
Calculate the TUs after we in the given dir.
Definition grid.cpp:242
cBspModel_t * CM_InlineModel(const mapTiles_t *mapTiles, const char *name)
Searches all inline models and return the cBspModel_t pointer for the given modelnumber or -name.
Definition bsp.cpp:929
int RT_CheckCell(mapTiles_t *mapTiles, Routing &routing, const int actorSize, const int x, const int y, const int z, const char **list)
This function looks to see if an actor of a given size can occupy a cell(s) and if so identifies the ...
Definition routing.cpp:360
void RT_UpdateConnectionColumn(mapTiles_t *mapTiles, Routing &routing, const int actorSize, const int x, const int y, const int dir, const char **list, const int minZ, const int maxZ)
Routing Function to update the connection between two fields.
Definition routing.cpp:1292
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
definitions common between client and server, but not game lib
#define TU_MOVE_DIAGONAL
Definition defines.h:75
#define TU_FLYING_MOVING_FACTOR
Definition defines.h:80
#define DIRECTION_CROUCH
Definition defines.h:334
#define MAX_ROUTE_TUS
Definition defines.h:83
#define PATHFINDING_MAX_FALL
Definition defines.h:309
#define PLAYER_HEIGHT
Definition defines.h:125
#define ROUTING_NOT_REACHABLE
Definition defines.h:283
#define ACTOR_MAX_SIZE
Definition defines.h:305
#define TU_MOVE_STRAIGHT
Definition defines.h:74
#define TU_MOVE_FALL
Definition defines.h:77
#define UNIT_HEIGHT
Definition defines.h:122
#define CELL_HEIGHT
A cell's height in QUANT sized units.
Definition defines.h:296
#define TU_MOVE_CLIMB
Definition defines.h:76
#define DIRECTION_FALL
Definition defines.h:335
#define TU_CROUCH_MOVING_FACTOR
Definition defines.h:79
#define ACTOR_MAX_STATES
Definition defines.h:338
#define DIRECTION_CLIMB_DOWN
Definition defines.h:332
#define DIRECTION_STAND_UP
Definition defines.h:333
#define ROUTING_UNREACHABLE
Definition defines.h:284
#define PATHFINDING_MAX_STEPUP
Definition defines.h:317
#define ACTOR_SIZE_NORMAL
Definition defines.h:302
#define TU_CROUCH
Definition defines.h:72
#define PATHFINDING_HEIGHT
15 max, adjusting above 8 will require a rewrite to the DV code
Definition defines.h:294
#define DIRECTION_CLIMB_UP
Definition defines.h:331
void Grid_CalcPathing(const Routing &routing, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t from, int maxTUs, forbiddenList_t *fb_list)
Recalculate the pathing table for the given actor(-position).
Definition grid.cpp:497
pos_t Grid_MoveLength(const pathing_t *path, const pos3_t to, byte crouchingState, bool stored)
Return the needed TUs to walk to a given position.
Definition grid.cpp:698
static bool Grid_CheckForbidden(const pos3_t exclude, const actorSizeEnum_t actorSize, pathing_t *path, pos3_t chkPos)
Checks one cell on the grid against the 'forbiddenList' (i.e. cells blocked by other entities).
Definition grid.cpp:96
int Grid_GetTUsForDirection(const int dir, bool crouched)
Returns the amounts of TUs that are needed to perform one step into the given direction.
Definition grid.cpp:766
pos_t Grid_Fall(const Routing &routing, const actorSizeEnum_t actorSize, const pos3_t pos)
Calculated the new height level when something falls down from a certain position.
Definition grid.cpp:783
void Grid_PosToVec(const Routing &routing, const actorSizeEnum_t actorSize, const pos3_t pos, vec3_t vec)
Converts a grid position to world coordinates.
Definition grid.cpp:832
bool Grid_ShouldUseAutostand(const pathing_t *path, const pos3_t toPos)
Checks if a crouched actor could save TUs by standing up, walking and crouching again.
Definition grid.cpp:818
#define RT_SAREA(path, x, y, z, state)
Definition grid.cpp:34
void Grid_MoveStore(pathing_t *path)
Caches the calculated move.
Definition grid.cpp:683
#define RT_AREA_POS(path, p, state)
Definition grid.cpp:32
int Grid_MoveNext(const pathing_t *path, const pos3_t toPos, byte crouchingState)
Get the direction to use to move to a position (used to reconstruct the path).
Definition grid.cpp:719
bool Grid_FindPath(const Routing &routing, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t from, const pos3_t targetPos, byte crouchingState, int maxTUs, forbiddenList_t *forbiddenList)
Tries to find a path from the given actor(-position) to a given target position.
Definition grid.cpp:590
void Grid_RecalcBoxRouting(mapTiles_t *mapTiles, Routing &routing, const GridBox &box, const char **list)
This function recalculates the routing in and around the box bounded by min and max.
Definition grid.cpp:854
unsigned int Grid_Ceiling(const Routing &routing, const actorSizeEnum_t actorSize, const pos3_t pos)
Returns the height of the floor in a cell.
Definition grid.cpp:741
void Grid_RecalcRouting(mapTiles_t *mapTiles, Routing &routing, const char *name, const GridBox &box, const char **list)
This function recalculates the routing surrounding the entity name.
Definition grid.cpp:922
#define RT_AREA_TEST_POS(path, p, state)
Definition grid.cpp:35
static void Grid_SetMoveData(pathing_t *path, const pos3_t toPos, const int crouch, const byte length, const int dir, const int oldZ)
Definition grid.cpp:124
static const int TUsUsed[]
Definition grid.cpp:41
#define RT_AREA_FROM_POS(path, p, state)
Definition grid.cpp:33
int Grid_Floor(const Routing &routing, const actorSizeEnum_t actorSize, const pos3_t pos)
Returns the height of the floor in a cell.
Definition grid.cpp:754
Battlescape grid functions.
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const vec4_t dvecs[PATHFINDING_DIRECTIONS]
Definition mathlib.cpp:58
void CalculateMinsMaxs(const vec3_t angles, const AABB &relBox, const vec3_t origin, AABB &absBox)
Calculates the bounding box in absolute coordinates, also for rotating objects. WARNING: do not use t...
Definition mathlib.cpp:546
void VectorCreateRotationMatrix(const vec3_t angles, vec3_t matrix[3])
Definition mathlib.cpp:592
void VectorRotate(vec3_t m[3], const vec3_t va, vec3_t vb)
Rotate a vector with a rotation matrix.
Definition mathlib.cpp:395
#define DV_FLAG_AUTODIVE
Definition mathlib.h:245
#define getDVflags(dv)
Definition mathlib.h:250
#define makeDV(dir, z)
Definition mathlib.h:247
#define FLYING_DIRECTIONS
Definition mathlib.h:89
#define CORE_DIRECTIONS
Definition mathlib.h:88
#define DV_FLAG_AUTOCROUCH
Definition mathlib.h:243
#define PATHFINDING_DIRECTIONS
Definition mathlib.h:87
#define DV_FLAG_AUTOCROUCHED
Definition mathlib.h:244
static struct mdfour * m
Definition md4.cpp:35
void PQueueFree(priorityQueue_t *pq)
free up memory for pqueue
Definition pqueue.cpp:83
void PQueueInitialise(priorityQueue_t *pq, uint32_t maxElements)
initialise the priority queue with a maximum size of maxelements.
Definition pqueue.cpp:36
void PQueuePush(priorityQueue_t *pq, const pos4_t item, priorityQueueRating_t r)
Definition pqueue.cpp:47
void PQueuePop(priorityQueue_t *pq, pos4_t item)
remove the first node from the pqueue and provide a pointer to it
Definition pqueue.cpp:91
Header file for the priority queue implementation.
#define PQueueIsEmpty(pq)
Definition pqueue.h:48
#define PLAYER_STANDING_HEIGHT
Definition q_sizes.h:12
#define PLAYER_CROUCHING_HEIGHT
Definition q_sizes.h:13
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition r_gl.h:110
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
grid pathfinding and routing
#define QuantToModel(x)
Definition routing.h:79
#define ModelCeilingToQuant(x)
Definition routing.h:77
#define SizedPosToVec(p, actorSize, v)
SizedPosToVect locates the center of an actor based on size and position.
Definition routing.h:84
#define OBJSET(obj, val)
Definition shared.h:177
#define lengthof(x)
Definition shared.h:105
#define CASSERT(x)
Definition shared.h:107
vec3_t angles
Definition typedefs.h:28
AABB cbmBox
Definition typedefs.h:27
vec3_t origin
Definition typedefs.h:28
A list of locations that cannot be moved to.
Definition grid.h:35
actorSizeEnum_t getEntSize(pos_t **current)
Definition grid.h:64
pos_t ** getNext(pos_t **prev)
Definition grid.h:54
byte areaStored[ACTOR_MAX_STATES][PATHFINDING_HEIGHT][PATHFINDING_WIDTH][PATHFINDING_WIDTH]
Definition grid.h:86
forbiddenList_t * fbList
Definition grid.h:92
dvec_t areaFrom[ACTOR_MAX_STATES][PATHFINDING_HEIGHT][PATHFINDING_WIDTH][PATHFINDING_WIDTH]
Definition grid.h:89
byte area[ACTOR_MAX_STATES][PATHFINDING_HEIGHT][PATHFINDING_WIDTH][PATHFINDING_WIDTH]
Definition grid.h:85
the priority queue struct the actual data is stored in priorityQueueElement_t
Definition pqueue.h:39
static mapTiles_t mapTiles
Tracing functions.
pos_t pos3_t[3]
Definition ufotypes.h:58
byte pos_t
Definition ufotypes.h:57
vec_t vec3_t[3]
Definition ufotypes.h:39
int32_t actorSizeEnum_t
Definition ufotypes.h:77
pos_t pos4_t[4]
Definition ufotypes.h:59
#define VectorDist(a, b)
Definition vector.h:69
#define Vector4Set(v, r, g, b, a)
Definition vector.h:62
#define VectorEqual(a, b)
Definition vector.h:65
#define VectorNotEmpty(a)
Definition vector.h:72
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define VectorCompare(a, b)
Definition vector.h:63
#define VectorAdd(a, b, dest)
Definition vector.h:47