46 #define RT_NO_OPENING -1
49 #define halfMicrostepSize (PATHFINDING_MICROSTEP_SIZE / 2 - DIST_EPSILON)
54 #define half1x1Width (UNIT_SIZE * 1 / 2 - WALL_SIZE - DIST_EPSILON)
55 #define half2x2Width (UNIT_SIZE * 2 / 2 - WALL_SIZE - DIST_EPSILON)
65 #if defined(COMPILE_MAP)
66 #define RT_COMPLETEBOXTRACE_SIZE(mapTiles, b, list, lvl) TR_SingleTileBoxTrace((mapTiles), Line(), (b), (lvl), MASK_NO_LIGHTCLIP, 0)
67 #define RT_COMPLETEBOXTRACE_PASSAGE(mapTiles, line, b, list) TR_SingleTileBoxTrace((mapTiles), (line), (b), TRACE_ALL_LEVELS, MASK_IMPASSABLE, MASK_PASSABLE)
69 #elif defined(COMPILE_UFO)
70 #define RT_COMPLETEBOXTRACE_SIZE(mapTiles, b, list, lvl) CM_EntCompleteBoxTrace((mapTiles), Line(), (b), (lvl), MASK_NO_LIGHTCLIP, 0, (list))
71 #define RT_COMPLETEBOXTRACE_PASSAGE(mapTiles, line, b, list) CM_EntCompleteBoxTrace((mapTiles), (line), (b), TRACE_ALL_LEVELS, MASK_IMPASSABLE, MASK_PASSABLE, (list))
74 #error Either COMPILE_MAP or COMPILE_UFO must be defined in order for tracing.c to work.
189 static void RT_DumpMap (
const Routing& routing,
actorSizeEnum_t actorSize,
int lx,
int ly,
int lz,
int hx,
int hy,
int hz)
191 Com_Printf(
"\nRT_DumpMap (%i %i %i) (%i %i %i)\n", lx, ly, lz, hx, hy, hz);
192 for (
int z = hz; z >= lz; --z) {
194 for (
int x = lx; x <= hx; ++x) {
198 for (
int y = hy; y >= ly; --y) {
200 for (
int x = lx; x <= hx; ++x) {
202 ,
RT_CONN_NX(routing, actorSize, x, y, z) ?
"w" :
" "
203 ,
RT_CONN_PY(routing, actorSize, x, y, z) ?
"n" :
" "
204 ,
RT_CONN_NY(routing, actorSize, x, y, z) ?
"s" :
" "
205 ,
RT_CONN_PX(routing, actorSize, x, y, z) ?
"e" :
" "
230 RT_DumpMap(routing,
ACTOR_SIZE_NORMAL, start[0], start[1], start[2], end[0], end[1], end[2]);
262 for (
int i = 0;
i < 3;
i++) {
265 while (end[
i] > start[
i]) {
283 while (end[i] > start[i]) {
337 for (
int i = 0;
i < pos[2];
i++) {
338 if (routing.
getCeiling(actorSize, pos[0], pos[1],
i) != 0)
371 const AABB ceilBox(-halfActorWidth, -halfActorWidth, 0,
372 halfActorWidth, halfActorWidth, 0);
417 routing.
setFilled(actorSize, x, y, 0, z);
423 routing.
setFilled(actorSize, x, y, 0, z);
431 assert(initial > bottom);
441 tr = RT_COMPLETEBOXTRACE_PASSAGE(mapTiles,
Line(), &box, list);
457 tr = RT_COMPLETEBOXTRACE_PASSAGE(mapTiles,
Line(), &box, list);
474 tstart[2] = box.
maxs[2];
478 tr = RT_COMPLETEBOXTRACE_PASSAGE(mapTiles,
Line(tstart, tend), &ceilBox, list);
489 if (tr.
endpos[2] > (z + 1) * UNIT_HEIGHT) {
490 const float topf = (z + 1) * UNIT_HEIGHT +
QuantToModel(routing.
getFloor(actorSize, x, y, z + 1) - 1);
491 top = std::min(tr.
endpos[2], topf);
501 UFO_assert(bottom <= top,
"\nassert(bottom <= top): x=%i y=%i bottom=%f top=%f\n", x, y, bottom, top);
512 const int cz = std::min(z, (
int)(floorf((topQ - 1) /
CELL_HEIGHT)));
517 for (
int i = fz;
i <= cz;
i++) {
521 routing.
setCeiling(actorSize, x, y,
i, topQ -
i * CELL_HEIGHT);
525 routing.
setFilled(actorSize, x, y, cz + 1, z);
541 static int RT_FillPassageData (
RoutingData* rtd,
const int dir,
const int x,
const int y,
const int z,
const int openingSize,
const int openingBase,
const int stepup)
543 const int openingTop = openingBase + openingSize;
560 int cz = ceil((
float)openingTop /
CELL_HEIGHT) - 1;
572 assert(fz <= z && z <= cz);
575 for (
int i = fz;
i <= cz;
i++) {
577 const int oh = openingTop - std::max(openingBase,
i *
CELL_HEIGHT);
613 return RT_COMPLETEBOXTRACE_PASSAGE(rtd->
mapTiles, traceLine, &box, rtd->
list);
688 if (start[0] == end[0] || start[1] == end[1]) {
698 midfloor = std::max(midfloor, midfloor2);
702 return std::max(floorLimit, midfloor);
719 if (start[0] == end[0] || start[1] == end[1]) {
729 midceil = std::min(midceil, midceil2);
733 return std::min(ceilLimit, midceil);
752 return floorf(adj_lo / CELL_HEIGHT);
774 static int RT_TraceOpening (
const RoutingData* rtd,
const vec3_t start,
const vec3_t end,
const int ax,
const int ay,
const int bottom,
const int top,
int lo,
int hi,
int* foundLow,
int* foundHigh)
783 *foundLow = *foundHigh = 0;
790 const int tempZ =
RT_CalcNewZ(rtd, ax, ay, top, hi);
795 *foundLow = *foundHigh = hi;
816 *foundLow = *foundHigh = 0;
831 start[2] = end[2] = 0;
852 *foundLow = tempBottom;
869 tempZ =
RT_TraceOpening(rtd, start, end, ax, ay, bottom, top, lo, hi, foundLow, foundHigh);
877 tempZ =
RT_TraceOpening(rtd, start, end, ax, ay, bottom, top, lo, lo + 1, foundLow, foundHigh);
904 const int top = opening->
base + opening->
size;
912 bases[0] = from->
floor;
914 bases[steps] = std::max(0, floorVal) + az *
CELL_HEIGHT;
928 const float sx = start[0];
929 const float sy = start[1];
930 const float ex = end[0];
931 const float ey = end[1];
933 int newBottom = std::max(bases[0], bases[steps]);
935 for (
int i = 1;
i < steps;
i++) {
936 start[0] = end[0] = sx + (ex - sx) * (
i / (
float)steps);
937 start[1] = end[1] = sy + (ey - sy) * (
i / (
float)steps);
941 if (tr.fraction >= 1.0f) {
953 Com_Printf(
"Adjusting middle trace- the known base is too high. \n");
959 Com_Printf(
"Microstep %i from (%f, %f, %f) to (%f, %f, %f) = %i [%f]\n",
960 i, start[0], start[1], start[2], end[0], end[1], end[2], bases[
i], tr.endpos[2]);\
962 newBottom = std::max(newBottom, (
int)bases[i]);
966 Com_Printf(
"z:%i az:%i bottom:%i new_bottom:%i top:%i bases[0]:%i bases[%i]:%i\n", from->
cell[2], az, opening->
base, newBottom, top, bases[0], steps, bases[steps]);
972 int current_h = bases[0];
977 for (
int i = 1;
i <= steps;
i++) {
979 Com_Printf(
"Tracing forward i:%i h:%i\n",
i, current_h);
985 Com_Printf(
" Skipped too many steps, reverting to i:%i\n",
i);
987 opening->
stepup = std::max(opening->
stepup, bases[
i] - current_h);
988 current_h = bases[
i];
997 if (bases[
i] > highest_h) {
998 highest_h = bases[
i];
1002 Com_Printf(
" Skipped because we are falling, skip:%i.\n", skipped);
1008 Com_Printf(
" Tripping skip counter to perform last tests.\n");
1016 current_h = bases[steps];
1018 highest_i = steps - 1;
1021 for (
int i = steps - 1;
i >= 0;
i--) {
1023 Com_Printf(
"Tracing backward i:%i h:%i\n",
i, current_h);
1029 Com_Printf(
" Skipped too many steps, reverting to i:%i\n",
i);
1032 current_h = bases[
i];
1041 if (bases[
i] > highest_h) {
1042 highest_h = bases[
i];
1046 Com_Printf(
" Skipped because we are falling, skip:%i.\n", skipped);
1052 Com_Printf(
" Tripping skip counter to perform last tests.\n");
1057 if (stairwaySituation) {
1058 const int middle = bases[4];
1060 if (stairwaySituation == 1) {
1061 if (bases[1] <= middle &&
1062 bases[2] <= middle &&
1063 bases[3] <= middle ) {
1065 Com_Printf(
"Addition granted by ugly stair hack-stepping up.\n");
1066 return opening->
base - middle;
1068 }
else if (stairwaySituation == 2) {
1069 if (bases[5] <= middle &&
1070 bases[6] <= middle &&
1071 bases[7] <= middle ) {
1073 Com_Printf(
"Addition granted by ugly stair hack-stepping down.\n");
1074 return opening->
base - middle;
1080 return opening->
base - newBottom;
1095 const int z = from->
cell[2];
1096 const int lower = std::max(from->
floor, to->
floor);
1098 const int ax = to->
cell[0];
1099 const int ay = to->
cell[1];
1103 opening->
size = hi - opening->
base;
1104 const int az = to->
floorZ;
1111 const int srcFloor = from->
floor;
1120 const int bonusSize =
RT_MicroTrace(rtd, from, ax, ay, az, stairway, opening);
1121 opening->
base -= bonusSize;
1122 opening->
size = hi - opening->
base;
1125 opening->
stepup = std::max(0, opening->
base - srcFloor);
1153 return opening->
size;
1173 const place_t* placeToCheck =
nullptr;
1204 placeToCheck = &above;
1207 if (!placeToCheck) {
1211 opening->
base = lowCeil;
1226 opening->
base = lowCeil;
1247 if ((adjCeiling == 0 && upperAdjCeiling == 0) || ceiling == 0) {
1259 const int absExtAdjCeiling = (z <
PATHFINDING_HEIGHT - 1) ? adjCeiling + (z + 1) * CELL_HEIGHT : absCeiling;
1263 if (absCeiling < absAdjFloor || absExtAdjCeiling < absFloor) {
1296 RoutingData rtd(mapTiles, routing, actorSize, list);
1299 const int ax = x +
dvecs[dir][0];
1300 const int ay = y + dvecs[dir][1];
1309 if (x == 126 && y == 129 && dir == 2) {
1322 for (z = minZ; z < maxZ; z++) {
1336 strncpy(filename, baseFilename,
sizeof(filename) - 1);
1337 sprintf(ext,
".%i.elevation.csv",
i);
1342 Sys_Error(
"Could not open file %s.", filename);
1352 FS_Printf(&f,
"h:%i c:%i,", routing.
getFloor(
i, x, y, z), routing.
getCeiling(
i, x, y, z));
1362 strncpy(filename, baseFilename,
sizeof(filename) - 1);
1363 sprintf(ext,
".%i.walls.csv",
i);
1368 Sys_Error(
"Could not open file %s.", filename);
1381 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_NX_PY(routing,
i, x, y, z),
RT_STEPUP_NX_PY(routing,
i, x, y, z));
1384 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_PY(routing,
i, x, y, z),
RT_STEPUP_PY(routing,
i, x, y, z));
1387 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_PX_PY(routing,
i, x, y, z),
RT_STEPUP_PX_PY(routing,
i, x, y, z));
1392 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_NX(routing,
i, x, y, z),
RT_STEPUP_NX(routing,
i, x, y, z));
1398 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_PX(routing,
i, x, y, z),
RT_STEPUP_PX(routing,
i, x, y, z));
1403 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_NX_NY(routing,
i, x, y, z),
RT_STEPUP_NX_NY(routing,
i, x, y, z));
1406 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_NY(routing,
i, x, y, z),
RT_STEPUP_NY(routing,
i, x, y, z));
1409 FS_Printf(&f,
"%3i-%3i ",
RT_CONN_PX_NY(routing,
i, x, y, z),
RT_STEPUP_PX_NY(routing,
i, x, y, z));
1430 int RT_DebugSpecial (
mapTiles_t*
mapTiles,
Routing& routing,
const int actorSize,
const int x,
const int y,
const int dir,
const char** list)
1432 RoutingData rtd(mapTiles, routing, actorSize, list);
1435 const int ax = x +
dvecs[dir][0];
1436 const int ay = y + dvecs[dir][1];
1450 Com_Printf(
"data at cursor XYZ(%i, %i, %i) Floor(%i) Ceiling(%i)\n", x, y, z,
1451 routing.
getFloor(actorSize, x, y, z),
1453 Com_Printf(
"connections ortho: (PX=%i, NX=%i, PY=%i, NY=%i))\n",
1458 Com_Printf(
"connections diago: (PX_PY=%i, NX_NY=%i, NX_PY=%i, PX_NY=%i))\n",
1463 Com_Printf(
"stepup ortho: (PX=%i, NX=%i, PY=%i, NY=%i))\n",
#define PATHFINDING_MIN_STEPUP
#define SizedPosToVec(p, actorSize, v)
SizedPosToVect locates the center of an actor based on size and position.
An 'opening' describes the connection between two adjacent spaces where an actor can exist in a cell...
#define VectorCopy(src, dest)
#define PATHFINDING_BIG_STEPDOWN
void Sys_Error(const char *error,...)
#define VectorSet(v, x, y, z)
void setCeiling(const actorSizeEnum_t actorSize, const int x, const int y, const int z, const int val)
#define ModelCeilingToQuant(x)
void setFloor(const int actorSize, const int x, const int y, const int z, const int val)
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
static void RT_TracePassage(RoutingData *rtd, const int x, const int y, const int z, const int ax, const int ay, opening_t *opening)
Performs traces to find a passage between two points.
#define RT_STEPUP_PY(r, actorSize, x, y, z)
#define RT_CONN_PX_PY(r, actorSize, x, y, z)
void RT_WriteCSVFiles(const Routing &routing, const char *baseFilename, const GridBox &box)
static int RT_TraceOnePassage(RoutingData *rtd, const place_t *from, const place_t *to, opening_t *opening)
Performs traces to find a passage between two points given an upper and lower bound.
#define RT_CONN_NY(r, actorSize, x, y, z)
static int RT_FillPassageData(RoutingData *rtd, const int dir, const int x, const int y, const int z, const int openingSize, const int openingBase, const int stepup)
Performs traces to find a passage between two points given an upper and lower bound.
#define RT_CONN_NX_PY(r, actorSize, x, y, z)
#define RT_CONN_PX_NY(r, actorSize, x, y, z)
#define RT_STEPUP_PX_NY(r, actorSize, x, y, z)
struct opening_s opening_t
An 'opening' describes the connection between two adjacent spaces where an actor can exist in a cell...
void setFilled(const actorSizeEnum_t actorSize, const int x, const int y, const int lowZ, const int highZ)
#define RT_STEPUP_NX_NY(r, actorSize, x, y, z)
const vec4_t dvecs[PATHFINDING_DIRECTIONS]
static void RT_StepupSet(RoutingData *rtd, const int x, const int y, const int z, const int dir, const int val)
static int RT_FindOpeningCeiling(const RoutingData *rtd, const vec3_t start, const vec3_t end, const int startingHeight, const int ceilLimit)
Performs traces to find the approximate ceiling of a passage.
void set(const AABB &other)
Copies the values from the given aabb.
void Com_Printf(const char *const fmt,...)
A 'place' is a part of a grid column where an actor can exist Unlike for a grid-cell, floor and ceiling are absolute values.
#define RT_STEPUP_PX_PY(r, actorSize, x, y, z)
void setStepup(const int actorSize, const int x, const int y, const int z, const int dir, const int val)
#define ACTOR_MAX_HEIGHT
The tallest actor's height in QUANT sized units.
#define CELL_HEIGHT
A cell's height in QUANT sized units.
static int RT_TraceOpening(const RoutingData *rtd, const vec3_t start, const vec3_t end, const int ax, const int ay, const int bottom, const int top, int lo, int hi, int *foundLow, int *foundHigh)
Performs actual trace to find a passage between two points given an upper and lower bound...
static int RT_MicroTrace(RoutingData *rtd, const place_t *from, const int ax, const int ay, const int az, const int stairwaySituation, opening_t *opening)
Performs small traces to find places when an actor can step up.
static void RT_PlaceInit(const Routing &routing, const actorSizeEnum_t actorSize, place_t *p, const int x, const int y, const int z)
void UFO_assert(bool condition, const char *fmt,...)
static trace_t RT_ObstructedTrace(const RoutingData *rtd, const Line &traceLine, int hi, int lo)
Helper function to trace for walls.
static const AABB footBox(-halfMicrostepSize,-halfMicrostepSize, 0, halfMicrostepSize, halfMicrostepSize, 0)
#define PATHFINDING_WIDTH
absolute max
#define RT_CONN_PX(r, actorSize, x, y, z)
Some macros to access routing table values as described above.
#define RT_STEPUP_NX(r, actorSize, x, y, z)
#define PATHFINDING_MAX_STEPUP
actorSizeEnum_t actorSize
#define RT_CONN_PY(r, actorSize, x, y, z)
bool RT_AllCellsBelowAreFilled(const Routing &routing, const int actorSize, const pos3_t pos)
Check if pos is on solid ground.
#define VecToPos(v, p)
Map boundary is +/- MAX_WORLD_WIDTH - to get into the positive area we add the possible max negative ...
signed char getFloor(const actorSizeEnum_t actorSize, const pos3_t pos) const
#define PosToVec(p, v)
Pos boundary size is +/- 128 - to get into the positive area we add the possible max negative value a...
int FS_Printf(qFILE *f, const char *msg,...)
Can print chunks for 1024 chars into a file.
#define PATHFINDING_MICROSTEP_SKIP
The number of microsteps that can be stepped over by an actor. Used to allow an actor to stepup when ...
RoutingData(mapTiles_t *mapTiles, Routing &r, actorSizeEnum_t actorSize, const char **list)
#define VectorInterpolation(p1, p2, frac, mid)
static int RT_CalcNewZ(const RoutingData *rtd, const int ax, const int ay, const int top, const int hi)
#define PATHFINDING_MICROSTEP_SIZE
The size (in model units) of a microstep. Must be a power of 2 and less than UNIT_SIZE.
byte getCeiling(const int actorSize, const pos3_t pos) const
grid pathfinding and routing
static int RT_FindOpeningFloorFrac(const RoutingData *rtd, const vec3_t start, const vec3_t end, const float frac, const int startingHeight)
Performs a trace to find the floor of a passage a fraction of the way from start to end...
static int RT_FindOpening(RoutingData *rtd, const place_t *from, const int ax, const int ay, const int bottom, const int top, int *foundLow, int *foundHigh)
Performs traces to find a passage between two points given an upper and lower bound.
#define ModelFloorToQuant(x)
These macros are meant to correctly convert from model units to QUANT units and back.
#define RT_STEPUP_PX(r, actorSize, x, y, z)
static bool RT_PlaceDoesIntersectEnough(const place_t *p, const place_t *other)
#define RT_CONN_NX_NY(r, actorSize, x, y, z)
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.
struct place_s place_t
A 'place' is a part of a grid column where an actor can exist Unlike for a grid-cell, floor and ceiling are absolute values.
#define PATHFINDING_HEIGHT
15 max, adjusting above 8 will require a rewrite to the DV code
#define VectorAdd(a, b, dest)
#define PATHFINDING_LEGROOMHEIGHT
#define PATHFINDING_MIN_OPENING
#define RT_STEPUP_NY(r, actorSize, x, y, z)
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
#define PATHFINDING_BIG_STEPUP
The home of the routing tables.
void setConn(const int actorSize, const int x, const int y, const int z, const int dir, const int val)
static int RT_UpdateConnection(RoutingData *rtd, const int x, const int y, const int ax, const int ay, const int z, const int dir)
Routing Function to update the connection between two fields.
void RT_GetMapSize(mapTiles_t *mapTiles, AABB &mapBox)
Calculate the map size via model data and store grid size in map_min and map_max. This is done with e...
static const AABB actor2x2Box(-half2x2Width,-half2x2Width, 0, half2x2Width, half2x2Width, 0)
#define RT_CONN_NX(r, actorSize, x, y, z)
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 ...
definitions common between client and server, but not game lib
void shift(const vec3_t shiftVec)
shove the whole box by the given vector
static void RT_ConnSetNoGo(RoutingData *rtd, const int x, const int y, const int z, const int dir)
#define PATHFINDING_NO_STEPUP
RT_data_s contains the essential data that is passed to most of the RT_* functions.
#define RT_STEPUP_NX_PY(r, actorSize, x, y, z)
static int RT_PlaceIsShifted(const place_t *p, const place_t *other)
This function detects a special stairway situation, where one place is right in front of a stairway a...
static const AABB actor1x1Box(-half1x1Width,-half1x1Width, 0, half1x1Width, half1x1Width, 0)
static int RT_FindOpeningCeilingFrac(const RoutingData *rtd, const vec3_t start, const vec3_t end, const float frac, const int startingHeight)
Performs a trace to find the ceiling of a passage a fraction of the way from start to end...
#define ACTOR_SIZE_NORMAL
bool RT_CanActorStandHere(const Routing &routing, const int actorSize, const pos3_t pos)
Check if an actor can stand(up) in the cell given by pos.
#define ACTOR_SIZE_INVALID
#define TRACE_VISIBLE_LEVELS
#define PLAYER_STANDING_HEIGHT
#define halfMicrostepSize
#define VectorSubtract(a, b, dest)
static mapTiles_t mapTiles
bool isUsable(void) const
static int RT_FindOpeningFloor(const RoutingData *rtd, const vec3_t start, const vec3_t end, const int startingHeight, const int floorLimit)
Performs traces to find the approximate floor of a passage.