Replace many cases of if else if statements with I_Asserts.

This is done specifically on static functions that aren't used as callbacks.
This is done to keep the code cleaner, and the I_Asserts get compiled out in Release builds.
Logic is left in the "public" functions to avoid crashes as a result of the modules.
This commit is contained in:
Sryder 2020-03-21 19:00:00 +00:00
parent aeb6567b53
commit 3d3b8b6bc6
3 changed files with 357 additions and 577 deletions

View file

@ -18,20 +18,12 @@ static boolean K_BHeapItemValidate(bheap_t *heap, bheapitem_t *item)
{ {
boolean heapitemvalid = false; boolean heapitemvalid = false;
if (heap == NULL) I_Assert(heap != NULL);
I_Assert(item != NULL);
if ((item->data != NULL) && (item->heapindex < SIZE_MAX / 2) && (item->owner == heap))
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapItemValidate.\n"); heapitemvalid = true;
}
else if (item == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_BHeapItemValidate.\n");
}
else
{
if ((item->data != NULL) && (item->heapindex < SIZE_MAX / 2) && (item->owner == heap))
{
heapitemvalid = true;
}
} }
return heapitemvalid; return heapitemvalid;
@ -53,40 +45,21 @@ static boolean K_BHeapItemValidate(bheap_t *heap, bheapitem_t *item)
static bheapitem_t *K_BHeapItemsCompare(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2) static bheapitem_t *K_BHeapItemsCompare(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2)
{ {
bheapitem_t *lowervalueitem = NULL; bheapitem_t *lowervalueitem = NULL;
if (heap == NULL)
I_Assert(heap != NULL);
I_Assert(K_BHeapValid(heap));
I_Assert(item1 != NULL);
I_Assert(item2 != NULL);
I_Assert(K_BHeapItemValidate(heap, item1));
I_Assert(K_BHeapItemValidate(heap, item2));
if (item1->value < item2->value)
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapItemsCompare.\n"); lowervalueitem = item1;
}
else if (K_BHeapValid(heap) == false)
{
CONS_Debug(DBG_GAMELOGIC, "Invalid heap in K_BHeapSwapItems.\n");
}
else if (item1 == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL item1 in K_BHeapItemsCompare.\n");
}
else if (item2 == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL item2 in K_BHeapItemsCompare.\n");
}
else if (K_BHeapItemValidate(heap, item1) == false)
{
CONS_Debug(DBG_GAMELOGIC, "Invalid item1 in K_BHeapItemsCompare.\n");
}
else if (K_BHeapItemValidate(heap, item2) == false)
{
CONS_Debug(DBG_GAMELOGIC, "Invalid item2 in K_BHeapItemsCompare.\n");
} }
else else
{ {
if (item1->value < item2->value) lowervalueitem = item2;
{
lowervalueitem = item1;
}
else
{
lowervalueitem = item2;
}
} }
return lowervalueitem; return lowervalueitem;
@ -107,31 +80,13 @@ static bheapitem_t *K_BHeapItemsCompare(bheap_t *heap, bheapitem_t *item1, bheap
--------------------------------------------------*/ --------------------------------------------------*/
static void K_BHeapSwapItems(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2) static void K_BHeapSwapItems(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2)
{ {
if (heap == NULL) I_Assert(heap != NULL);
{ I_Assert(K_BHeapValid(heap));
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapSwapItems.\n"); I_Assert(item1 != NULL);
} I_Assert(item2 != NULL);
else if (K_BHeapValid(heap) == false) I_Assert(K_BHeapItemValidate(heap, item1));
{ I_Assert(K_BHeapItemValidate(heap, item2));
CONS_Debug(DBG_GAMELOGIC, "Invalid heap in K_BHeapSwapItems.\n");
}
else if (item1 == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL item1 in K_BHeapSwapItems.\n");
}
else if (item2 == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL item2 in K_BHeapSwapItems.\n");
}
else if (K_BHeapItemValidate(heap, item1) == false)
{
CONS_Debug(DBG_GAMELOGIC, "Invalid item1 in K_BHeapSwapItems.\n");
}
else if (K_BHeapItemValidate(heap, item2) == false)
{
CONS_Debug(DBG_GAMELOGIC, "Invalid item2 in K_BHeapSwapItems.\n");
}
else
{ {
size_t tempitemindex = item1->heapindex; size_t tempitemindex = item1->heapindex;
bheapitem_t tempitemstore = *item1; bheapitem_t tempitemstore = *item1;
@ -170,18 +125,10 @@ static size_t K_BHeapItemGetParentIndex(bheapitem_t *item)
{ {
size_t parentindex = SIZE_MAX; size_t parentindex = SIZE_MAX;
if (item == NULL) I_Assert(item != NULL);
{ I_Assert(item->heapindex < (SIZE_MAX / 2));
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_BHeapItemGetParentIndex.\n");
} parentindex = (item->heapindex - 1U) / 2U;
else if (item->heapindex >= (SIZE_MAX / 2))
{
CONS_Debug(DBG_GAMELOGIC, "Bad item heapindex in K_BHeapItemGetParentIndex.\n");
}
else
{
parentindex = (item->heapindex - 1U) / 2U;
}
return parentindex; return parentindex;
} }
@ -201,18 +148,10 @@ static size_t K_BHeapItemGetLeftChildIndex(bheapitem_t *item)
{ {
size_t leftchildindex = SIZE_MAX; size_t leftchildindex = SIZE_MAX;
if (item == NULL) I_Assert(item != NULL);
{ I_Assert(item->heapindex < (SIZE_MAX / 2));
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_BHeapItemGetLeftChildIndex.\n");
} leftchildindex = (item->heapindex * 2U) + 1U;
else if (item->heapindex >= (SIZE_MAX / 2))
{
CONS_Debug(DBG_GAMELOGIC, "Bad item heapindex in K_BHeapItemGetLeftChildIndex.\n");
}
else
{
leftchildindex = (item->heapindex * 2U) + 1U;
}
return leftchildindex; return leftchildindex;
} }
@ -232,18 +171,10 @@ static size_t K_BHeapItemGetRightChildIndex(bheapitem_t *item)
{ {
size_t rightchildindex = SIZE_MAX; size_t rightchildindex = SIZE_MAX;
if (item == NULL) I_Assert(item != NULL);
{ I_Assert(item->heapindex < (SIZE_MAX / 2));
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_BHeapItemGetRightChildIndex.\n");
} rightchildindex = (item->heapindex * 2U) + 2U;
else if (item->heapindex >= (SIZE_MAX / 2))
{
CONS_Debug(DBG_GAMELOGIC, "Bad item heapindex in K_BHeapItemGetRightChildIndex.\n");
}
else
{
rightchildindex = (item->heapindex * 2U) + 2U;
}
return rightchildindex; return rightchildindex;
} }
@ -262,38 +193,27 @@ static size_t K_BHeapItemGetRightChildIndex(bheapitem_t *item)
--------------------------------------------------*/ --------------------------------------------------*/
static void K_BHeapSortUp(bheap_t *heap, bheapitem_t *item) static void K_BHeapSortUp(bheap_t *heap, bheapitem_t *item)
{ {
if (heap == NULL) I_Assert(heap != NULL);
{ I_Assert(K_BHeapValid(heap));
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapSortUp.\n"); I_Assert(item != NULL);
}
else if (K_BHeapValid(heap) == false)
{
CONS_Debug(DBG_GAMELOGIC, "Invalid heap in K_BHeapSortUp.\n");
}
else if (item == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_BHeapSortUp.\n");
}
else
{
if (item->heapindex > 0U)
{
size_t parentindex = SIZE_MAX;
do
{
parentindex = K_BHeapItemGetParentIndex(item);
// Swap the nodes if the parent has a higher value if (item->heapindex > 0U)
if (K_BHeapItemsCompare(heap, item, &heap->array[parentindex]) == item) {
{ size_t parentindex = SIZE_MAX;
K_BHeapSwapItems(heap, item, &heap->array[parentindex]); do
} {
else parentindex = K_BHeapItemGetParentIndex(item);
{
break; // Swap the nodes if the parent has a higher value
} if (K_BHeapItemsCompare(heap, item, &heap->array[parentindex]) == item)
} while (parentindex > 0U); {
} K_BHeapSwapItems(heap, item, &heap->array[parentindex]);
}
else
{
break;
}
} while (parentindex > 0U);
} }
} }
@ -311,71 +231,59 @@ static void K_BHeapSortUp(bheap_t *heap, bheapitem_t *item)
--------------------------------------------------*/ --------------------------------------------------*/
static void K_BHeapSortDown(bheap_t *heap, bheapitem_t *item) static void K_BHeapSortDown(bheap_t *heap, bheapitem_t *item)
{ {
if (heap == NULL) I_Assert(heap != NULL);
I_Assert(K_BHeapValid(heap));
I_Assert(item != NULL);
if (heap->count > 0U)
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapSortDown.\n"); size_t leftchildindex = SIZE_MAX;
} size_t rightchildindex = SIZE_MAX;
else if (K_BHeapValid(heap) == false) bheapitem_t *leftchild = NULL;
{ bheapitem_t *rightchild = NULL;
CONS_Debug(DBG_GAMELOGIC, "Invalid heap in K_BHeapSortDown.\n"); bheapitem_t *swapchild = NULL;
} boolean noswapneeded = false;
else if (item == NULL)
{ do
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_BHeapSortDown.\n");
}
else
{
if (heap->count > 0U)
{ {
size_t leftchildindex = SIZE_MAX; leftchildindex = K_BHeapItemGetLeftChildIndex(item);
size_t rightchildindex = SIZE_MAX; rightchildindex = K_BHeapItemGetRightChildIndex(item);
bheapitem_t *leftchild = NULL;
bheapitem_t *rightchild = NULL;
bheapitem_t *swapchild = NULL;
boolean noswapneeded = false;
do if (leftchildindex < heap->count)
{ {
leftchildindex = K_BHeapItemGetLeftChildIndex(item); leftchild = &heap->array[leftchildindex];
rightchildindex = K_BHeapItemGetRightChildIndex(item); swapchild = leftchild;
if (rightchildindex < heap->count)
if (leftchildindex < heap->count)
{ {
leftchild = &heap->array[leftchildindex]; rightchild = &heap->array[rightchildindex];
swapchild = leftchild; // Choose the lower child node to swap with
if (rightchildindex < heap->count) if (K_BHeapItemsCompare(heap, leftchild, rightchild) == rightchild)
{ {
rightchild = &heap->array[rightchildindex]; swapchild = rightchild;
// Choose the lower child node to swap with
if (K_BHeapItemsCompare(heap, leftchild, rightchild) == rightchild)
{
swapchild = rightchild;
}
}
// Swap with the lower child, if it's lower than item
if (K_BHeapItemsCompare(heap, swapchild, item) == swapchild)
{
K_BHeapSwapItems(heap, item, swapchild);
}
else
{
noswapneeded = true;
} }
}
// Swap with the lower child, if it's lower than item
if (K_BHeapItemsCompare(heap, swapchild, item) == swapchild)
{
K_BHeapSwapItems(heap, item, swapchild);
} }
else else
{ {
noswapneeded = true; noswapneeded = true;
} }
}
else
{
noswapneeded = true;
}
if (noswapneeded) if (noswapneeded)
{ {
break; break;
} }
} while (item->heapindex < (heap->count - 1U)); } while (item->heapindex < (heap->count - 1U));
}
} }
} }

View file

@ -23,14 +23,10 @@ static const size_t DEFAULT_CLOSEDSET_CAPACITY = 8U;
static UINT32 K_NodeGetFScore(const pathfindnode_t *const node) static UINT32 K_NodeGetFScore(const pathfindnode_t *const node)
{ {
UINT32 fscore = UINT32_MAX; UINT32 fscore = UINT32_MAX;
if (node == NULL)
{ I_Assert(node != NULL);
CONS_Debug(DBG_GAMELOGIC, "NULL node in K_PathfindNodeGetFScore.");
} fscore = node->gscore + node->hscore;
else
{
fscore = node->gscore + node->hscore;
}
return fscore; return fscore;
} }
@ -52,7 +48,7 @@ static void K_NodeUpdateHeapIndex(void *const node, const size_t newheapindex)
{ {
if (node == NULL) if (node == NULL)
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL node in K_PathfindNodeUpdateHeapIndex.\n"); CONS_Debug(DBG_GAMELOGIC, "NULL node in K_NodeUpdateHeapIndex.\n");
} }
else else
{ {
@ -84,28 +80,20 @@ static pathfindnode_t *K_NodesArrayContainsNodeData(
size_t nodesarraycount) size_t nodesarraycount)
{ {
pathfindnode_t *foundnode = NULL; pathfindnode_t *foundnode = NULL;
size_t i = 0U;
if (nodesarray == NULL) I_Assert(nodesarray != NULL);
I_Assert(nodedata != NULL);
// It is more likely that we'll find the node we are looking for from the end of the array
// Yes, the for loop looks weird, remember that size_t is unsigned and we want to check 0, after it hits 0 it
// will loop back up to SIZE_MAX
for (i = nodesarraycount - 1U; i < nodesarraycount; i--)
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL nodesarray in K_NodesArrayContainsWaypoint.\n"); if (nodesarray[i].nodedata == nodedata)
}
else if (nodedata == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL nodedata in K_NodesArrayContainsWaypoint.\n");
}
else
{
size_t i;
// It is more likely that we'll find the node we are looking for from the end of the array
// Yes, the for loop looks weird, remember that size_t is unsigned and we want to check 0, after it hits 0 it
// will loop back up to SIZE_MAX
for (i = nodesarraycount - 1U; i < nodesarraycount; i--)
{ {
if (nodesarray[i].nodedata == nodedata) foundnode = &nodesarray[i];
{ break;
foundnode = &nodesarray[i];
break;
}
} }
} }
return foundnode; return foundnode;
@ -127,28 +115,19 @@ static pathfindnode_t *K_NodesArrayContainsNodeData(
static boolean K_ClosedsetContainsNode(pathfindnode_t **closedset, pathfindnode_t *node, size_t closedsetcount) static boolean K_ClosedsetContainsNode(pathfindnode_t **closedset, pathfindnode_t *node, size_t closedsetcount)
{ {
boolean nodeisinclosedset = false; boolean nodeisinclosedset = false;
size_t i = 0U;
if (closedset == NULL) I_Assert(closedset != NULL);
I_Assert(node != NULL);
// It is more likely that we'll find the node we are looking for from the end of the array
// Yes, the for loop looks weird, remember that size_t is unsigned and we want to check 0, after it hits 0 it
// will loop back up to SIZE_MAX
for (i = closedsetcount - 1U; i < closedsetcount; i--)
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL closedset in K_PathfindClosedsetContainsNode.\n"); if (closedset[i] == node)
}
else if (node == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL node in K_PathfindClosedsetContainsNode.\n");
}
else
{
size_t i;
// It is more likely that we'll find the node we are looking for from the end of the array
// Yes, the for loop looks weird, remember that size_t is unsigned and we want to check 0, after it hits 0 it
// will loop back up to SIZE_MAX
for (i = closedsetcount - 1U; i < closedsetcount; i--)
{ {
if (closedset[i] == node) nodeisinclosedset = true;
{ break;
nodeisinclosedset = true;
break;
}
} }
} }
return nodeisinclosedset; return nodeisinclosedset;
@ -227,15 +206,9 @@ static boolean K_ReconstructPath(path_t *const path, pathfindnode_t *const desti
{ {
boolean reconstructsuccess = false; boolean reconstructsuccess = false;
if (path == NULL) I_Assert(path != NULL);
{ I_Assert(destinationnode != NULL);
CONS_Debug(DBG_GAMELOGIC, "NULL path in K_ReconstructPath.\n");
}
else if (destinationnode == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL destinationnode in K_ReconstructPath.\n");
}
else
{ {
size_t numnodes = 0U; size_t numnodes = 0U;
pathfindnode_t *thisnode = destinationnode; pathfindnode_t *thisnode = destinationnode;

View file

@ -345,21 +345,11 @@ static void K_DebugWaypointsSpawnLine(waypoint_t *const waypoint1, waypoint_t *c
UINT32 numofframes = 1; // If this was 0 it could divide by 0 UINT32 numofframes = 1; // If this was 0 it could divide by 0
// Error conditions // Error conditions
if (waypoint1 == NULL || waypoint2 == NULL) I_Assert(waypoint1 != NULL);
{ I_Assert(waypoint1->mobj != NULL);
CONS_Debug(DBG_GAMELOGIC, "NULL waypoint in K_DebugWaypointsSpawnLine.\n"); I_Assert(waypoint2 != NULL);
return; I_Assert(waypoint2->mobj != NULL);
} I_Assert(cv_kartdebugwaypoints.value != 0);
if (waypoint1->mobj == NULL || waypoint2->mobj == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL mobj on waypoint in K_DebugWaypointsSpawnLine.\n");
return;
}
if (cv_kartdebugwaypoints.value == 0)
{
CONS_Debug(DBG_GAMELOGIC, "In K_DebugWaypointsSpawnLine when kartdebugwaypoints is off.\n");
return;
}
waypointmobj1 = waypoint1->mobj; waypointmobj1 = waypoint1->mobj;
waypointmobj2 = waypoint2->mobj; waypointmobj2 = waypoint2->mobj;
@ -603,15 +593,9 @@ static void K_UpdateNodesArrayBaseSize(size_t newnodesarraysize)
static UINT32 K_DistanceBetweenWaypoints(waypoint_t *const waypoint1, waypoint_t *const waypoint2) static UINT32 K_DistanceBetweenWaypoints(waypoint_t *const waypoint1, waypoint_t *const waypoint2)
{ {
UINT32 finaldist = UINT32_MAX; UINT32 finaldist = UINT32_MAX;
if (waypoint1 == NULL) I_Assert(waypoint1 != NULL);
{ I_Assert(waypoint2 != NULL);
CONS_Debug(DBG_GAMELOGIC, "NULL waypoint1 in K_DistanceBetweenWaypoints.\n");
}
else if (waypoint2 == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL waypoint2 in K_DistanceBetweenWaypoints.\n");
}
else
{ {
const fixed_t xydist = const fixed_t xydist =
P_AproxDistance(waypoint1->mobj->x - waypoint2->mobj->x, waypoint1->mobj->y - waypoint2->mobj->y); P_AproxDistance(waypoint1->mobj->x - waypoint2->mobj->x, waypoint1->mobj->y - waypoint2->mobj->y);
@ -1104,21 +1088,12 @@ static boolean K_CheckWaypointForMobj(waypoint_t *const waypoint, void *const mo
boolean mobjsmatch = false; boolean mobjsmatch = false;
// Error Conditions // Error Conditions
if (waypoint == NULL) I_Assert(waypoint != NULL);
I_Assert(waypoint->mobj != NULL);
I_Assert(mobjpointer != NULL);
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL waypoint in K_CheckWaypointForMobj.\n"); mobj_t *const mobj = (mobj_t *)mobjpointer;
}
else if (waypoint->mobj == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "Waypoint has NULL mobj in K_CheckWaypointForMobj.\n");
}
else if (mobjpointer == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL mobjpointer in K_CheckWaypointForMobj.\n");
}
else
{
mobj_t *mobj = (mobj_t *)mobjpointer;
if (P_MobjWasRemoved(mobj)) if (P_MobjWasRemoved(mobj))
{ {
@ -1170,76 +1145,61 @@ static waypoint_t *K_TraverseWaypoints(
waypoint_t *foundwaypoint = NULL; waypoint_t *foundwaypoint = NULL;
// Error conditions // Error conditions
if (condition == NULL) I_Assert(condition != NULL);
{ I_Assert(conditionalfunc != NULL);
CONS_Debug(DBG_GAMELOGIC, "NULL condition in K_TraverseWaypoints.\n"); I_Assert(visitedarray != NULL);
}
else if (conditionalfunc == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL conditionalfunc in K_TraverseWaypoints.\n");
}
else if (visitedarray == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL visitedarray in K_TraverseWaypoints.\n");
}
else
{
searchwaypointstart: searchwaypointstart:
if (waypoint == NULL) I_Assert(waypoint != NULL);
{
size_t waypointindex = K_GetWaypointHeapIndex(waypoint);
// If we've already visited this waypoint, we've already checked the next waypoints, no point continuing
if ((waypointindex != SIZE_MAX) && (visitedarray[waypointindex] != true))
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL waypoint in K_TraverseWaypoints.\n"); // Mark this waypoint as being visited
} visitedarray[waypointindex] = true;
else
{ if (conditionalfunc(waypoint, condition) == true)
size_t waypointindex = K_GetWaypointHeapIndex(waypoint);
// If we've already visited this waypoint, we've already checked the next waypoints, no point continuing
if ((waypointindex != SIZE_MAX) && (visitedarray[waypointindex] != true))
{ {
// Mark this waypoint as being visited foundwaypoint = waypoint;
visitedarray[waypointindex] = true; }
else
if (conditionalfunc(waypoint, condition) == true) {
// If this waypoint only has one next waypoint, set the waypoint to be the next one and jump back
// to the start, this is to avoid going too deep into the stack where we can
// Yes this is a horrible horrible goto, but the alternative is a do while loop with an extra
// variable, which is slightly more confusing. This is probably the fastest and least confusing
// option that keeps this functionality
if (waypoint->numnextwaypoints == 1 && waypoint->nextwaypoints[0] != NULL)
{ {
foundwaypoint = waypoint; waypoint = waypoint->nextwaypoints[0];
goto searchwaypointstart;
} }
else else if (waypoint->numnextwaypoints != 0)
{ {
// If this waypoint only has one next waypoint, set the waypoint to be the next one and jump back // The nesting here is a bit nasty, but it's better than potentially a lot of function calls on
// to the start, this is to avoid going too deep into the stack where we can // the stack, and another function would be very small in this case
// Yes this is a horrible horrible goto, but the alternative is a do while loop with an extra UINT32 i;
// variable, which is slightly more confusing. This is probably the fastest and least confusing // For each next waypoint, Search through it's path continuation until we hopefully find the one
// option that keeps this functionality // we're looking for
if (waypoint->numnextwaypoints == 1 && waypoint->nextwaypoints[0] != NULL) for (i = 0; i < waypoint->numnextwaypoints; i++)
{ {
waypoint = waypoint->nextwaypoints[0]; if (waypoint->nextwaypoints[i] != NULL)
goto searchwaypointstart;
}
else if (waypoint->numnextwaypoints != 0)
{
// The nesting here is a bit nasty, but it's better than potentially a lot of function calls on
// the stack, and another function would be very small in this case
UINT32 i;
// For each next waypoint, Search through it's path continuation until we hopefully find the one
// we're looking for
for (i = 0; i < waypoint->numnextwaypoints; i++)
{ {
if (waypoint->nextwaypoints[i] != NULL) foundwaypoint = K_TraverseWaypoints(waypoint->nextwaypoints[i], conditionalfunc,
{ condition, visitedarray);
foundwaypoint = K_TraverseWaypoints(waypoint->nextwaypoints[i], conditionalfunc,
condition, visitedarray);
if (foundwaypoint != NULL) if (foundwaypoint != NULL)
{ {
break; break;
}
} }
} }
} }
else }
{ else
// No next waypoints, this function will be returned from {
} // No next waypoints, this function will be returned from
} }
} }
} }
@ -1270,24 +1230,13 @@ static waypoint_t *K_SearchWaypointGraph(
waypoint_t *foundwaypoint = NULL; waypoint_t *foundwaypoint = NULL;
// Error conditions // Error conditions
if (condition == NULL) I_Assert(condition != NULL);
{ I_Assert(conditionalfunc != NULL);
CONS_Debug(DBG_GAMELOGIC, "NULL condition in K_SearchWaypointGraph.\n"); I_Assert(firstwaypoint != NULL);
}
else if (conditionalfunc == NULL) visitedarray = Z_Calloc(numwaypoints * sizeof(boolean), PU_STATIC, NULL);
{ foundwaypoint = K_TraverseWaypoints(firstwaypoint, conditionalfunc, condition, visitedarray);
CONS_Debug(DBG_GAMELOGIC, "NULL conditionalfunc in K_SearchWaypointGraph.\n"); Z_Free(visitedarray);
}
else if (firstwaypoint == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "K_SearchWaypointsForMobj called when no first waypoint.\n");
}
else
{
visitedarray = Z_Calloc(numwaypoints * sizeof(boolean), PU_STATIC, NULL);
foundwaypoint = K_TraverseWaypoints(firstwaypoint, conditionalfunc, condition, visitedarray);
Z_Free(visitedarray);
}
return foundwaypoint; return foundwaypoint;
} }
@ -1339,30 +1288,19 @@ static waypoint_t *K_SearchWaypointHeap(
waypoint_t *foundwaypoint = NULL; waypoint_t *foundwaypoint = NULL;
// Error conditions // Error conditions
if (condition == NULL) I_Assert(condition != NULL);
I_Assert(conditionalfunc != NULL);
I_Assert(waypointheap != NULL);
// Simply search through the waypointheap for the waypoint which matches the condition. Much simpler when no
// pathfinding is needed. Search up to numwaypoints and NOT numwaypointmobjs as numwaypoints is the real number of
// waypoints setup in the heap while numwaypointmobjs ends up being the capacity
for (i = 0; i < numwaypoints; i++)
{ {
CONS_Debug(DBG_GAMELOGIC, "NULL condition in K_SearchWaypointHeap.\n"); if (conditionalfunc(&waypointheap[i], condition) == true)
}
else if (conditionalfunc == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "NULL conditionalfunc in K_SearchWaypointHeap.\n");
}
else if (waypointheap == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "K_SearchWaypointHeap called when no waypointheap.\n");
}
else
{
// Simply search through the waypointheap for the waypoint which matches the condition. Much simpler when no
// pathfinding is needed. Search up to numwaypoints and NOT numwaypointmobjs as numwaypoints is the real number of
// waypoints setup in the heap while numwaypointmobjs ends up being the capacity
for (i = 0; i < numwaypoints; i++)
{ {
if (conditionalfunc(&waypointheap[i], condition) == true) foundwaypoint = &waypointheap[i];
{ break;
foundwaypoint = &waypointheap[i];
break;
}
} }
} }
@ -1408,37 +1346,30 @@ waypoint_t *K_SearchWaypointHeapForMobj(mobj_t *const mobj)
--------------------------------------------------*/ --------------------------------------------------*/
static UINT32 K_SetupCircuitLength(void) static UINT32 K_SetupCircuitLength(void)
{ {
if ((firstwaypoint == NULL) || (numwaypoints == 0U)) I_Assert(firstwaypoint != NULL);
I_Assert(numwaypoints > 0U);
I_Assert(finishline != NULL);
// The circuit length only makes sense in circuit maps, sprint maps do not need to use it
// The main usage of the circuit length is to add onto a player's distance to finish line so crossing the finish
// line places people correctly relative to each other
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == LF_SECTIONRACE)
{ {
CONS_Debug(DBG_GAMELOGIC, "K_SetupCircuitLength called with no waypoints.\n"); circuitlength = 0U;
}
else if (finishline == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "K_SetupCircuitLength called with no finishline waypoint.\n");
} }
else else
{ {
// The circuit length only makes sense in circuit maps, sprint maps do not need to use it // Create a fake finishline waypoint, then try and pathfind to the finishline from it
// The main usage of the circuit length is to add onto a player's distance to finish line so crossing the finish waypoint_t fakefinishline = *finishline;
// line places people correctly relative to each other path_t bestcircuitpath = {};
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == LF_SECTIONRACE) const boolean useshortcuts = false;
{ const boolean huntbackwards = false;
circuitlength = 0U;
}
else
{
// Create a fake finishline waypoint, then try and pathfind to the finishline from it
waypoint_t fakefinishline = *finishline;
path_t bestcircuitpath = {};
const boolean useshortcuts = false;
const boolean huntbackwards = false;
K_PathfindToWaypoint(&fakefinishline, finishline, &bestcircuitpath, useshortcuts, huntbackwards); K_PathfindToWaypoint(&fakefinishline, finishline, &bestcircuitpath, useshortcuts, huntbackwards);
circuitlength = bestcircuitpath.totaldist; circuitlength = bestcircuitpath.totaldist;
Z_Free(bestcircuitpath.array); Z_Free(bestcircuitpath.array);
}
} }
return circuitlength; return circuitlength;
@ -1460,35 +1391,27 @@ static UINT32 K_SetupCircuitLength(void)
static void K_AddPrevToWaypoint(waypoint_t *const waypoint, waypoint_t *const prevwaypoint) static void K_AddPrevToWaypoint(waypoint_t *const waypoint, waypoint_t *const prevwaypoint)
{ {
// Error conditions // Error conditions
if (waypoint == NULL) I_Assert(waypoint != NULL);
I_Assert(prevwaypoint != NULL);
waypoint->numprevwaypoints++;
waypoint->prevwaypoints =
Z_Realloc(waypoint->prevwaypoints, waypoint->numprevwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL);
if (!waypoint->prevwaypoints)
{ {
CONS_Debug(DBG_SETUP, "NULL waypoint in K_AddPrevToWaypoint.\n"); I_Error("K_AddPrevToWaypoint: Failed to reallocate memory for previous waypoints.");
} }
else if (prevwaypoint == NULL)
waypoint->prevwaypointdistances =
Z_Realloc(waypoint->prevwaypointdistances, waypoint->numprevwaypoints * sizeof(fixed_t), PU_LEVEL, NULL);
if (!waypoint->prevwaypointdistances)
{ {
CONS_Debug(DBG_SETUP, "NULL prevwaypoint in K_AddPrevToWaypoint.\n"); I_Error("K_AddPrevToWaypoint: Failed to reallocate memory for previous waypoint distances.");
} }
else
{
waypoint->numprevwaypoints++;
waypoint->prevwaypoints =
Z_Realloc(waypoint->prevwaypoints, waypoint->numprevwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL);
if (!waypoint->prevwaypoints) waypoint->prevwaypoints[waypoint->numprevwaypoints - 1] = prevwaypoint;
{
I_Error("K_AddPrevToWaypoint: Failed to reallocate memory for previous waypoints.");
}
waypoint->prevwaypointdistances =
Z_Realloc(waypoint->prevwaypointdistances, waypoint->numprevwaypoints * sizeof(fixed_t), PU_LEVEL, NULL);
if (!waypoint->prevwaypointdistances)
{
I_Error("K_AddPrevToWaypoint: Failed to reallocate memory for previous waypoint distances.");
}
waypoint->prevwaypoints[waypoint->numprevwaypoints - 1] = prevwaypoint;
}
} }
/*-------------------------------------------------- /*--------------------------------------------------
@ -1509,52 +1432,42 @@ static waypoint_t *K_MakeWaypoint(mobj_t *const mobj)
mobj_t *otherwaypointmobj = NULL; mobj_t *otherwaypointmobj = NULL;
// Error conditions // Error conditions
if (mobj == NULL || P_MobjWasRemoved(mobj)) I_Assert(mobj != NULL);
{ I_Assert(!P_MobjWasRemoved(mobj));
CONS_Debug(DBG_SETUP, "NULL mobj in K_MakeWaypoint.\n"); I_Assert(waypointcap != NULL); // No waypoint mobjs in map load
} I_Assert(numwaypoints < numwaypointmobjs); // waypoint array reached max capacity
else if (waypointcap == NULL)
{
CONS_Debug(DBG_SETUP, "K_MakeWaypoint called with NULL waypointcap.\n");
}
else if (numwaypoints >= numwaypointmobjs)
{
CONS_Debug(DBG_SETUP, "K_MakeWaypoint called with max waypoint capacity reached.\n");
}
else
{
// numwaypoints is incremented later in K_SetupWaypoint
madewaypoint = &waypointheap[numwaypoints];
numwaypoints++;
P_SetTarget(&madewaypoint->mobj, mobj); // numwaypoints is incremented later in K_SetupWaypoint
madewaypoint = &waypointheap[numwaypoints];
numwaypoints++;
// Go through the other waypoint mobjs in the map to find out how many waypoints are after this one P_SetTarget(&madewaypoint->mobj, mobj);
for (otherwaypointmobj = waypointcap; otherwaypointmobj != NULL; otherwaypointmobj = otherwaypointmobj->tracer)
// Go through the other waypoint mobjs in the map to find out how many waypoints are after this one
for (otherwaypointmobj = waypointcap; otherwaypointmobj != NULL; otherwaypointmobj = otherwaypointmobj->tracer)
{
// threshold = next waypoint id, movecount = my id
if (mobj->threshold == otherwaypointmobj->movecount)
{ {
// threshold = next waypoint id, movecount = my id madewaypoint->numnextwaypoints++;
if (mobj->threshold == otherwaypointmobj->movecount)
{
madewaypoint->numnextwaypoints++;
}
} }
}
// No next waypoints // No next waypoints
if (madewaypoint->numnextwaypoints != 0) if (madewaypoint->numnextwaypoints != 0)
{
// Allocate memory to hold enough pointers to all of the next waypoints
madewaypoint->nextwaypoints =
Z_Calloc(madewaypoint->numnextwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL);
if (madewaypoint->nextwaypoints == NULL)
{ {
// Allocate memory to hold enough pointers to all of the next waypoints I_Error("K_MakeWaypoint: Out of Memory allocating next waypoints.");
madewaypoint->nextwaypoints = }
Z_Calloc(madewaypoint->numnextwaypoints * sizeof(waypoint_t *), PU_LEVEL, NULL); madewaypoint->nextwaypointdistances =
if (madewaypoint->nextwaypoints == NULL) Z_Calloc(madewaypoint->numnextwaypoints * sizeof(fixed_t), PU_LEVEL, NULL);
{ if (madewaypoint->nextwaypointdistances == NULL)
I_Error("K_MakeWaypoint: Out of Memory allocating next waypoints."); {
} I_Error("K_MakeWaypoint: Out of Memory allocating next waypoint distances.");
madewaypoint->nextwaypointdistances =
Z_Calloc(madewaypoint->numnextwaypoints * sizeof(fixed_t), PU_LEVEL, NULL);
if (madewaypoint->nextwaypointdistances == NULL)
{
I_Error("K_MakeWaypoint: Out of Memory allocating next waypoint distances.");
}
} }
} }
@ -1578,93 +1491,83 @@ static waypoint_t *K_SetupWaypoint(mobj_t *const mobj)
waypoint_t *thiswaypoint = NULL; waypoint_t *thiswaypoint = NULL;
// Error conditions // Error conditions
if (mobj == NULL || P_MobjWasRemoved(mobj)) I_Assert(mobj != NULL);
I_Assert(!P_MobjWasRemoved(mobj));
I_Assert(mobj->type == MT_WAYPOINT);
I_Assert(waypointcap != NULL); // no waypoint mobjs in map load
// If we have waypoints already created, search through them first to see if this mobj is already added.
if (firstwaypoint != NULL)
{ {
CONS_Debug(DBG_SETUP, "NULL mobj in K_SetupWaypoint.\n"); thiswaypoint = K_SearchWaypointHeapForMobj(mobj);
} }
else if (mobj->type != MT_WAYPOINT)
// The waypoint hasn't already been made, so make it
if (thiswaypoint == NULL)
{ {
CONS_Debug(DBG_SETUP, "Non MT_WAYPOINT mobj in K_SetupWaypoint. Type=%d.\n", mobj->type); mobj_t *otherwaypointmobj = NULL;
} UINT32 nextwaypointindex = 0;
else if (waypointcap == NULL)
{ thiswaypoint = K_MakeWaypoint(mobj);
CONS_Debug(DBG_SETUP, "K_SetupWaypoint called with NULL waypointcap.\n");
} if (thiswaypoint != NULL)
else
{
// If we have waypoints already created, search through them first to see if this mobj is already added.
if (firstwaypoint != NULL)
{ {
thiswaypoint = K_SearchWaypointHeapForMobj(mobj); // Set the first waypoint if it isn't already
} if (firstwaypoint == NULL)
// The waypoint hasn't already been made, so make it
if (thiswaypoint == NULL)
{
mobj_t *otherwaypointmobj = NULL;
UINT32 nextwaypointindex = 0;
thiswaypoint = K_MakeWaypoint(mobj);
if (thiswaypoint != NULL)
{ {
// Set the first waypoint if it isn't already firstwaypoint = thiswaypoint;
if (firstwaypoint == NULL) }
{
firstwaypoint = thiswaypoint;
}
if (K_GetWaypointIsFinishline(thiswaypoint)) if (K_GetWaypointIsFinishline(thiswaypoint))
{ {
if (finishline != NULL) if (finishline != NULL)
{
const INT32 oldfinishlineid = K_GetWaypointID(finishline);
const INT32 thiswaypointid = K_GetWaypointID(thiswaypoint);
CONS_Alert(
CONS_WARNING, "Multiple finish line waypoints with IDs %d and %d! Using %d.",
oldfinishlineid, thiswaypointid, thiswaypointid);
}
finishline = thiswaypoint;
}
if (thiswaypoint->numnextwaypoints > 0)
{
waypoint_t *nextwaypoint = NULL;
fixed_t nextwaypointdistance = 0;
// Go through the waypoint mobjs to setup the next waypoints and make this waypoint know they're its
// next. I kept this out of K_MakeWaypoint so the stack isn't gone down as deep
for (otherwaypointmobj = waypointcap;
otherwaypointmobj != NULL;
otherwaypointmobj = otherwaypointmobj->tracer)
{
// threshold = next waypoint id, movecount = my id
if (mobj->threshold == otherwaypointmobj->movecount)
{
nextwaypoint = K_SetupWaypoint(otherwaypointmobj);
nextwaypointdistance = K_DistanceBetweenWaypoints(thiswaypoint, nextwaypoint);
thiswaypoint->nextwaypoints[nextwaypointindex] = nextwaypoint;
thiswaypoint->nextwaypointdistances[nextwaypointindex] = nextwaypointdistance;
K_AddPrevToWaypoint(nextwaypoint, thiswaypoint);
nextwaypoint->prevwaypointdistances[nextwaypoint->numprevwaypoints - 1] = nextwaypointdistance;
nextwaypointindex++;
}
if (nextwaypointindex >= thiswaypoint->numnextwaypoints)
{
break;
}
}
}
else
{ {
const INT32 oldfinishlineid = K_GetWaypointID(finishline);
const INT32 thiswaypointid = K_GetWaypointID(thiswaypoint);
CONS_Alert( CONS_Alert(
CONS_WARNING, "Waypoint with ID %d has no next waypoint.\n", K_GetWaypointID(thiswaypoint)); CONS_WARNING, "Multiple finish line waypoints with IDs %d and %d! Using %d.",
oldfinishlineid, thiswaypointid, thiswaypointid);
}
finishline = thiswaypoint;
}
if (thiswaypoint->numnextwaypoints > 0)
{
waypoint_t *nextwaypoint = NULL;
fixed_t nextwaypointdistance = 0;
// Go through the waypoint mobjs to setup the next waypoints and make this waypoint know they're its
// next. I kept this out of K_MakeWaypoint so the stack isn't gone down as deep
for (otherwaypointmobj = waypointcap;
otherwaypointmobj != NULL;
otherwaypointmobj = otherwaypointmobj->tracer)
{
// threshold = next waypoint id, movecount = my id
if (mobj->threshold == otherwaypointmobj->movecount)
{
nextwaypoint = K_SetupWaypoint(otherwaypointmobj);
nextwaypointdistance = K_DistanceBetweenWaypoints(thiswaypoint, nextwaypoint);
thiswaypoint->nextwaypoints[nextwaypointindex] = nextwaypoint;
thiswaypoint->nextwaypointdistances[nextwaypointindex] = nextwaypointdistance;
K_AddPrevToWaypoint(nextwaypoint, thiswaypoint);
nextwaypoint->prevwaypointdistances[nextwaypoint->numprevwaypoints - 1] = nextwaypointdistance;
nextwaypointindex++;
}
if (nextwaypointindex >= thiswaypoint->numnextwaypoints)
{
break;
}
} }
} }
else else
{ {
CONS_Debug(DBG_SETUP, "K_SetupWaypoint failed to make new waypoint with ID %d.\n", mobj->movecount); CONS_Alert(
CONS_WARNING, "Waypoint with ID %d has no next waypoint.\n", K_GetWaypointID(thiswaypoint));
} }
} }
else
{
CONS_Debug(DBG_SETUP, "K_SetupWaypoint failed to make new waypoint with ID %d.\n", mobj->movecount);
}
} }
return thiswaypoint; return thiswaypoint;
@ -1684,51 +1587,43 @@ static boolean K_AllocateWaypointHeap(void)
boolean allocationsuccessful = false; boolean allocationsuccessful = false;
// Error conditions // Error conditions
if (waypointheap != NULL) I_Assert(waypointheap == NULL); // waypointheap is already allocated
I_Assert(waypointcap != NULL); // no waypoint mobjs at map load
// This should be an allocation for the first time. Reset the number of mobjs back to 0 if it's not already
numwaypointmobjs = 0;
// Find how many waypoint mobjs there are in the map, this is the maximum number of waypoints there CAN be
for (waypointmobj = waypointcap; waypointmobj != NULL; waypointmobj = waypointmobj->tracer)
{ {
CONS_Debug(DBG_SETUP, "K_AllocateWaypointHeap called when waypointheap is already allocated.\n"); if (waypointmobj->type != MT_WAYPOINT)
{
CONS_Debug(DBG_SETUP,
"Non MT_WAYPOINT mobj in waypointcap in K_AllocateWaypointHeap. Type=%d\n.", waypointmobj->type);
continue;
}
numwaypointmobjs++;
} }
else if (waypointcap == NULL)
if (numwaypointmobjs > 0)
{ {
CONS_Debug(DBG_SETUP, "K_AllocateWaypointHeap called with NULL waypointcap.\n"); // Allocate space in the heap for every mobj, it's possible some mobjs aren't linked up and not all of the
// heap allocated will be used, but it's a fairly reasonable assumption that this isn't going to be awful
waypointheap = Z_Calloc(numwaypointmobjs * sizeof(waypoint_t), PU_LEVEL, NULL);
if (waypointheap == NULL)
{
// We could theoretically CONS_Debug here and continue without using waypoints, but I feel that will
// require error checks that will end up spamming the console when we think waypoints SHOULD be working.
// Safer to just exit if out of memory
I_Error("K_AllocateWaypointHeap: Out of memory.");
}
allocationsuccessful = true;
} }
else else
{ {
// This should be an allocation for the first time. Reset the number of mobjs back to 0 if it's not already CONS_Debug(DBG_SETUP, "No waypoint mobjs in waypointcap.\n");
numwaypointmobjs = 0;
// Find how many waypoint mobjs there are in the map, this is the maximum number of waypoints there CAN be
for (waypointmobj = waypointcap; waypointmobj != NULL; waypointmobj = waypointmobj->tracer)
{
if (waypointmobj->type != MT_WAYPOINT)
{
CONS_Debug(DBG_SETUP,
"Non MT_WAYPOINT mobj in waypointcap in K_AllocateWaypointHeap. Type=%d\n.", waypointmobj->type);
continue;
}
numwaypointmobjs++;
}
if (numwaypointmobjs > 0)
{
// Allocate space in the heap for every mobj, it's possible some mobjs aren't linked up and not all of the
// heap allocated will be used, but it's a fairly reasonable assumption that this isn't going to be awful
waypointheap = Z_Calloc(numwaypointmobjs * sizeof(waypoint_t), PU_LEVEL, NULL);
if (waypointheap == NULL)
{
// We could theoretically CONS_Debug here and continue without using waypoints, but I feel that will
// require error checks that will end up spamming the console when we think waypoints SHOULD be working.
// Safer to just exit if out of memory
I_Error("K_AllocateWaypointHeap: Out of memory.");
}
allocationsuccessful = true;
}
else
{
CONS_Debug(DBG_SETUP, "No waypoint mobjs in waypointcap.\n");
}
} }
return allocationsuccessful; return allocationsuccessful;
@ -1794,7 +1689,11 @@ boolean K_SetupWaypointList(void)
finishline = firstwaypoint; finishline = firstwaypoint;
} }
(void)K_SetupCircuitLength(); if (K_SetupCircuitLength() == 0
&& ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) != LF_SECTIONRACE))
{
CONS_Alert(CONS_ERROR, "Circuit track waypoints do not form a circuit.\n");
}
setupsuccessful = true; setupsuccessful = true;
} }