diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index e1b340f27..2adef6aff 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -34,7 +34,8 @@ DEarthquake::DEarthquake() //========================================================================== DEarthquake::DEarthquake (AActor *center, int intensityX, int intensityY, int intensityZ, int duration, - int damrad, int tremrad, FSoundID quakesound, int flags) + int damrad, int tremrad, FSoundID quakesound, int flags, + fixed_t waveSpeedX, fixed_t waveSpeedY, fixed_t waveSpeedZ) : DThinker(STAT_EARTHQUAKE) { m_QuakeSFX = quakesound; @@ -48,6 +49,9 @@ DEarthquake::DEarthquake (AActor *center, int intensityX, int intensityY, int in m_CountdownStart = duration; m_Countdown = duration; m_Flags = flags; + m_WaveSpeedX = waveSpeedX; + m_WaveSpeedY = waveSpeedY; + m_WaveSpeedZ = waveSpeedZ; } //========================================================================== @@ -80,6 +84,14 @@ void DEarthquake::Serialize (FArchive &arc) { arc << m_CountdownStart; } + if (SaveVersion < 4521) + { + m_WaveSpeedX = m_WaveSpeedY = m_WaveSpeedZ = 0; + } + else + { + arc << m_WaveSpeedX << m_WaveSpeedY << m_WaveSpeedZ; + } } //========================================================================== @@ -151,6 +163,17 @@ void DEarthquake::Tick () } } +fixed_t DEarthquake::GetModWave(fixed_t waveMultiplier) const +{ + //QF_WAVE converts intensity into amplitude and unlocks a new property, the wave length. + //This is, in short, waves per second (full cycles, mind you, from 0 to 360.) + //Named waveMultiplier because that's as the name implies: adds more waves per second. + + fixed_t wavesPerSecond = (waveMultiplier >> 15) * m_Countdown % (TICRATE * 2); + fixed_t index = ((wavesPerSecond * (FINEANGLES / 2)) / (TICRATE)); + return finesine[index & FINEMASK]; +} + //========================================================================== // // DEarthquake :: GetModIntensity @@ -163,13 +186,15 @@ fixed_t DEarthquake::GetModIntensity(int intensity) const { assert(m_CountdownStart >= m_Countdown); intensity += intensity; // always doubled + if (m_Flags & (QF_SCALEDOWN | QF_SCALEUP)) { int scalar; if ((m_Flags & (QF_SCALEDOWN | QF_SCALEUP)) == (QF_SCALEDOWN | QF_SCALEUP)) { scalar = (m_Flags & QF_MAX) ? MAX(m_Countdown, m_CountdownStart - m_Countdown) - : MIN(m_Countdown, m_CountdownStart - m_Countdown); + : MIN(m_Countdown, m_CountdownStart - m_Countdown); + if (m_Flags & QF_FULLINTENSITY) { scalar *= 2; @@ -186,10 +211,6 @@ fixed_t DEarthquake::GetModIntensity(int intensity) const assert(m_CountdownStart > 0); intensity = intensity * (scalar << FRACBITS) / m_CountdownStart; } - else - { - intensity <<= FRACBITS; - } return intensity; } @@ -200,17 +221,16 @@ fixed_t DEarthquake::GetModIntensity(int intensity) const // Searches for all quakes near the victim and returns their combined // intensity. // +// Pre: jiggers was pre-zeroed by the caller. +// //========================================================================== -int DEarthquake::StaticGetQuakeIntensities(AActor *victim, - fixed_t &intensityX, fixed_t &intensityY, fixed_t &intensityZ, - fixed_t &relIntensityX, fixed_t &relIntensityY, fixed_t &relIntensityZ) +int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jiggers) { if (victim->player != NULL && (victim->player->cheats & CF_NOCLIP)) { return 0; } - intensityX = intensityY = intensityZ = relIntensityX = relIntensityY = relIntensityZ = 0; TThinkerIterator iterator(STAT_EARTHQUAKE); DEarthquake *quake; @@ -228,17 +248,44 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, fixed_t x = quake->GetModIntensity(quake->m_IntensityX); fixed_t y = quake->GetModIntensity(quake->m_IntensityY); fixed_t z = quake->GetModIntensity(quake->m_IntensityZ); - if (quake->m_Flags & QF_RELATIVE) + if (!(quake->m_Flags & QF_WAVE)) { - relIntensityX = MAX(relIntensityX, x); - relIntensityY = MAX(relIntensityY, y); - relIntensityZ = MAX(relIntensityZ, z); + if (quake->m_Flags & QF_RELATIVE) + { + jiggers.RelIntensityX = MAX(x, jiggers.RelIntensityX); + jiggers.RelIntensityY = MAX(y, jiggers.RelIntensityY); + jiggers.RelIntensityZ = MAX(z, jiggers.RelIntensityZ); + } + else + { + jiggers.IntensityX = MAX(x, jiggers.IntensityX); + jiggers.IntensityY = MAX(y, jiggers.IntensityY); + jiggers.IntensityZ = MAX(z, jiggers.IntensityZ); + } } else { - intensityX = MAX(intensityX, x); - intensityY = MAX(intensityY, y); - intensityZ = MAX(intensityZ, z); + fixed_t mx = FixedMul(x, quake->GetModWave(quake->m_WaveSpeedX)); + fixed_t my = FixedMul(y, quake->GetModWave(quake->m_WaveSpeedY)); + fixed_t mz = FixedMul(z, quake->GetModWave(quake->m_WaveSpeedZ)); + + // [RH] This only gives effect to the last sine quake. I would + // prefer if some way was found to make multiples coexist + // peacefully, but just summing them together is undesirable + // because they could cancel each other out depending on their + // relative phases. + if (quake->m_Flags & QF_RELATIVE) + { + jiggers.RelOffsetX = mx; + jiggers.RelOffsetY = my; + jiggers.RelOffsetZ = mz; + } + else + { + jiggers.OffsetX = mx; + jiggers.OffsetY = my; + jiggers.OffsetZ = mz; + } } } } @@ -252,7 +299,9 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, // //========================================================================== -bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags) +bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration, + int damrad, int tremrad, FSoundID quakesfx, int flags, + fixed_t waveSpeedX, fixed_t waveSpeedY, fixed_t waveSpeedZ) { AActor *center; bool res = false; @@ -265,7 +314,8 @@ bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, { if (activator != NULL) { - new DEarthquake(activator, intensityX, intensityY, intensityZ, duration, damrad, tremrad, quakesfx, flags); + new DEarthquake(activator, intensityX, intensityY, intensityZ, duration, damrad, tremrad, + quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ); return true; } } @@ -275,7 +325,8 @@ bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, while ( (center = iterator.Next ()) ) { res = true; - new DEarthquake(center, intensityX, intensityY, intensityZ, duration, damrad, tremrad, quakesfx, flags); + new DEarthquake(center, intensityX, intensityY, intensityZ, duration, damrad, tremrad, + quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ); } } @@ -284,5 +335,5 @@ bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, bool P_StartQuake(AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx) { //Maintains original behavior by passing 0 to intensityZ, and flags. - return P_StartQuakeXYZ(activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0); + return P_StartQuakeXYZ(activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0); } diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 02ba94036..7c994f3c7 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -138,6 +138,15 @@ enum QF_SCALEUP = 1 << 2, QF_MAX = 1 << 3, QF_FULLINTENSITY = 1 << 4, + QF_WAVE = 1 << 5, +}; + +struct FQuakeJiggers +{ + int IntensityX, IntensityY, IntensityZ; + int RelIntensityX, RelIntensityY, RelIntensityZ; + int OffsetX, OffsetY, OffsetZ; + int RelOffsetX, RelOffsetY, RelOffsetZ; }; class DEarthquake : public DThinker @@ -145,7 +154,9 @@ class DEarthquake : public DThinker DECLARE_CLASS (DEarthquake, DThinker) HAS_OBJECT_POINTERS public: - DEarthquake(AActor *center, int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags); + DEarthquake(AActor *center, int intensityX, int intensityY, int intensityZ, int duration, + int damrad, int tremrad, FSoundID quakesfx, int flags, + fixed_t waveSpeedX, fixed_t waveSpeedY, fixed_t waveSpeedZ); void Serialize (FArchive &arc); void Tick (); @@ -156,12 +167,12 @@ public: FSoundID m_QuakeSFX; int m_Flags; int m_IntensityX, m_IntensityY, m_IntensityZ; + fixed_t m_WaveSpeedX, m_WaveSpeedY, m_WaveSpeedZ; fixed_t GetModIntensity(int intensity) const; + fixed_t GetModWave(fixed_t waveMultiplier) const; - static int StaticGetQuakeIntensities(AActor *viewer, - fixed_t &intensityX, fixed_t &intensityY, fixed_t &intensityZ, - fixed_t &relIntensityX, fixed_t &relIntensityY, fixed_t &relIntensityZ); + static int StaticGetQuakeIntensities(AActor *viewer, FQuakeJiggers &jiggers); private: DEarthquake (); diff --git a/src/p_spec.h b/src/p_spec.h index 2edfe6390..b0c66b10e 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -929,7 +929,7 @@ void P_DoDeferedScripts (void); // // [RH] p_quake.c // -bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags); +bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags, fixed_t waveSpeedX, fixed_t waveSpeedY, fixed_t waveSpeedZ); bool P_StartQuake(AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx); #endif diff --git a/src/r_utility.cpp b/src/r_utility.cpp index c82216e74..60e2c1af1 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -770,9 +770,19 @@ bool R_GetViewInterpolationStatus() // //========================================================================== -static fixed_t QuakePower(fixed_t factor, fixed_t intensity) -{ - return FixedMul(factor, pr_torchflicker(intensity * 2) - intensity); +static fixed_t QuakePower(fixed_t factor, fixed_t intensity, fixed_t offset) +{ + fixed_t randumb; + + if (intensity == 0) + { + randumb = 0; + } + else + { + randumb = pr_torchflicker(intensity * 2) - intensity; + } + return FixedMul(factor, randumb + offset); } //========================================================================== @@ -885,40 +895,43 @@ void R_SetupFrame (AActor *actor) if (!paused) { - fixed_t intensityX, intensityY, intensityZ, relIntensityX, relIntensityY, relIntensityZ; - if (DEarthquake::StaticGetQuakeIntensities(camera, - intensityX, intensityY, intensityZ, - relIntensityX, relIntensityY, relIntensityZ) > 0) + FQuakeJiggers jiggers = { 0, }; + + if (DEarthquake::StaticGetQuakeIntensities(camera, jiggers) > 0) { fixed_t quakefactor = FLOAT2FIXED(r_quakeintensity); - if (relIntensityX != 0) + if ((jiggers.RelIntensityX | jiggers.RelOffsetX) != 0) { int ang = (camera->angle) >> ANGLETOFINESHIFT; - fixed_t power = QuakePower(quakefactor, relIntensityX); + fixed_t power = QuakePower(quakefactor, jiggers.RelIntensityX, jiggers.RelOffsetX); viewx += FixedMul(finecosine[ang], power); viewy += FixedMul(finesine[ang], power); } - if (relIntensityY != 0) + if ((jiggers.RelIntensityY | jiggers.RelOffsetY) != 0) { int ang = (camera->angle + ANG90) >> ANGLETOFINESHIFT; - fixed_t power = QuakePower(quakefactor, relIntensityY); + fixed_t power = QuakePower(quakefactor, jiggers.RelIntensityY, jiggers.RelOffsetY); viewx += FixedMul(finecosine[ang], power); viewy += FixedMul(finesine[ang], power); } - if (intensityX != 0) - { - viewx += QuakePower(quakefactor, intensityX); - } - if (intensityY != 0) - { - viewy += QuakePower(quakefactor, intensityY); - } // FIXME: Relative Z is not relative - intensityZ = MAX(intensityZ, relIntensityZ); - if (intensityZ != 0) + // [MC]On it! Will be introducing pitch after QF_WAVE. + if ((jiggers.RelIntensityZ | jiggers.RelOffsetZ) != 0) { - viewz += QuakePower(quakefactor, intensityZ); + viewz += QuakePower(quakefactor, jiggers.RelIntensityZ, jiggers.RelOffsetZ); + } + if ((jiggers.IntensityX | jiggers.OffsetX) != 0) + { + viewx += QuakePower(quakefactor, jiggers.IntensityX, jiggers.OffsetX); + } + if ((jiggers.IntensityY | jiggers.OffsetY) != 0) + { + viewy += QuakePower(quakefactor, jiggers.IntensityY, jiggers.OffsetY); + } + if ((jiggers.IntensityZ | jiggers.OffsetZ) != 0) + { + viewz += QuakePower(quakefactor, jiggers.IntensityZ, jiggers.OffsetZ); } } } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index c30d09c7a..2c289849a 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4419,7 +4419,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_QuakeEx) { - ACTION_PARAM_START(8); + ACTION_PARAM_START(11); ACTION_PARAM_INT(intensityX, 0); ACTION_PARAM_INT(intensityY, 1); ACTION_PARAM_INT(intensityZ, 2); @@ -4428,7 +4428,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_QuakeEx) ACTION_PARAM_INT(tremrad, 5); ACTION_PARAM_SOUND(sound, 6); ACTION_PARAM_INT(flags, 7); - P_StartQuakeXYZ(self, 0, intensityX, intensityY, intensityZ, duration, damrad, tremrad, sound, flags); + ACTION_PARAM_FIXED(mulWaveX, 8); + ACTION_PARAM_FIXED(mulWaveY, 9); + ACTION_PARAM_FIXED(mulWaveZ, 10); + P_StartQuakeXYZ(self, 0, intensityX, intensityY, intensityZ, duration, damrad, tremrad, sound, flags, mulWaveX, mulWaveY, mulWaveZ); } //=========================================================================== diff --git a/src/version.h b/src/version.h index 794bdcec8..de33e93a7 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4520 +#define SAVEVER 4521 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index e8906af3f..f84151d18 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -299,7 +299,7 @@ ACTOR Actor native //: Thinker action native A_SetUserArray(name varname, int index, int value); action native A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0); action native A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); - action native A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0); + action native A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, float mulWaveX = 1, float mulWaveY = 1, float mulWaveZ = 1); action native A_SetTics(int tics); action native A_SetDamageType(name damagetype); action native A_DropItem(class item, int dropamount = -1, int chance = 256); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 78149430a..e6434a08e 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -466,6 +466,7 @@ enum QF_SCALEUP = 1 << 2, QF_MAX = 1 << 3, QF_FULLINTENSITY = 1 << 4, + QF_WAVE = 1 << 5, }; // This is only here to provide one global variable for testing.