Change XYZ Quaking from Major Cooke

- Relative quakes are different from other quakes; all quakes affecting
  the camera do not become relative if one of them is relative.
- Use a single function call to get quake visual parameters instead of four.
- Thrust things in a psuedo-ellipse if they're inside a damaging quake whose
  IntensityX != IntensityY.
- Don't break old savegames.
This commit is contained in:
Randy Heit 2015-02-18 14:48:52 -06:00
parent 7050d03222
commit e377c2c4f8
4 changed files with 96 additions and 95 deletions

View file

@ -42,12 +42,11 @@ DEarthquake::DEarthquake (AActor *center, int intensityX, int intensityY, int in
// Radii are specified in tile units (64 pixels) // Radii are specified in tile units (64 pixels)
m_DamageRadius = damrad << (FRACBITS); m_DamageRadius = damrad << (FRACBITS);
m_TremorRadius = tremrad << (FRACBITS); m_TremorRadius = tremrad << (FRACBITS);
m_Intensity = intensityX; m_IntensityX = intensityX;
m_IntensityY = intensityY;
m_IntensityZ = intensityZ;
m_Countdown = duration; m_Countdown = duration;
m_Flags = flags; m_Flags = flags;
m_iX = intensityX;
m_iY = intensityY;
m_iZ = intensityZ;
} }
//========================================================================== //==========================================================================
@ -58,10 +57,20 @@ DEarthquake::DEarthquake (AActor *center, int intensityX, int intensityY, int in
void DEarthquake::Serialize (FArchive &arc) void DEarthquake::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); //[MC] m_Intensity is unused now but I don't want to break compatibility... Super::Serialize (arc);
arc << m_Spot << m_Intensity << m_Countdown arc << m_Spot << m_IntensityX << m_Countdown
<< m_TremorRadius << m_DamageRadius << m_TremorRadius << m_DamageRadius
<< m_QuakeSFX << m_Flags << m_iX << m_iY << m_iZ; << m_QuakeSFX;
if (SaveVersion < 4519)
{
m_IntensityY = m_IntensityX;
m_IntensityZ = 0;
m_Flags = 0;
}
else
{
arc << m_IntensityY << m_IntensityZ << m_Flags;
}
} }
//========================================================================== //==========================================================================
@ -106,7 +115,18 @@ void DEarthquake::Tick ()
} }
// Thrust player around // Thrust player around
angle_t an = victim->angle + ANGLE_1*pr_quake(); 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]);
}
} }
} }
} }
@ -130,18 +150,20 @@ void DEarthquake::Tick ()
// //
//========================================================================== //==========================================================================
int DEarthquake::StaticGetQuakeIntensity (AActor *victim, int selector) int DEarthquake::StaticGetQuakeIntensities(AActor *victim,
int &x, int &y, int &z, int &relx, int &rely, int &relz)
{ {
int intensity = 0;
int quakeIntensity = 0;
TThinkerIterator<DEarthquake> iterator (STAT_EARTHQUAKE);
DEarthquake *quake;
if (victim->player != NULL && (victim->player->cheats & CF_NOCLIP)) if (victim->player != NULL && (victim->player->cheats & CF_NOCLIP))
{ {
return 0; return 0;
} }
x = y = z = relx = rely = 0;
TThinkerIterator<DEarthquake> iterator(STAT_EARTHQUAKE);
DEarthquake *quake;
int count = 0;
while ( (quake = iterator.Next()) != NULL) while ( (quake = iterator.Next()) != NULL)
{ {
if (quake->m_Spot != NULL) if (quake->m_Spot != NULL)
@ -150,64 +172,25 @@ int DEarthquake::StaticGetQuakeIntensity (AActor *victim, int selector)
victim->y - quake->m_Spot->y); victim->y - quake->m_Spot->y);
if (dist < quake->m_TremorRadius) if (dist < quake->m_TremorRadius)
{ {
switch (selector) ++count;
if (quake->m_Flags & QF_RELATIVE)
{ {
default: relx = MAX(relx, quake->m_IntensityX);
case 0: rely = MAX(rely, quake->m_IntensityY);
quakeIntensity = quake->m_iX; relz = MAX(relz, quake->m_IntensityZ);
break; }
case 1: else
quakeIntensity = quake->m_iY; {
break; x = MAX(x, quake->m_IntensityX);
case 2: y = MAX(y, quake->m_IntensityY);
quakeIntensity = quake->m_iZ; z = MAX(z, quake->m_IntensityZ);
break;
} }
if (intensity < quakeIntensity)
intensity = quakeIntensity;
} }
} }
} }
return intensity; return count;
} }
//==========================================================================
//
// DEarthquake::StaticGetQuakeIntensity
//
// Searches for all quakes near the victim and returns their combined
// intensity.
//
//==========================================================================
int DEarthquake::StaticGetQuakeFlags(AActor *victim)
{
int flags = 0;
TThinkerIterator<DEarthquake> iterator(STAT_EARTHQUAKE);
DEarthquake *quake;
if (victim->player != NULL && (victim->player->cheats & CF_NOCLIP))
{
return 0;
}
while ((quake = iterator.Next()) != NULL)
{
if (quake->m_Spot != NULL)
{
fixed_t dist = P_AproxDistance(victim->x - quake->m_Spot->x,
victim->y - quake->m_Spot->y);
if (dist < quake->m_TremorRadius)
{
if (!(flags & QF_RELATIVE) && (quake->m_Flags & QF_RELATIVE))
flags += QF_RELATIVE;
}
}
}
return flags;
}
//========================================================================== //==========================================================================
// //
// P_StartQuake // P_StartQuake

