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.
This commit is contained in:
James R 2021-02-15 23:01:13 -08:00
parent 4f96fead3a
commit 82718216cc
6 changed files with 134 additions and 22 deletions

View file

@ -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);
}
}
/*--------------------------------------------------

View file

@ -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;

View file

@ -23,6 +23,7 @@
typedef struct waypoint_s
{
mobj_t *mobj;
boolean onaline;
struct waypoint_s **nextwaypoints;
struct waypoint_s **prevwaypoints;
UINT32 *nextwaypointdistances;

View file

@ -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.

View file

@ -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);

View file

@ -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);
}
}