Пример #1
0
/**
 * @brief Calculate the TUs after we in the given dir
 * @param[in] path Pointer to client or server side pathing table (clPathMap, svPathMap)
 */
void Step::calcNewTUs (const pathing_t *path)
{
	const byte TUsSoFar = RT_AREA_POS(path, fromPos, crouchingState);
	/* Find the number of TUs used (normally) to move in this direction. */
	const byte TUsForMove = Grid_GetTUsForDirection(dir, crouchingState);

	/* Now add the TUs needed to get to the originating cell. */
	TUsAfter = TUsSoFar + TUsForMove;
}
Пример #2
0
/**
 * @brief Return the needed TUs to walk to a given position
 * @param[in] path Pointer to client or server side pathing table (clPathMap, svPathMap)
 * @param[in] to Position to walk to
 * @param[in] crouchingState Whether the actor is currently crouching, 1 is yes, 0 is no.
 * @param[in] stored Use the stored mask (the cached move) of the routing data
 * @return ROUTING_NOT_REACHABLE if the move isn't possible
 * @return length of move otherwise (TUs)
 */
pos_t Grid_MoveLength (const pathing_t *path, const pos3_t to, byte crouchingState, bool stored)
{
	/* Confirm bounds */
	assert(to[2] < PATHFINDING_HEIGHT);
	assert(crouchingState == 0 || crouchingState == 1);	/* s.a. ACTOR_MAX_STATES */

	if (!stored)
		return RT_AREA_POS(path, to, crouchingState);
	else
		return RT_SAREA(path, to[0], to[1], to[2], crouchingState);
}
Пример #3
0
static void Grid_SetMoveData (pathing_t *path, const pos3_t toPos, const int c, const byte length, const int dir, const int oz, const int oc, priorityQueue_t *pqueue)
{
	pos4_t dummy;

	RT_AREA_TEST_POS(path, toPos, c);
	RT_AREA_POS(path, toPos, c) = length;	/**< Store TUs for this square. */
	RT_AREA_FROM_POS(path, toPos, c) = makeDV(dir, oz); /**< Store origination information for this square. */

	Vector4Set(dummy, toPos[0], toPos[1], toPos[2], c);
	/** @todo add heuristic for A* algorithm */
	PQueuePush(pqueue, dummy, length);
}
Пример #4
0
/**
 * @brief Get the direction to use to move to a position (used to reconstruct the path)
 * @param[in] path Pointer to client or server side pathing table (le->PathMap, svPathMap)
 * @param[in] toPos The desired location
 * @param[in] crouchingState Whether the actor is currently crouching, 1 is yes, 0 is no.
 * @return a direction vector (see dvecs and DIRECTIONS)
 * @sa Grid_MoveCheck
 */
int Grid_MoveNext (const pathing_t *path, const pos3_t toPos, byte crouchingState)
{
	const pos_t l = RT_AREA_POS(path, toPos, crouchingState); /**< Get TUs for this square */

	/* Check to see if the TUs needed to move here are greater than 0 and less then ROUTING_NOT_REACHABLE */
	if (!l || l == ROUTING_NOT_REACHABLE) {
		/* ROUTING_UNREACHABLE means, not possible/reachable */
		return ROUTING_UNREACHABLE;
	}

	/* Return the information indicating how the actor got to this cell */
	return RT_AREA_FROM_POS(path, toPos, crouchingState);
}
Пример #5
0
/**
 * @brief Return the needed TUs to walk to a given position
 * @param[in] path Pointer to client or server side pathing table (clPathMap, svPathMap)
 * @param[in] to Position to walk to
 * @param[in] crouchingState Whether the actor is currently crouching, 1 is yes, 0 is no.
 * @param[in] stored Use the stored mask (the cached move) of the routing data
 * @return ROUTING_NOT_REACHABLE if the move isn't possible
 * @return length of move otherwise (TUs)
 */
