Merge branch 'touching_fixes' into 'next'

Fixes with respect to sector special touching and slopes

Some important stuff.

* SF_TRIGGERSPECIAL_TOUCH now actually works. Previously, it abandoned the loop early if ANY bounding sector didn't have that sector flag, which it likely didn't - only checking one extra sector's worth of FOFs. Also, the teleport handling there is more robust, and actually bails out if you teleport, instead of just awkwardly continuing through the loop.
* SF_TRIGGERSPECIAL_TOUCH now works for each time thinkers, too.
* Fixed a bug with being able to go under lava because P_CheckSolidLava doesn't take slopes into account.
* Also, P_CanRunOnWater supports slopes now too.
* Quicksand supports slopes and reverse gravity now.
* Space Countdown supports slopes now.

Also, an experiment behind a #define which currently isn't turned on:

* UNDER A #define, "SECTORSPECIALSAFTERTHINK", WHICH IS CURRENTLY TURNED OFF, BUT I WILL WANT TO TURN ON IN INTERNAL: Moved sector touch handling to P_PlayerAfterThinker (from P_PlayerThinker before movement). Allows for being able to trigger moving slope sectors that are going down, most specifically lava (didn't matter in RVZS in 2.1 because you could clip through the sides and go underneath the lava, causing damage - a sloped testwad version of that prevented going underneath.) Also fixes one-frame standing on deathpits before you die. Basically means sector triggers effectively happen one tic earlier, since it's after movement.

See merge request !131
This commit is contained in:
Monster Iestyn 2017-06-22 17:30:57 -04:00
commit 44f33e6732
5 changed files with 231 additions and 57 deletions

View file

@ -498,4 +498,8 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// \note You should leave this enabled unless you're working with a future SRB2 version.
#define MUSICSLOT_COMPATIBILITY
/// Handle touching sector specials in P_PlayerAfterThink instead of P_PlayerThink.
/// \note Required for proper collision with moving sloped surfaces that have sector specials on them.
//#define SECTORSPECIALSAFTERTHINK
#endif // __DOOMDEF__

View file

@ -2073,6 +2073,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
boolean inAndOut = false;
boolean floortouch = false;
fixed_t bottomheight, topheight;
msecnode_t *node;
for (i = 0; i < MAXPLAYERS; i++)
{
@ -2134,7 +2135,23 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
if ((netgame || multiplayer) && players[j].spectator)
continue;
if (players[j].mo->subsector->sector != targetsec)
if (players[j].mo->subsector->sector == targetsec)
;
else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
for (node = players[j].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == targetsec)
{
insector = true;
break;
}
}
if (!insector)
continue;
}
else
continue;
topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec);
@ -2184,7 +2201,27 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
if ((netgame || multiplayer) && players[i].spectator)
continue;
if (players[i].mo->subsector->sector != sec)
if (players[i].mo->subsector->sector == sec)
;
else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sec)
{
insector = true;
break;
}
}
if (!insector)
continue;
}
else
continue;
if (!(players[i].mo->subsector->sector == sec
|| P_PlayerTouchingSectorSpecial(&players[i], 2, (GETSECSPECIAL(sec->special, 2))) == sec))
continue;
if (floortouch == true && P_IsObjectOnGroundIn(players[i].mo, sec))

View file

@ -2138,10 +2138,18 @@ boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover)
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
&& !(rover->master->flags & ML_BLOCKMONSTERS)
&& ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > *rover->topheight - FixedMul(16*FRACUNIT, mo->scale)))
return true;
{
fixed_t topheight =
#ifdef ESLOPE
*rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) :
#endif
*rover->topheight;
if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
&& !(rover->master->flags & ML_BLOCKMONSTERS)
&& ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > topheight - FixedMul(16*FRACUNIT, mo->scale)))
return true;
}
return false;
}
@ -3076,11 +3084,17 @@ static boolean P_SceneryZMovement(mobj_t *mo)
//
boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
{
fixed_t topheight =
#ifdef ESLOPE
*rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) :
#endif
*rover->topheight;
if (!(player->pflags & PF_NIGHTSMODE) && !player->homing
&& (((player->charability == CA_SWIM) || player->powers[pw_super] || player->charflags & SF_RUNONWATER) && player->mo->ceilingz-*rover->topheight >= player->mo->height)
&& (((player->charability == CA_SWIM) || player->powers[pw_super] || player->charflags & SF_RUNONWATER) && player->mo->ceilingz-topheight >= player->mo->height)
&& (rover->flags & FF_SWIMMABLE) && !(player->pflags & PF_SPINNING) && player->speed > FixedMul(player->runspeed, player->mo->scale)
&& !(player->pflags & PF_SLIDING)
&& abs(player->mo->z - *rover->topheight) < FixedMul(30*FRACUNIT, player->mo->scale))
&& abs(player->mo->z - topheight) < FixedMul(30*FRACUNIT, player->mo->scale))
return true;
return false;

View file

