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. 113 typedef struct place_s {
164 typedef struct opening_s {
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);
422 if (
tr.fraction >= 1.0) {
423 routing.
setFilled(actorSize, x, y, 0, z);
428 bottom =
tr.endpos[2];
431 assert(initial > bottom);
442 if (
tr.fraction < 1.0) {
458 if (
tr.fraction < 1.0) {
474 tstart[2] = box.
maxs[2];
478 tr = RT_COMPLETEBOXTRACE_PASSAGE(
mapTiles,
Line(tstart, tend), &ceilBox, list);
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++) {
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);
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)
777 if (
tr.fraction >= 1.0) {
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) {
1263 if (absCeiling < absAdjFloor || absExtAdjCeiling < absFloor) {
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++) {
1337 sprintf(ext,
".%i.elevation.csv",
i);
1352 FS_Printf(&
f,
"h:%i c:%i,", routing.
getFloor(
i, x, y, z), routing.
getCeiling(
i, x, y, z));
1363 sprintf(ext,
".%i.walls.csv",
i);
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)
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.
#define VectorCopy(src, dest)
#define PATHFINDING_BIG_STEPDOWN
void Sys_Error(const char *error,...)
#define VectorSet(v, x, y, z)
#define ModelCeilingToQuant(x)
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
actorSizeEnum_t actorSize
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 setFilled(const actorSizeEnum_t actorSize, const int x, const int y, const int lowZ, const int highZ)
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)
#define RT_STEPUP_NX_NY(r, actorSize, x, y, z)
const vec4_t dvecs[PATHFINDING_DIRECTIONS]
bool isUsable(void) const
An 'opening' describes the connection between two adjacent spaces where an actor can exist in a cell...
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 Com_Printf(const char *const fmt,...)
void setFloor(const int actorSize, const int x, const int y, const int z, const int val)
static const AABB actor1x1Box(-half1x1Width, -half1x1Width, 0, half1x1Width, half1x1Width, 0)
#define RT_STEPUP_PX_PY(r, actorSize, x, y, z)
#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.
#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
void set(const AABB &other)
Copies the values from the given aabb.
void setStepup(const int actorSize, const int x, const int y, const int z, const int dir, const int val)
byte getCeiling(const int actorSize, const pos3_t pos) const
#define RT_CONN_PY(r, actorSize, x, y, z)
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.
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 ...
#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 ...
#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.
void shift(const vec3_t shiftVec)
shove the whole box by the given vector
void setConn(const int actorSize, const int x, const int y, const int z, const int dir, const int val)
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)
static const AABB actor2x2Box(-half2x2Width, -half2x2Width, 0, half2x2Width, half2x2Width, 0)
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.
#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.
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 footBox(-halfMicrostepSize, -halfMicrostepSize, 0, halfMicrostepSize, halfMicrostepSize, 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
static void RT_ConnSetNoGo(RoutingData *rtd, const int x, const int y, const int z, const int dir)
#define PATHFINDING_NO_STEPUP
RoutingData(mapTiles_t *mapTiles, Routing &r, actorSizeEnum_t actorSize, const char **list)
#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 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
void setCeiling(const actorSizeEnum_t actorSize, const int x, const int y, const int z, const int val)
signed char getFloor(const actorSizeEnum_t actorSize, const pos3_t pos) const
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)
RT_data_s contains the essential data that is passed to most of the RT_* functions.
static mapTiles_t mapTiles
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.