pos_t Grid_MoveLength (const pathing_t *path, const pos3_t to, byte crouchingState, qboolean stored)
{
#ifdef PARANOID
	if (to[2] >= PATHFINDING_HEIGHT) {
		Com_DPrintf(DEBUG_PATHING, "Grid_MoveLength: WARNING to[2] = %i(>= HEIGHT)\n", to[2]);
		return ROUTING_NOT_REACHABLE;
	}
#endif
	/* Confirm bounds */
	assert(to[2] < PATHFINDING_HEIGHT);
	assert(crouchingState == 0 || crouchingState == 1);	/* s.a. ACTOR_MAX_STATES */

	if (!stored)
		return RT_AREA_POS(path, to, crouchingState);
	else
		return RT_SAREA(path, to[0], to[1], to[2], crouchingState);
}
Пример #6
0
/**
 * @brief Checks if a crouched actor could save TUs by standing up, walking and crouching again.
 * @param[in] path Pointer to client or server side pathing table
 * @param[in] toPos Desired position
 */
bool Grid_ShouldUseAutostand (const pathing_t *path, const pos3_t toPos)
{
	const int tusCrouched = RT_AREA_POS(path, toPos, 1);
	const int tusUpright = RT_AREA_POS(path, toPos, 0);
	return tusUpright + 2 * TU_CROUCH < tusCrouched;
}
Пример #7
0
/**
 * @brief Tries to find a path from the given actor(-position) to a given target position
 *
 * Unlike Grid_CalcPathing, this function does not neccessarily calculate the TU values for
 * all positions reachable from 'from'. Instead it tries to find the shortest/fastest path to
 * the target position. There is no limit to maxTUs.
 *
 * @param[in] routing Reference to client or server side routing table (clMap, svMap)
 * @param[in] actorSize The size of thing to calc the move for (e.g. size=2 means 2x2).
 * The plan is to have the 'origin' in 2x2 units in the bottom-left (towards the lower coordinates) corner of the 2x2 square.
 * @param[in,out] path Pointer to client or server side pathing table (clMap, svMap)
 * @param[in] from The position to start the calculation from.
 * @param[in] targetPos The position where we want to end up.
 * @param[in] maxTUs The maximum TUs away from 'from' to calculate move-information for
 * @param[in] crouchingState Whether the actor is currently crouching, 1 is yes, 0 is no.
 * @param[in] fb_list Forbidden list (entities are standing at those points)
 * @param[in] fb_length Length of forbidden list
 * @sa G_MoveCalc
 * @sa CL_ConditionalMoveCalc
 */
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, byte ** fb_list, int fb_length)
{
	bool found = false;
	int count;
	priorityQueue_t pqueue;
	pos4_t epos; /**< Extended position; includes crouching state */
	pos3_t pos;
	/* this is the position of the current actor- so the actor can stand in the cell it is in when pathfinding */
	pos3_t excludeFromForbiddenList;

	/* Confirm bounds */
	assert((from[2]) < PATHFINDING_HEIGHT);
	assert(crouchingState == 0 || crouchingState == 1);	/* s.a. ACTOR_MAX_STATES */

	/* reset move data */
	OBJSET(path->area,     ROUTING_NOT_REACHABLE);
	OBJSET(path->areaFrom, ROUTING_NOT_REACHABLE);
	path->fblist = fb_list;
	path->fblength = fb_length;

	/* Prepare exclusion of starting-location (i.e. this should be ent-pos or le-pos) in Grid_CheckForbidden */
	VectorCopy(from, excludeFromForbiddenList);
	/* set starting position to 0 TUs.*/
	RT_AREA_POS(path, from, crouchingState) = 0;

	PQueueInitialise(&pqueue, 1024);
	Vector4Set(epos, from[0], from[1], from[2], crouchingState);
	PQueuePush(&pqueue, epos, 0);

	count = 0;
	while (!PQueueIsEmpty(&pqueue)) {
		PQueuePop(&pqueue, epos);
		VectorCopy(epos, pos);
		count++;

		/* if reaching that square already took too many TUs,
		 * don't bother to reach new squares *from* there. */
		const byte usedTUs = RT_AREA_POS(path, pos, crouchingState);
		if (usedTUs >= maxTUs)
			continue;

		for (int dir = 0; dir < PATHFINDING_DIRECTIONS; dir++) {
			Step step(routing, pos, actorSize, crouchingState, dir);
			/* Directions 12, 14, and 15 are currently undefined. */
			if (dir == 12 || dir == 14 || dir == 15)
				continue;
			/* If this is a crouching or crouching move, forget it. */
			if (dir == DIRECTION_STAND_UP || dir == DIRECTION_CROUCH)
				continue;

			if (!step.init())
				continue;		/* either dir is irrelevant or something worse happened */

			if (!step.isPossible(path))
				continue;

			/* Is this a better move into this cell? */
			RT_AREA_TEST_POS(path, step.toPos, step.crouchingState);
			if (RT_AREA_POS(path, step.toPos, step.crouchingState) <= step.TUsAfter) {
				continue;	/* This move is not optimum. */
			}

			/* Test for forbidden (by other entities) areas. */
			/* Do NOT check the forbiddenList. We might find a multi-turn path. */
#if 0
			if (Grid_CheckForbidden(excludeFromForbiddenList, step.actorSize, path, step.toPos[0], step.toPos[1], step.toPos[2])) {
				continue;		/* That spot is occupied. */
			}
#endif

			/* Store move in pathing table. */
			Grid_SetMoveData(path, step.toPos, step.crouchingState, step.TUsAfter, step.dir, step.fromPos[2]);

			pos4_t dummy;
			const int dist = step.TUsAfter + (int) (2 * VectorDist(step.toPos, targetPos));
			Vector4Set(dummy, step.toPos[0], step.toPos[1], step.toPos[2], step.crouchingState);
			PQueuePush(&pqueue, dummy, dist);

			if (VectorEqual(step.toPos, targetPos)) {
				found = true;
				break;
			}
		}
		if (found)
			break;
	}
	/* Com_Printf("Loop: %i", count); */
	PQueueFree(&pqueue);
	return found;
}
Пример #8
0
/**
 * @brief Recalculate the pathing table for the given actor(-position)
 *
 * We calculate the table for ALL possible movement states (atm stand and crouch)
 * to be able to propose smart things like autostand.
 * @param[in] routing Reference to client or server side routing table (clMap, svMap)
 * @param[in] actorSize The size of thing to calc the move for (e.g. size=2 means 2x2).
 * The plan is to have the 'origin' in 2x2 units in the bottom-left (towards the lower coordinates) corner of the 2x2 square.
 * @param[in,out] path Pointer to client or server side pathing table (clMap, svMap)
 * @param[in] from The position to start the calculation from.
 * @param[in] maxTUs The maximum TUs away from 'from' to calculate move-information for
 * @param[in] fb_list Forbidden list (entities are standing at those points)
 * @param[in] fb_length Length of forbidden list
 * @sa G_MoveCalc
 * @sa CL_ConditionalMoveCalc
 */