View file

@ -147,15 +147,12 @@ public:
void Tick (); void Tick ();
TObjPtr<AActor> m_Spot; TObjPtr<AActor> m_Spot;
fixed_t m_TremorRadius, m_DamageRadius; fixed_t m_TremorRadius, m_DamageRadius;
int m_Intensity;
int m_Countdown; int m_Countdown;
FSoundID m_QuakeSFX; FSoundID m_QuakeSFX;
int m_Flags; int m_Flags;
int m_iX, m_iY, m_iZ; int m_IntensityX, m_IntensityY, m_IntensityZ;
static int StaticGetQuakeFlags(AActor *viewer); static int StaticGetQuakeIntensities(AActor *viewer, int &x, int &y, int &z, int &relx, int &rely, int &relz);
static int StaticGetQuakeIntensity (AActor *viewer, int selector);
private: private:
DEarthquake (); DEarthquake ();

View file

@ -764,6 +764,23 @@ bool R_GetViewInterpolationStatus()
return NoInterpolateView; 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,37 +892,41 @@ void R_SetupFrame (AActor *actor)
if (!paused) if (!paused)
{ {
int intensityX = DEarthquake::StaticGetQuakeIntensity(camera, 0); int intensityX, intensityY, intensityZ, relIntensityX, relIntensityY, relIntensityZ;
int intensityY = DEarthquake::StaticGetQuakeIntensity(camera, 1); if (DEarthquake::StaticGetQuakeIntensities(camera,
int intensityZ = DEarthquake::StaticGetQuakeIntensity(camera, 2); intensityX, intensityY, intensityZ,
int quakeflags = DEarthquake::StaticGetQuakeFlags(camera); relIntensityX, relIntensityY, relIntensityZ) > 0)
if (intensityX || intensityY || intensityZ)
{ {
fixed_t quakefactor = FLOAT2FIXED(r_quakeintensity); fixed_t quakefactor = FLOAT2FIXED(r_quakeintensity);
if ((quakeflags & QF_RELATIVE) && (intensityX != intensityY)) if (relIntensityX != 0)
{ {
if (intensityX) int ang = (camera->angle) >> ANGLETOFINESHIFT;
{ fixed_t power = QuakePower(quakefactor, relIntensityX);
int ang = (camera->angle) >> ANGLETOFINESHIFT; viewx += FixedMul(finecosine[ang], power);
int tflicker = pr_torchflicker(); viewy += FixedMul(finesine[ang], power);
viewx += FixedMul(finecosine[ang], (quakefactor * ((tflicker % (intensityX << 2)) - (intensityX << 1))));
viewy += FixedMul(finesine[ang], (quakefactor * ((tflicker % (intensityX << 2)) - (intensityX << 1))));
}
if (intensityY)
{
int ang = (camera->angle + ANG90) >> ANGLETOFINESHIFT;
int tflicker = pr_torchflicker();
viewx += FixedMul(finecosine[ang], (quakefactor * ((tflicker % (intensityY << 2)) - (intensityY << 1))));
viewy += FixedMul(finesine[ang], (quakefactor * ((tflicker % (intensityY << 2)) - (intensityY << 1))));
}
} }
else if (relIntensityY != 0)
{ {
if (intensityX) viewx += quakefactor * ((pr_torchflicker() % (intensityX << 2)) - (intensityX << 1)); int ang = (camera->angle + ANG90) >> ANGLETOFINESHIFT;
if (intensityY) viewy += quakefactor * ((pr_torchflicker() % (intensityY << 2)) - (intensityY << 1)); 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);
} }
if (intensityZ) viewz += quakefactor * ((pr_torchflicker() % (intensityZ << 2)) - (intensityZ << 1));
} }
} }

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the // Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got. // SVN revision ever got.
#define SAVEVER 4518 #define SAVEVER 4519
#define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)