UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
grid.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 1997-2001 Id Software, Inc.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 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 
41 static 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, /* ??? */
58  TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & E */
59  TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & W */
60  TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & N */
61  TU_MOVE_STRAIGHT * TU_FLYING_MOVING_FACTOR, /* FLY UP & S */
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 
96 static 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 
124 static 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 
134 class Step {
135 private:
137  bool flier;
150  const Routing& routing;
151 public:
152  const int dir;
154  pos3_t toPos; /* The position we are moving to with this step. */
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 
177 Step::Step (const Routing& r, const pos3_t _fromPos, const actorSizeEnum_t _actorSize, const byte _crouchingState, const int _dir) :
178  flier(false), hasLadderToClimb(false), hasLadderSupport(false), actorHeight(0), actorCrouchedHeight(0), routing(
179  r), dir(_dir), actorSize(_actorSize), crouchingState(_crouchingState), TUsAfter(0)
180 {
181  VectorCopy(_fromPos, fromPos);
182 }
183 
188 bool Step::init ()
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 
217 bool Step::calcNewPos (void)
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];
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 
242 void 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
271 
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));
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 
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. */
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 
443 bool 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. */
465  if (!checkVerticalDirections()) {
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 
497 void 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 
590 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)
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 
698 pos_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 
719 int Grid_MoveNext (const pathing_t* path, const pos3_t toPos, byte crouchingState)
720 {
721  const pos_t moveLen = RT_AREA_POS(path, toPos, crouchingState);
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 
741 unsigned 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 
754 int 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 
766 int 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 
783 pos_t Grid_Fall (const Routing& routing, const actorSizeEnum_t actorSize, const pos3_t pos)
784 {
785  int z = pos[2];
786  bool flier = false;
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 
818 bool 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 
832 void 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 
854 void 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 
922 void 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 }
void set(const pos3_t mini, const pos3_t maxi)
Definition: mathlib.h:148
pos3_t fromPos
Definition: grid.cpp:153
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
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
CASSERT(lengthof(TUsUsed)==PATHFINDING_DIRECTIONS)
#define SizedPosToVec(p, actorSize, v)
SizedPosToVect locates the center of an actor based on size and position.
Definition: routing.h:84
#define VectorCopy(src, dest)
Definition: vector.h:51
bool checkVerticalDirections() const
Checks if we can move in the given vertical direction.
Definition: grid.cpp:408
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
#define getDVflags(dv)
Definition: mathlib.h:250
pos_t getMinZ() const
Definition: mathlib.h:180
vec3_t origin
Definition: typedefs.h:28
#define TU_FLYING_MOVING_FACTOR
Definition: defines.h:80
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
#define ModelCeilingToQuant(x)
Definition: routing.h:77
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
byte TUsAfter
Definition: grid.cpp:157
const Routing & routing
Definition: grid.cpp:150
pos_t getMaxY() const
Definition: mathlib.h:186
void expandXY(const int byVal)
expand the box in four directions, but clip them to the maximum boundaries
Definition: mathlib.h:206
pos_t getMaxX() const
Definition: mathlib.h:183
#define DIRECTION_CLIMB_UP
Definition: defines.h:331
#define ACTOR_MAX_SIZE
Definition: defines.h:305
void PQueuePush(priorityQueue_t *pq, const pos4_t item, priorityQueueRating_t r)
Definition: pqueue.cpp:47
#define makeDV(dir, z)
Definition: mathlib.h:247
bool init()
Initialize the other Step data.
Definition: grid.cpp:188
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
#define DIRECTION_STAND_UP
Definition: defines.h:333
int32_t actorSizeEnum_t
Definition: ufotypes.h:77
#define DV_FLAG_AUTOCROUCHED
Definition: mathlib.h:244
Definition: aabb.h:42
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
dvec_t areaFrom[ACTOR_MAX_STATES][PATHFINDING_HEIGHT][PATHFINDING_WIDTH][PATHFINDING_WIDTH]
Definition: grid.h:89
#define OBJSET(obj, val)
Definition: shared.h:177
#define TU_CROUCH
Definition: defines.h:72
#define DIRECTION_CLIMB_DOWN
Definition: defines.h:332
pos3_t toPos
Definition: grid.cpp:154
byte getStepupHeight(const int actorSize, const int x, const int y, const int z, const int dir) const
return the value without the flags for z-level change
Definition: typedefs.h:305
#define VectorDist(a, b)
Definition: vector.h:69
#define UNIT_HEIGHT
Definition: defines.h:122
const vec4_t dvecs[PATHFINDING_DIRECTIONS]
Definition: mathlib.cpp:58
void set(const AABB &other)
Copies the values from the given aabb.
Definition: aabb.h:60
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
void PQueueFree(priorityQueue_t *pq)
free up memory for pqueue
Definition: pqueue.cpp:83
void VectorCreateRotationMatrix(const vec3_t angles, vec3_t matrix[3])
Definition: mathlib.cpp:592
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
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
vec3_t maxs
Definition: aabb.h:258
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
#define TU_MOVE_STRAIGHT
Definition: defines.h:74
byte isStepUpLevel(const actorSizeEnum_t actorSize, const pos3_t pos, const int dir) const
Definition: typedefs.h:311
pos_t ** getNext(pos_t **prev)
Definition: grid.h:54
pos_t pos4_t[4]
Definition: ufotypes.h:59
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
#define CELL_HEIGHT
A cell's height in QUANT sized units.
Definition: defines.h:296
#define PATHFINDING_MAX_FALL
Definition: defines.h:309
#define TU_MOVE_CLIMB
Definition: defines.h:76
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
#define PQueueIsEmpty(pq)
Definition: pqueue.h:48
byte area[ACTOR_MAX_STATES][PATHFINDING_HEIGHT][PATHFINDING_WIDTH][PATHFINDING_WIDTH]
Definition: grid.h:85
#define RT_AREA_TEST_POS(path, p, state)
Definition: grid.cpp:35
the priority queue struct the actual data is stored in priorityQueueElement_t
Definition: pqueue.h:39
byte isStepDownLevel(const actorSizeEnum_t actorSize, const pos3_t pos, const int dir) const
Definition: typedefs.h:308
#define FLYING_DIRECTIONS
Definition: mathlib.h:89
bool checkFlyingDirections() const
Checks if we can move in the given flying direction.
Definition: grid.cpp:378
const byte crouchingState
Definition: grid.cpp:156
int actorCrouchedHeight
Definition: grid.cpp:149
#define PATHFINDING_DIRECTIONS
Definition: mathlib.h:87
#define RT_AREA_FROM_POS(path, p, state)
Definition: grid.cpp:33
#define Vector4Set(v, r, g, b, a)
Definition: vector.h:62
#define PATHFINDING_MAX_STEPUP
Definition: defines.h:317
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
pos_t getMinY() const
Definition: mathlib.h:177
pos_t getMinX() const
Definition: mathlib.h:174
Header file for the priority queue implementation.
signed char getFloor(const actorSizeEnum_t actorSize, const pos3_t pos) const
Definition: typedefs.h:262
static forbiddenList_t forbiddenList
A list of locations that cannot be moved to.
Definition: cl_actor.cpp:602
bool isPossible(const pathing_t *path)
Definition: grid.cpp:443
Step(const Routing &r, const pos3_t fromPos, const actorSizeEnum_t actorSize, const byte crouchingState, const int dir)
Constructor.
Definition: grid.cpp:177
bool checkWalkingDirections(const pathing_t *path)
Checks if we can walk in the given direction First test for opening height availability. Then test for stepup compatibility. Last test for fall.
Definition: grid.cpp:259
Definition: grid.h:83
#define MAX_ROUTE_TUS
Definition: defines.h:83
#define VectorNotEmpty(a)
Definition: vector.h:72
#define RT_SAREA(path, x, y, z, state)
Definition: grid.cpp:34
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
pos_t pos3_t[3]
Definition: ufotypes.h:58
byte getCeiling(const int actorSize, const pos3_t pos) const
Definition: typedefs.h:272
vec3_t angles
Definition: typedefs.h:28
void clipToMaxBoundaries()
Definition: mathlib.h:215
void getCenter(vec3_t center) const
Calculates the center of the bounding box.
Definition: aabb.h:155
grid pathfinding and routing
#define DV_FLAG_AUTODIVE
Definition: mathlib.h:245
AABB cbmBox
Definition: typedefs.h:27
static const int TUsUsed[]
Definition: grid.cpp:41
#define RT_AREA_POS(path, p, state)
Definition: grid.cpp:32
#define DIRECTION_CROUCH
Definition: defines.h:334
byte areaStored[ACTOR_MAX_STATES][PATHFINDING_HEIGHT][PATHFINDING_WIDTH][PATHFINDING_WIDTH]
Definition: grid.h:86
#define DIRECTION_FALL
Definition: defines.h:335
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
#define TU_CROUCH_MOVING_FACTOR
Definition: defines.h:79
#define VectorCompare(a, b)
Definition: vector.h:63
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 Grid_MoveStore(pathing_t *path)
Caches the calculated move.
Definition: grid.cpp:683
#define PATHFINDING_HEIGHT
15 max, adjusting above 8 will require a rewrite to the DV code
Definition: defines.h:294
#define VectorAdd(a, b, dest)
Definition: vector.h:47
bool flier
Definition: grid.cpp:137
Battlescape grid functions.
#define QuantToModel(x)
Definition: routing.h:79
void addOneZ()
Definition: mathlib.h:212
#define PLAYER_CROUCHING_HEIGHT
Definition: q_sizes.h:13
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
pos_t getMaxZ() const
Definition: mathlib.h:189
#define TU_MOVE_DIAGONAL
Definition: defines.h:75
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
#define CORE_DIRECTIONS
Definition: mathlib.h:88
const int dir
Definition: grid.cpp:152
a struct holding the relevant data to check if we can move between two adjacent cells ...
Definition: grid.cpp:134
#define DV_FLAG_AUTOCROUCH
Definition: mathlib.h:243
actorSizeEnum_t actorSize
Definition: grid.cpp:155
forbiddenList_t * fbList
Definition: grid.h:92
vec_t vec3_t[3]
Definition: ufotypes.h:39
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 PQueuePop(priorityQueue_t *pq, pos4_t item)
remove the first node from the pqueue and provide a pointer to it
Definition: pqueue.cpp:91
definitions common between client and server, but not game lib
void shift(const vec3_t shiftVec)
shove the whole box by the given vector
Definition: aabb.h:246
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
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 lengthof(x)
Definition: shared.h:105
#define ROUTING_UNREACHABLE
Definition: defines.h:284
bool isZero() const
Definition: mathlib.h:196
A list of locations that cannot be moved to.
Definition: grid.h:35
#define ACTOR_MAX_STATES
Definition: defines.h:338
#define ACTOR_SIZE_NORMAL
Definition: defines.h:302
bool calcNewPos()
Calculate the cell the we end up in if moving in the give dir.
Definition: grid.cpp:217
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
#define ROUTING_NOT_REACHABLE
Definition: defines.h:283
uint8_t byte
Definition: ufotypes.h:34
#define VectorEqual(a, b)
Definition: vector.h:65
static struct mdfour * m
Definition: md4.cpp:35
int actorHeight
Definition: grid.cpp:148
#define TU_MOVE_FALL
Definition: defines.h:77
#define PLAYER_STANDING_HEIGHT
Definition: q_sizes.h:12
actorSizeEnum_t getEntSize(pos_t **current)
Definition: grid.h:64
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
void PQueueInitialise(priorityQueue_t *pq, uint32_t maxElements)
initialise the priority queue with a maximum size of maxelements.
Definition: pqueue.cpp:36
#define PLAYER_HEIGHT
Definition: defines.h:125
Tracing functions.
byte getConn(const int actorSize, const int x, const int y, const int z, const int dir) const
Definition: typedefs.h:291
byte pos_t
Definition: ufotypes.h:57
static mapTiles_t mapTiles
bool hasLadderSupport
Definition: grid.cpp:146