void Grid_CalcPathing (const Routing &routing, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t from, int maxTUs, byte ** fb_list, int fb_length)
{
	priorityQueue_t pqueue;
	pos4_t epos; /**< Extended position; includes crouching state */
	pos3_t pos;
	int amst; /* acronym for actor movement state */
	/* this is the position of the current actor- so the actor can stand in the cell it is in when pathfinding */
	pos3_t excludeFromForbiddenList;

	/* Confirm bounds */
	assert((from[2]) < PATHFINDING_HEIGHT);

	/* reset move data */
	OBJSET(path->area,     ROUTING_NOT_REACHABLE);
	OBJSET(path->areaFrom, ROUTING_NOT_REACHABLE);
	path->fblist = fb_list;
	path->fblength = fb_length;

	maxTUs = std::min(maxTUs, MAX_ROUTE_TUS);

	/* Prepare exclusion of starting-location (i.e. this should be ent-pos or le-pos) in Grid_CheckForbidden */
	VectorCopy(from, excludeFromForbiddenList);

	for (amst = 0; amst < ACTOR_MAX_STATES; amst++) {
		/* set starting position to 0 TUs.*/
		RT_AREA_POS(path, from, amst) = 0;

		PQueueInitialise(&pqueue, 1024);
		Vector4Set(epos, from[0], from[1], from[2], amst);
		PQueuePush(&pqueue, epos, 0);

		int count = 0;
		while (!PQueueIsEmpty(&pqueue)) {
			int dir;
			PQueuePop(&pqueue, epos);
			VectorCopy(epos, pos);
			count++;

			/* if reaching that square already took too many TUs,
			 * don't bother to reach new squares *from* there. */
			const byte usedTUs = RT_AREA_POS(path, pos, amst);
			if (usedTUs >= maxTUs)
				continue;

			for (dir = 0; dir < PATHFINDING_DIRECTIONS; ++dir) {
				Step step(routing, pos, actorSize, amst, dir);
				/* Directions 12, 14, and 15 are currently undefined. */
				if (dir == 12 || dir == 14 || dir == 15)
					continue;
				/* If this is a crouching or crouching move, forget it. */
				if (dir == DIRECTION_STAND_UP || dir == DIRECTION_CROUCH)
					continue;

				if (!step.init())
					continue; /* either dir is irrelevant or something worse happened */

				if (step.isPossible(path)) {
					/* Is this a better move into this cell? */
					RT_AREA_TEST_POS(path, step.toPos, step.crouchingState);
					if (RT_AREA_POS(path, step.toPos, step.crouchingState) <= step.TUsAfter) {
						continue; /* This move is not optimum. */
					}

					/* Test for forbidden (by other entities) areas. */
					if (Grid_CheckForbidden(excludeFromForbiddenList, step.actorSize, path, step.toPos[0],
							step.toPos[1], step.toPos[2])) {
						continue; /* That spot is occupied. */
					}

					/* Store move in pathing table. */
					Grid_SetMoveData(path, step.toPos, step.crouchingState, step.TUsAfter, step.dir, step.fromPos[2]);

					pos4_t dummy;
					Vector4Set(dummy, step.toPos[0], step.toPos[1], step.toPos[2], step.crouchingState);
					PQueuePush(&pqueue, dummy, step.TUsAfter);
				}
			}
		}
		/* Com_Printf("Loop: %i", count); */
		PQueueFree(&pqueue);
	}
}
Пример #9
0
/**
 * @brief Checks if we can walk in the given direction
 * First test for opening height availability. Then test for stepup compatibility. Last test for fall.
 * @note Fliers use this code only when they are walking.
 * @param[in] path Pointer to client or server side pathing table (clPathMap, svPathMap)
 * @return false if we can't fly there
 */
