Improvements to player finish distances

Figure out the circuit length on map load
player->distancetofinish is now a total distance on circuit maps
some hacky alterations around circuit finish lines to correctly calculate distancetofinish
This commit is contained in:
Sryder 2019-06-28 21:11:26 +01:00
parent 04966f5613
commit 10adecb4a6
3 changed files with 252 additions and 40 deletions

View file

@ -5673,20 +5673,19 @@ static void K_KartDrift(player_t *player, boolean onground)
}
/*--------------------------------------------------
static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
static waypoint_t *K_GetPlayerClosestWaypoint(player_t *player)
Gets the next waypoint of a player, by finding their closest waypoint, then checking which of itself and next or
previous waypoints are infront of the player.
Gets the closest waypoint of a player.
Input Arguments:-
player - The player the next waypoint is being found for
player - The player the closest waypoint is being found for
Return:-
The waypoint that is the player's next waypoint
The waypoint that is the player's closest waypoint
--------------------------------------------------*/
static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
static waypoint_t *K_GetPlayerClosestWaypoint(player_t *player)
{
waypoint_t *bestwaypoint = NULL;
waypoint_t *closestwaypoint = NULL;
if ((player != NULL) && (player->mo != NULL))
{
mobj_t *wpmobj;
@ -5709,23 +5708,62 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
}
waypoint = K_SearchWaypointGraphForMobj(closestwpmobj);
closestwaypoint = waypoint;
}
return closestwaypoint;
}
/*--------------------------------------------------
static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
Gets the next waypoint of a player, by finding their closest waypoint, then checking which of itself and next or
previous waypoints are infront of the player.
Input Arguments:-
player - The player the next waypoint is being found for
Return:-
The waypoint that is the player's next waypoint
--------------------------------------------------*/
static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
{
waypoint_t *bestwaypoint = NULL;
if ((player != NULL) && (player->mo != NULL))
{
waypoint_t *waypoint = NULL;
waypoint = K_GetPlayerClosestWaypoint(player);
bestwaypoint = waypoint;
// check the waypoint's location in relation to the player
// If it's generally in front, it's fine, otherwise, use the best next/previous waypoint.
// EXCEPTION: If our closest waypoint is the finishline AND we're facing towards it, don't do this.
// Otherwise it breaks the distance calculations.
if (waypoint != NULL)
{
angle_t playerangle = player->mo->angle;
boolean finishlinehack = false;
angle_t playerangle = player->mo->angle;
angle_t angletowaypoint =
R_PointToAngle2(player->mo->x, player->mo->y, waypoint->mobj->x, waypoint->mobj->y);
angle_t angledelta = playerangle - angletowaypoint;
angle_t angledelta = playerangle - angletowaypoint;
if (angledelta > ANGLE_180)
{
angledelta = InvAngle(angletowaypoint);
angledelta = InvAngle(angledelta);
}
if (angledelta > ANGLE_90)
if (bestwaypoint == K_GetFinishLineWaypoint())
{
// facing towards the finishline
if (angledelta <= ANGLE_90)
{
finishlinehack = true;
}
}
if ((angledelta > ANGLE_45) && (finishlinehack == false))
{
angle_t nextbestdelta = angledelta;
size_t i = 0U;
@ -5780,8 +5818,69 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
return bestwaypoint;
}
static boolean K_PlayerCloserToNextWaypoints(waypoint_t *const waypoint, player_t *const player)
{
boolean nextiscloser = true;
if ((waypoint != NULL) && (player != NULL) && (player->mo != NULL))
{
size_t i = 0U;
waypoint_t *currentwpcheck = NULL;
angle_t angletoplayer = ANGLE_MAX;
angle_t currentanglecheck = ANGLE_MAX;
angle_t bestangle = ANGLE_MAX;
angletoplayer = R_PointToAngle2(waypoint->mobj->x, waypoint->mobj->y,
player->mo->x, player->mo->y);
for (i = 0U; i < waypoint->numnextwaypoints; i++)
{
currentwpcheck = waypoint->nextwaypoints[i];
currentanglecheck = R_PointToAngle2(
waypoint->mobj->x, waypoint->mobj->y, currentwpcheck->mobj->x, currentwpcheck->mobj->y);
// Get delta angle
currentanglecheck = currentanglecheck - angletoplayer;
if (currentanglecheck > ANGLE_180)
{
currentanglecheck = InvAngle(currentanglecheck);
}
if (currentanglecheck < bestangle)
{
bestangle = currentanglecheck;
}
}
for (i = 0U; i < waypoint->numprevwaypoints; i++)
{
currentwpcheck = waypoint->prevwaypoints[i];
currentanglecheck = R_PointToAngle2(
waypoint->mobj->x, waypoint->mobj->y, currentwpcheck->mobj->x, currentwpcheck->mobj->y);
// Get delta angle
currentanglecheck = currentanglecheck - angletoplayer;
if (currentanglecheck > ANGLE_180)
{
currentanglecheck = InvAngle(currentanglecheck);
}
if (currentanglecheck < bestangle)
{
bestangle = currentanglecheck;
nextiscloser = false;
break;
}
}
}
return nextiscloser;
}
/*--------------------------------------------------
static void K_UpdateDistanceFromFinishLine(player_t *player)
static void K_UpdateDistanceFromFinishLine(player_t *const player)
Updates the distance a player has to the finish line.
@ -5791,40 +5890,70 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
Return:-
None
--------------------------------------------------*/
static void K_UpdateDistanceFromFinishLine(player_t *player)
static void K_UpdateDistanceFromFinishLine(player_t *const player)
{
if ((player != NULL) && (player->mo != NULL))
{
waypoint_t *finishline = K_GetFinishLineWaypoint();
player->nextwaypoint = K_GetPlayerNextWaypoint(player);
// bestwaypoint is now the waypoint that is in front of us
if ((player->nextwaypoint != NULL) && (finishline != NULL))
if (player->exiting)
{
const boolean useshortcuts = false;
const boolean huntbackwards = false;
boolean pathfindsuccess = false;
path_t pathtofinish = {};
player->nextwaypoint = K_GetFinishLineWaypoint();
player->distancetofinish = 0U;
}
else
{
waypoint_t *finishline = K_GetFinishLineWaypoint();
player->nextwaypoint = K_GetPlayerNextWaypoint(player);
pathfindsuccess =
K_PathfindToWaypoint(player->nextwaypoint, finishline, &pathtofinish, useshortcuts, huntbackwards);
// Update the player's distance to the finish line if a path was found.
// Using shortcuts won't find a path, so the distance won't be updated until the player gets back on track
if (pathfindsuccess == true)
// nextwaypoint is now the waypoint that is in front of us
if ((player->nextwaypoint != NULL) && (finishline != NULL))
{
// Add euclidean distance to the next waypoint to the distancetofinish
UINT32 adddist;
fixed_t disttowaypoint =
P_AproxDistance(
player->mo->x - player->nextwaypoint->mobj->x,
player->mo->y - player->nextwaypoint->mobj->y);
disttowaypoint = P_AproxDistance(disttowaypoint, player->mo->z - player->nextwaypoint->mobj->z);
const boolean useshortcuts = false;
const boolean huntbackwards = false;
boolean pathfindsuccess = false;
path_t pathtofinish = {};
adddist = ((UINT32)disttowaypoint) >> FRACBITS;
pathfindsuccess =
K_PathfindToWaypoint(player->nextwaypoint, finishline, &pathtofinish, useshortcuts, huntbackwards);
player->distancetofinish = pathtofinish.totaldist + adddist;
Z_Free(pathtofinish.array);
// Update the player's distance to the finish line if a path was found.
// Using shortcuts won't find a path, so distance won't be updated until the player gets back on track
if (pathfindsuccess == true)
{
// Add euclidean distance to the next waypoint to the distancetofinish
UINT32 adddist;
fixed_t disttowaypoint =
P_AproxDistance(
player->mo->x - player->nextwaypoint->mobj->x,
player->mo->y - player->nextwaypoint->mobj->y);
disttowaypoint = P_AproxDistance(disttowaypoint, player->mo->z - player->nextwaypoint->mobj->z);
adddist = ((UINT32)disttowaypoint) >> FRACBITS;
player->distancetofinish = pathtofinish.totaldist + adddist;
Z_Free(pathtofinish.array);
// distancetofinish is currently a flat distance to the finish line, but in order to be fully
// correct we need to add to it the length of the entire circuit multiplied by the number of laps
// left after this one. This will give us the total distance to the finish line, and allow item
// distance calculation to work easily
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == 0U)
{
const UINT8 numfulllapsleft = ((UINT8)cv_numlaps.value - player->laps);
player->distancetofinish += numfulllapsleft * K_GetCircuitLength();
// An additional HACK, to fix looking backwards towards the finish line
// If the player's next waypoint is the finishline and the angle distance from player to
// connectin waypoints implies they're closer to a next waypoint, add a full track distance
if (player->nextwaypoint == finishline)
{
if (K_PlayerCloserToNextWaypoints(player->nextwaypoint, player) == true)
{
player->distancetofinish += K_GetCircuitLength();
}
}
}
}
}
}
}

View file

@ -4,6 +4,7 @@
#include "p_local.h"
#include "p_tick.h"
#include "z_zone.h"
#include "g_game.h"
// The number of sparkles per waypoint connection in the waypoint visualisation
static const UINT32 SPARKLES_PER_CONNECTION = 16U;
@ -18,6 +19,8 @@ static waypoint_t *waypointheap = NULL;
static waypoint_t *firstwaypoint = NULL;
static waypoint_t *finishline = NULL;
static UINT32 circuitlength = 0U;
static size_t numwaypoints = 0U;
static size_t numwaypointmobjs = 0U;
static size_t baseopensetsize = OPENSET_BASE_SIZE;
@ -160,6 +163,15 @@ INT32 K_GetWaypointID(waypoint_t *waypoint)
return waypointid;
}
/*--------------------------------------------------
UINT32 K_GetCircuitLength(void)
See header file for description.
--------------------------------------------------*/
UINT32 K_GetCircuitLength(void)
{
return circuitlength;
}
/*--------------------------------------------------
size_t K_GetWaypointHeapIndex(waypoint_t *waypoint)
@ -306,6 +318,10 @@ void K_DebugWaypointsVisualise(void)
{
debugmobj->color = SKINCOLOR_ORANGE;
}
else if (waypoint == players[displayplayers[0]].nextwaypoint)
{
debugmobj->color = SKINCOLOR_YELLOW;
}
else
{
debugmobj->color = SKINCOLOR_BLUE;
@ -1267,6 +1283,56 @@ waypoint_t *K_SearchWaypointHeapForMobj(mobj_t *const mobj)
return foundwaypoint;
}
/*--------------------------------------------------
static UINT32 K_SetupCircuitLength(void)
Sets up the Circuit Length by getting the best path from the finishwaypoint back to itself.
On sprint maps, circuitlength is 0.
Input Arguments:-
None
Return:-
Length of the circuit
--------------------------------------------------*/
static UINT32 K_SetupCircuitLength(void)
{
if ((firstwaypoint == NULL) || (numwaypoints == 0U))
{
CONS_Debug(DBG_GAMELOGIC, "K_SetupCircuitLength called with no waypoints.\n");
}
else if (finishline == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "K_SetupCircuitLength called with no finishline waypoint.\n");
}
else
{
// 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)
{
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);
circuitlength = bestcircuitpath.totaldist;
Z_Free(bestcircuitpath.array);
}
}
return circuitlength;
}
/*--------------------------------------------------
static void K_AddPrevToWaypoint(waypoint_t *const waypoint, waypoint_t *const prevwaypoint)
@ -1616,6 +1682,9 @@ boolean K_SetupWaypointList(void)
K_GetWaypointID(firstwaypoint));
finishline = firstwaypoint;
}
(void)K_SetupCircuitLength();
setupsuccessful = true;
}
}
@ -1634,6 +1703,7 @@ void K_ClearWaypoints(void)
waypointheap = NULL;
firstwaypoint = NULL;
finishline = NULL;
numwaypoints = 0;
numwaypointmobjs = 0;
numwaypoints = 0U;
numwaypointmobjs = 0U;
circuitlength = 0U;
}

View file

@ -109,6 +109,19 @@ INT32 K_GetWaypointNextID(waypoint_t *waypoint);
INT32 K_GetWaypointID(waypoint_t *waypoint);
/*--------------------------------------------------
UINT32 K_GetCircuitLength(void)
Returns the circuit length, 0 on sprint maps.
Input Arguments:-
Return:-
The circuit length.
--------------------------------------------------*/
UINT32 K_GetCircuitLength(void);
/*--------------------------------------------------
boolean K_PathfindToWaypoint(
waypoint_t *const sourcewaypoint,