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 } } } diff --git a/src/k_respawn.c b/src/k_respawn.c index 016420105..409340a3f 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 39e9efa5e..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) @@ -253,6 +285,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 +358,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) { @@ -1678,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..5cf2e81fe 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 * nearest, + line_t ** near_line, + const fixed_t x, + const fixed_t y) +{ + const fixed_t d = dist2line(line, x, y); + + if (d < *nearest) + { + *nearest = 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 nearest = 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], &nearest, &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], &nearest, &near_line, x, y); + } + } + else + { + while ((line = P_FindSpecialLineFromTag(special, -1, line)) != -1) + { + checknearline(&lines[line], &nearest, &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 52e489727..25a505821 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11334,6 +11334,18 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) return true; } +static void P_SnapToFinishLine(mobj_t *mobj) +{ + 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, finishline, (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); @@ -11717,7 +11729,10 @@ 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 + mobj->reactiontime = 0; // Also don't respawn at finish lines + + P_SnapToFinishLine(mobj); } else {