bool Step::checkWalkingDirections (const pathing_t *path)
{
	int nx, ny, nz;
	int passageHeight;
	/** @todo falling_height should be replaced with an arbitrary max falling height based on the actor. */
	const int fallingHeight = PATHFINDING_MAX_FALL;/**<This is the maximum height that an actor can fall. */
	const int stepupHeight = routing.getStepupHeight(actorSize, fromPos[0], fromPos[1], fromPos[2], dir);		/**< The actual stepup height without the level flags */
	int heightChange;
	/** @todo actor_stepup_height should be replaced with an arbitrary max stepup height based on the actor. */
	int actorStepupHeight = PATHFINDING_MAX_STEPUP;

	/* This is the standard passage height for all units trying to move horizontally. */
	passageHeight = routing.getConn(actorSize, fromPos, dir);
	if (passageHeight < actorHeight) {
#if 0
/** I know this code could be streamlined, but until I understand it myself, plz leave it like it is !*/
		int dvFlagsNew = 0;
		if (!crouchingState									/* not in std crouch mode */
		 && passageHeight >= actorCrouchedHeight) {			/* and passage is tall enough for crouching ? */
															/* we should try autocrouching */
			int dvFlagsOld = getDVflags(RT_AREA_POS(path, fromPos, crouchingState));
			int toHeight = routing.getCeiling(actorSize, toPos) - routing.getFloor(actorSize, toPos);
			int tuCr = Grid_GetTUsForDirection(dir, 1);		/* 1 means crouched */
			int newTUs = 0;

			if (toHeight >= actorHeight) {					/* can we stand in the new cell ? */
				if ((dvFlagsOld & DV_FLAG_AUTOCROUCH)		/* already in auto-crouch mode ? */
				 || (dvFlagsOld & DV_FLAG_AUTOCROUCHED)) {
					dvFlagsNew |= DV_FLAG_AUTOCROUCHED;		/* keep that ! */
					newTUs = tuCr + TU_CROUCH;				/* TUs for crouching plus getting up */
				}
				else {
					dvFlagsNew |= DV_FLAG_AUTODIVE;
					newTUs = tuCr + 2 * TU_CROUCH;			/* TUs for crouching plus getting down and up */
				}
			}
			else {											/* we can't stand there */
				if (dvFlagsOld & DV_FLAG_AUTOCROUCHED) {
					dvFlagsNew |= DV_FLAG_AUTOCROUCHED;		/* keep that ! */
					newTUs = tuCr;							/* TUs just for crouching */
				}
				else {
					dvFlagsNew |= DV_FLAG_AUTOCROUCH;		/* get down ! */
					newTUs = tuCr + TU_CROUCH;				/* TUs for crouching plus getting down */
				}
			}
		}
		else
#endif
			return false;	/* Passage is not tall enough. */
	}

	/* If we are moving horizontally, use the stepup requirement of the floors.
	 * The new z coordinate may need to be adjusted from stepup.
	 * Also, actor_stepup_height must be at least the cell's positive stepup value to move that direction. */
	/* If the actor cannot reach stepup, then we can't go this way. */
	if (actorStepupHeight < stepupHeight) {
		return false;	/* Actor cannot stepup high enough. */
	}

	nx = toPos[0];
	ny = toPos[1];
	nz = toPos[2];

	if (routing.isStepUpLevel(actorSize, fromPos, dir) && toPos[2] < PATHFINDING_HEIGHT - 1) {
		toPos[2]++;
		/**
		 * @note If you need to know about how pathfinding works,  you need to understand the
		 * following brief.  It may cause nausea, but is an important concept.
		 *
		 * @brief OK, now some crazy tests:
		 * Because of the grid based nature of this game, each cell can have at most only ONE
		 * floor that can be stood upon.  If an actor can walk down a slope that is in the
		 * same level, and actor should be able to walk on (and not fall into) the slope that
		 * decends a game level.  BUT it is possible for an actor to be able to crawl under a
		 * floor that can be stood on, with this opening being in the same cell as the floor.
		 * SO to prevent any conflicts, we will move down a floor under the following conditions:
		 * - The STEPDOWN flag is set
		 * - The floor in the immediately adjacent cell is lower than the current floor, but not
		 *   more than CELL_HEIGHT units (in QUANT units) below the current floor.
		 * - The actor's stepup value is at least the inverse stepup value.  This is the stepup
		 *   FROM the cell we are moving towards back into the cell we are starting in.  This
		 *    ensures that the actor can actually WALK BACK.
		 * If the actor does not have a high enough stepup but meets all the other requirements to
		 * descend the level, the actor will move into a fall state, provided that there is no
		 * floor in the adjacent cell.
		 *
		 * This will prevent actors from walking under a floor in the same cell in order to fall
		 * to the floor beneath.  They will need to be able to step down into the cell or will
		 * not be able to use the opening.
		 */
	} else if (routing.isStepDownLevel(actorSize, fromPos, dir) && toPos[2] > 0
		&& actorStepupHeight >= routing.getStepupHeight(actorSize, nx, ny, nz - 1, dir ^ 1)) {
		toPos[2]--;		/* Stepping down into lower cell. */
	}

	heightChange = routing.getFloor(actorSize, toPos) - routing.getFloor(actorSize, fromPos) + (toPos[2] - fromPos[2]) * CELL_HEIGHT;

	/* If the actor tries to fall more than falling_height, then prohibit the move. */
	if (heightChange < -fallingHeight && !hasLadderSupport) {
		return false;		/* Too far a drop without a ladder. */
	}

	/* If we are walking normally, we can fall if we move into a cell that does not
	 * have its STEPDOWN flag set and has a negative floor:
	 * Set heightChange to 0.
	 * The actor enters the cell.
	 * The actor will be forced to fall (dir 13) from the destination cell to the cell below. */
	if (routing.getFloor(actorSize, toPos) < 0) {
		/* We cannot fall if STEPDOWN is defined. */
		if (routing.isStepDownLevel(actorSize, fromPos, dir)) {
			return false;		/* There is stepdown from here. */
		}
		heightChange = 0;
		toPos[2]--;
	}
	return true;
}
Пример #10
0
static void Grid_SetMoveData (pathing_t *path, const pos3_t toPos, const int crouch, const byte length, const int dir, const int oldZ)
{
	RT_AREA_TEST_POS(path, toPos, crouch);
	RT_AREA_POS(path, toPos, crouch) = length;	/**< Store TUs for this square. */
	RT_AREA_FROM_POS(path, toPos, crouch) = makeDV(dir, oldZ); /**< Store origination information for this square. */
}
Пример #11
0
/**
 * @brief Recalculate the pathing table for the given actor(-position)
 * @param[in] map Pointer to client or server side routing table (clMap, svMap)
 * @param[in] actorSize The size of thing to calc the move for (e.g. size=2 means 2x2).
 * The plan is to have the 'origin' in 2x2 units in the bottom-left (towards the lower coordinates) corner of the 2x2 square.
 * @param[in,out] path Pointer to client or server side pathing table (clMap, svMap)
 * @param[in] from The position to start the calculation from.
 * @param[in] distance The maximum TUs away from 'from' to calculate move-information for
 * @param[in] crouchingState Whether the actor is currently crouching, 1 is yes, 0 is no.
 * @param[in] fb_list Forbidden list (entities are standing at those points)
 * @param[in] fb_length Length of forbidden list
 * @sa Grid_MoveMark
 * @sa G_MoveCalc
 * @sa CL_ConditionalMoveCalc
 */