@ -3619,14 +3619,49 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
{
if (roversector)
{
if (players[i].mo->subsector->sector != roversector)
if (players[i].mo->subsector->sector == roversector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == roversector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2;
}
else
goto DoneSection2;
if (!P_ThingIsOnThe3DFloor(players[i].mo, sector, roversector))
goto DoneSection2;
}
else
{
if (players[i].mo->subsector->sector != sector)
if (players[i].mo->subsector->sector == sector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2;
}
else
goto DoneSection2;
if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector))
@ -4377,6 +4412,7 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
{
sector_t *sector;
ffloor_t *rover;
fixed_t topheight, bottomheight;
sector = mo->subsector->sector;
if (!sector->ffloors)
@ -4384,8 +4420,6 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
for (rover = sector->ffloors; rover; rover = rover->next)
{
fixed_t topheight, bottomheight;
if (!rover->master->frontsector->special)
continue;
@ -4433,6 +4467,8 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
return NULL;
}
#define TELEPORTED (player->mo->subsector->sector != originalsector)
/** Checks if a player is standing on or is inside a 3D floor (e.g. water) and
* applies any specials.
*
@ -4441,12 +4477,12 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
*/
static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
{
sector_t *originalsector = player->mo->subsector->sector;
ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = sector->ffloors; rover; rover = rover->next)
{
fixed_t topheight, bottomheight;
if (!rover->master->frontsector->special)
continue;
@ -4490,7 +4526,10 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
// This FOF has the special we're looking for, but are we allowed to touch it?
if (sector == player->mo->subsector->sector
|| (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH))
{
P_ProcessSpecialSector(player, rover->master->frontsector, sector);
if TELEPORTED return;
}
}
// Allow sector specials to be applied to polyobjects!
@ -4501,7 +4540,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
boolean touching = false;
boolean inside = false;
while(po)
while (po)
{
if (po->flags & POF_NOSPECIALS)
{
@ -4577,6 +4616,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
}
P_ProcessSpecialSector(player, polysec, sector);
if TELEPORTED return;
po = (polyobj_t *)(po->link.next);
}
@ -4681,40 +4721,43 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector)
*/
void P_PlayerInSpecialSector(player_t *player)
{
sector_t *sector;
sector_t *originalsector;
sector_t *loopsector;
msecnode_t *node;
if (!player->mo)
return;
// Do your ->subsector->sector first
sector = player->mo->subsector->sector;
P_PlayerOnSpecial3DFloor(player, sector);
// After P_PlayerOnSpecial3DFloor, recheck if the player is in that sector,
// because the player can be teleported in between these times.
if (sector == player->mo->subsector->sector)
P_RunSpecialSectorCheck(player, sector);
originalsector = player->mo->subsector->sector;
// Iterate through touching_sectorlist
P_PlayerOnSpecial3DFloor(player, originalsector); // Handle FOFs first.
if TELEPORTED return;
P_RunSpecialSectorCheck(player, originalsector);
if TELEPORTED return;
// Iterate through touching_sectorlist for SF_TRIGGERSPECIAL_TOUCH
for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
sector = node->m_sector;
loopsector = node->m_sector;
if (sector == player->mo->subsector->sector) // Don't duplicate
if (loopsector == originalsector) // Don't duplicate
continue;
// Check 3D floors...
P_PlayerOnSpecial3DFloor(player, sector);
P_PlayerOnSpecial3DFloor(player, loopsector);
if TELEPORTED return;
if (!(sector->flags & SF_TRIGGERSPECIAL_TOUCH))
return;
// After P_PlayerOnSpecial3DFloor, recheck if the player is in that sector,
// because the player can be teleported in between these times.
if (sector == player->mo->subsector->sector)
P_RunSpecialSectorCheck(player, sector);
if (!(loopsector->flags & SF_TRIGGERSPECIAL_TOUCH))
continue;
P_RunSpecialSectorCheck(player, loopsector);
if TELEPORTED return;
}
}
#undef TELEPORTED
/** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up.
*
* \sa P_CheckTimeLimit, P_CheckPointLimit

View file

@ -1607,9 +1607,8 @@ void P_DoPlayerExit(player_t *player)
#define SPACESPECIAL 12
boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
{
sector_t *sector;
sector = mo->subsector->sector;
sector_t *sector = mo->subsector->sector;
fixed_t topheight, bottomheight;
if (GETSECSPECIAL(sector->special, 1) == SPACESPECIAL)
return true;
@ -1622,11 +1621,18 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
{
if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL)
continue;
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (mo->z > *rover->topheight)
if (mo->z + (mo->height/2) > topheight)
continue;
if (mo->z + (mo->height/2) < *rover->bottomheight)
if (mo->z + (mo->height/2) < bottomheight)
continue;
return true;
@ -1638,9 +1644,10 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand
{
sector_t *sector;
sector_t *sector = mo->subsector->sector;
fixed_t topheight, bottomheight;
sector = mo->subsector->sector;
fixed_t flipoffset = ((mo->eflags & MFE_VERTICALFLIP) ? (mo->height/2) : 0);
if (sector->ffloors)
{
@ -1654,10 +1661,18 @@ boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand
if (!(rover->flags & FF_QUICKSAND))
continue;
if (mo->z > *rover->topheight)
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (mo->z + flipoffset > topheight)
continue;
if (mo->z + (mo->height/2) < *rover->bottomheight)
if (mo->z + (mo->height/2) + flipoffset < bottomheight)
continue;
return true;
@ -1940,6 +1955,7 @@ static void P_CheckQuicksand(player_t *player)
{
ffloor_t *rover;
fixed_t sinkspeed, friction;
fixed_t topheight, bottomheight;
if (!(player->mo->subsector->sector->ffloors && player->mo->momz <= 0))
return;
@ -1951,16 +1967,38 @@ static void P_CheckQuicksand(player_t *player)
if (!(rover->flags & FF_QUICKSAND))
continue;
if (*rover->topheight >= player->mo->z && *rover->bottomheight < player->mo->z + player->mo->height)
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (topheight >= player->mo->z && bottomheight < player->mo->z + player->mo->height)
{
sinkspeed = abs(rover->master->v1->x - rover->master->v2->x)>>1;
sinkspeed = FixedDiv(sinkspeed,TICRATE*FRACUNIT);
player->mo->z -= sinkspeed;
if (player->mo->eflags & MFE_VERTICALFLIP)
{
fixed_t ceilingheight = P_GetCeilingZ(player->mo, player->mo->subsector->sector, player->mo->x, player->mo->y, NULL);
if (player->mo->z <= player->mo->subsector->sector->floorheight)
player->mo->z = player->mo->subsector->sector->floorheight;
player->mo->z += sinkspeed;
if (player->mo->z + player->mo->height >= ceilingheight)
player->mo->z = ceilingheight - player->mo->height;
}
else
{
fixed_t floorheight = P_GetFloorZ(player->mo, player->mo->subsector->sector, player->mo->x, player->mo->y, NULL);
player->mo->z -= sinkspeed;
if (player->mo->z <= floorheight)
player->mo->z = floorheight;
}
friction = abs(rover->master->v1->y - rover->master->v2->y)>>6;
@ -2321,11 +2359,11 @@ static void P_DoClimbing(player_t *player)
floorclimb = true;
#ifdef ESLOPE
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
bottomheight = *rover->bottomheight;
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
// Only supports rovers that are moving like an 'elevator', not just the top or bottom.
@ -2514,13 +2552,20 @@ static void P_DoClimbing(player_t *player)
// Is there a FOF directly below that we can move onto?
if (glidesector->sector->ffloors)
{
fixed_t topheight;
ffloor_t *rover;
for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
continue;
if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
#else
topheight = *rover->topheight;
#endif
if (topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
{
foundfof = true;
break;
@ -2898,14 +2943,12 @@ static void P_DoTeeter(player_t *player)
{
if (!(rover->flags & FF_EXISTS)) continue;
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#ifdef ESLOPE
if (*rover->t_slope)
topheight = P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y);
if (*rover->b_slope)
bottomheight = P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y);
#endif
if (P_CheckSolidLava(player->mo, rover))
@ -8511,13 +8554,23 @@ static void P_CalcPostImg(player_t *player)
else if (sector->ffloors)
{
ffloor_t *rover;
fixed_t topheight;
fixed_t bottomheight;
for (rover = sector->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS))
continue;
if (pviewheight >= *rover->topheight || pviewheight <= *rover->bottomheight)
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (pviewheight >= topheight || pviewheight <= bottomheight)
continue;
if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1)
@ -8529,13 +8582,23 @@ static void P_CalcPostImg(player_t *player)
if (sector->ffloors)
{
ffloor_t *rover;
fixed_t topheight;
fixed_t bottomheight;
for (rover = sector->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKPLAYER)
continue;
if (pviewheight >= *rover->topheight || pviewheight <= *rover->bottomheight)
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (pviewheight >= topheight || pviewheight <= bottomheight)
continue;
*type = postimg_water;
@ -8759,6 +8822,7 @@ void P_PlayerThink(player_t *player)
// check water content, set stuff in mobj
P_MobjCheckWater(player->mo);
#ifndef SECTORSPECIALSAFTERTHINK
#ifdef POLYOBJECTS
if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo))
#endif
@ -8767,6 +8831,7 @@ void P_PlayerThink(player_t *player)
if (!player->spectator)
P_PlayerInSpecialSector(player);
#endif
if (player->playerstate == PST_DEAD)
{
@ -9128,6 +9193,17 @@ void P_PlayerAfterThink(player_t *player)
cmd = &player->cmd;
#ifdef SECTORSPECIALSAFTERTHINK
#ifdef POLYOBJECTS
if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo))
#endif
player->onconveyor = 0;
// check special sectors : damage & secrets
if (!player->spectator)
P_PlayerInSpecialSector(player);
#endif
if (splitscreen && player == &players[secondarydisplayplayer])
thiscam = &camera2;
else if (player == &players[displayplayer])