mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-07 13:30:16 +00:00
8ca5f3821d
in DEarthQuake::StaticGetQuakeIntensity. The reason for this: Quakes were never supposed to be additive. Many maps, including Hexen's own have placed quake spots so that they cover a larger area but the areas covered by the single spots overlap. On such maps the view will shake like crazy and render the map nearly unplayable. SVN r480 (trunk)
182 lines
4.4 KiB
C++
182 lines
4.4 KiB
C++
#include "templates.h"
|
|
#include "doomtype.h"
|
|
#include "doomstat.h"
|
|
#include "p_local.h"
|
|
#include "actor.h"
|
|
#include "m_bbox.h"
|
|
#include "m_random.h"
|
|
#include "s_sound.h"
|
|
#include "a_sharedglobal.h"
|
|
#include "statnums.h"
|
|
|
|
static FRandom pr_quake ("Quake");
|
|
|
|
IMPLEMENT_POINTY_CLASS (DEarthquake)
|
|
DECLARE_POINTER (m_Spot)
|
|
END_POINTERS
|
|
|
|
//==========================================================================
|
|
//
|
|
// DEarthquake :: DEarthquake private constructor
|
|
//
|
|
//==========================================================================
|
|
|
|
DEarthquake::DEarthquake()
|
|
: DThinker(STAT_EARTHQUAKE)
|
|
{
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DEarthquake :: DEarthquake public constructor
|
|
//
|
|
//==========================================================================
|
|
|
|
DEarthquake::DEarthquake (AActor *center, int intensity, int duration,
|
|
int damrad, int tremrad)
|
|
: DThinker(STAT_EARTHQUAKE)
|
|
{
|
|
m_QuakeSFX = S_FindSound ("world/quake");
|
|
m_Spot = center;
|
|
// Radii are specified in tile units (64 pixels)
|
|
m_DamageRadius = damrad << (FRACBITS+6);
|
|
m_TremorRadius = tremrad << (FRACBITS+6);
|
|
m_Intensity = intensity;
|
|
m_Countdown = duration;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DEarthquake :: Serialize
|
|
//
|
|
//==========================================================================
|
|
|
|
void DEarthquake::Serialize (FArchive &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
arc << m_Spot << m_Intensity << m_Countdown
|
|
<< m_TremorRadius << m_DamageRadius;
|
|
m_QuakeSFX = S_FindSound ("world/quake");
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DEarthquake :: Tick
|
|
//
|
|
// Deals damage to any players near the earthquake and makes sure it's
|
|
// making noise.
|
|
//
|
|
//==========================================================================
|
|
|
|
void DEarthquake::Tick ()
|
|
{
|
|
int i;
|
|
|
|
if (m_Spot == NULL)
|
|
{
|
|
Destroy ();
|
|
return;
|
|
}
|
|
|
|
if (!S_IsActorPlayingSomething (m_Spot, CHAN_BODY, m_QuakeSFX))
|
|
S_SoundID (m_Spot, CHAN_BODY, m_QuakeSFX, 1, ATTN_NORM);
|
|
|
|
if (m_DamageRadius > 0)
|
|
{
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
if (playeringame[i] && !(players[i].cheats & CF_NOCLIP))
|
|
{
|
|
AActor *victim = players[i].mo;
|
|
fixed_t dist;
|
|
|
|
dist = P_AproxDistance (victim->x - m_Spot->x, victim->y - m_Spot->y);
|
|
// Check if in damage radius
|
|
if (dist < m_DamageRadius && victim->z <= victim->floorz)
|
|
{
|
|
if (pr_quake() < 50)
|
|
{
|
|
P_DamageMobj (victim, NULL, NULL, pr_quake.HitDice (1), NAME_None);
|
|
}
|
|
// Thrust player around
|
|
angle_t an = victim->angle + ANGLE_1*pr_quake();
|
|
P_ThrustMobj (victim, an, m_Intensity << (FRACBITS-1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (--m_Countdown == 0)
|
|
{
|
|
Destroy ();
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// DEarthquake::StaticGetQuakeIntensity
|
|
//
|
|
// Searches for all quakes near the victim and returns their combined
|
|
// intensity.
|
|
//
|
|
//==========================================================================
|
|
|
|
int DEarthquake::StaticGetQuakeIntensity (AActor *victim)
|
|
{
|
|
int intensity = 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 (intensity < quake->m_Intensity)
|
|
intensity = quake->m_Intensity;
|
|
}
|
|
}
|
|
}
|
|
return intensity;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_StartQuake
|
|
//
|
|
//==========================================================================
|
|
|
|
bool P_StartQuake (AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad)
|
|
{
|
|
AActor *center;
|
|
bool res = false;
|
|
|
|
intensity = clamp (intensity, 1, 9);
|
|
|
|
if (tid == 0)
|
|
{
|
|
if (activator != NULL)
|
|
{
|
|
new DEarthquake(activator, intensity, duration, damrad, tremrad);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FActorIterator iterator (tid);
|
|
while ( (center = iterator.Next ()) )
|
|
{
|
|
res = true;
|
|
new DEarthquake (center, intensity, duration, damrad, tremrad);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|