void Grid_MoveCalc (const routing_t *map, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t from, byte crouchingState, int distance, byte ** fb_list, int fb_length)
{
	int dir;
	int count;
	priorityQueue_t pqueue;
	pos4_t epos; /**< Extended position; includes crouching state */
	pos3_t pos;
	/* this is the position of the current actor- so the actor can stand in the cell it is in when pathfinding */
	pos3_t excludeFromForbiddenList;

	/* reset move data */
	OBJSET(path->area,     ROUTING_NOT_REACHABLE);
	OBJSET(path->areaFrom, ROUTING_NOT_REACHABLE);
	path->fblist = fb_list;
	path->fblength = fb_length;

	if (distance > MAX_ROUTE + 3)	/* +3 is added to calc at least one square (diagonal) more */
		distance = MAX_ROUTE + 3;	/* and later show one step beyond the walkable path in red */

	/* Prepare exclusion of starting-location (i.e. this should be ent-pos or le-pos) in Grid_CheckForbidden */
	VectorCopy(from, excludeFromForbiddenList);

	PQueueInitialise(&pqueue, 1024);
	Vector4Set(epos, from[0], from[1], from[2], crouchingState);
	PQueuePush(&pqueue, epos, 0);

	/* Confirm bounds */
	assert((from[2]) < PATHFINDING_HEIGHT);
	assert(crouchingState == 0 || crouchingState == 1);	/* s.a. ACTOR_MAX_STATES */

	/* set starting position to 0 TUs.*/
	RT_AREA_POS(path, from, crouchingState) = 0;

	Com_DPrintf(DEBUG_PATHING, "Grid_MoveCalc: Start at (%i %i %i) c:%i\n", from[0], from[1], from[2], crouchingState);

	count = 0;
	while (!PQueueIsEmpty(&pqueue)) {
		byte TUsSoFar;
		PQueuePop(&pqueue, epos);
		VectorCopy(epos, pos);
		count++;

		/**< if reaching that square already took too many TUs,
		 * don't bother to reach new squares *from* there. */
		TUsSoFar = RT_AREA_POS(path, pos, crouchingState);
		if (TUsSoFar >= distance || TUsSoFar >= MAX_MOVELENGTH)
			continue;

		for (dir = 0; dir < PATHFINDING_DIRECTIONS; dir++) {
			/* Directions 12, 14, and 15 are currently undefined. */
			if (dir == 12 || dir == 14 || dir == 15)
				continue;
			/* If this is a crouching or crouching move, forget it. */
			if (dir == DIRECTION_STAND_UP || dir == DIRECTION_CROUCH)
				continue;

			Grid_MoveMark(map, excludeFromForbiddenList, actorSize, path, pos, epos[3], dir, &pqueue);
		}
	}
	/* Com_Printf("Loop: %i", count); */
	PQueueFree(&pqueue);

	Com_DPrintf(DEBUG_PATHING, "Grid_MoveCalc: Done\n\n");
}
Пример #12
0
/**
 * @param[in] map Pointer to client or server side routing table (clMap, svMap)
 * @param[in] exclude Exclude this position from the forbidden list check
 * @param[in] actorSize Give the field size of the actor (e.g. for 2x2 units) to check linked fields as well.
 * @param[in,out] path Pointer to client or server side pathing table (clMap, svMap)
 * @param[in] pos Current location in the map.
 * @param[in] crouchingState Whether the actor is currently crouching, 1 is yes, 0 is no.
 * @param[in] dir Direction vector index (see DIRECTIONS and dvecs)
 * @param[in,out] pqueue Priority queue (heap) to insert the now reached tiles for reconsidering
 * @sa Grid_CheckForbidden
 */
