Merge branch 'more-polyobject-cleanup' into 'next'

Smooth polyobject movement and other cleanup

See merge request STJr/SRB2!947
This commit is contained in:
MascaraSnake 2020-05-18 16:00:55 -04:00
commit 6f854f2de3
6 changed files with 193 additions and 235 deletions

View File

@ -631,6 +631,7 @@ mobj_t *P_GetLastWaypoint(UINT8 sequence);
mobj_t *P_GetPreviousWaypoint(mobj_t *current, boolean wrap);
mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap);
mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo);
boolean P_IsDegeneratedWaypointSequence(UINT8 sequence);
// =====================================
// Internal parameters, used for engine.

View File

@ -1569,15 +1569,39 @@ void T_PolyObjMove(polymove_t *th)
}
}
static void T_MovePolyObj(polyobj_t *po, fixed_t distx, fixed_t disty, fixed_t distz)
{
polyobj_t *child;
INT32 start;
Polyobj_moveXY(po, distx, disty, true);
// TODO: use T_MovePlane
po->lines[0]->backsector->floorheight += distz;
po->lines[0]->backsector->ceilingheight += distz;
// Sal: Remember to check your sectors!
// Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
// Apply action to mirroring polyobjects as well
start = 0;
while ((child = Polyobj_GetChild(po, &start)))
{
if (child->isBad)
continue;
Polyobj_moveXY(child, distx, disty, true);
// TODO: use T_MovePlane
child->lines[0]->backsector->floorheight += distz;
child->lines[0]->backsector->ceilingheight += distz;
P_CheckSector(child->lines[0]->backsector, (boolean)(child->damage));
}
}
void T_PolyObjWaypoint(polywaypoint_t *th)
{
mobj_t *target = NULL;
mobj_t *waypoint = NULL;
fixed_t adjustx, adjusty, adjustz;
fixed_t momx, momy, momz, dist;
INT32 start;
polyobj_t *po = Polyobj_GetForNum(th->polyObjNum);
polyobj_t *oldpo = po;
fixed_t speed = th->speed;
if (!po)
#ifdef RANGECHECK
@ -1594,7 +1618,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
if (!po->thinker)
po->thinker = &th->thinker;
target = th->target;
target = waypoints[th->sequence][th->pointnum];
if (!target)
{
@ -1602,152 +1626,93 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
return;
}
// Compensate for position offset
adjustx = po->centerPt.x + th->diffx;
adjusty = po->centerPt.y + th->diffy;
adjustz = po->lines[0]->backsector->floorheight + (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2 + th->diffz;
dist = P_AproxDistance(P_AproxDistance(target->x - adjustx, target->y - adjusty), target->z - adjustz);
if (dist < 1)
dist = 1;
momx = FixedMul(FixedDiv(target->x - adjustx, dist), (th->speed));
momy = FixedMul(FixedDiv(target->y - adjusty, dist), (th->speed));
momz = FixedMul(FixedDiv(target->z - adjustz, dist), (th->speed));
// Calculate the distance between the polyobject and the waypoint
// 'dist' already equals this.
// Will the polyobject be FURTHER away if the momx/momy/momz is added to
// its current coordinates, or closer? (shift down to fracunits to avoid approximation errors)
if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(target->x - adjustx - momx, target->y - adjusty - momy), target->z - adjustz - momz)>>FRACBITS)
// Move along the waypoint sequence until speed for the current tic is exhausted
while (speed > 0)
{
// If further away, set XYZ of polyobject to waypoint location
fixed_t amtx, amty, amtz;
fixed_t diffz;
amtx = (target->x - th->diffx) - po->centerPt.x;
amty = (target->y - th->diffy) - po->centerPt.y;
Polyobj_moveXY(po, amtx, amty, true);
// TODO: use T_MovePlane
amtz = (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2;
diffz = po->lines[0]->backsector->floorheight - (target->z - amtz);
po->lines[0]->backsector->floorheight = target->z - amtz;
po->lines[0]->backsector->ceilingheight = target->z + amtz;
// Sal: Remember to check your sectors!
// Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
// Apply action to mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
mobj_t *waypoint = NULL;
fixed_t pox, poy, poz;
fixed_t distx, disty, distz, dist;
// Current position of polyobject
pox = po->centerPt.x;
poy = po->centerPt.y;
poz = (po->lines[0]->backsector->floorheight + po->lines[0]->backsector->ceilingheight)/2;
// Calculate the distance between the polyobject and the waypoint
distx = target->x - pox;
disty = target->y - poy;
distz = target->z - poz;
dist = P_AproxDistance(P_AproxDistance(distx, disty), distz);
if (dist < 1)
dist = 1;
// Will the polyobject overshoot its target?
if (speed < dist)
{
if (po->isBad)
continue;
// No. Move towards waypoint
fixed_t momx, momy, momz;
Polyobj_moveXY(po, amtx, amty, true);
// TODO: use T_MovePlane
po->lines[0]->backsector->floorheight += diffz; // move up/down by same amount as the parent did
po->lines[0]->backsector->ceilingheight += diffz;
// Sal: Remember to check your sectors!
// Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
}
po = oldpo;
if (!th->stophere)
{
CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n");
waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false);
if (!waypoint && th->wrap) // If specified, wrap waypoints
{
if (!th->continuous)
{
th->wrap = 0;
th->stophere = true;
}
waypoint = (th->direction == -1) ? P_GetLastWaypoint(th->sequence) : P_GetFirstWaypoint(th->sequence);
}
else if (!waypoint && th->comeback) // Come back to the start
{
th->direction = -th->direction;
if (!th->continuous)
th->comeback = false;
waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false);
}
}
if (waypoint)
{
CONS_Debug(DBG_POLYOBJ, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
target = waypoint;
th->pointnum = target->health;
// Set the mobj as your target! -- Monster Iestyn 27/12/19
P_SetTarget(&th->target, target);
// calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
dist = P_AproxDistance(P_AproxDistance(target->x - adjustx, target->y - adjusty), target->z - adjustz);
if (dist < 1)
dist = 1;
momx = FixedMul(FixedDiv(target->x - adjustx, dist), (th->speed));
momy = FixedMul(FixedDiv(target->y - adjusty, dist), (th->speed));
momz = FixedMul(FixedDiv(target->z - adjustz, dist), (th->speed));
momx = FixedMul(FixedDiv(target->x - pox, dist), speed);
momy = FixedMul(FixedDiv(target->y - poy, dist), speed);
momz = FixedMul(FixedDiv(target->z - poz, dist), speed);
T_MovePolyObj(po, momx, momy, momz);
return;
}
else
{
momx = momy = momz = 0;
// Yes. Teleport to waypoint and look for the next one
T_MovePolyObj(po, distx, disty, distz);
if (!th->stophere)
CONS_Debug(DBG_POLYOBJ, "Next waypoint not found!\n");
{
CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n");
waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false);
if (po->thinker == &th->thinker)
po->thinker = NULL;
if (!waypoint && th->returnbehavior == PWR_WRAP) // If specified, wrap waypoints
{
if (!th->continuous)
{
th->returnbehavior = PWR_STOP;
th->stophere = true;
}
P_RemoveThinker(&th->thinker);
return;
waypoint = (th->direction == -1) ? P_GetLastWaypoint(th->sequence) : P_GetFirstWaypoint(th->sequence);
}
else if (!waypoint && th->returnbehavior == PWR_COMEBACK) // Come back to the start
{
th->direction = -th->direction;
if (!th->continuous)
th->returnbehavior = PWR_STOP;
waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false);
}
}
if (waypoint)
{
CONS_Debug(DBG_POLYOBJ, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
target = waypoint;
th->pointnum = target->health;
// Calculate remaining speed
speed -= dist;
}
else
{
if (!th->stophere)
CONS_Debug(DBG_POLYOBJ, "Next waypoint not found!\n");
if (po->thinker == &th->thinker)
po->thinker = NULL;
P_RemoveThinker(&th->thinker);
return;
}
}
}
else
{
// momx/momy/momz already equals the right speed
}
// Move the polyobject
Polyobj_moveXY(po, momx, momy, true);
// TODO: use T_MovePlane
po->lines[0]->backsector->floorheight += momz;
po->lines[0]->backsector->ceilingheight += momz;
// Sal: Remember to check your sectors!
// Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
// Apply action to mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
{
if (po->isBad)
continue;
Polyobj_moveXY(po, momx, momy, true);
// TODO: use T_MovePlane
po->lines[0]->backsector->floorheight += momz;
po->lines[0]->backsector->ceilingheight += momz;
// Sal: Remember to check your sectors!
// Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
}
}
void T_PolyDoorSlide(polyslidedoor_t *th)
@ -2166,8 +2131,6 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
polyobj_t *po;
polywaypoint_t *th;
mobj_t *first = NULL;
mobj_t *last = NULL;
mobj_t *target = NULL;
if (!(po = Polyobj_GetForNum(pwdata->polyObjNum)))
{
@ -2191,17 +2154,16 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
// set fields
th->polyObjNum = pwdata->polyObjNum;
th->speed = pwdata->speed;
th->sequence = pwdata->sequence; // Used to specify sequence #
th->direction = pwdata->reverse ? -1 : 1;
th->sequence = pwdata->sequence;
th->direction = (pwdata->flags & PWF_REVERSE) ? -1 : 1;
th->comeback = pwdata->comeback;
th->continuous = pwdata->continuous;
th->wrap = pwdata->wrap;
th->returnbehavior = pwdata->returnbehavior;
if (pwdata->flags & PWF_LOOP)
th->continuous = true;
th->stophere = false;
// Find the first waypoint we need to use
first = (th->direction == -1) ? P_GetLastWaypoint(th->sequence) : P_GetFirstWaypoint(th->sequence);
last = (th->direction == -1) ? P_GetFirstWaypoint(th->sequence) : P_GetLastWaypoint(th->sequence);
if (!first)
{
@ -2211,47 +2173,16 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
return false;
}
// Hotfix to not crash on single-waypoint sequences -Red
if (!last)
last = first;
// Set diffx, diffy, diffz
// Put these at 0 for now...might not be needed after all.
th->diffx = 0;//first->x - po->centerPt.x;
th->diffy = 0;//first->y - po->centerPt.y;
th->diffz = 0;//first->z - (po->lines[0]->backsector->floorheight + (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2);
if (last->x == po->centerPt.x
&& last->y == po->centerPt.y
&& last->z == (po->lines[0]->backsector->floorheight + (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2))
// Sanity check: If all waypoints are in the same location,
// don't allow the movement to be continuous so we don't get stuck in an infinite loop.
if (th->continuous && P_IsDegeneratedWaypointSequence(th->sequence))
{
// Already at the destination point...
if (!th->wrap)
{
po->thinker = NULL;
P_RemoveThinker(&th->thinker);
}
CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjWaypoint: All waypoints are in the same location!\n");
th->continuous = false;
}
// Find the actual target movement waypoint
target = first;
th->pointnum = first->health;
if (!target)
{
CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjWaypoint: Missing target waypoint!\n");
po->thinker = NULL;
P_RemoveThinker(&th->thinker);
return false;
}
// Set pointnum
th->pointnum = target->health;
th->target = NULL; // set to NULL first so the below doesn't go wrong
// Set the mobj as your target! -- Monster Iestyn 27/12/19
P_SetTarget(&th->target, target);
// We don't deal with the mirror crap here, we'll
// handle that in the T_Thinker function.
return true;
}

View File

@ -140,26 +140,26 @@ typedef struct polymove_s
UINT32 angle; // angle along which to move
} polymove_t;
// PolyObject waypoint movement return behavior
typedef enum
{
PWR_STOP, // Stop after reaching last waypoint
PWR_WRAP, // Wrap back to first waypoint
PWR_COMEBACK, // Repeat sequence in reverse
} polywaypointreturn_e;
typedef struct polywaypoint_s
{
thinker_t thinker; // must be first
INT32 polyObjNum; // numeric id of polyobject
INT32 speed; // resultant velocity
INT32 sequence; // waypoint sequence #
INT32 pointnum; // waypoint #
INT32 direction; // 1 for normal, -1 for backwards
UINT8 comeback; // reverses and comes back when the end is reached
UINT8 wrap; // Wrap around waypoints
UINT8 continuous; // continuously move - used with COMEBACK or WRAP
UINT8 stophere; // Will stop after it reaches the next waypoint
// Difference between location of PO and location of waypoint (offset)
fixed_t diffx;
fixed_t diffy;
fixed_t diffz;
mobj_t *target; // next waypoint mobj
INT32 polyObjNum; // numeric id of polyobject
INT32 speed; // resultant velocity
INT32 sequence; // waypoint sequence #
INT32 pointnum; // waypoint #
INT32 direction; // 1 for normal, -1 for backwards
UINT8 returnbehavior; // behavior after reaching the last waypoint
UINT8 continuous; // continuously move - used with PWR_WRAP or PWR_COMEBACK
UINT8 stophere; // Will stop after it reaches the next waypoint
} polywaypoint_t;
typedef struct polyslidedoor_s
@ -254,15 +254,19 @@ typedef struct polymovedata_s
UINT8 overRide; // if true, will override any action on the object
} polymovedata_t;
typedef enum
{
PWF_REVERSE = 1, // Move through waypoints in reverse order
PWF_LOOP = 1<<1, // Loop movement (used with PWR_WRAP or PWR_COMEBACK)
} polywaypointflags_e;
typedef struct polywaypointdata_s
{
INT32 polyObjNum; // numeric id of polyobject to affect
INT32 sequence; // waypoint sequence #
fixed_t speed; // linear speed
UINT8 reverse; // if true, will go in reverse waypoint order
UINT8 comeback; // reverses and comes back when the end is reached
UINT8 wrap; // Wrap around waypoints
UINT8 continuous; // continuously move - used with COMEBACK or WRAP
INT32 polyObjNum; // numeric id of polyobject to affect
INT32 sequence; // waypoint sequence #
fixed_t speed; // linear speed
UINT8 returnbehavior; // behavior after reaching the last waypoint
UINT8 flags; // PWF_ flags
} polywaypointdata_t;
// polyobject door types

