Skip to content

Commit

Permalink
Heretic: Added MF3_WALLBOUNCE for bouncing missiles
Browse files Browse the repository at this point in the history
The wallbounce flag causes missiles to bounce off walls instead of exploding. The code is the same that is used in Hexen.
  • Loading branch information
skyjake committed Sep 14, 2019
1 parent 173064f commit c07eaf3
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 113 deletions.
4 changes: 3 additions & 1 deletion doomsday/apps/plugins/common/include/p_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,12 @@ dd_bool P_CheckSides(mobj_t *actor, coord_t x, coord_t y);
* @return dd_bool @c true iff the mobj is not blocked by anything.
*/
dd_bool P_TestMobjLocation(mobj_t *mobj);

void P_BounceWall(mobj_t *mobj);

#endif

#if __JHEXEN__
void P_BounceWall(mobj_t *mobj);

mobj_t *P_CheckOnMobj(mobj_t *mobj);

Expand Down
178 changes: 93 additions & 85 deletions doomsday/apps/plugins/common/src/world/p_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2859,7 +2859,8 @@ void P_HandleSectorHeightChange(int sectorIdx)
P_ChangeSector((Sector *)P_ToPtr(DMU_SECTOR, sectorIdx), false /*don't crush*/);
}

#if __JHERETIC__ || __JHEXEN__
#if defined (__JHERETIC__) || defined(__JHEXEN__)

dd_bool P_TestMobjLocation(mobj_t *mo)
{
int const oldFlags = mo->flags;
Expand All @@ -2875,6 +2876,97 @@ dd_bool P_TestMobjLocation(mobj_t *mo)
// XY is ok, now check Z
return mo->origin[VZ] >= mo->floorZ && (mo->origin[VZ] + mo->height) <= mo->ceilingZ;
}

struct ptr_boucetraverse_params_t {
mobj_t *bounceMobj;
Line * bestLine;
coord_t bestDistance;
};

static int PTR_BounceTraverse(Intercept const *icpt, void *context)
{
DENG_ASSERT(icpt->type == ICPT_LINE);

ptr_boucetraverse_params_t &parm = *static_cast<ptr_boucetraverse_params_t *>(context);

Line *line = icpt->line;
if (!P_GetPtrp(line, DMU_FRONT_SECTOR) || !P_GetPtrp(line, DMU_BACK_SECTOR))
{
if (Line_PointOnSide(line, parm.bounceMobj->origin) < 0)
{
return false; // Don't hit the back side.
}
goto bounceblocking;
}

Interceptor_AdjustOpening(icpt->trace, line);

if (Interceptor_Opening(icpt->trace)->range < parm.bounceMobj->height)
{
goto bounceblocking; // Doesn't fit.
}
if (Interceptor_Opening(icpt->trace)->top - parm.bounceMobj->origin[VZ] <
parm.bounceMobj->height)
{
goto bounceblocking; // Mobj is too high...
}
// if (parm.bounceMobj->origin[VZ] - Interceptor_Opening(icpt->trace)->bottom < 0)
// {
// goto bounceblocking; // Mobj is too low...
// }
// This line doesn't block movement...
return false;

// The line does block movement, see if it is closer than best so far.
bounceblocking:
if (icpt->distance < parm.bestDistance)
{
parm.bestDistance = icpt->distance;
parm.bestLine = line;
}
return false;
}

void P_BounceWall(mobj_t *mo)
{
if (!mo) return;

// Trace a line from the origin to the would be destination point (which is
// apparently not reachable) to find a line from which we'll calculate the
// inverse "bounce" vector.
vec2d_t leadPos = {mo->origin[VX] + (mo->mom[MX] > 0 ? mo->radius : -mo->radius),
mo->origin[VY] + (mo->mom[MY] > 0 ? mo->radius : -mo->radius)};
vec2d_t destPos;
V2d_Sum(destPos, leadPos, mo->mom);

ptr_boucetraverse_params_t parm;
parm.bounceMobj = mo;
parm.bestLine = 0;
parm.bestDistance = 1; // Intercept distances are normalized [0..1]

P_PathTraverse2(leadPos, destPos, PTF_LINE, PTR_BounceTraverse, &parm);

if (parm.bestLine)
{
// fprintf(stderr, "mo %p: bouncing off line %p, dist=%f\n",
// mo, parm.bestLine, parm.bestDistance);

int const side = Line_PointOnSide(parm.bestLine, mo->origin) < 0;
vec2d_t lineDirection;
P_GetDoublepv(parm.bestLine, DMU_DXY, lineDirection);

angle_t lineAngle = M_PointToAngle(lineDirection) + (side ? ANG180 : 0);
angle_t moveAngle = M_PointToAngle(mo->mom);
angle_t deltaAngle = (2 * lineAngle) - moveAngle;

coord_t moveLen = M_ApproxDistance(mo->mom[MX], mo->mom[MY]) * 0.75f /*Friction*/;
if (moveLen < 1) moveLen = 2;

uint an = deltaAngle >> ANGLETOFINESHIFT;
V2d_Set(mo->mom, moveLen * FIX2FLT(finecosine[an]), moveLen * FIX2FLT(finesine[an]));
}
}

