diff --git a/src/doom/p_map.c b/src/doom/p_map.c index e2884d99cd..12964155bb 100644 --- a/src/doom/p_map.c +++ b/src/doom/p_map.c @@ -1101,7 +1101,7 @@ boolean PTR_ShootTraverse (intercept_t* in) } } - // [crispy] check if the pullet puff's z-coordinate is below of above + // [crispy] check if the bullet puff's z-coordinate is below of above // its spawning sector's floor or ceiling, respectively, and move its // coordinates to the point where the trajectory hits the plane if (aimslope) diff --git a/src/heretic/m_random.c b/src/heretic/m_random.c index 1249512813..5141555993 100644 --- a/src/heretic/m_random.c +++ b/src/heretic/m_random.c @@ -83,3 +83,9 @@ int P_SubRandom (void) int r = P_Random(); return r - P_Random(); } + +int Crispy_SubRandom (void) +{ + int r = Crispy_Random(); + return r - Crispy_Random(); +} diff --git a/src/heretic/m_random.h b/src/heretic/m_random.h index 36ef27fcd3..91702b0cd9 100644 --- a/src/heretic/m_random.h +++ b/src/heretic/m_random.h @@ -35,6 +35,7 @@ extern int rndindex; // Defined version of P_Random() - P_Random() int P_SubRandom (void); +int Crispy_SubRandom (void); #endif // HERETIC_M_RANDOM_H diff --git a/src/heretic/p_local.h b/src/heretic/p_local.h index 6c9d2502c4..a1946289bc 100644 --- a/src/heretic/p_local.h +++ b/src/heretic/p_local.h @@ -146,6 +146,7 @@ boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax); void P_MobjThinker(thinker_t *thinker); void P_BlasterMobjThinker(thinker_t *thinker); void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z); +void P_SpawnPuffSafe(fixed_t x, fixed_t y, fixed_t z, boolean safe); void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage); void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator); void P_RipperBlood(mobj_t * mo); diff --git a/src/heretic/p_map.c b/src/heretic/p_map.c index 3d9cb7eb9b..9d2de4dd53 100644 --- a/src/heretic/p_map.c +++ b/src/heretic/p_map.c @@ -1301,6 +1301,7 @@ boolean PTR_ShootTraverse(intercept_t * in) if (in->isaline) { + boolean safe = false; li = in->d.line; if (li->special) P_ShootSpecialLine(shootthing, li); @@ -1344,10 +1345,39 @@ boolean PTR_ShootTraverse(intercept_t * in) if (z > li->frontsector->ceilingheight) return false; // don't shoot the sky! if (li->backsector && li->backsector->ceilingpic == skyflatnum) + { + // [crispy] fix hitscan puffs not appearing in outdoor areas + if (li->backsector->ceilingheight < z) return false; // it's a sky hack wall + else + safe = true; + } } - P_SpawnPuff(x, y, z); + // [crispy] check if the hitscan puff's z-coordinate is below of above + // its spawning sector's floor or ceiling, respectively, and move its + // coordinates to the point where the trajectory hits the plane + if (aimslope) + { + const int lineside = P_PointOnLineSide(x, y, li); + int side; + + if ((side = li->sidenum[lineside]) != NO_INDEX) + { + const sector_t *const sector = sides[side].sector; + + if (z < sector->floorheight || + (z > sector->ceilingheight && sector->ceilingpic != skyflatnum)) + { + z = BETWEEN(sector->floorheight, sector->ceilingheight, z); + frac = FixedDiv(z - shootz, FixedMul(aimslope, attackrange)); + x = trace.x + FixedMul (trace.dx, frac); + y = trace.y + FixedMul (trace.dy, frac); + } + } + } + + P_SpawnPuffSafe(x, y, z, safe); return false; // don't go any farther } diff --git a/src/heretic/p_mobj.c b/src/heretic/p_mobj.c index ff68ae63e6..f7132bdd25 100644 --- a/src/heretic/p_mobj.c +++ b/src/heretic/p_mobj.c @@ -78,6 +78,40 @@ boolean P_SetMobjState(mobj_t * mobj, statenum_t state) return (true); } +// [crispy] return the latest "safe" state in a state sequence, +// so that no action pointer is ever called +static statenum_t P_LatestSafeState(statenum_t state) +{ + statenum_t safestate = S_NULL; + static statenum_t laststate, lastsafestate; + + if (state == laststate) + { + return lastsafestate; + } + + for (laststate = state; state != S_NULL; state = states[state].nextstate) + { + if (safestate == S_NULL) + { + safestate = state; + } + + if (states[state].action) + { + safestate = S_NULL; + } + + // [crispy] a state with -1 tics never changes + if (states[state].tics == -1 || state == states[state].nextstate) + { + break; + } + } + + return lastsafestate = safestate; +} + //---------------------------------------------------------------------------- // // FUNC P_SetMobjStateNF @@ -110,7 +144,7 @@ boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state) // //---------------------------------------------------------------------------- -void P_ExplodeMissile(mobj_t * mo) +static void P_ExplodeMissileSafe(mobj_t * mo, boolean safe) { if (mo->type == MT_WHIRLWIND) { @@ -120,7 +154,7 @@ void P_ExplodeMissile(mobj_t * mo) } } mo->momx = mo->momy = mo->momz = 0; - P_SetMobjState(mo, mobjinfo[mo->type].deathstate); + P_SetMobjState(mo, safe ? P_LatestSafeState(mobjinfo[mo->type].deathstate) : (statenum_t)mobjinfo[mo->type].deathstate); //mo->tics -= P_Random()&3; mo->flags &= ~MF_MISSILE; if (mo->info->deathsound) @@ -129,6 +163,11 @@ void P_ExplodeMissile(mobj_t * mo) } } +void P_ExplodeMissile(mobj_t * mo) +{ + P_ExplodeMissileSafe(mo, false); +} + //---------------------------------------------------------------------------- // // PROC P_FloorBounceMissile @@ -361,6 +400,7 @@ void P_XYMovement(mobj_t * mo) } else if (mo->flags & MF_MISSILE) { // Explode a missile + boolean safe = false; if (ceilingline && ceilingline->backsector && ceilingline->backsector->ceilingpic == skyflatnum) { // Hack to prevent missiles exploding against the sky @@ -369,13 +409,17 @@ void P_XYMovement(mobj_t * mo) mo->momx = mo->momy = 0; mo->momz = -FRACUNIT; } - else + if (mo->z > ceilingline->backsector->ceilingheight) { P_RemoveMobj(mo); + return; + } + else + { + safe = true; } - return; } - P_ExplodeMissile(mo); + P_ExplodeMissileSafe(mo, safe); } //else if(mo->info->crashstate) //{ @@ -872,7 +916,7 @@ void P_MobjThinker(thinker_t *thinker) =============== */ -mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) +static mobj_t *P_SpawnMobjSafe(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, boolean safe) { mobj_t *mobj; state_t *st; @@ -896,12 +940,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { mobj->reactiontime = info->reactiontime; } - mobj->lastlook = P_Random() % MAXPLAYERS; + mobj->lastlook = safe ? Crispy_Random () % MAXPLAYERS : P_Random () % MAXPLAYERS; // Set the state, but do not use P_SetMobjState, because action // routines can't be called yet. If the spawnstate has an action // routine, it will not be called. - st = &states[info->spawnstate]; + st = &states[safe ? P_LatestSafeState(info->spawnstate) : (statenum_t)info->spawnstate]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; @@ -962,6 +1006,11 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) return (mobj); } +mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) +{ + return P_SpawnMobjSafe(x, y, z, type, false); +} + /* =============== = @@ -1226,11 +1275,11 @@ void P_SpawnMapThing(mapthing_t * mthing) //--------------------------------------------------------------------------- -void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z) +void P_SpawnPuffSafe(fixed_t x, fixed_t y, fixed_t z, boolean safe) { mobj_t *puff; - z += (P_SubRandom() << 10); + z += safe ? (Crispy_SubRandom() << 10) : (P_SubRandom() << 10); puff = P_SpawnMobj(x, y, z, PuffType); if (puff->info->attacksound) { @@ -1252,6 +1301,11 @@ void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z) puff->interp = -1; } +void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z) +{ + P_SpawnPuffSafe(x, y, z, false); +} + /* ================ =