diff --git a/src/common/engine/m_random.h b/src/common/engine/m_random.h index ba0bcaf62..bc7eb4d0d 100644 --- a/src/common/engine/m_random.h +++ b/src/common/engine/m_random.h @@ -37,6 +37,7 @@ #include #include "basics.h" +#include "tarray.h" #include "sfmt/SFMTObj.h" class FSerializer; diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 322d32341..4a549bfbd 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -549,6 +549,8 @@ enum ActorBounceFlag BOUNCE_BounceOnUnrips = 1<<16, // projectile bounces on actors with DONTRIP BOUNCE_NotOnSky = 1<<17, // Don't bounce on sky floors / ceilings / walls BOUNCE_DEH = 1<<18, // Flag was set through Dehacked. + BOUNCE_KeepAngle = 1<<19, // Don't change yaw when bouncing off a surface. + BOUNCE_ModifyPitch = 1<<20, // Change pitch when bouncing off a surface. BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, diff --git a/src/playsim/p_acs.cpp b/src/playsim/p_acs.cpp index 89aee643d..652dd6141 100644 --- a/src/playsim/p_acs.cpp +++ b/src/playsim/p_acs.cpp @@ -10337,6 +10337,11 @@ int DLevelScript::RunScript() } } + // There are several or more p-codes that can trigger a division or modulus of zero. + // Reset the active behavior back to the original if this happens. + if (state == SCRIPT_DivideBy0 || state == SCRIPT_ModulusBy0) + activeBehavior = savedActiveBehavior; + if (runaway != 0 && InModuleScriptNumber >= 0) { auto scriptptr = activeBehavior->GetScriptPtr(InModuleScriptNumber); diff --git a/src/playsim/p_effect.h b/src/playsim/p_effect.h index 1e5ba2705..29042b293 100644 --- a/src/playsim/p_effect.h +++ b/src/playsim/p_effect.h @@ -70,6 +70,7 @@ enum EParticleFlags SPF_NOFACECAMERA = 1 << 12, SPF_ROLLCENTER = 1 << 13, SPF_STRETCHPIXELS = 1 << 14, + SPF_ALLOWSHADERS = 1 << 15, }; class DVisualThinker; diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 6c74b494f..a79436dd1 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -3653,7 +3653,8 @@ bool FSlide::BounceWall(AActor *mo) } moveangle = mo->Vel.Angle(); deltaangle = (lineangle * 2) - moveangle; - mo->Angles.Yaw = deltaangle; + if (!(mo->BounceFlags & BOUNCE_KeepAngle)) + mo->Angles.Yaw = deltaangle; movelen = mo->Vel.XY().Length() * GetWallBounceFactor(mo); @@ -3751,8 +3752,10 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) DAngle angle = BlockingMobj->AngleTo(mo) + DAngle::fromDeg((pr_bounce() % 16) - 8); double speed = mo->VelXYToSpeed() * GetWallBounceFactor(mo); // [GZ] was 0.75, using wallbouncefactor seems more consistent if (fabs(speed) < EQUAL_EPSILON) speed = 0; - mo->Angles.Yaw = angle; - mo->VelFromAngle(speed); + if (!(mo->BounceFlags & BOUNCE_KeepAngle)) + mo->Angles.Yaw = angle; + mo->Vel.X = speed * angle.Cos(); + mo->Vel.Y = speed * angle.Sin(); mo->PlayBounceSound(true, 1.0); } else @@ -3781,6 +3784,9 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) mo->Vel *= mo->bouncefactor; } + if (mo->BounceFlags & BOUNCE_ModifyPitch) + mo->Angles.Pitch = -VecToAngle(mo->Vel.XY().Length(), mo->Vel.Z); + mo->PlayBounceSound(true, 1.0); if (mo->BounceFlags & BOUNCE_MBF) // Bring it to rest below a certain speed { diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 5f68723d0..3f9e4efc1 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1824,7 +1824,8 @@ bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) if (BounceFlags & (BOUNCE_HereticType | BOUNCE_MBF)) { Vel -= norm * dot; - AngleFromVel(); + if (!(BounceFlags & BOUNCE_KeepAngle)) + AngleFromVel(); if (!(BounceFlags & BOUNCE_MBF)) // Heretic projectiles die, MBF projectiles don't. { flags |= MF_INBOUNCE; @@ -1838,9 +1839,13 @@ bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) { // The reflected velocity keeps only about 70% of its original speed Vel = (Vel - norm * dot) * bouncefactor; - AngleFromVel(); + if (!(BounceFlags & BOUNCE_KeepAngle)) + AngleFromVel(); } + if (BounceFlags & BOUNCE_ModifyPitch) + Angles.Pitch = -VecToAngle(Vel.XY().Length(), Vel.Z); + PlayBounceSound(true, 1.0); // Set bounce state diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index be0630bd3..bbec77694 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -1501,7 +1501,7 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, FRenderState& state, particle_t * foglevel = (uint8_t)clamp(sector->lightlevel, 0, 255); trans = particle->alpha; - OverrideShader = 0; + OverrideShader = (particle->flags & SPF_ALLOWSHADERS) ? -1 : 0; modelframe = nullptr; texture = nullptr; topclip = LARGE_VALUE; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index fa8d66674..8692936c1 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -407,6 +407,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG2(BOUNCE_NotOnShootables, DONTBOUNCEONSHOOTABLES, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_BounceOnUnrips, BOUNCEONUNRIPPABLES, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_NotOnSky, DONTBOUNCEONSKY, AActor, BounceFlags), + DEFINE_FLAG2(BOUNCE_KeepAngle, KEEPBOUNCEANGLE, AActor, BounceFlags), + DEFINE_FLAG2(BOUNCE_ModifyPitch, BOUNCEMODIFIESPITCH, AActor, BounceFlags), DEFINE_FLAG2(OF_Transient, NOSAVEGAME, AActor, ObjectFlags), diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index e56b826c3..bc0fc4e82 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -723,6 +723,7 @@ enum EParticleFlags SPF_NOFACECAMERA = 1 << 12, SPF_ROLLCENTER = 1 << 13, SPF_STRETCHPIXELS = 1 << 14, + SPF_ALLOWSHADERS = 1 << 15, SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG };