From b672ffa8ba598df341585ac02a7e5eae3dc3fe90 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 14 Feb 2021 22:55:03 -0800 Subject: [PATCH 1/7] Check previously considered best waypoint when pathfinding to solve overlapping waypoints Previously could skip the waypoint that was actually closer and assume the further is the best. --- src/k_waypoint.c | 58 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/k_waypoint.c b/src/k_waypoint.c index 39e9efa5e..4150ff333 100644 --- a/src/k_waypoint.c +++ b/src/k_waypoint.c @@ -253,6 +253,40 @@ waypoint_t *K_GetClosestWaypointToMobj(mobj_t *const mobj) return closestwaypoint; } +/*-------------------------------------------------- + static void K_CompareOverlappingWaypoint + ( waypoint_t *const checkwaypoint, + waypoint_t **const bestwaypoint, + fixed_t *const bestfindist) + + Solves touching overlapping waypoint radiuses by sorting by distance to + finish line. +--------------------------------------------------*/ +static void K_CompareOverlappingWaypoint +( waypoint_t *const checkwaypoint, + waypoint_t **const bestwaypoint, + fixed_t *const bestfindist) +{ + const boolean useshortcuts = false; + const boolean huntbackwards = false; + boolean pathfindsuccess = false; + path_t pathtofinish = {}; + + pathfindsuccess = + K_PathfindToWaypoint(checkwaypoint, finishline, &pathtofinish, useshortcuts, huntbackwards); + + if (pathfindsuccess == true) + { + if ((INT32)(pathtofinish.totaldist) < *bestfindist) + { + *bestwaypoint = checkwaypoint; + *bestfindist = pathtofinish.totaldist; + } + + Z_Free(pathtofinish.array); + } +} + /*-------------------------------------------------- waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj) @@ -292,30 +326,18 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj) rad = (checkwaypoint->mobj->radius / FRACUNIT); - if (closestdist < rad && checkdist < rad && finishline != NULL) + // remember: huge radius + if (closestdist <= rad && checkdist <= rad && finishline != NULL) { - const boolean useshortcuts = false; - const boolean huntbackwards = false; - boolean pathfindsuccess = false; - path_t pathtofinish = {}; - // If the mobj is touching multiple waypoints at once, // then solve ties by taking the one closest to the finish line. // Prevents position from flickering wildly when taking turns. - pathfindsuccess = - K_PathfindToWaypoint(checkwaypoint, finishline, &pathtofinish, useshortcuts, huntbackwards); + // For the first couple overlapping, check the previous best too. + if (bestfindist == INT32_MAX) + K_CompareOverlappingWaypoint(bestwaypoint, &bestwaypoint, &bestfindist); - if (pathfindsuccess == true) - { - if ((INT32)(pathtofinish.totaldist) < bestfindist) - { - bestwaypoint = checkwaypoint; - bestfindist = pathtofinish.totaldist; - } - - Z_Free(pathtofinish.array); - } + K_CompareOverlappingWaypoint(checkwaypoint, &bestwaypoint, &bestfindist); } else if (checkdist < closestdist && bestfindist == INT32_MAX) { From b4eefec81d143856bcd7d9cd4d91297dfe573249 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 14 Feb 2021 22:56:36 -0800 Subject: [PATCH 2/7] Fix angle issue with finish line waypoint hack The other hack which adds distance is also gone. It's not needed for ...reasons. All this was Sal's massive brain. --- src/k_kart.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 4d5e1770e..94b2b1237 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6553,8 +6553,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) if (bestwaypoint == K_GetFinishLineWaypoint()) { + waypoint_t *nextwaypoint = waypoint->nextwaypoints[0]; + angle_t angletonextwaypoint = + R_PointToAngle2(waypoint->mobj->x, waypoint->mobj->y, nextwaypoint->mobj->x, nextwaypoint->mobj->y); + // facing towards the finishline - if (angledelta <= ANGLE_90) + if (abs(AngleDifference(angletonextwaypoint, angletowaypoint)) <= ANGLE_90) { finishlinehack = true; } @@ -6698,6 +6702,7 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) return bestwaypoint; } +#if 0 static boolean K_PlayerCloserToNextWaypoints(waypoint_t *const waypoint, player_t *const player) { boolean nextiscloser = true; @@ -6758,6 +6763,7 @@ static boolean K_PlayerCloserToNextWaypoints(waypoint_t *const waypoint, player_ return nextiscloser; } +#endif /*-------------------------------------------------- void K_UpdateDistanceFromFinishLine(player_t *const player) @@ -6837,6 +6843,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) player->distancetofinish += numfulllapsleft * K_GetCircuitLength(); +#if 0 // 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 @@ -6847,6 +6854,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) player->distancetofinish += K_GetCircuitLength(); } } +#endif } } } From 29d9bafb9e405fe6df8db2abc273c06def5356dd Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 14 Feb 2021 23:04:17 -0800 Subject: [PATCH 3/7] Snap finish line waypoints to the nearest point of the finish line Finish line waypoints must be exactly on the finish line to avoid erroneous finish line distance from crossing the waypoint before/after the line. This is only a problem in circuit maps and on laps before the last, due to the multiplied circuit length. --- src/p_mobj.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 2bc6c620f..ac48b953d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11325,6 +11325,39 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) return true; } +static fixed_t dist2vert(const vertex_t *v, const mobj_t *o) +{ + return abs(FixedHypot(v->x - o->x, v->y - o->y)); +} + +static void P_SnapToFinishLine(mobj_t *mobj) +{ + const sector_t *sector = mobj->subsector->sector; + size_t i; + fixed_t d; + fixed_t nearest = INT32_MAX; + line_t *nearest_line = NULL; + for (i = 0; i < sector->linecount; ++i) + { + if ( + sector->lines[i]->special == 2001 && // case 2001: Finish Line + ( + (d = dist2vert(sector->lines[i]->v1, mobj)) < nearest || + (d = dist2vert(sector->lines[i]->v2, mobj)) < nearest + ) + ){ + nearest = d; + nearest_line = sector->lines[i]; + } + } + if (nearest < INT32_MAX) + { + P_UnsetThingPosition(mobj); + P_ClosestPointOnLine(mobj->x, mobj->y, nearest_line, (vertex_t *)&mobj->x); + P_SetThingPosition(mobj); + } +} + static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) { boolean override = LUAh_MapThingSpawn(mobj, mthing); @@ -11708,7 +11741,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean } if (mthing->args[2] == 1) { - mobj->extravalue2 = 1; // args[1] of 1 means the waypoint is at the finish line + mobj->extravalue2 = 1; // args[2] of 1 means the waypoint is at the finish line + P_SnapToFinishLine(mobj); } else { From 4f96fead3a0f8025c5a926257a7eb7e8665db6ed Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 15 Feb 2021 01:46:29 -0800 Subject: [PATCH 4/7] Search entire map, not just waypoint's sector, for finish line --- src/p_mobj.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index ac48b953d..286c99742 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11332,22 +11332,19 @@ static fixed_t dist2vert(const vertex_t *v, const mobj_t *o) static void P_SnapToFinishLine(mobj_t *mobj) { - const sector_t *sector = mobj->subsector->sector; - size_t i; + INT32 i = -1; fixed_t d; fixed_t nearest = INT32_MAX; line_t *nearest_line = NULL; - for (i = 0; i < sector->linecount; ++i) + // case 2001: Finish Line + while ((i = P_FindSpecialLineFromTag(2001, -1, i)) != -1) { if ( - sector->lines[i]->special == 2001 && // case 2001: Finish Line - ( - (d = dist2vert(sector->lines[i]->v1, mobj)) < nearest || - (d = dist2vert(sector->lines[i]->v2, mobj)) < nearest - ) + (d = dist2vert(lines[i].v1, mobj)) < nearest || + (d = dist2vert(lines[i].v2, mobj)) < nearest ){ nearest = d; - nearest_line = sector->lines[i]; + nearest_line = &lines[i]; } } if (nearest < INT32_MAX) From 82718216ccd11f0218d039da23f46af4ddabcabc Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 15 Feb 2021 23:01:13 -0800 Subject: [PATCH 5/7] Respawn slightly before a waypoint, in the direction you came from, if the waypoint is exactly on a line See notably the finish line. Basically respawning exactly on a line can let you cross it twice, if you crossed it before respawning, or NOT cross it, depending on which direction you drive after landing. So this just respawns very slightly before the line so you can cross (or not cross) it normally. --- src/k_respawn.c | 20 ++++++++++++++ src/k_waypoint.c | 38 ++++++++++++++++++++++++++ src/k_waypoint.h | 1 + src/p_maputl.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ src/p_maputl.h | 1 + src/p_mobj.c | 26 +++--------------- 6 files changed, 134 insertions(+), 22 deletions(-) diff --git a/src/k_respawn.c b/src/k_respawn.c index 7052fe466..897300254 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -54,6 +54,21 @@ fixed_t K_RespawnOffset(player_t *player, boolean flip) return z; } +/*-------------------------------------------------- + static void K_FudgeRespawn(player_t *player, const waypoint_t *const waypoint) + + Fudges respawn coordinates to slightly before the waypoint if it would + be exactly on a line. See K_GetWaypointIsOnLine. +--------------------------------------------------*/ +static void K_FudgeRespawn(player_t *player, const waypoint_t *const waypoint) +{ + const angle_t from = R_PointToAngle2(waypoint->mobj->x, waypoint->mobj->y, + player->mo->x, player->mo->y) >> ANGLETOFINESHIFT; + + player->respawn.pointx += FixedMul(16, FINECOSINE(from)); + player->respawn.pointy += FixedMul(16, FINESINE(from)); +} + /*-------------------------------------------------- static void K_RespawnAtWaypoint(player_t *player, waypoint_t *waypoint) @@ -83,6 +98,11 @@ static void K_RespawnAtWaypoint(player_t *player, waypoint_t *waypoint) player->respawn.pointz = waypoint->mobj->z; player->respawn.flip = (waypoint->mobj->flags2 & MF2_OBJECTFLIP) ? true : false; // K_RespawnOffset wants a boolean! player->respawn.pointz += K_RespawnOffset(player, player->respawn.flip); + + if (waypoint->onaline) + { + K_FudgeRespawn(player, waypoint); + } } /*-------------------------------------------------- diff --git a/src/k_waypoint.c b/src/k_waypoint.c index 4150ff333..ae6841a34 100644 --- a/src/k_waypoint.c +++ b/src/k_waypoint.c @@ -153,6 +153,38 @@ boolean K_GetWaypointIsSpawnpoint(waypoint_t *waypoint) return waypointisspawnpoint; } +/*-------------------------------------------------- + static boolean K_GetWaypointIsOnLine(waypoint_t *const waypoint) + + Checks if a waypoint is exactly on a line. Moving to an exact point + on a line won't count as crossing it. Moving off of that point does. + Respawning to a waypoint which is exactly on a line is the easiest + way to for this to occur. + + Return:- + Whether the waypoint is exactly on a line. +--------------------------------------------------*/ +static boolean K_GetWaypointIsOnLine(waypoint_t *const waypoint) +{ + const fixed_t x = waypoint->mobj->x; + const fixed_t y = waypoint->mobj->y; + + line_t *line = P_FindNearestLine(x, y, + waypoint->mobj->subsector->sector, -1); + + vertex_t point; + + if (line != NULL) + { + P_ClosestPointOnLine(x, y, line, &point); + + if (x == point.x && y == point.y) + return true; + } + + return false; +} + /*-------------------------------------------------- INT32 K_GetWaypointNextID(waypoint_t *waypoint) @@ -1700,6 +1732,12 @@ static waypoint_t *K_SetupWaypoint(mobj_t *const mobj) finishline = thiswaypoint; } + /* only relevant for respawning */ + if (K_GetWaypointIsSpawnpoint(thiswaypoint)) + { + thiswaypoint->onaline = K_GetWaypointIsOnLine(thiswaypoint); + } + if (thiswaypoint->numnextwaypoints > 0) { waypoint_t *nextwaypoint = NULL; diff --git a/src/k_waypoint.h b/src/k_waypoint.h index 41230b49b..f49e162e8 100644 --- a/src/k_waypoint.h +++ b/src/k_waypoint.h @@ -23,6 +23,7 @@ typedef struct waypoint_s { mobj_t *mobj; + boolean onaline; struct waypoint_s **nextwaypoints; struct waypoint_s **prevwaypoints; UINT32 *nextwaypointdistances; diff --git a/src/p_maputl.c b/src/p_maputl.c index 9131c24bb..4dce1e6fd 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -259,6 +259,76 @@ fixed_t P_InterceptVector(divline_t *v2, divline_t *v1) return frac; } +static fixed_t dist2line(const line_t *ld, const fixed_t x, const fixed_t y) +{ + return FixedHypot + ( + ld->v1->x + (ld->dx / 2) - x, + ld->v1->y + (ld->dy / 2) - y + ); +} + +static void checknearline +( line_t * line, + fixed_t * near, + line_t ** near_line, + const fixed_t x, + const fixed_t y) +{ + const fixed_t d = dist2line(line, x, y); + + if (d < *near) + { + *near = d; + *near_line = line; + } +} + +// +// P_FindNearestLine +// Returns the nearest line to a point which +// is in a sector and/or a specific type. +// +line_t * P_FindNearestLine +( const fixed_t x, + const fixed_t y, + const sector_t * sector, + const INT32 special) +{ + fixed_t near = INT32_MAX; + line_t *near_line = NULL; + size_t i; + INT32 line = -1; + + if (special == -1) + { + if (sector == NULL) + sector = R_PointInSubsector(x, y)->sector; + + for (i = 0; i < sector->linecount; ++i) + { + checknearline(sector->lines[i], &near, &near_line, x, y); + } + } + else if (sector != NULL) + { + for (i = 0; i < sector->linecount; ++i) + { + if (sector->lines[i]->special == special) + checknearline(sector->lines[i], &near, &near_line, x, y); + } + } + else + { + while ((line = P_FindSpecialLineFromTag(special, -1, line)) != -1) + { + checknearline(&lines[line], &near, &near_line, x, y); + } + } + + return near_line; +} + // // P_LineOpening // Sets opentop and openbottom to the window through a two sided line. diff --git a/src/p_maputl.h b/src/p_maputl.h index ce4509ca9..6f0c1f8ad 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -49,6 +49,7 @@ void P_MakeDivline(line_t *li, divline_t *dl); void P_CameraLineOpening(line_t *plinedef); fixed_t P_InterceptVector(divline_t *v2, divline_t *v1); INT32 P_BoxOnLineSide(fixed_t *tmbox, line_t *ld); +line_t * P_FindNearestLine(const fixed_t x, const fixed_t y, const sector_t *, const INT32 special); void P_UnsetPrecipThingPosition(precipmobj_t *thing); void P_SetPrecipitationThingPosition(precipmobj_t *thing); void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y); diff --git a/src/p_mobj.c b/src/p_mobj.c index 286c99742..137802730 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11325,32 +11325,14 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) return true; } -static fixed_t dist2vert(const vertex_t *v, const mobj_t *o) -{ - return abs(FixedHypot(v->x - o->x, v->y - o->y)); -} - static void P_SnapToFinishLine(mobj_t *mobj) { - INT32 i = -1; - fixed_t d; - fixed_t nearest = INT32_MAX; - line_t *nearest_line = NULL; - // case 2001: Finish Line - while ((i = P_FindSpecialLineFromTag(2001, -1, i)) != -1) - { - if ( - (d = dist2vert(lines[i].v1, mobj)) < nearest || - (d = dist2vert(lines[i].v2, mobj)) < nearest - ){ - nearest = d; - nearest_line = &lines[i]; - } - } - if (nearest < INT32_MAX) + line_t *finishline = P_FindNearestLine(mobj->x, mobj->y, + mobj->subsector->sector, 2001); // case 2001: Finish Line + if (finishline != NULL) { P_UnsetThingPosition(mobj); - P_ClosestPointOnLine(mobj->x, mobj->y, nearest_line, (vertex_t *)&mobj->x); + P_ClosestPointOnLine(mobj->x, mobj->y, finishline, (vertex_t *)&mobj->x); P_SetThingPosition(mobj); } } From 130e1fc4f92329cee00bc2de759d2ba1ba4d89c0 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 15 Feb 2021 23:12:30 -0800 Subject: [PATCH 6/7] Windows??? --- src/p_maputl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/p_maputl.c b/src/p_maputl.c index 4dce1e6fd..5cf2e81fe 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -270,16 +270,16 @@ static fixed_t dist2line(const line_t *ld, const fixed_t x, const fixed_t y) static void checknearline ( line_t * line, - fixed_t * near, + fixed_t * nearest, line_t ** near_line, const fixed_t x, const fixed_t y) { const fixed_t d = dist2line(line, x, y); - if (d < *near) + if (d < *nearest) { - *near = d; + *nearest = d; *near_line = line; } } @@ -295,7 +295,7 @@ line_t * P_FindNearestLine const sector_t * sector, const INT32 special) { - fixed_t near = INT32_MAX; + fixed_t nearest = INT32_MAX; line_t *near_line = NULL; size_t i; INT32 line = -1; @@ -307,7 +307,7 @@ line_t * P_FindNearestLine for (i = 0; i < sector->linecount; ++i) { - checknearline(sector->lines[i], &near, &near_line, x, y); + checknearline(sector->lines[i], &nearest, &near_line, x, y); } } else if (sector != NULL) @@ -315,14 +315,14 @@ line_t * P_FindNearestLine for (i = 0; i < sector->linecount; ++i) { if (sector->lines[i]->special == special) - checknearline(sector->lines[i], &near, &near_line, x, y); + checknearline(sector->lines[i], &nearest, &near_line, x, y); } } else { while ((line = P_FindSpecialLineFromTag(special, -1, line)) != -1) { - checknearline(&lines[line], &near, &near_line, x, y); + checknearline(&lines[line], &nearest, &near_line, x, y); } } From 9fae8dbb41ed3c741a8b443da58fd5f8352273d6 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 15 Feb 2021 23:08:32 -0800 Subject: [PATCH 7/7] Don't respawn on the finish line waypoint This causes you to respawn at the waypoint before the finish line waypoint, which I think looks a bit nicer. --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 137802730..3dd5108a0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11721,6 +11721,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (mthing->args[2] == 1) { mobj->extravalue2 = 1; // args[2] of 1 means the waypoint is at the finish line + mobj->reactiontime = 0; // Also don't respawn at finish lines + P_SnapToFinishLine(mobj); } else