diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 326a6f1867..f516b79f1e 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -873,7 +873,7 @@ public: void PlayPushSound(); // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor - bool FloorBounceMissile (secplane_t &plane); + bool FloorBounceMissile (secplane_t &plane, bool is3DFloor); // Called by RoughBlockCheck bool IsOkayToAttack (AActor *target); diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index f8b23a8118..84accbe760 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -2486,7 +2486,9 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, // If it's a bouncer, let it bounce off its new floor, too. if (thing->BounceFlags & BOUNCE_Floors) { - thing->FloorBounceMissile(tm.floorsector->floorplane); + F3DFloor* ff = nullptr; + NextLowestFloorAt(tm.sector, tm.pos.X, tm.pos.Y, tm.pos.Z, 0, thing->MaxStepHeight, nullptr, &ff); + thing->FloorBounceMissile(ff != nullptr ? *ff->top.plane : tm.floorsector->floorplane, ff != nullptr); } else { @@ -3603,14 +3605,17 @@ bool FSlide::BounceWall(AActor *mo) { // Could not find a wall, so bounce off the floor/ceiling instead. double floordist = mo->Z() - mo->floorz; double ceildist = mo->ceilingz - mo->Z(); + F3DFloor* ff = nullptr; if (floordist <= ceildist) { - mo->FloorBounceMissile(mo->Sector->floorplane); + NextLowestFloorAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), 0, mo->MaxStepHeight, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); return true; } else { - mo->FloorBounceMissile(mo->Sector->ceilingplane); + NextHighestCeilingAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), mo->Top(), 0, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->bottom.plane : mo->ceilingsector->ceilingplane, ff != nullptr); return true; } } diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index acc18902ab..e25545f804 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1732,7 +1732,7 @@ void AActor::PlayBounceSound(bool onfloor) // Returns true if the missile was destroyed //---------------------------------------------------------------------------- -bool AActor::FloorBounceMissile (secplane_t &plane) +bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) { if (flags & MF_MISSILE) { @@ -1808,11 +1808,15 @@ bool AActor::FloorBounceMissile (secplane_t &plane) return true; } - double dot = (Vel | plane.Normal()) * 2; + DVector3 norm = plane.Normal(); + if (is3DFloor) + norm = -norm; + + double dot = (Vel | norm) * 2; if (BounceFlags & (BOUNCE_HereticType | BOUNCE_MBF)) { - Vel -= plane.Normal() * dot; + Vel -= norm * dot; AngleFromVel(); if (!(BounceFlags & BOUNCE_MBF)) // Heretic projectiles die, MBF projectiles don't. { @@ -1826,7 +1830,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane) else // Don't run through this for MBF-style bounces { // The reflected velocity keeps only about 70% of its original speed - Vel = (Vel - plane.Normal() * dot) * bouncefactor; + Vel = (Vel - norm * dot) * bouncefactor; AngleFromVel(); } @@ -1850,10 +1854,10 @@ bool AActor::FloorBounceMissile (secplane_t &plane) } else if (BounceFlags & (BOUNCE_AutoOff|BOUNCE_AutoOffFloorOnly)) { - if (plane.fC() > 0 || (BounceFlags & BOUNCE_AutoOff)) + if (norm.Z > 0 || (BounceFlags & BOUNCE_AutoOff)) { // AutoOff only works when bouncing off a floor, not a ceiling (or in compatibility mode.) - if (!(flags & MF_NOGRAVITY) && (Vel.Z < 3)) + if (!(flags & MF_NOGRAVITY) && ((Vel | norm) < 3)) BounceFlags &= ~BOUNCE_TypeMask; } } @@ -2646,7 +2650,9 @@ static void P_ZMovement (AActor *mo, double oldfloorz) mo->SetZ(mo->floorz); if (mo->BounceFlags & BOUNCE_Floors) { - mo->FloorBounceMissile (mo->floorsector->floorplane); + F3DFloor* ff = nullptr; + NextLowestFloorAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), 0, mo->MaxStepHeight, nullptr, &ff); + mo->FloorBounceMissile (ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); /* if (!CanJump(mo)) */ return; } else if (mo->flags3 & MF3_NOEXPLODEFLOOR) @@ -2682,7 +2688,9 @@ static void P_ZMovement (AActor *mo, double oldfloorz) } else if (mo->BounceFlags & BOUNCE_MBF && mo->Vel.Z) // check for MBF-like bounce on non-missiles { - mo->FloorBounceMissile(mo->floorsector->floorplane); + F3DFloor* ff = nullptr; + NextLowestFloorAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), 0, mo->MaxStepHeight, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); } if (mo->flags3 & MF3_ISMONSTER) // Blasted mobj falling { @@ -2753,7 +2761,9 @@ static void P_ZMovement (AActor *mo, double oldfloorz) mo->SetZ(mo->ceilingz - mo->Height); if (mo->BounceFlags & BOUNCE_Ceilings) { // ceiling bounce - mo->FloorBounceMissile (mo->ceilingsector->ceilingplane); + F3DFloor* ff = nullptr; + NextHighestCeilingAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), mo->Top(), 0, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->bottom.plane : mo->ceilingsector->ceilingplane, ff != nullptr); /* if (!CanJump(mo)) */ return; } if (mo->flags & MF_SKULLFLY) diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 18cd8aa32f..2cf04fd80a 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -1851,8 +1851,9 @@ DEFINE_ACTION_FUNCTION(AActor, BouncePlane) { PARAM_SELF_PROLOGUE(AActor); PARAM_POINTER(plane, secplane_t); + PARAM_BOOL(is3DFloor); - ACTION_RETURN_BOOL(self->FloorBounceMissile(*plane)); + ACTION_RETURN_BOOL(self->FloorBounceMissile(*plane, is3DFloor)); } DEFINE_ACTION_FUNCTION(AActor, PlayBounceSound) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 37b36e9e7c..e0633d599b 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -866,7 +866,7 @@ class Actor : Thinker native native void PlayPushSound(); native bool BounceActor(Actor blocking, bool onTop); native bool BounceWall(Line l = null); - native bool BouncePlane(readonly plane); + native bool BouncePlane(readonly plane, bool is3DFloor = false); native void PlayBounceSound(bool onFloor); native bool ReflectOffActor(Actor blocking);