diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index c3a227b36..874ecbb51 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -33,8 +33,8 @@ DEarthquake::DEarthquake() // //========================================================================== -DEarthquake::DEarthquake (AActor *center, int intensity, int duration, - int damrad, int tremrad, FSoundID quakesound) +DEarthquake::DEarthquake (AActor *center, int intensityX, int intensityY, int intensityZ, int duration, + int damrad, int tremrad, FSoundID quakesound, int flags) : DThinker(STAT_EARTHQUAKE) { m_QuakeSFX = quakesound; @@ -42,8 +42,11 @@ DEarthquake::DEarthquake (AActor *center, int intensity, int duration, // Radii are specified in tile units (64 pixels) m_DamageRadius = damrad << (FRACBITS); m_TremorRadius = tremrad << (FRACBITS); - m_Intensity = intensity; + m_IntensityX = intensityX; + m_IntensityY = intensityY; + m_IntensityZ = intensityZ; m_Countdown = duration; + m_Flags = flags; } //========================================================================== @@ -55,9 +58,19 @@ DEarthquake::DEarthquake (AActor *center, int intensity, int duration, void DEarthquake::Serialize (FArchive &arc) { Super::Serialize (arc); - arc << m_Spot << m_Intensity << m_Countdown + arc << m_Spot << m_IntensityX << m_Countdown << m_TremorRadius << m_DamageRadius << m_QuakeSFX; + if (SaveVersion < 4519) + { + m_IntensityY = m_IntensityX; + m_IntensityZ = 0; + m_Flags = 0; + } + else + { + arc << m_IntensityY << m_IntensityZ << m_Flags; + } } //========================================================================== @@ -102,7 +115,18 @@ void DEarthquake::Tick () } // Thrust player around angle_t an = victim->angle + ANGLE_1*pr_quake(); - P_ThrustMobj (victim, an, m_Intensity << (FRACBITS-1)); + if (m_IntensityX == m_IntensityY) + { // Thrust in a circle + P_ThrustMobj (victim, an, m_IntensityX << (FRACBITS-1)); + } + else + { // Thrust in an ellipse + an >>= ANGLETOFINESHIFT; + // So this is actually completely wrong, but it ought to be good + // enough. Otherwise, I'd have to use tangents and square roots. + victim->velx += FixedMul(m_IntensityX << (FRACBITS-1), finecosine[an]); + victim->vely += FixedMul(m_IntensityY << (FRACBITS-1), finesine[an]); + } } } } @@ -126,17 +150,20 @@ void DEarthquake::Tick () // //========================================================================== -int DEarthquake::StaticGetQuakeIntensity (AActor *victim) +int DEarthquake::StaticGetQuakeIntensities(AActor *victim, + int &x, int &y, int &z, int &relx, int &rely, int &relz) { - int intensity = 0; - TThinkerIterator iterator (STAT_EARTHQUAKE); - DEarthquake *quake; - if (victim->player != NULL && (victim->player->cheats & CF_NOCLIP)) { return 0; } + x = y = z = relx = rely = 0; + + TThinkerIterator iterator(STAT_EARTHQUAKE); + DEarthquake *quake; + int count = 0; + while ( (quake = iterator.Next()) != NULL) { if (quake->m_Spot != NULL) @@ -145,12 +172,23 @@ int DEarthquake::StaticGetQuakeIntensity (AActor *victim) victim->y - quake->m_Spot->y); if (dist < quake->m_TremorRadius) { - if (intensity < quake->m_Intensity) - intensity = quake->m_Intensity; + ++count; + if (quake->m_Flags & QF_RELATIVE) + { + relx = MAX(relx, quake->m_IntensityX); + rely = MAX(rely, quake->m_IntensityY); + relz = MAX(relz, quake->m_IntensityZ); + } + else + { + x = MAX(x, quake->m_IntensityX); + y = MAX(y, quake->m_IntensityY); + z = MAX(z, quake->m_IntensityZ); + } } } } - return intensity; + return count; } //========================================================================== @@ -159,18 +197,20 @@ int DEarthquake::StaticGetQuakeIntensity (AActor *victim) // //========================================================================== -bool P_StartQuake (AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx) +bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags) { AActor *center; bool res = false; - intensity = clamp (intensity, 1, 9); + if (intensityX) intensityX = clamp(intensityX, 1, 9); + if (intensityY) intensityY = clamp(intensityY, 1, 9); + if (intensityZ) intensityZ = clamp(intensityZ, 1, 9); if (tid == 0) { if (activator != NULL) { - new DEarthquake(activator, intensity, duration, damrad, tremrad, quakesfx); + new DEarthquake(activator, intensityX, intensityY, intensityZ, duration, damrad, tremrad, quakesfx, flags); return true; } } @@ -180,9 +220,14 @@ bool P_StartQuake (AActor *activator, int tid, int intensity, int duration, int while ( (center = iterator.Next ()) ) { res = true; - new DEarthquake (center, intensity, duration, damrad, tremrad, quakesfx); + new DEarthquake(center, intensityX, intensityY, intensityZ, duration, damrad, tremrad, quakesfx, flags); } } return res; } + +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); +} diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index a898433f0..e153f7070 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -131,23 +131,28 @@ protected: DFlashFader (); }; +enum +{ + QF_RELATIVE = 1, +}; + class DEarthquake : public DThinker { DECLARE_CLASS (DEarthquake, DThinker) HAS_OBJECT_POINTERS public: - DEarthquake (AActor *center, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx); + DEarthquake(AActor *center, int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags); void Serialize (FArchive &arc); void Tick (); - TObjPtr m_Spot; fixed_t m_TremorRadius, m_DamageRadius; - int m_Intensity; int m_Countdown; FSoundID m_QuakeSFX; + int m_Flags; + int m_IntensityX, m_IntensityY, m_IntensityZ; - static int StaticGetQuakeIntensity (AActor *viewer); + static int StaticGetQuakeIntensities(AActor *viewer, int &x, int &y, int &z, int &relx, int &rely, int &relz); private: DEarthquake (); diff --git a/src/p_spec.h b/src/p_spec.h index 0d7ef4cff..2edfe6390 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -929,6 +929,7 @@ void P_DoDeferedScripts (void); // // [RH] p_quake.c // -bool P_StartQuake (AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx); +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_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 585e3dcf3..a65c90d93 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -764,6 +764,23 @@ bool R_GetViewInterpolationStatus() return NoInterpolateView; } +//========================================================================== +// +// QuakePower +// +//========================================================================== + +static fixed_t QuakePower(fixed_t factor, int intensity) +{ + if (intensity == 0) + { + return 0; + } + else + { + return factor * ((pr_torchflicker() % (intensity << 2)) - (intensity << 1)); + } +} //========================================================================== // @@ -875,13 +892,41 @@ void R_SetupFrame (AActor *actor) if (!paused) { - int intensity = DEarthquake::StaticGetQuakeIntensity (camera); - if (intensity != 0) + int intensityX, intensityY, intensityZ, relIntensityX, relIntensityY, relIntensityZ; + if (DEarthquake::StaticGetQuakeIntensities(camera, + intensityX, intensityY, intensityZ, + relIntensityX, relIntensityY, relIntensityZ) > 0) { fixed_t quakefactor = FLOAT2FIXED(r_quakeintensity); - viewx += quakefactor * ((pr_torchflicker() % (intensity<<2)) - (intensity<<1)); - viewy += quakefactor * ((pr_torchflicker() % (intensity<<2)) - (intensity<<1)); + if (relIntensityX != 0) + { + int ang = (camera->angle) >> ANGLETOFINESHIFT; + fixed_t power = QuakePower(quakefactor, relIntensityX); + viewx += FixedMul(finecosine[ang], power); + viewy += FixedMul(finesine[ang], power); + } + if (relIntensityY != 0) + { + int ang = (camera->angle + ANG90) >> ANGLETOFINESHIFT; + fixed_t power = QuakePower(quakefactor, relIntensityY); + 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) + { + viewz += QuakePower(quakefactor, intensityZ); + } } } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 117207302..c30d09c7a 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4409,6 +4409,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) P_StartQuake(self, 0, intensity, duration, damrad, tremrad, sound); } +//=========================================================================== +// +// A_QuakeEx +// +// Extended version of A_Quake. Takes individual axis into account and can +// take a flag. +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_QuakeEx) +{ + ACTION_PARAM_START(8); + ACTION_PARAM_INT(intensityX, 0); + ACTION_PARAM_INT(intensityY, 1); + ACTION_PARAM_INT(intensityZ, 2); + ACTION_PARAM_INT(duration, 3); + ACTION_PARAM_INT(damrad, 4); + 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); +} + //=========================================================================== // // A_Weave diff --git a/src/version.h b/src/version.h index 09b830438..2be4787ee 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 4518 +#define SAVEVER 4519 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index c03c86596..e8906af3f 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -299,6 +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_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 aedd01284..3df42e0f8 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -458,6 +458,11 @@ enum FAF_NODISTFACTOR = 8, }; +// Flags for A_QuakeEx +enum +{ + QF_RELATIVE = 1, +}; // This is only here to provide one global variable for testing. native int testglobalvar;