static void Grid_MoveMark (const routing_t *map, const pos3_t exclude, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t pos, byte crouchingState, const int dir, priorityQueue_t *pqueue)
{
	step_t step_;
	step_t *step = &step_;	/* temporary solution */
	pos3_t toPos;
	byte TUsSoFar, TUsForMove, TUsAfter;

	if (!Grid_StepInit(step, map, actorSize, crouchingState, dir))
		return;		/* either dir is irrelevant or something worse happened */

	TUsSoFar = RT_AREA_POS(path, pos, crouchingState);
	/* Find the number of TUs used (normally) to move in this direction. */
	TUsForMove = Grid_GetTUsForDirection(dir, crouchingState);

	/* calculate the position we would normally end up if moving in the given dir. */
	if (!Grid_StepCalcNewPos(step, pos, toPos, dir)) {
		return;
	}
	/* If there is no passageway (or rather lack of a wall) to the desired cell, then return. */
	/* If the flier is moving up or down diagonally, then passage height will also adjust */
	if (dir >= FLYING_DIRECTIONS) {
		if (!Grid_StepCheckFlyingDirections(step, pos, toPos, dir)) {
			return;
		}
	} else if (dir < CORE_DIRECTIONS) {
		/** note that this function may modify toPos ! */
		if (!Grid_StepCheckWalkingDirections(step, path, pos, toPos, dir, crouchingState)) {
			return;
		}
	} else {
		/* else there is no movement that uses passages. */
		/* If we are falling, the height difference is the floor value. */
		if (!Grid_StepCheckVerticalDirections(step, pos, dir)) {
			return;
		}
	}

	/* OK, at this point we are certain of a few things:
	 * There is not a wall obstructing access to the destination cell.
	 * If the actor is not a flier, the actor will not rise more than actor_stepup_height or fall more than
	 *    falling_height, unless climbing.
	 *
	 * If the actor is a flier, as long as there is a passage, it can be moved through.
	 * There are no floor difference restrictions for fliers, only obstructions. */

	/* nz can't move out of bounds */
	if (toPos[2] >= PATHFINDING_HEIGHT)
		toPos[2] = PATHFINDING_HEIGHT - 1;

	/* Now add the TUs needed to get to the originating cell. */
	TUsAfter = TUsSoFar + TUsForMove;

	/* Is this a better move into this cell? */
	RT_AREA_TEST_POS(path, toPos, crouchingState);
	if (RT_AREA_POS(path, toPos, crouchingState) <= TUsAfter) {
		return;	/* This move is not optimum. */
	}

	/* Test for forbidden (by other entities) areas. */
	if (Grid_CheckForbidden(exclude, actorSize, path, toPos[0], toPos[1], toPos[2])) {
		return;		/* That spot is occupied. */
	}

	/* Store move. */
	if (pqueue) {
		Grid_SetMoveData(path, toPos, crouchingState, TUsAfter, dir, pos[2], crouchingState, pqueue);
	}
}