#endif

#if __JHEXEN__
Expand Down Expand Up @@ -3133,90 +3225,6 @@ mobj_t *P_CheckOnMobj(mobj_t *mo)
return 0;
}

struct ptr_boucetraverse_params_t
{
mobj_t *bounceMobj;
Line *bestLine;
coord_t bestDistance;
};

static int PTR_BounceTraverse(Intercept const *icpt, void *context)
{
DENG_ASSERT(icpt->type == ICPT_LINE);

ptr_boucetraverse_params_t &parm = *static_cast<ptr_boucetraverse_params_t *>(context);

Line *line = icpt->line;
if(!P_GetPtrp(line, DMU_FRONT_SECTOR) || !P_GetPtrp(line, DMU_BACK_SECTOR))
{
if(Line_PointOnSide(line, parm.bounceMobj->origin) < 0)
{
return false; // Don't hit the back side.
}

goto bounceblocking;
}

Interceptor_AdjustOpening(icpt->trace, line);

if(Interceptor_Opening(icpt->trace)->range < parm.bounceMobj->height)
{
goto bounceblocking; // Doesn't fit.
}
if(Interceptor_Opening(icpt->trace)->top - parm.bounceMobj->origin[VZ] < parm.bounceMobj->height)
{
goto bounceblocking; // Mobj is too high...
}

return false; // This line doesn't block movement...

// the line does block movement, see if it is closer than best so far.
bounceblocking:
if(icpt->distance < parm.bestDistance)
{
parm.bestDistance = icpt->distance;
parm.bestLine = line;
}

return true; // Stop.
}

void P_BounceWall(mobj_t *mo)
{
if(!mo) return;

// Trace a line from the origin to the would be destination point (which is
// apparently not reachable) to find a line from which we'll calculate the
// inverse "bounce" vector.
vec2d_t leadPos = { mo->origin[VX] + (mo->mom[MX] > 0? mo->radius : -mo->radius),
mo->origin[VY] + (mo->mom[MY] > 0? mo->radius : -mo->radius) };
vec2d_t destPos; V2d_Sum(destPos, leadPos, mo->mom);

ptr_boucetraverse_params_t parm;
parm.bounceMobj = mo;
parm.bestLine = 0;
parm.bestDistance = 1; // Intercept distances are normalized [0..1]

P_PathTraverse2(leadPos, destPos, PTF_LINE, PTR_BounceTraverse, &parm);

if(parm.bestLine)
{
int const side = Line_PointOnSide(parm.bestLine, mo->origin) < 0;
vec2d_t lineDirection; P_GetDoublepv(parm.bestLine, DMU_DXY, lineDirection);

angle_t lineAngle = M_PointToAngle(lineDirection) + (side? ANG180 : 0);
angle_t moveAngle = M_PointToAngle(mo->mom);
angle_t deltaAngle = (2 * lineAngle) - moveAngle;

coord_t moveLen = M_ApproxDistance(mo->mom[MX], mo->mom[MY]) * 0.75f /*Friction*/;
if(moveLen < 1) moveLen = 2;

uint an = deltaAngle >> ANGLETOFINESHIFT;
V2d_Set(mo->mom, moveLen * FIX2FLT(finecosine[an]),
moveLen * FIX2FLT(finesine [an]));
}
}

static sfxenum_t usePuzzleItemFailSound(mobj_t *user)
{
if(Mobj_IsPlayer(user))
Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/plugins/heretic/defs/flags.ded
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ Flag { ID = "mf2_dontdraw"; Value = 0x100000; }
Flag { ID = "mf3_noinfight"; Value = 0x1; }
Flag { ID = "mf3_clientaction"; Value = 0x2; }
Flag { ID = "mf3_nomorph"; Value = 0x4; }

Flag { ID = "mf3_wallbounce"; Value = 0x8; }
1 change: 1 addition & 0 deletions doomsday/apps/plugins/heretic/include/p_mobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class MapStateWriter;
#define MF3_NOINFIGHT 0x00000001 // Mobj will never be targeted for in-fighting
#define MF3_CLIENTACTION 0x00000002 // States' action funcs are executed by client
#define MF3_NOMORPH 0x00000004 // Mobj cannot be morphed to Chicken
#define MF3_WALLBOUNCE 0x00000008 // Mobj bounces off walls

// --- mobj.intflags --- (added in MOBJ_SAVEVERSION 6)
// Internal mobj flags cannot be set using an external definition.
Expand Down
52 changes: 26 additions & 26 deletions doomsday/apps/plugins/heretic/src/p_mobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,16 @@ void P_MobjMoveXY(mobj_t *mo)
}
else if(mo->flags & MF_MISSILE)
{
if (mo->flags3 & MF3_WALLBOUNCE)
{
P_BounceWall(mo);
return;
}

// Explode a missile
Sector* backSec;

/// @kludge: Prevent missiles exploding against the sky.
// @kludge: Prevent missiles exploding against the sky.
if(tmCeilingLine && (backSec = P_GetPtrp(tmCeilingLine, DMU_BACK_SECTOR)))
{
if((P_GetIntp(P_GetPtrp(backSec, DMU_CEILING_MATERIAL), DMU_FLAGS) & MATF_SKYMASK) &&
Expand All @@ -321,11 +327,9 @@ void P_MobjMoveXY(mobj_t *mo)
{
P_MobjRemove(mo, false);
}

return;
}
}

if(tmFloorLine && (backSec = P_GetPtrp(tmFloorLine, DMU_BACK_SECTOR)))
{
if((P_GetIntp(P_GetPtrp(backSec, DMU_FLOOR_MATERIAL), DMU_FLAGS) & MATF_SKYMASK) &&
Expand All @@ -340,7 +344,6 @@ void P_MobjMoveXY(mobj_t *mo)
{
P_MobjRemove(mo, false);
}

return;
}
}
Expand Down Expand Up @@ -527,9 +530,9 @@ void P_MobjMoveZ(mobj_t *mo)
// Squat down. Decrease viewheight for a moment after
// hitting the ground hard and utter appropriate sound.
mo->player->viewHeightDelta = mo->mom[MZ] / 8;
#if __JHERETIC__
//#if __JHERETIC__
mo->player->jumpTics = 12; // Can't jump in a while.
#endif
//#endif
// Fix DOOM bug - dead players grunting when hitting the ground
// (e.g., after an archvile attack)
if(mo->player->health > 0)
Expand Down Expand Up @@ -557,34 +560,33 @@ void P_MobjMoveZ(mobj_t *mo)
P_FloorBounceMissile(mo);
return;
}
#if __JHERETIC__
else if(mo->type == MT_MNTRFX2)
{ // Minotaur floor fire can go up steps
{
// Minotaur floor fire can go up steps
return;
}
else
#endif
{
P_ExplodeMissile(mo);
return;
}
}

if(movingDown && mo->mom[MZ] < 0)
mo->mom[MZ] = 0;

#if __JHERETIC__
{
statenum_t state;
mo->mom[MZ] = 0;
}

if((state = P_GetState(mo->type, SN_CRASH)) != S_NULL &&
(mo->flags & MF_CORPSE))
// Set corpses to CRASH state.
{
P_MobjChangeState(mo, state);
return;
}
statenum_t state;
if((state = P_GetState(mo->type, SN_CRASH)) != S_NULL &&
(mo->flags & MF_CORPSE))
{
P_MobjChangeState(mo, state);
return;
}
}
#endif
}
else if(mo->flags2 & MF2_LOGRAV)
{
Expand Down Expand Up @@ -619,16 +621,14 @@ void P_MobjMoveZ(mobj_t *mo)
if(P_GetIntp(P_GetPtrp(Mobj_Sector(mo), DMU_CEILING_MATERIAL),
DMU_FLAGS) & MATF_SKYMASK)
{
#if __JHERETIC__
if(mo->type == MT_BLOODYSKULL)
{
mo->mom[MX] = mo->mom[MY] = 0;
mo->mom[MZ] = -1;
}
else
#endif
// Don't explode against sky.
{
// Don't explode against sky.
P_MobjRemove(mo, false);
}
return;
Expand Down Expand Up @@ -1581,12 +1581,12 @@ mobj_t* P_SpawnMissile(mobjtype_t type, mobj_t* source, mobj_t* dest, dd_bool ch
th->mom[MY] *= dist;
th->mom[MZ] *= dist;

#if __JHERETIC__
//#if __JHERETIC__
/// @kludge Set this global ptr as we need access to the mobj even if it
/// explodes instantly in order to assign values to it.
missileMobj = th;
// kludge end.
#endif
//#endif

if(checkSpawn)
return (P_CheckMissileSpawn(th)? th : NULL);
Expand Down Expand Up @@ -1749,12 +1749,12 @@ mobj_t* P_SpawnMissileAngle(mobjtype_t type, mobj_t* source, angle_t mangle, coo
th->mom[MZ] = momZ;
}

#if __JHERETIC__
//#if __JHERETIC__
/// @kludge Set this global ptr as we need access to the mobj even if it
/// explodes instantly in order to assign values to it.
missileMobj = th;
// kludge end.
#endif
//#endif

if(P_CheckMissileSpawn(th))
return th;
Expand Down

0 comments on commit c07eaf3

Please sign in to comment.