diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5afb0c207..7d925e065 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,14 @@
## Changes
+- **Reimplemented _Move Over/Under Things_ feature**ยน, making it much less bug-prone
- **Improved Automap line thickening when the window is downscaled**
- **Tweaked zooming effect**
+**1\.** Among other changes, the setting itself has been extended: a value of `1` enables the feature only for players,
+while a value of `2` enables it for all Things. This differs from the previous implementation, wherein `1` would enable
+the feature for all Things.
+
## Bug Fixes
- **FOV effects not being cleared thoroughly upon loading levels**
diff --git a/README.md b/README.md
index daa6ce2d8..61e88792d 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ For these settings, their CVAR names are provided alongside the _CFG-Only_ label
- **Extended _Level Brightness_ range:** [-8, 8]
- **_"Direct + Auto"_ mode for Vertical Aiming**
- **_Direct Vertical Aiming_ for melee attacks**
-- **_Things move over/under things_** setting [p.f. Crispy Doom]
+- **_Move Over/Under Things_** setting [partially p.f. Crispy Doom, DSDA-Doom]
- **Jumping** (default key: Alt, must be enabled first) [p.f. Crispy Doom]
- **Crouching/ducking** (default key: C, must be enabled first) [i.b. ZDoom]
- **_Field of View_** setting [p.f. Doom Retro]
diff --git a/src/m_menu.c b/src/m_menu.c
index 1a8621943..a713b1154 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -4892,6 +4892,10 @@ static void M_ChangeViewHeight(void)
oldviewheight = viewheight_value;
}
+static const char *over_under_str[] = {
+ "Off", "Player Only", "All Things", NULL
+};
+
static const char *impact_pitch_str[] = {
"Off", "Fall", "Damage", "Both", NULL
};
@@ -4904,8 +4908,8 @@ setup_menu_t gen_settings6[] = {
{"Nugget - Gameplay", S_SKIP|S_TITLE, m_null, M_X, M_Y + gen6_title1 * M_SPC},
- {"Things Move Over/Under Things", S_YESNO|S_STRICT|S_CRITICAL, m_null, M_X, M_Y + gen6_overunder * M_SPC, {"over_under"}},
- {"Allow Jumping/Crouching", S_YESNO|S_STRICT|S_CRITICAL, m_null, M_X, M_Y + gen6_jump_crouch * M_SPC, {"jump_crouch"}},
+ {"Move Over/Under Things", S_CHOICE|S_STRICT|S_CRITICAL, m_null, M_X, M_Y + gen6_overunder * M_SPC, {"over_under"}, 0, NULL, over_under_str},
+ {"Allow Jumping/Crouching", S_YESNO |S_STRICT|S_CRITICAL, m_null, M_X, M_Y + gen6_jump_crouch * M_SPC, {"jump_crouch"}},
{"", S_SKIP, m_null, M_X, M_Y + gen6_stub1 * M_SPC},
{"Nugget - View", S_SKIP|S_TITLE, m_null, M_X, M_Y + gen6_title2 * M_SPC},
diff --git a/src/m_misc.c b/src/m_misc.c
index 3fad66048..703a6b375 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -721,8 +721,8 @@ default_t defaults[] = {
{
"over_under",
(config_t *) &over_under, NULL,
- {0}, {0,1}, number, ss_gen, wad_yes,
- "1 to allow things to move over/under other things"
+ {0}, {0,2}, number, ss_gen, wad_yes,
+ "Allow movement over/under things (1 = Player only, 2 = All things)"
},
{
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 762a0454b..d72a15903 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -407,14 +407,38 @@ static boolean P_Move(mobj_t *actor, boolean dropoff) // killough 9/12/98
if (actor->flags & MF_FLOAT && floatok)
{
+ // [Nugget] Over/Under
+ const fixed_t oldz = actor->z;
+
if (actor->z < tmfloorz) // must adjust height
- actor->z += FLOATSPEED;
+ {
+ actor->z += FLOATSPEED;
+
+ // [Nugget] Over/Under: don't ascend into other things
+ if (actor->above_thing
+ && (actor->above_thing->z < (actor->z + actor->height)))
+ {
+ actor->z = actor->above_thing->z - actor->height;
+ }
+ }
else
+ {
actor->z -= FLOATSPEED;
- actor->flags |= MF_INFLOAT;
+ // [Nugget] Over/Under: don't descend into other things
+ if (actor->below_thing
+ && (actor->z < (actor->below_thing->z + actor->below_thing->height)))
+ {
+ actor->z = actor->below_thing->z + actor->below_thing->height;
+ }
+ }
- return true;
+ // [Nugget] Conditions: only if we actually moved
+ if (NOTCASUALPLAY(actor->z != oldz))
+ {
+ actor->flags |= MF_INFLOAT;
+ return true;
+ }
}
if (!numspechit)
@@ -460,8 +484,14 @@ static boolean P_Move(mobj_t *actor, boolean dropoff) // killough 9/12/98
// killough 11/98: fall more slowly, under gravity, if felldown==true
if (!(actor->flags & MF_FLOAT) && (!felldown || demo_version < 203))
+ {
actor->z = actor->floorz;
+ // [Nugget] Over/Under
+ if (actor->below_thing)
+ { actor->z = MAX(actor->floorz, actor->below_thing->z + actor->below_thing->height); }
+ }
+
return true;
}
diff --git a/src/p_map.c b/src/p_map.c
index 117669088..94424af6b 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -494,6 +494,41 @@ static boolean P_ProjectileImmune(mobj_t *target, mobj_t *source)
);
}
+// [Nugget] Over/Under /------------------------------------------------------
+
+// Potential over/under mobjs
+static mobj_t *p_below_tmthing, *p_above_tmthing, // For `tmthing`
+ *p_below_thing_s, *p_above_thing_s, // For `thing` ("setter")
+ *p_below_thing_g, *p_above_thing_g; // `thing` itself ("getter")
+
+static void P_SetOverUnderMobjs(mobj_t *thing)
+{
+ if (casual_play && over_under)
+ {
+ mobj_t *pbtg = p_below_thing_g ? p_below_thing_g->below_thing : NULL,
+ *pbts = p_below_thing_s,
+ *patg = p_above_thing_g ? p_above_thing_g->above_thing : NULL,
+ *pats = p_above_thing_s;
+
+ thing->below_thing = p_below_tmthing;
+ thing->above_thing = p_above_tmthing;
+
+ if (p_below_thing_g
+ && ((!pbtg) || ((pbtg->z + pbtg->height) < (pbts->z + pbts->height))))
+ {
+ p_below_thing_g->below_thing = p_below_thing_s;
+ }
+
+ if (p_above_thing_g
+ && ((!patg) || (pats->z < patg->z)))
+ {
+ p_above_thing_g->above_thing = p_above_thing_s;
+ }
+ }
+}
+
+// [Nugget] -----------------------------------------------------------------/
+
static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static
{
fixed_t blockdist;
@@ -543,6 +578,51 @@ static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static
return true;
}
+ // [Nugget]: [DSDA] check if a mobj passed over/under another object
+ if (casual_play && over_under
+ && (tmthing->flags & MF_SOLID) && !(thing->flags & MF_SPECIAL)
+ && ((over_under == 2) || tmthing->player || thing->player))
+ {
+ if (thing->z + thing->height <= tmthing->z)
+ {
+ // Over
+
+ if ((!p_below_tmthing)
+ || ((p_below_tmthing->z + p_below_tmthing->height) < (thing->z + thing->height)))
+ {
+ p_below_tmthing = thing;
+ }
+
+ if ((!p_above_thing_s)
+ || (tmthing->z < p_above_thing_s->z))
+ {
+ p_above_thing_s = tmthing;
+ p_above_thing_g = thing;
+ }
+
+ return true;
+ }
+ else if (tmthing->z + tmthing->height <= thing->z)
+ {
+ // Under
+
+ if ((!p_above_tmthing)
+ || (thing->z < p_above_tmthing->z))
+ {
+ p_above_tmthing = thing;
+ }
+
+ if ((!p_below_thing_s)
+ || ((p_below_thing_s->z + p_below_thing_s->height) < (tmthing->z + tmthing->height)))
+ {
+ p_below_thing_s = tmthing;
+ p_below_thing_g = thing;
+ }
+
+ return true;
+ }
+ }
+
// check for skulls slamming into things
if (tmthing->flags & MF_SKULLFLY)
@@ -552,15 +632,6 @@ static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static
int damage = ((P_Random(pr_skullfly)%8)+1)*tmthing->info->damage;
- // [Nugget]: [crispy] check if attacking skull flies over/under thing
- if (casual_play && over_under)
- {
- if (tmthing->z > thing->z + thing->height)
- { return true; } // over
- else if (tmthing->z + tmthing->height < thing->z)
- { return true; } // under
- }
-
// [Nugget] Fix lost soul collision
if (casual_play && comp_lscollision && !(thing->flags & MF_SHOOTABLE))
{ return !(thing->flags & MF_SOLID); }
@@ -662,37 +733,6 @@ static boolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static
return !solid;
}
- // [Nugget] Allow things to move over/under solid things
- if (casual_play && over_under && (thing->flags & MF_SOLID))
- {
- if (tmthing->z >= thing->z + thing->height)
- {
- // Over
- thing->intflags |= MIF_OVERUNDER;
- tmthing->intflags |= MIF_OVERUNDER;
-
- tmfloorz = MAX(thing->z + thing->height, tmfloorz);
- thing->ceilingz = MIN(tmthing->z, thing->ceilingz);
-
- return true;
- }
- else if (tmthing->z + tmthing->height <= thing->z)
- {
- // Under
- thing->intflags |= MIF_OVERUNDER;
- tmthing->intflags |= MIF_OVERUNDER;
-
- tmceilingz = MIN(thing->z, tmceilingz);
- thing->floorz = MAX(tmthing->z + tmthing->height, thing->floorz);
-
- return true;
- }
- else {
- thing->intflags &= ~MIF_OVERUNDER;
- tmthing->intflags &= ~MIF_OVERUNDER;
- }
- }
-
// RjY
// comperr_hangsolid, an attempt to handle blocking hanging bodies
// A solid hanging body will allow sufficiently small things underneath it.
@@ -841,6 +881,10 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+ // [Nugget] Over/Under
+ p_below_tmthing = p_below_thing_s = p_below_thing_g =
+ p_above_tmthing = p_above_thing_s = p_above_thing_g = NULL;
+
for (bx=xl ; bx<=xh ; bx++)
for (by=yl ; by<=yh ; by++)
if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
@@ -886,6 +930,17 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean dropoff)
if (!P_CheckPosition(thing, x, y))
return false; // solid wall or thing
+ // [Nugget] Over/Under
+ if (casual_play && over_under)
+ {
+ // `tmfloorz` may have changed, so make sure the thing fits
+ if (p_above_tmthing && (p_above_tmthing->z < (tmfloorz + thing->height)))
+ { return false; }
+
+ // If move was valid, set new over/under mobjs
+ P_SetOverUnderMobjs(thing);
+ }
+
if (!(thing->flags & MF_NOCLIP))
{
// killough 7/26/98: reformatted slightly
@@ -1122,6 +1177,8 @@ static boolean P_ThingHeightClip(mobj_t *thing)
P_CheckPosition(thing, thing->x, thing->y);
+ P_SetOverUnderMobjs(tmthing); // [Nugget] Over/Under
+
// what about stranding a monster partially off an edge?
// killough 11/98: Answer: see below (upset balance if hanging off ledge)
@@ -1131,8 +1188,42 @@ static boolean P_ThingHeightClip(mobj_t *thing)
if (onfloor) // walking monsters rise and fall with the floor
{
+ const fixed_t oldz = thing->z; // [Nugget] Over/Under
+
thing->z = thing->floorz;
+ // [Nugget] Over/Under
+ if (casual_play && over_under)
+ {
+ if (thing->z < oldz && thing->below_thing)
+ { thing->z = MAX(thing->z, thing->below_thing->z + thing->below_thing->height); }
+
+ if (oldz < thing->z)
+ {
+ mobj_t *below_thing = thing, *above_thing;
+
+ do {
+ if ((above_thing = below_thing->above_thing))
+ {
+ above_thing->z = MAX(above_thing->z, below_thing->z + below_thing->height);
+ }
+ } while ((below_thing = below_thing->above_thing));
+ }
+ else if (thing->z < oldz)
+ {
+ mobj_t *below_thing = thing, *above_thing;
+ const fixed_t zdiff = oldz - thing->z;
+
+ do {
+ if ((above_thing = below_thing->above_thing)
+ && ((above_thing->z - zdiff) == (below_thing->z + below_thing->height)))
+ {
+ above_thing->z = below_thing->z + below_thing->height;
+ }
+ } while ((below_thing = below_thing->above_thing));
+ }
+ }
+
// killough 11/98: Possibly upset balance of objects hanging off ledges
if (thing->intflags & MIF_FALLING && thing->gear >= MAXGEAR)
thing->gear = 0;
@@ -2494,6 +2585,185 @@ void P_MapEnd(void)
tmthing = NULL;
}
+// [Nugget]: [DSDA] heretic /-------------------------------------------------
+
+static overunder_t zdir = OU_NONE;
+
+static void P_FakeZMovement(mobj_t *mo)
+{
+ const fixed_t oldz = mo->z;
+
+ // Adjust height
+ mo->z += mo->momz;
+
+ // Float down towards target if too close
+ if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) && mo->target)
+ {
+ const fixed_t delta = mo->target->z + (mo->height >> 1) - mo->z;
+
+ if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) < abs(delta) * 3)
+ { mo->z += (delta < 0) ? -FLOATSPEED : FLOATSPEED; }
+ }
+
+ // Clip movement
+ if (mo->z <= mo->floorz)
+ {
+ // Hit the floor
+
+ mo->z = mo->floorz;
+
+ if (mo->momz < 0) { mo->momz = 0; }
+
+ if (mo->flags & MF_SKULLFLY)
+ { mo->momz = -mo->momz; } // The skull slammed into something
+ }
+ else if (mo->flags2 & MF2_LOGRAV)
+ {
+ if (!mo->momz) { mo->momz = -(GRAVITY >> 3) * 2; }
+ else { mo->momz -= GRAVITY >> 3; }
+ }
+ else if (!(mo->flags & MF_NOGRAVITY))
+ {
+ if (!mo->momz) { mo->momz = -GRAVITY; }
+ else { mo->momz -= GRAVITY; }
+ }
+
+ if (mo->z + mo->height > mo->ceilingz)
+ {
+ // Hit the ceiling
+
+ mo->z = mo->ceilingz - mo->height;
+
+ if (mo->momz > 0) { mo->momz = 0; }
+
+ if (mo->flags & MF_SKULLFLY)
+ { mo->momz = -mo->momz; } // The skull slammed into something
+ }
+
+ zdir = (oldz < mo->z) ? OU_OVER : OU_UNDER;
+}
+
+static boolean PIT_CheckOverUnderMobjZ(mobj_t *thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
+ { return true; } // Can't hit thing
+
+ blockdist = thing->radius + tmthing->radius;
+
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ { return true; } // Didn't hit thing
+
+ if (thing == tmthing)
+ { return true; } // Don't clip against self
+
+ if (thing->z + thing->height <= tmthing->z)
+ {
+ // Over
+
+ if ((!p_below_tmthing)
+ || ((p_below_tmthing->z + p_below_tmthing->height) < (thing->z + thing->height)))
+ {
+ p_below_tmthing = thing;
+ }
+
+ if ((!p_above_thing_s)
+ || (tmthing->z < p_above_thing_s->z))
+ {
+ p_above_thing_s = tmthing;
+ p_above_thing_g = thing;
+ }
+
+ return true;
+ }
+ else if (tmthing->z + tmthing->height <= thing->z)
+ {
+ // Under
+
+ if ((!p_above_tmthing)
+ || (thing->z < p_above_tmthing->z))
+ {
+ p_above_tmthing = thing;
+ }
+
+ if ((!p_below_thing_s)
+ || ((p_below_thing_s->z + p_below_thing_s->height) < (tmthing->z + tmthing->height)))
+ {
+ p_below_thing_s = tmthing;
+ p_below_thing_g = thing;
+ }
+
+ return true;
+ }
+
+ return !((thing->flags & MF_SOLID && !(thing->flags & MF_NOCLIP))
+ && (tmthing->flags & MF_SOLID || demo_compatibility));
+}
+
+// Checks if the new Z position is legal
+overunder_t P_CheckOverUnderMobj(mobj_t *thing, boolean fakemove)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+ const mobj_t oldmo = *thing; // Save the old mobj before the fake movement
+ overunder_t ret = OU_NONE;
+
+ if (!(casual_play && over_under)) { return ret; }
+
+ tmx = thing->x;
+ tmy = thing->y;
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmbbox[BOXTOP] = tmy + tmthing->radius;
+ tmbbox[BOXBOTTOM] = tmy - tmthing->radius;
+ tmbbox[BOXRIGHT] = tmx + tmthing->radius;
+ tmbbox[BOXLEFT] = tmx - tmthing->radius;
+
+ newsubsec = R_PointInSubsector(tmx, tmy);
+ floorline = blockline = ceilingline = NULL;
+
+ // The base floor / ceiling is from the subsector that contains the
+ // point. Any contacted lines the step closer together will adjust them
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+
+ validcount++;
+ numspechit = 0;
+
+ if (tmflags & MF_NOCLIP) { return ret; }
+
+ // Check things first, possibly picking things up
+ // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+ // into mapblocks based on their origin point, and can overlap into adjacent
+ // blocks by up to MAXRADIUS units
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ p_below_tmthing = p_below_thing_s = p_below_thing_g =
+ p_above_tmthing = p_above_thing_s = p_above_thing_g = NULL;
+
+ zdir = OU_NONE;
+
+ if (fakemove) { P_FakeZMovement(tmthing); }
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockThingsIterator(bx, by, PIT_CheckOverUnderMobjZ))
+ {
+ P_SetOverUnderMobjs(tmthing);
+ ret = zdir;
+ }
+
+ *tmthing = oldmo;
+ return ret;
+}
+
+// [Nugget] -----------------------------------------------------------------/
+
// [FG] SPECHITS overflow emulation from Chocolate Doom / PrBoom+
static void SpechitOverrun(line_t *ld)
diff --git a/src/p_map.h b/src/p_map.h
index df0171fb5..1b9d071bf 100644
--- a/src/p_map.h
+++ b/src/p_map.h
@@ -78,6 +78,14 @@ extern msecnode_t *sector_list; // phares 3/16/98
extern fixed_t tmbbox[4]; // phares 3/20/98
extern line_t *blockline; // killough 8/11/98
+typedef enum {
+ OU_UNDER = -1,
+ OU_NONE,
+ OU_OVER,
+} overunder_t;
+
+overunder_t P_CheckOverUnderMobj(mobj_t *thing, boolean fakemove); // [Nugget]: [DSDA]
+
extern boolean boomshot; // [Nugget] Explosive hitscan cheat
#endif // __P_MAP__
diff --git a/src/p_mobj.c b/src/p_mobj.c
index ca332be16..c4d7d35b5 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -145,8 +145,7 @@ void P_XYMovement (mobj_t* mo)
fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice
- if (!(mo->momx | mo->momy) // Any momentum?
- && !(mo->intflags & MIF_OVERUNDER)) // [Nugget]
+ if (!(mo->momx | mo->momy)) // Any momentum?
{
if (mo->flags & MF_SKULLFLY)
{
@@ -292,12 +291,24 @@ void P_XYMovement (mobj_t* mo)
}
// no friction for missiles or skulls ever, no friction when airborne
- if (mo->flags & (MF_MISSILE | MF_SKULLFLY)
- // [Nugget] Do apply friction if airborne with noclip or flight cheat enabled
- || (mo->z > mo->floorz
- && !(casual_play && player && (mo->flags & MF_NOCLIP || player->cheats & CF_FLY))))
+ if (mo->flags & (MF_MISSILE | MF_SKULLFLY))
return;
+ // [Nugget] Do apply friction if airborne...
+ if (
+ (mo->z > mo->floorz)
+ && !(casual_play
+ && ( // ... using noclip or flight cheat
+ (player && player->cheats & (CF_NOCLIP|CF_FLY))
+ // ... on top of a mobj
+ || (mo->below_thing && (mo->z == (mo->below_thing->z + mo->below_thing->height)))
+ )
+ )
+ )
+ {
+ return;
+ }
+
// killough 8/11/98: add bouncers
// killough 9/15/98: add objects falling off ledges
// killough 11/98: only include bouncers hanging off ledges
@@ -729,6 +740,7 @@ static inline void MusInfoThinker (mobj_t *thing)
void P_MobjThinker (mobj_t* mobj)
{
extern boolean cheese; // [Nugget] cheese :)
+ boolean oucheck = false; // [Nugget] Over/Under
// [crispy] support MUSINFO lump (dynamic music changing)
if (mobj->type == MT_MUSICSOURCE)
@@ -778,26 +790,45 @@ void P_MobjThinker (mobj_t* mobj)
// removed old code which looked at target references
// (we use pointer reference counting now)
- // [Nugget] Things with both MF_SKULLFLY and MIF_OVERUNDER
- // have buggy behavior, so take the latter away
- if ((mobj->flags & MF_SKULLFLY) && (mobj->intflags & MIF_OVERUNDER))
- { mobj->intflags &= ~MIF_OVERUNDER; }
-
// momentum movement
- if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY
- || mobj->intflags & MIF_OVERUNDER) // [Nugget]
+ if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY)
{
P_XYMovement(mobj);
mobj->intflags &= ~MIF_SCROLLING;
if (mobj->thinker.function.p1 == (actionf_p1)P_RemoveThinkerDelayed) // killough
return; // mobj was removed
+
+ oucheck = true; // [Nugget] Over/Under
}
if (mobj->z != mobj->floorz || mobj->momz)
{
- P_ZMovement(mobj);
+ // [Nugget]: [DSDA]
+ if (casual_play && over_under && (mobj->flags & MF_SOLID))
+ {
+ overunder_t zdir;
+
+ if (!(zdir = P_CheckOverUnderMobj(mobj, true)))
+ {
+ P_ZMovement(mobj);
+ }
+ else
+ {
+ mobj->momz = 0;
+
+ if (mobj->below_thing && zdir == OU_UNDER)
+ { mobj->z = mobj->below_thing->z + mobj->below_thing->height; }
+ else if (mobj->above_thing) // zdir == OU_OVER
+ { mobj->z = mobj->above_thing->z - mobj->height; }
+ }
+ }
+ else
+ P_ZMovement(mobj);
+
if (mobj->thinker.function.p1 == (actionf_p1)P_RemoveThinkerDelayed) // killough
return; // mobj was removed
+
+ oucheck = true; // [Nugget] Over/Under
}
else
if (!(mobj->momx | mobj->momy) && !sentient(mobj))
@@ -815,6 +846,37 @@ void P_MobjThinker (mobj_t* mobj)
mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque
}
+ // [Nugget] Over/Under: if we didn't check for over/under mobjs already,
+ // it means that this mobj is immobile, and its over/under mobjs, if any,
+ // were set by other mobj(s); check if they're still valid
+ if (casual_play && over_under && !oucheck)
+ {
+ const mobj_t *oumobj;
+ fixed_t blockdist;
+
+ if ((oumobj = mobj->below_thing))
+ {
+ blockdist = mobj->radius + oumobj->radius;
+
+ if ( (abs(mobj->x - oumobj->x) >= blockdist)
+ || (abs(mobj->y - oumobj->y) >= blockdist))
+ {
+ mobj->below_thing = NULL;
+ }
+ }
+
+ if ((oumobj = mobj->above_thing))
+ {
+ blockdist = mobj->radius + oumobj->radius;
+
+ if ( (abs(mobj->x - oumobj->x) >= blockdist)
+ || (abs(mobj->y - oumobj->y) >= blockdist))
+ {
+ mobj->above_thing = NULL;
+ }
+ }
+ }
+
if (mbf21)
{
sector_t* sector = mobj->subsector->sector;
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 8dd355beb..9db5afeb0 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -235,9 +235,8 @@ enum {
MIF_FLIP = 16,
// [Nugget]
MIF_CROUCHING = 32, // Mobj (player) is crouching
- MIF_OVERUNDER = 64, // Mobj is over/under another mobj
- MIF_EXTRASPAWNED = 128, // [So Doom] Nightmare-spawned, Icon of Sin-spawned and Archvile-resurrected monsters
- MIF_CHEESE = 256,
+ MIF_EXTRASPAWNED = 64, // [So Doom] Nightmare-spawned, Icon of Sin-spawned and Archvile-resurrected monsters
+ MIF_CHEESE = 128,
};
// Map Object definition.
diff --git a/src/p_user.c b/src/p_user.c
index 4bf734fb4..2d17bb139 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -234,9 +234,15 @@ void P_MovePlayer (player_t* player)
mo->angle += cmd->angleturn << 16;
onground = mo->z <= mo->floorz;
- // [Nugget] Allow mid-air control with noclip or flight cheat enabled
- if (casual_play)
- { onground |= ((player->mo->flags & MF_NOCLIP) || (player->cheats & CF_FLY)); }
+
+ // [Nugget] Allow movement if...
+ if (casual_play) {
+ onground |=
+ // ... using noclip or flight cheat
+ (player->cheats & (CF_NOCLIP|CF_FLY))
+ // ... on top of a mobj
+ || (mo->below_thing && (mo->z == (mo->below_thing->z + mo->below_thing->height)));
+ }
// [Nugget]
if (player->cheats & CF_FLY)