View File

@ -2018,14 +2018,9 @@ static void SavePolywaypointThinker(const thinker_t *th, UINT8 type)
WRITEINT32(save_p, ht->sequence);
WRITEINT32(save_p, ht->pointnum);
WRITEINT32(save_p, ht->direction);
WRITEUINT8(save_p, ht->comeback);
WRITEUINT8(save_p, ht->wrap);
WRITEUINT8(save_p, ht->returnbehavior);
WRITEUINT8(save_p, ht->continuous);
WRITEUINT8(save_p, ht->stophere);
WRITEFIXED(save_p, ht->diffx);
WRITEFIXED(save_p, ht->diffy);
WRITEFIXED(save_p, ht->diffz);
WRITEUINT32(save_p, SaveMobjnum(ht->target));
}
static void SavePolyslidedoorThinker(const thinker_t *th, const UINT8 type)
@ -3157,14 +3152,9 @@ static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker)
ht->sequence = READINT32(save_p);
ht->pointnum = READINT32(save_p);
ht->direction = READINT32(save_p);
ht->comeback = READUINT8(save_p);
ht->wrap = READUINT8(save_p);
ht->returnbehavior = READUINT8(save_p);
ht->continuous = READUINT8(save_p);
ht->stophere = READUINT8(save_p);
ht->diffx = READFIXED(save_p);
ht->diffy = READFIXED(save_p);
ht->diffz = READFIXED(save_p);
ht->target = LoadMobj(READUINT32(save_p));
return &ht->thinker;
}
@ -3411,7 +3401,6 @@ static void P_NetUnArchiveThinkers(void)
case tc_polywaypoint:
th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint);
restoreNum = true;
break;
case tc_polyslidedoor:
@ -3471,7 +3460,6 @@ static void P_NetUnArchiveThinkers(void)
if (restoreNum)
{
executor_t *delay = NULL;
polywaypoint_t *polywp = NULL;
UINT32 mobjnum;
for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next)
{
@ -3482,15 +3470,6 @@ static void P_NetUnArchiveThinkers(void)
continue;
delay->caller = P_FindNewPosition(mobjnum);
}
for (currentthinker = thlist[THINK_POLYOBJ].next; currentthinker != &thlist[THINK_POLYOBJ]; currentthinker = currentthinker->next)
{
if (currentthinker->function.acp1 != (actionf_p1)T_PolyObjWaypoint)
continue;
polywp = (void *)currentthinker;
if (!(mobjnum = (UINT32)(size_t)polywp->target))
continue;
polywp->target = P_FindNewPosition(mobjnum);
}
}
}

View File

@ -239,6 +239,38 @@ mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo)
return result;
}
// Return true if all waypoints are in the same location
boolean P_IsDegeneratedWaypointSequence(UINT8 sequence)
{
mobj_t *first, *waypoint;
UINT8 wp;
if (numwaypoints[sequence] <= 1)
return true;
first = waypoints[sequence][0];
for (wp = 1; wp < numwaypoints[sequence]; wp++)
{
waypoint = waypoints[sequence][wp];
if (!waypoint)
continue;
if (waypoint->x != first->x)
return false;
if (waypoint->y != first->y)
return false;
if (waypoint->z != first->z)
return false;
}
return true;
}
/** Logs an error about a map being corrupt, then terminate.
* This allows reporting highly technical errors for usefulness, without
* confusing a novice map designer who simply needs to run ZenNode.

View File

@ -1276,10 +1276,21 @@ static boolean PolyWaypoint(line_t *line)
pwd.polyObjNum = line->tag;
pwd.speed = sides[line->sidenum[0]].textureoffset / 8;
pwd.sequence = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Sequence #
pwd.reverse = (line->flags & ML_EFFECT1) == ML_EFFECT1; // Reverse?
pwd.comeback = (line->flags & ML_EFFECT2) == ML_EFFECT2; // Return when reaching end?
pwd.wrap = (line->flags & ML_EFFECT3) == ML_EFFECT3; // Wrap around waypoints
pwd.continuous = (line->flags & ML_EFFECT4) == ML_EFFECT4; // Continuously move - used with COMEBACK or WRAP
// Behavior after reaching the last waypoint?
if (line->flags & ML_EFFECT3)
pwd.returnbehavior = PWR_WRAP; // Wrap back to first waypoint
else if (line->flags & ML_EFFECT2)
pwd.returnbehavior = PWR_COMEBACK; // Go through sequence in reverse
else
pwd.returnbehavior = PWR_STOP; // Stop
// Flags
pwd.flags = 0;
if (line->flags & ML_EFFECT1)
pwd.flags |= PWF_REVERSE;
if (line->flags & ML_EFFECT4)
pwd.flags |= PWF_LOOP;
return EV_DoPolyObjWaypoint(&pwd);
}