diff --git a/src/common/engine/m_haptics.cpp b/src/common/engine/m_haptics.cpp index c91885a6d..351eb4d2d 100644 --- a/src/common/engine/m_haptics.cpp +++ b/src/common/engine/m_haptics.cpp @@ -141,6 +141,8 @@ CUSTOM_CVARD(Int, haptics_compat, HAPTCOMPAT_MATCH, CVAR_ARCHIVE | CVAR_GLOBALCO if (self >= NUM_HAPTCOMPAT) self = NUM_HAPTCOMPAT-1; } +CVARD(Bool, haptics_do_action, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "allow haptic feedback for player doing things"); + // CODE -------------------------------------------------------------------- //========================================================================== diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 94a9398cb..10a4ed8ae 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -119,6 +119,7 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- EXTERN_CVAR (Int, cl_rockettrails) +EXTERN_CVAR (Bool, haptics_do_action) // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -6987,13 +6988,17 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 if (cl_pufftype == 1) puff->renderflags |= RF_INVISIBLE; } + bool meleeFromPlayer = ( + (flags & PF_MELEERANGE) && source->player + && (source->player->mo == players[consoleplayer].mo || source->player->mo == players[consoleplayer].camera)); + if ((flags & PF_HITTHING) && puff->SeeSound.isvalid()) { // Hit thing sound - S_Sound (puff, CHAN_BODY, 0, puff->SeeSound, 1, ATTN_NORM); + S_Sound (puff, CHAN_BODY, (meleeFromPlayer&&haptics_do_action)?CHANF_RUMBLE:CHANF_NONE, puff->SeeSound, 1, ATTN_NORM); } else if (puff->AttackSound.isvalid()) { - S_Sound (puff, CHAN_BODY, 0, puff->AttackSound, 1, ATTN_NORM); + S_Sound (puff, CHAN_BODY, (meleeFromPlayer&&haptics_do_action)?CHANF_RUMBLE:CHANF_NONE, puff->AttackSound, 1, ATTN_NORM); } } @@ -7702,12 +7707,12 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct AActor *th = Spawn (source->Level, type, pos, ALLOW_REPLACE); - P_PlaySpawnSound(th, source); - // record missile's originator if (owner == NULL) owner = source; th->target = owner; + P_PlaySpawnSound(th, source); + double speed = th->Speed; // [RH] @@ -7798,9 +7803,10 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct } AActor *th = Spawn (source->Level, type, source->PosPlusZ(32.), ALLOW_REPLACE); - P_PlaySpawnSound(th, source); th->target = owner; // record missile's originator + P_PlaySpawnSound(th, source); + th->Angles.Yaw = source->AngleTo(dest); th->VelFromAngle(); @@ -7889,9 +7895,11 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z, mo = Spawn (source->Level, type, source->PosAtZ(z), ALLOW_REPLACE); - P_PlaySpawnSound(mo, source); if (owner == NULL) owner = source; mo->target = owner; + + P_PlaySpawnSound(mo, source); + mo->Angles.Yaw = angle; mo->VelFromAngle(speed); mo->Vel.Z = vz; @@ -8037,8 +8045,8 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, DVector3 pos = source->Vec2OffsetZ(x, y, z); AActor *MissileActor = Spawn (source->Level, type, pos, ALLOW_REPLACE); if (pMissileActor) *pMissileActor = MissileActor; - P_PlaySpawnSound(MissileActor, source); MissileActor->target = source; + P_PlaySpawnSound(MissileActor, source); MissileActor->Angles.Yaw = an; if (MissileActor->flags3 & (MF3_FLOORHUGGER | MF3_CEILINGHUGGER)) { diff --git a/src/playsim/p_spec.cpp b/src/playsim/p_spec.cpp index 691947f02..21a7e56e0 100644 --- a/src/playsim/p_spec.cpp +++ b/src/playsim/p_spec.cpp @@ -186,6 +186,16 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType, DVe { P_ChangeSwitchTexture (line->sidedef[0], repeat, special); } + + if ((mo == players[consoleplayer].mo || mo == players[consoleplayer].camera) && + (activationType == SPAC_Use || activationType == SPAC_Push || activationType == SPAC_UseThrough || activationType == SPAC_UseBack)) + { + IFVIRTUALPTR(mo, AActor, PlayerUsedSomethingMakeRumble) + { + VMValue params[5] = { mo, activationType, Level->levelnum, line->linenum, line->special}; + VMCall(func, params, 5, nullptr, 0); + } + } } // some old WADs use this method to create walls that change the texture when shot. else if (activationType == SPAC_Impact && // only for shootable triggers diff --git a/src/sound/s_doomsound.cpp b/src/sound/s_doomsound.cpp index dcb0ff05e..6ff228fb6 100644 --- a/src/sound/s_doomsound.cpp +++ b/src/sound/s_doomsound.cpp @@ -36,7 +36,6 @@ ** */ -#include "v_font.h" #include #include @@ -45,6 +44,7 @@ #endif #include "a_sharedglobal.h" +#include "c_cvars.h" #include "c_dispatch.h" #include "cmdlib.h" #include "d_player.h" @@ -67,8 +67,13 @@ #include "s_sound.h" #include "serializer_doom.h" #include "v_draw.h" +#include "v_font.h" #include "vm.h" +// EXTERNAL DATA DEFINITIONS ------------------------------------------------- + +EXTERN_CVAR(Bool, haptics_do_action); + // PUBLIC DATA DEFINITIONS ------------------------------------------------- static FString LastLocalSndInfo; @@ -525,6 +530,18 @@ void S_SoundPitchActor(AActor *ent, int channel, EChanFlags flags, FSoundID soun flags = (EChanFlag)(flags - CHANF_RUMBLE); } } + else if (!(flags & CHANF_RUMBLE)) + { + // add flag if needed + if (haptics_do_action && ( + // sound from self + (ent->player && (ent->player->mo == players[consoleplayer].mo || ent->player->mo == players[consoleplayer].camera)) || + // sound from self missile + ((ent->flags & MF_MISSILE) + && ent->target && ent->target->player + && (ent->target->player->mo == players[consoleplayer].mo || ent->target->player->mo == players[consoleplayer].camera)) + )) flags |= CHANF_RUMBLE; + } if (VerifyActorSound(ent, sound_id, channel, flags)) soundEngine->StartSound (SOURCE_Actor, ent, nullptr, channel, flags, sound_id, volume, attenuation, 0, pitch, startTime); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 1579d24cf..a83e30f09 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1262,6 +1262,7 @@ OptionMenu "HapticsOptions" protected Option "$HAPMNU_COMPAT", "haptics_compat", "HapticsCompatTypes" StaticText "" StaticText "$HAPMNU_OPTIONS" + Option "$HAPMNU_OPT_ACTION", "haptics_do_action", "OnOff" } //------------------------------------------------------------------------------------------- diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 7c3d56d9f..22ccfa7c6 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -2,6 +2,7 @@ ** actor.zs ** **--------------------------------------------------------------------------- +** ** Copyright 2010-2017 Christoph Oelckers ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -28,6 +29,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -1709,6 +1711,19 @@ class Actor : Thinker native } } + //---------------------------------------------------------------------------- + // + // player rumble events + // + //---------------------------------------------------------------------------- + + virtual void PlayerUsedSomethingMakeRumble(int activationType, int levelNum, int lineNum, int lineSpecial) + { + if (!CVar.GetCVar("haptics_do_action").GetBool()) return; + + Haptics.Rumble("*usesuccess"); + } + //---------------------------------------------------------------------------- // // PROC A_CheckSkullDone