mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-28 04:51:42 +00:00
Merge branch 'circuit-pathfind' into 'master'
Circuit pathfinding See merge request KartKrew/Kart!673
This commit is contained in:
commit
89d6506b44
5 changed files with 406 additions and 238 deletions
45
src/k_bot.c
45
src/k_bot.c
|
|
@ -298,7 +298,7 @@ boolean K_BotCanTakeCut(player_t *player)
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
|
static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
|
||||||
|
|
||||||
Gets the bot's speed value, adjusted for predictions.
|
What the bot "thinks" their speed is, for predictions.
|
||||||
Mainly to make bots brake earlier when on friction sectors.
|
Mainly to make bots brake earlier when on friction sectors.
|
||||||
|
|
||||||
Input Arguments:-
|
Input Arguments:-
|
||||||
|
|
@ -312,6 +312,12 @@ static fixed_t K_BotSpeedScaled(player_t *player, fixed_t speed)
|
||||||
{
|
{
|
||||||
fixed_t result = speed;
|
fixed_t result = speed;
|
||||||
|
|
||||||
|
if (P_IsObjectOnGround(player->mo) == false)
|
||||||
|
{
|
||||||
|
// You have no air control, so don't predict too far ahead.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (player->mo->movefactor != FRACUNIT)
|
if (player->mo->movefactor != FRACUNIT)
|
||||||
{
|
{
|
||||||
fixed_t moveFactor = player->mo->movefactor;
|
fixed_t moveFactor = player->mo->movefactor;
|
||||||
|
|
@ -650,7 +656,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
||||||
const fixed_t speed = K_BotSpeedScaled(player, P_AproxDistance(player->mo->momx, player->mo->momy));
|
const fixed_t speed = K_BotSpeedScaled(player, P_AproxDistance(player->mo->momx, player->mo->momy));
|
||||||
|
|
||||||
const INT32 startDist = (DEFAULT_WAYPOINT_RADIUS * 2 * mapobjectscale) / FRACUNIT;
|
const INT32 startDist = (DEFAULT_WAYPOINT_RADIUS * 2 * mapobjectscale) / FRACUNIT;
|
||||||
const INT32 distance = ((speed / FRACUNIT) * futuresight) + startDist;
|
const INT32 maxDist = startDist * 4; // This function gets very laggy when it goes far distances, and going too far isn't very helpful anyway.
|
||||||
|
const INT32 distance = min(((speed / FRACUNIT) * futuresight) + startDist, maxDist);
|
||||||
|
|
||||||
// Halves radius when encountering a wall on your way to your destination.
|
// Halves radius when encountering a wall on your way to your destination.
|
||||||
fixed_t radreduce = FRACUNIT;
|
fixed_t radreduce = FRACUNIT;
|
||||||
|
|
@ -660,7 +667,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
||||||
angle_t angletonext = ANGLE_MAX;
|
angle_t angletonext = ANGLE_MAX;
|
||||||
INT32 disttonext = INT32_MAX;
|
INT32 disttonext = INT32_MAX;
|
||||||
|
|
||||||
waypoint_t *finishLine = K_GetFinishLineWaypoint();
|
|
||||||
waypoint_t *wp = player->nextwaypoint;
|
waypoint_t *wp = player->nextwaypoint;
|
||||||
mobj_t *prevwpmobj = player->mo;
|
mobj_t *prevwpmobj = player->mo;
|
||||||
|
|
||||||
|
|
@ -676,8 +682,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
||||||
angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y);
|
angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y);
|
||||||
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y) / FRACUNIT;
|
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y) / FRACUNIT;
|
||||||
|
|
||||||
pathfindsuccess = K_PathfindToWaypoint(
|
pathfindsuccess = K_PathfindThruCircuit(
|
||||||
player->nextwaypoint, finishLine,
|
player->nextwaypoint, (unsigned)distanceleft,
|
||||||
&pathtofinish,
|
&pathtofinish,
|
||||||
useshortcuts, huntbackwards
|
useshortcuts, huntbackwards
|
||||||
);
|
);
|
||||||
|
|
@ -720,35 +726,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
||||||
// We're done!!
|
// We're done!!
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == pathtofinish.numnodes-1 && disttonext > 0)
|
|
||||||
{
|
|
||||||
// We were pathfinding to the finish, but we want to go past it.
|
|
||||||
// Set up a new pathfind.
|
|
||||||
|
|
||||||
waypoint_t *next = NULL;
|
|
||||||
|
|
||||||
if (finishLine->numnextwaypoints == 0)
|
|
||||||
{
|
|
||||||
distanceleft = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// default to first one
|
|
||||||
next = wp->nextwaypoints[0];
|
|
||||||
|
|
||||||
pathfindsuccess = K_PathfindToWaypoint(
|
|
||||||
next, finishLine,
|
|
||||||
&pathtofinish,
|
|
||||||
useshortcuts, huntbackwards
|
|
||||||
);
|
|
||||||
|
|
||||||
if (pathfindsuccess == false)
|
|
||||||
{
|
|
||||||
distanceleft = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Z_Free(pathtofinish.array);
|
Z_Free(pathtofinish.array);
|
||||||
|
|
|
||||||
410
src/k_pathfind.c
410
src/k_pathfind.c
|
|
@ -190,6 +190,10 @@ static boolean K_PathfindSetupValid(const pathfindsetup_t *const pathfindsetup)
|
||||||
{
|
{
|
||||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL gettraversable function.\n");
|
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL gettraversable function.\n");
|
||||||
}
|
}
|
||||||
|
else if (pathfindsetup->getfinished == NULL)
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL getfinished function.\n");
|
||||||
|
}
|
||||||
else if (pathfindsetup->getconnectednodes(pathfindsetup->startnodedata, &sourcenodenumconnectednodes) == NULL)
|
else if (pathfindsetup->getconnectednodes(pathfindsetup->startnodedata, &sourcenodenumconnectednodes) == NULL)
|
||||||
{
|
{
|
||||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindSetupValid: Source node returned NULL connecting nodes.\n");
|
CONS_Debug(DBG_GAMELOGIC, "K_PathfindSetupValid: Source node returned NULL connecting nodes.\n");
|
||||||
|
|
@ -295,242 +299,244 @@ boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup
|
||||||
{
|
{
|
||||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: Pathfinding setup is not valid.\n");
|
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: Pathfinding setup is not valid.\n");
|
||||||
}
|
}
|
||||||
else if (pathfindsetup->startnodedata == pathfindsetup->endnodedata)
|
else
|
||||||
{
|
{
|
||||||
// At the destination, return a simple 1 node path
|
|
||||||
pathfindnode_t singlenode = {0};
|
pathfindnode_t singlenode = {0};
|
||||||
singlenode.camefrom = NULL;
|
singlenode.camefrom = NULL;
|
||||||
singlenode.nodedata = pathfindsetup->endnodedata;
|
singlenode.nodedata = pathfindsetup->startnodedata;
|
||||||
singlenode.heapindex = SIZE_MAX;
|
singlenode.heapindex = SIZE_MAX;
|
||||||
singlenode.hscore = 0U;
|
singlenode.hscore = 0U;
|
||||||
singlenode.gscore = 0U;
|
singlenode.gscore = 0U;
|
||||||
|
|
||||||
K_ReconstructPath(path, &singlenode);
|
if (pathfindsetup->getfinished(&singlenode, pathfindsetup) == true)
|
||||||
|
|
||||||
pathfindsuccess = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bheap_t openset = {0};
|
|
||||||
bheapitem_t poppedbheapitem = {0};
|
|
||||||
pathfindnode_t *nodesarray = NULL;
|
|
||||||
pathfindnode_t **closedset = NULL;
|
|
||||||
pathfindnode_t *newnode = NULL;
|
|
||||||
pathfindnode_t *currentnode = NULL;
|
|
||||||
pathfindnode_t *connectingnode = NULL;
|
|
||||||
void **connectingnodesdata = NULL;
|
|
||||||
void *checknodedata = NULL;
|
|
||||||
UINT32 *connectingnodecosts = NULL;
|
|
||||||
size_t numconnectingnodes = 0U;
|
|
||||||
size_t connectingnodeheapindex = 0U;
|
|
||||||
size_t nodesarraycount = 0U;
|
|
||||||
size_t closedsetcount = 0U;
|
|
||||||
size_t i = 0U;
|
|
||||||
UINT32 tentativegscore = 0U;
|
|
||||||
|
|
||||||
// Set the dynamic structure capacites to defaults if they are 0
|
|
||||||
if (pathfindsetup->nodesarraycapacity == 0U)
|
|
||||||
{
|
{
|
||||||
pathfindsetup->nodesarraycapacity = DEFAULT_NODEARRAY_CAPACITY;
|
// At the destination, return a simple 1 node path
|
||||||
|
K_ReconstructPath(path, &singlenode);
|
||||||
|
pathfindsuccess = true;
|
||||||
}
|
}
|
||||||
if (pathfindsetup->opensetcapacity == 0U)
|
else
|
||||||
{
|
{
|
||||||
pathfindsetup->opensetcapacity = DEFAULT_OPENSET_CAPACITY;
|
bheap_t openset = {0};
|
||||||
}
|
bheapitem_t poppedbheapitem = {0};
|
||||||
if (pathfindsetup->closedsetcapacity == 0U)
|
pathfindnode_t *nodesarray = NULL;
|
||||||
{
|
pathfindnode_t **closedset = NULL;
|
||||||
pathfindsetup->closedsetcapacity = DEFAULT_CLOSEDSET_CAPACITY;
|
pathfindnode_t *newnode = NULL;
|
||||||
}
|
pathfindnode_t *currentnode = NULL;
|
||||||
|
pathfindnode_t *connectingnode = NULL;
|
||||||
|
void **connectingnodesdata = NULL;
|
||||||
|
void *checknodedata = NULL;
|
||||||
|
UINT32 *connectingnodecosts = NULL;
|
||||||
|
size_t numconnectingnodes = 0U;
|
||||||
|
size_t connectingnodeheapindex = 0U;
|
||||||
|
size_t nodesarraycount = 0U;
|
||||||
|
size_t closedsetcount = 0U;
|
||||||
|
size_t i = 0U;
|
||||||
|
UINT32 tentativegscore = 0U;
|
||||||
|
|
||||||
// Allocate the necessary memory
|
// Set the dynamic structure capacites to defaults if they are 0
|
||||||
nodesarray = Z_Calloc(pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
if (pathfindsetup->nodesarraycapacity == 0U)
|
||||||
if (nodesarray == NULL)
|
|
||||||
{
|
|
||||||
I_Error("K_PathfindAStar: Out of memory allocating nodes array.");
|
|
||||||
}
|
|
||||||
closedset = Z_Calloc(pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
|
||||||
if (closedset == NULL)
|
|
||||||
{
|
|
||||||
I_Error("K_PathfindAStar: Out of memory allocating closed set.");
|
|
||||||
}
|
|
||||||
K_BHeapInit(&openset, pathfindsetup->opensetcapacity);
|
|
||||||
|
|
||||||
// Create the first node and add it to the open set
|
|
||||||
newnode = &nodesarray[nodesarraycount];
|
|
||||||
newnode->heapindex = SIZE_MAX;
|
|
||||||
newnode->nodedata = pathfindsetup->startnodedata;
|
|
||||||
newnode->camefrom = NULL;
|
|
||||||
newnode->gscore = 0U;
|
|
||||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
|
||||||
nodesarraycount++;
|
|
||||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
|
||||||
|
|
||||||
// update openset capacity if it changed
|
|
||||||
if (openset.capacity != pathfindsetup->opensetcapacity)
|
|
||||||
{
|
|
||||||
pathfindsetup->opensetcapacity = openset.capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each node in the openset, adding new ones from each node to it
|
|
||||||
// this continues until a path is found or there are no more nodes to check
|
|
||||||
while (openset.count > 0U)
|
|
||||||
{
|
|
||||||
// pop the best node off of the openset
|
|
||||||
K_BHeapPop(&openset, &poppedbheapitem);
|
|
||||||
currentnode = (pathfindnode_t*)poppedbheapitem.data;
|
|
||||||
|
|
||||||
if (currentnode->nodedata == pathfindsetup->endnodedata)
|
|
||||||
{
|
{
|
||||||
pathfindsuccess = K_ReconstructPath(path, currentnode);
|
pathfindsetup->nodesarraycapacity = DEFAULT_NODEARRAY_CAPACITY;
|
||||||
break;
|
}
|
||||||
|
if (pathfindsetup->opensetcapacity == 0U)
|
||||||
|
{
|
||||||
|
pathfindsetup->opensetcapacity = DEFAULT_OPENSET_CAPACITY;
|
||||||
|
}
|
||||||
|
if (pathfindsetup->closedsetcapacity == 0U)
|
||||||
|
{
|
||||||
|
pathfindsetup->closedsetcapacity = DEFAULT_CLOSEDSET_CAPACITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place the node we just popped into the closed set, as we are now evaluating it
|
// Allocate the necessary memory
|
||||||
if (closedsetcount >= pathfindsetup->closedsetcapacity)
|
nodesarray = Z_Calloc(pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||||
|
if (nodesarray == NULL)
|
||||||
{
|
{
|
||||||
// Need to reallocate closedset to fit another node
|
I_Error("K_PathfindAStar: Out of memory allocating nodes array.");
|
||||||
pathfindsetup->closedsetcapacity = pathfindsetup->closedsetcapacity * 2;
|
}
|
||||||
closedset =
|
closedset = Z_Calloc(pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||||
Z_Realloc(closedset, pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
if (closedset == NULL)
|
||||||
if (closedset == NULL)
|
{
|
||||||
|
I_Error("K_PathfindAStar: Out of memory allocating closed set.");
|
||||||
|
}
|
||||||
|
K_BHeapInit(&openset, pathfindsetup->opensetcapacity);
|
||||||
|
|
||||||
|
// Create the first node and add it to the open set
|
||||||
|
newnode = &nodesarray[nodesarraycount];
|
||||||
|
newnode->heapindex = SIZE_MAX;
|
||||||
|
newnode->nodedata = pathfindsetup->startnodedata;
|
||||||
|
newnode->camefrom = NULL;
|
||||||
|
newnode->gscore = 0U;
|
||||||
|
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||||
|
nodesarraycount++;
|
||||||
|
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||||
|
|
||||||
|
// update openset capacity if it changed
|
||||||
|
if (openset.capacity != pathfindsetup->opensetcapacity)
|
||||||
|
{
|
||||||
|
pathfindsetup->opensetcapacity = openset.capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through each node in the openset, adding new ones from each node to it
|
||||||
|
// this continues until a path is found or there are no more nodes to check
|
||||||
|
while (openset.count > 0U)
|
||||||
|
{
|
||||||
|
// pop the best node off of the openset
|
||||||
|
K_BHeapPop(&openset, &poppedbheapitem);
|
||||||
|
currentnode = (pathfindnode_t*)poppedbheapitem.data;
|
||||||
|
|
||||||
|
if (pathfindsetup->getfinished(currentnode, pathfindsetup) == true)
|
||||||
{
|
{
|
||||||
I_Error("K_PathfindAStar: Out of memory reallocating closed set.");
|
pathfindsuccess = K_ReconstructPath(path, currentnode);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
closedset[closedsetcount] = currentnode;
|
|
||||||
closedsetcount++;
|
|
||||||
|
|
||||||
// Get the needed data for the next nodes from the current node
|
// Place the node we just popped into the closed set, as we are now evaluating it
|
||||||
connectingnodesdata = pathfindsetup->getconnectednodes(currentnode->nodedata, &numconnectingnodes);
|
if (closedsetcount >= pathfindsetup->closedsetcapacity)
|
||||||
connectingnodecosts = pathfindsetup->getconnectioncosts(currentnode->nodedata);
|
|
||||||
|
|
||||||
if (connectingnodesdata == NULL)
|
|
||||||
{
|
|
||||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node data.\n");
|
|
||||||
}
|
|
||||||
else if (connectingnodecosts == NULL)
|
|
||||||
{
|
|
||||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node costs.\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For each connecting node add it to the openset if it's unevaluated and not there,
|
|
||||||
// skip it if it's in the closedset or not traversable
|
|
||||||
for (i = 0; i < numconnectingnodes; i++)
|
|
||||||
{
|
{
|
||||||
checknodedata = connectingnodesdata[i];
|
// Need to reallocate closedset to fit another node
|
||||||
|
pathfindsetup->closedsetcapacity = pathfindsetup->closedsetcapacity * 2;
|
||||||
if (checknodedata == NULL)
|
closedset =
|
||||||
|
Z_Realloc(closedset, pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||||
|
if (closedset == NULL)
|
||||||
{
|
{
|
||||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node has a NULL connecting node.\n");
|
I_Error("K_PathfindAStar: Out of memory reallocating closed set.");
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
closedset[closedsetcount] = currentnode;
|
||||||
|
closedsetcount++;
|
||||||
|
|
||||||
|
// Get the needed data for the next nodes from the current node
|
||||||
|
connectingnodesdata = pathfindsetup->getconnectednodes(currentnode->nodedata, &numconnectingnodes);
|
||||||
|
connectingnodecosts = pathfindsetup->getconnectioncosts(currentnode->nodedata);
|
||||||
|
|
||||||
|
if (connectingnodesdata == NULL)
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node data.\n");
|
||||||
|
}
|
||||||
|
else if (connectingnodecosts == NULL)
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node costs.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For each connecting node add it to the openset if it's unevaluated and not there,
|
||||||
|
// skip it if it's in the closedset or not traversable
|
||||||
|
for (i = 0; i < numconnectingnodes; i++)
|
||||||
{
|
{
|
||||||
// skip this node if it isn't traversable
|
checknodedata = connectingnodesdata[i];
|
||||||
if (pathfindsetup->gettraversable(checknodedata, currentnode->nodedata) == false)
|
|
||||||
|
if (checknodedata == NULL)
|
||||||
{
|
{
|
||||||
continue;
|
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node has a NULL connecting node.\n");
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out what the gscore of this route for the connecting node is
|
|
||||||
tentativegscore = currentnode->gscore + connectingnodecosts[i];
|
|
||||||
|
|
||||||
// find this data in the nodes array if it's been generated before
|
|
||||||
connectingnode = K_NodesArrayContainsNodeData(nodesarray, checknodedata, nodesarraycount);
|
|
||||||
|
|
||||||
if (connectingnode != NULL)
|
|
||||||
{
|
|
||||||
// The connecting node has been seen before, so it must be in either the closedset (skip it)
|
|
||||||
// or the openset (re-evaluate it's gscore)
|
|
||||||
if (K_ClosedsetContainsNode(closedset, connectingnode, closedsetcount) == true)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (tentativegscore < connectingnode->gscore)
|
|
||||||
{
|
|
||||||
// The node is not in the closedset, update it's gscore if this path to it is faster
|
|
||||||
connectingnode->gscore = tentativegscore;
|
|
||||||
connectingnode->camefrom = currentnode;
|
|
||||||
|
|
||||||
connectingnodeheapindex =
|
|
||||||
K_BHeapContains(&openset, connectingnode, connectingnode->heapindex);
|
|
||||||
if (connectingnodeheapindex != SIZE_MAX)
|
|
||||||
{
|
|
||||||
K_UpdateBHeapItemValue(
|
|
||||||
&openset.array[connectingnodeheapindex], K_NodeGetFScore(connectingnode));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// SOMEHOW the node is not in either the closed set OR the open set
|
|
||||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node is not in either set.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Node is not created yet, so it hasn't been seen so far
|
// skip this node if it isn't traversable
|
||||||
// Reallocate nodesarray if it's full
|
if (pathfindsetup->gettraversable(checknodedata, currentnode->nodedata) == false)
|
||||||
if (nodesarraycount >= pathfindsetup->nodesarraycapacity)
|
|
||||||
{
|
{
|
||||||
pathfindnode_t *nodesarrayrealloc = NULL;
|
continue;
|
||||||
pathfindsetup->nodesarraycapacity = pathfindsetup->nodesarraycapacity * 2;
|
|
||||||
nodesarrayrealloc = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
|
||||||
|
|
||||||
if (nodesarrayrealloc == NULL)
|
|
||||||
{
|
|
||||||
I_Error("K_PathfindAStar: Out of memory reallocating nodes array.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to update pointers in closedset, openset, and node "camefrom" if nodesarray moved.
|
|
||||||
if (nodesarray != nodesarrayrealloc)
|
|
||||||
{
|
|
||||||
size_t j = 0U;
|
|
||||||
size_t arrayindex = 0U;
|
|
||||||
for (j = 0U; j < closedsetcount; j++)
|
|
||||||
{
|
|
||||||
arrayindex = closedset[j] - nodesarray;
|
|
||||||
closedset[j] = &nodesarrayrealloc[arrayindex];
|
|
||||||
}
|
|
||||||
for (j = 0U; j < openset.count; j++)
|
|
||||||
{
|
|
||||||
arrayindex = ((pathfindnode_t *)(openset.array[j].data)) - nodesarray;
|
|
||||||
openset.array[j].data = &nodesarrayrealloc[arrayindex];
|
|
||||||
}
|
|
||||||
for (j = 0U; j < nodesarraycount; j++)
|
|
||||||
{
|
|
||||||
if (nodesarrayrealloc[j].camefrom != NULL)
|
|
||||||
{
|
|
||||||
arrayindex = nodesarrayrealloc[j].camefrom - nodesarray;
|
|
||||||
nodesarrayrealloc[j].camefrom = &nodesarrayrealloc[arrayindex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayindex = currentnode - nodesarray;
|
|
||||||
currentnode = &nodesarrayrealloc[arrayindex];
|
|
||||||
}
|
|
||||||
|
|
||||||
nodesarray = nodesarrayrealloc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the new node and add it to the nodes array and open set
|
// Figure out what the gscore of this route for the connecting node is
|
||||||
newnode = &nodesarray[nodesarraycount];
|
tentativegscore = currentnode->gscore + connectingnodecosts[i];
|
||||||
newnode->heapindex = SIZE_MAX;
|
|
||||||
newnode->nodedata = checknodedata;
|
// find this data in the nodes array if it's been generated before
|
||||||
newnode->camefrom = currentnode;
|
connectingnode = K_NodesArrayContainsNodeData(nodesarray, checknodedata, nodesarraycount);
|
||||||
newnode->gscore = tentativegscore;
|
|
||||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
if (connectingnode != NULL)
|
||||||
nodesarraycount++;
|
{
|
||||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
// The connecting node has been seen before, so it must be in either the closedset (skip it)
|
||||||
|
// or the openset (re-evaluate it's gscore)
|
||||||
|
if (K_ClosedsetContainsNode(closedset, connectingnode, closedsetcount) == true)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (tentativegscore < connectingnode->gscore)
|
||||||
|
{
|
||||||
|
// The node is not in the closedset, update it's gscore if this path to it is faster
|
||||||
|
connectingnode->gscore = tentativegscore;
|
||||||
|
connectingnode->camefrom = currentnode;
|
||||||
|
|
||||||
|
connectingnodeheapindex =
|
||||||
|
K_BHeapContains(&openset, connectingnode, connectingnode->heapindex);
|
||||||
|
if (connectingnodeheapindex != SIZE_MAX)
|
||||||
|
{
|
||||||
|
K_UpdateBHeapItemValue(
|
||||||
|
&openset.array[connectingnodeheapindex], K_NodeGetFScore(connectingnode));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SOMEHOW the node is not in either the closed set OR the open set
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node is not in either set.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Node is not created yet, so it hasn't been seen so far
|
||||||
|
// Reallocate nodesarray if it's full
|
||||||
|
if (nodesarraycount >= pathfindsetup->nodesarraycapacity)
|
||||||
|
{
|
||||||
|
pathfindnode_t *nodesarrayrealloc = NULL;
|
||||||
|
pathfindsetup->nodesarraycapacity = pathfindsetup->nodesarraycapacity * 2;
|
||||||
|
nodesarrayrealloc = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||||
|
|
||||||
|
if (nodesarrayrealloc == NULL)
|
||||||
|
{
|
||||||
|
I_Error("K_PathfindAStar: Out of memory reallocating nodes array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to update pointers in closedset, openset, and node "camefrom" if nodesarray moved.
|
||||||
|
if (nodesarray != nodesarrayrealloc)
|
||||||
|
{
|
||||||
|
size_t j = 0U;
|
||||||
|
size_t arrayindex = 0U;
|
||||||
|
for (j = 0U; j < closedsetcount; j++)
|
||||||
|
{
|
||||||
|
arrayindex = closedset[j] - nodesarray;
|
||||||
|
closedset[j] = &nodesarrayrealloc[arrayindex];
|
||||||
|
}
|
||||||
|
for (j = 0U; j < openset.count; j++)
|
||||||
|
{
|
||||||
|
arrayindex = ((pathfindnode_t *)(openset.array[j].data)) - nodesarray;
|
||||||
|
openset.array[j].data = &nodesarrayrealloc[arrayindex];
|
||||||
|
}
|
||||||
|
for (j = 0U; j < nodesarraycount; j++)
|
||||||
|
{
|
||||||
|
if (nodesarrayrealloc[j].camefrom != NULL)
|
||||||
|
{
|
||||||
|
arrayindex = nodesarrayrealloc[j].camefrom - nodesarray;
|
||||||
|
nodesarrayrealloc[j].camefrom = &nodesarrayrealloc[arrayindex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayindex = currentnode - nodesarray;
|
||||||
|
currentnode = &nodesarrayrealloc[arrayindex];
|
||||||
|
}
|
||||||
|
|
||||||
|
nodesarray = nodesarrayrealloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the new node and add it to the nodes array and open set
|
||||||
|
newnode = &nodesarray[nodesarraycount];
|
||||||
|
newnode->heapindex = SIZE_MAX;
|
||||||
|
newnode->nodedata = checknodedata;
|
||||||
|
newnode->camefrom = currentnode;
|
||||||
|
newnode->gscore = tentativegscore;
|
||||||
|
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||||
|
nodesarraycount++;
|
||||||
|
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the memory
|
// Clean up the memory
|
||||||
K_BHeapFree(&openset);
|
K_BHeapFree(&openset);
|
||||||
Z_Free(closedset);
|
Z_Free(closedset);
|
||||||
Z_Free(nodesarray);
|
Z_Free(nodesarray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathfindsuccess;
|
return pathfindsuccess;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ typedef UINT32(*getnodeheuristicfunc)(void*, void*);
|
||||||
// function pointer for getting if a node is traversable from its base data
|
// function pointer for getting if a node is traversable from its base data
|
||||||
typedef boolean(*getnodetraversablefunc)(void*, void*);
|
typedef boolean(*getnodetraversablefunc)(void*, void*);
|
||||||
|
|
||||||
|
// function pointer for getting if a node is our pathfinding end point
|
||||||
|
typedef boolean(*getpathfindfinishedfunc)(void*, void*);
|
||||||
|
|
||||||
|
|
||||||
// A pathfindnode contains information about a node from the pathfinding
|
// A pathfindnode contains information about a node from the pathfinding
|
||||||
// heapindex is only used within the pathfinding algorithm itself, and is always 0 after it is completed
|
// heapindex is only used within the pathfinding algorithm itself, and is always 0 after it is completed
|
||||||
|
|
@ -58,10 +61,12 @@ typedef struct pathfindsetup_s {
|
||||||
size_t nodesarraycapacity;
|
size_t nodesarraycapacity;
|
||||||
void *startnodedata;
|
void *startnodedata;
|
||||||
void *endnodedata;
|
void *endnodedata;
|
||||||
|
UINT32 endgscore;
|
||||||
getconnectednodesfunc getconnectednodes;
|
getconnectednodesfunc getconnectednodes;
|
||||||
getnodeconnectioncostsfunc getconnectioncosts;
|
getnodeconnectioncostsfunc getconnectioncosts;
|
||||||
getnodeheuristicfunc getheuristic;
|
getnodeheuristicfunc getheuristic;
|
||||||
getnodetraversablefunc gettraversable;
|
getnodetraversablefunc gettraversable;
|
||||||
|
getpathfindfinishedfunc getfinished;
|
||||||
} pathfindsetup_t;
|
} pathfindsetup_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
153
src/k_waypoint.c
153
src/k_waypoint.c
|
|
@ -1039,6 +1039,68 @@ static boolean K_WaypointPathfindTraversableNoShortcuts(void *data, void *prevda
|
||||||
return traversable;
|
return traversable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
static boolean K_WaypointPathfindReachedEnd(void *data, void *setupData)
|
||||||
|
|
||||||
|
Returns if the current waypoint data is our end point of our pathfinding.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
data - Should point to a pathfindnode_t to compare
|
||||||
|
setupData - Should point to the pathfindsetup_t to compare
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
True if the waypoint is the pathfind end point, false otherwise.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
static boolean K_WaypointPathfindReachedEnd(void *data, void *setupData)
|
||||||
|
{
|
||||||
|
boolean isEnd = false;
|
||||||
|
|
||||||
|
if (data == NULL || setupData == NULL)
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "K_WaypointPathfindReachedEnd received NULL data.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathfindnode_t *node = (pathfindnode_t *)data;
|
||||||
|
pathfindsetup_t *setup = (pathfindsetup_t *)setupData;
|
||||||
|
|
||||||
|
isEnd = (node->nodedata == setup->endnodedata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData)
|
||||||
|
|
||||||
|
Returns if the current waypoint data reaches our end G score.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
data - Should point to a pathfindnode_t to compare
|
||||||
|
setupData - Should point to the pathfindsetup_t to compare
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
True if the waypoint reached the G score, false otherwise.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData)
|
||||||
|
{
|
||||||
|
boolean scoreReached = false;
|
||||||
|
|
||||||
|
if (data == NULL || setupData == NULL)
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "K_WaypointPathfindReachedGScore received NULL data.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathfindnode_t *node = (pathfindnode_t *)data;
|
||||||
|
pathfindsetup_t *setup = (pathfindsetup_t *)setupData;
|
||||||
|
|
||||||
|
scoreReached = (node->gscore >= setup->endgscore);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scoreReached;
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
boolean K_PathfindToWaypoint(
|
boolean K_PathfindToWaypoint(
|
||||||
waypoint_t *const sourcewaypoint,
|
waypoint_t *const sourcewaypoint,
|
||||||
|
|
@ -1087,18 +1149,19 @@ boolean K_PathfindToWaypoint(
|
||||||
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
||||||
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
||||||
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
||||||
|
getpathfindfinishedfunc finishedfunc = K_WaypointPathfindReachedEnd;
|
||||||
|
|
||||||
if (huntbackwards)
|
if (huntbackwards)
|
||||||
{
|
{
|
||||||
nextnodesfunc = K_WaypointPathfindGetPrev;
|
nextnodesfunc = K_WaypointPathfindGetPrev;
|
||||||
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useshortcuts)
|
if (useshortcuts)
|
||||||
{
|
{
|
||||||
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
||||||
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
||||||
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
||||||
|
|
@ -1108,6 +1171,90 @@ boolean K_PathfindToWaypoint(
|
||||||
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
||||||
pathfindsetup.getheuristic = heuristicfunc;
|
pathfindsetup.getheuristic = heuristicfunc;
|
||||||
pathfindsetup.gettraversable = traversablefunc;
|
pathfindsetup.gettraversable = traversablefunc;
|
||||||
|
pathfindsetup.getfinished = finishedfunc;
|
||||||
|
|
||||||
|
pathfound = K_PathfindAStar(returnpath, &pathfindsetup);
|
||||||
|
|
||||||
|
K_UpdateOpensetBaseSize(pathfindsetup.opensetcapacity);
|
||||||
|
K_UpdateClosedsetBaseSize(pathfindsetup.closedsetcapacity);
|
||||||
|
K_UpdateNodesArrayBaseSize(pathfindsetup.nodesarraycapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathfound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
boolean K_PathfindThruCircuit(
|
||||||
|
waypoint_t *const sourcewaypoint,
|
||||||
|
const UINT32 traveldistance,
|
||||||
|
path_t *const returnpath,
|
||||||
|
const boolean useshortcuts,
|
||||||
|
const boolean huntbackwards)
|
||||||
|
|
||||||
|
See header file for description.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
boolean K_PathfindThruCircuit(
|
||||||
|
waypoint_t *const sourcewaypoint,
|
||||||
|
const UINT32 traveldistance,
|
||||||
|
path_t *const returnpath,
|
||||||
|
const boolean useshortcuts,
|
||||||
|
const boolean huntbackwards)
|
||||||
|
{
|
||||||
|
boolean pathfound = false;
|
||||||
|
|
||||||
|
if (sourcewaypoint == NULL)
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "NULL sourcewaypoint in K_PathfindThruCircuit.\n");
|
||||||
|
}
|
||||||
|
else if (finishline == NULL)
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "NULL finishline in K_PathfindThruCircuit.\n");
|
||||||
|
}
|
||||||
|
else if (((huntbackwards == false) && (sourcewaypoint->numnextwaypoints == 0))
|
||||||
|
|| ((huntbackwards == true) && (sourcewaypoint->numprevwaypoints == 0)))
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC,
|
||||||
|
"K_PathfindThruCircuit: sourcewaypoint with ID %d has no next waypoint\n",
|
||||||
|
K_GetWaypointID(sourcewaypoint));
|
||||||
|
}
|
||||||
|
else if (((huntbackwards == false) && (finishline->numprevwaypoints == 0))
|
||||||
|
|| ((huntbackwards == true) && (finishline->numnextwaypoints == 0)))
|
||||||
|
{
|
||||||
|
CONS_Debug(DBG_GAMELOGIC,
|
||||||
|
"K_PathfindThruCircuit: finishline with ID %d has no previous waypoint\n",
|
||||||
|
K_GetWaypointID(finishline));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathfindsetup_t pathfindsetup = {0};
|
||||||
|
getconnectednodesfunc nextnodesfunc = K_WaypointPathfindGetNext;
|
||||||
|
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
||||||
|
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
||||||
|
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
||||||
|
getpathfindfinishedfunc finishedfunc = K_WaypointPathfindReachedGScore;
|
||||||
|
|
||||||
|
if (huntbackwards)
|
||||||
|
{
|
||||||
|
nextnodesfunc = K_WaypointPathfindGetPrev;
|
||||||
|
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useshortcuts)
|
||||||
|
{
|
||||||
|
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
||||||
|
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
||||||
|
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
||||||
|
pathfindsetup.startnodedata = sourcewaypoint;
|
||||||
|
pathfindsetup.endnodedata = finishline;
|
||||||
|
pathfindsetup.endgscore = traveldistance;
|
||||||
|
pathfindsetup.getconnectednodes = nextnodesfunc;
|
||||||
|
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
||||||
|
pathfindsetup.getheuristic = heuristicfunc;
|
||||||
|
pathfindsetup.gettraversable = traversablefunc;
|
||||||
|
pathfindsetup.getfinished = finishedfunc;
|
||||||
|
|
||||||
pathfound = K_PathfindAStar(returnpath, &pathfindsetup);
|
pathfound = K_PathfindAStar(returnpath, &pathfindsetup);
|
||||||
|
|
||||||
|
|
@ -1183,18 +1330,19 @@ waypoint_t *K_GetNextWaypointToDestination(
|
||||||
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
getnodeconnectioncostsfunc nodecostsfunc = K_WaypointPathfindGetNextCosts;
|
||||||
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
getnodeheuristicfunc heuristicfunc = K_WaypointPathfindGetHeuristic;
|
||||||
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
getnodetraversablefunc traversablefunc = K_WaypointPathfindTraversableNoShortcuts;
|
||||||
|
getpathfindfinishedfunc finishedfunc = K_WaypointPathfindReachedEnd;
|
||||||
|
|
||||||
if (huntbackwards)
|
if (huntbackwards)
|
||||||
{
|
{
|
||||||
nextnodesfunc = K_WaypointPathfindGetPrev;
|
nextnodesfunc = K_WaypointPathfindGetPrev;
|
||||||
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
nodecostsfunc = K_WaypointPathfindGetPrevCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useshortcuts)
|
if (useshortcuts)
|
||||||
{
|
{
|
||||||
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
traversablefunc = K_WaypointPathfindTraversableAllEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
pathfindsetup.opensetcapacity = K_GetOpensetBaseSize();
|
||||||
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
pathfindsetup.closedsetcapacity = K_GetClosedsetBaseSize();
|
||||||
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
pathfindsetup.nodesarraycapacity = K_GetNodesArrayBaseSize();
|
||||||
|
|
@ -1204,6 +1352,7 @@ waypoint_t *K_GetNextWaypointToDestination(
|
||||||
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
pathfindsetup.getconnectioncosts = nodecostsfunc;
|
||||||
pathfindsetup.getheuristic = heuristicfunc;
|
pathfindsetup.getheuristic = heuristicfunc;
|
||||||
pathfindsetup.gettraversable = traversablefunc;
|
pathfindsetup.gettraversable = traversablefunc;
|
||||||
|
pathfindsetup.getfinished = finishedfunc;
|
||||||
|
|
||||||
pathfindsuccess = K_PathfindAStar(&pathtowaypoint, &pathfindsetup);
|
pathfindsuccess = K_PathfindAStar(&pathtowaypoint, &pathfindsetup);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,37 @@ boolean K_PathfindToWaypoint(
|
||||||
const boolean huntbackwards);
|
const boolean huntbackwards);
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
boolean K_PathfindThruCircuit(
|
||||||
|
waypoint_t *const sourcewaypoint,
|
||||||
|
const UINT32 traveldistance,
|
||||||
|
path_t *const returnpath,
|
||||||
|
const boolean useshortcuts,
|
||||||
|
const boolean huntbackwards)
|
||||||
|
|
||||||
|
Tries a pathfind to the finish line waypoint, similar to K_PathfindToWaypoint, but it will continue
|
||||||
|
until it reaches the specified distance. The final path returned will only have the waypoints up to the
|
||||||
|
specified distance.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
sourcewaypoint - The waypoint to start searching from
|
||||||
|
traveldistance - How far along the circuit it will try to pathfind.
|
||||||
|
returnpath - The path_t that will contain the final found path
|
||||||
|
useshortcuts - Whether to use waypoints that are marked as being shortcuts in the search
|
||||||
|
huntbackwards - Goes through the waypoints backwards if true
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
True if a circuit path could be constructed, false if it couldn't.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
|
||||||
|
boolean K_PathfindThruCircuit(
|
||||||
|
waypoint_t *const sourcewaypoint,
|
||||||
|
const UINT32 traveldistance,
|
||||||
|
path_t *const returnpath,
|
||||||
|
const boolean useshortcuts,
|
||||||
|
const boolean huntbackwards);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
waypoint_t *K_GetNextWaypointToDestination(
|
waypoint_t *K_GetNextWaypointToDestination(
|
||||||
waypoint_t *const sourcewaypoint,
|
waypoint_t *const sourcewaypoint,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue