vkdoom_m/src/g_shared/a_lightning.cpp
Christoph Oelckers eab06ef086 - more Build cleanup: Moved clearbufshort out of Build derived headers, removed the inline version for GCC 32 bit which was actually Build derived and renamed the C-version of this function, which does not originate from Build to 'fillshort'.
- cleaned out a lot the SafeDivScale stuff in m_fixed.h. The only SafeDivScale variant still in use was #16 for FixedDiv, so all the SafeDivScale stuff has been removed and the 16 variant renamed to FixedDiv because that's the only form in which it is still being used. (2x in R_DrawVoxel and 1x in ACS's FixedDiv PCode.)
- removed Build notice from m_fixed.h because aside from the inlines includes there is nothing here from Build anymore.
2016-12-09 13:04:53 +01:00

197 lines
4.4 KiB
C++

#include "a_lightning.h"
#include "doomstat.h"
#include "p_lnspec.h"
#include "statnums.h"
#include "m_random.h"
#include "templates.h"
#include "s_sound.h"
#include "p_acs.h"
#include "r_sky.h"
#include "g_level.h"
#include "r_state.h"
#include "serializer.h"
static FRandom pr_lightning ("Lightning");
IMPLEMENT_CLASS(DLightningThinker, false, false)
DLightningThinker::DLightningThinker ()
: DThinker (STAT_LIGHTNING)
{
Stopped = false;
LightningFlashCount = 0;
NextLightningFlash = ((pr_lightning()&15)+5)*35; // don't flash at level start
LightningLightLevels.Resize(numsectors);
fillshort(&LightningLightLevels[0], numsectors, SHRT_MAX);
}
DLightningThinker::~DLightningThinker ()
{
}
void DLightningThinker::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("stopped", Stopped)
("next", NextLightningFlash)
("count", LightningFlashCount)
("levels", LightningLightLevels);
}
void DLightningThinker::Tick ()
{
if (!NextLightningFlash || LightningFlashCount)
{
LightningFlash();
}
else
{
--NextLightningFlash;
if (Stopped) Destroy();
}
}
void DLightningThinker::LightningFlash ()
{
int i, j;
sector_t *tempSec;
BYTE flashLight;
if (LightningFlashCount)
{
LightningFlashCount--;
if (LightningFlashCount)
{ // reduce the brightness of the flash
tempSec = sectors;
for (i = numsectors, j = 0; i > 0; ++j, --i, ++tempSec)
{
// [RH] Checking this sector's applicability to lightning now
// is not enough to know if we should lower its light level,
// because it might have changed since the lightning flashed.
// Instead, change the light if this sector was effected by
// the last flash.
if (LightningLightLevels[j] < tempSec->lightlevel-4)
{
tempSec->ChangeLightLevel(-4);
}
}
}
else
{ // remove the alternate lightning flash special
tempSec = sectors;
for (i = numsectors, j = 0; i > 0; ++j, --i, ++tempSec)
{
if (LightningLightLevels[j] != SHRT_MAX)
{
tempSec->SetLightLevel(LightningLightLevels[j]);
}
}
fillshort(&LightningLightLevels[0], numsectors, SHRT_MAX);
level.flags &= ~LEVEL_SWAPSKIES;
}
return;
}
LightningFlashCount = (pr_lightning()&7)+8;
flashLight = 200+(pr_lightning()&31);
tempSec = sectors;
for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec)
{
// allow combination of the lightning sector specials with bit masks
int special = tempSec->special;
if (tempSec->GetTexture(sector_t::ceiling) == skyflatnum
|| special == Light_IndoorLightning1
|| special == Light_IndoorLightning2
|| special == Light_OutdoorLightning)
{
LightningLightLevels[j] = tempSec->lightlevel;
if (special == Light_IndoorLightning1)
{
tempSec->SetLightLevel(MIN<int> (tempSec->lightlevel+64, flashLight));
}
else if (special == Light_IndoorLightning2)
{
tempSec->SetLightLevel(MIN<int> (tempSec->lightlevel+32, flashLight));
}
else
{
tempSec->SetLightLevel(flashLight);
}
if (tempSec->lightlevel < LightningLightLevels[j])
{ // The lightning is darker than this sector already is, so no lightning here.
tempSec->SetLightLevel(LightningLightLevels[j]);
LightningLightLevels[j] = SHRT_MAX;
}
}
}
level.flags |= LEVEL_SWAPSKIES; // set alternate sky
S_Sound (CHAN_AUTO, "world/thunder", 1.0, ATTN_NONE);
FBehavior::StaticStartTypedScripts (SCRIPT_Lightning, NULL, false); // [RH] Run lightning scripts
// Calculate the next lighting flash
if (!NextLightningFlash)
{
if (pr_lightning() < 50)
{ // Immediate Quick flash
NextLightningFlash = (pr_lightning()&15)+16;
}
else
{
if (pr_lightning() < 128 && !(level.time&32))
{
NextLightningFlash = ((pr_lightning()&7)+2)*35;
}
else
{
NextLightningFlash = ((pr_lightning()&15)+5)*35;
}
}
}
}
void DLightningThinker::ForceLightning (int mode)
{
switch (mode)
{
default:
NextLightningFlash = 0;
break;
case 1:
NextLightningFlash = 0;
// Fall through
case 2:
Stopped = true;
break;
}
}
static DLightningThinker *LocateLightning ()
{
TThinkerIterator<DLightningThinker> iterator (STAT_LIGHTNING);
return iterator.Next ();
}
void P_StartLightning ()
{
DLightningThinker *lightning = LocateLightning ();
if (lightning == NULL)
{
new DLightningThinker ();
}
}
void P_ForceLightning (int mode)
{
DLightningThinker *lightning = LocateLightning ();
if (lightning == NULL)
{
lightning = new DLightningThinker ();
}
if (lightning != NULL)
{
lightning->ForceLightning (mode);
}
}