Skip to content

Commit

Permalink
Refactor|libhexen: Moved LightningAnimator to new source files
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Aug 27, 2014
1 parent e4c7649 commit 37d15b9
Show file tree
Hide file tree
Showing 4 changed files with 306 additions and 228 deletions.
2 changes: 2 additions & 0 deletions doomsday/plugins/hexen/hexen.pro
Expand Up @@ -36,6 +36,7 @@ HEADERS += \
include/intermission.h \
include/info.h \
include/jhexen.h \
include/lightninganimator.h \
include/m_cheat.h \
include/m_random.h \
include/p_enemy.h \
Expand Down Expand Up @@ -77,6 +78,7 @@ SOURCES += \
src/hconsole.cpp \
src/hrefresh.cpp \
src/intermission.cpp \
src/lightninganimator.cpp \
src/m_cheat.cpp \
src/m_random.c \
src/p_enemy.c \
Expand Down
62 changes: 62 additions & 0 deletions doomsday/plugins/hexen/include/lightninganimator.h
@@ -0,0 +1,62 @@
/** @file lightninganimator.h Animator for map-wide lightning effects.
*
* @authors Copyright © 2004-2014 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2005-2014 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 1999 Activision
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

#ifndef LIBHEXEN_PLAY_LIGHTNINGANIMATOR_H
#define LIBHEXEN_PLAY_LIGHTNINGANIMATOR_H

#include "jhexen.h"

/**
* Animator for the map-wide lightning effects.
*/
class LightningAnimator
{
public:
LightningAnimator();

/**
* Determines whether lightning is enabled for the current map.
*/
bool enabled() const;

/**
* Manually trigger a lightning flash which will begin animating on the next game tic.
* Can be used to trigger a flash at specific times.
*/
void triggerFlash();

/**
* Animate lightning for the current map. To be called once per GAMETIC.
*/
void advanceTime();

/**
* Initialize the lightning animator for the current map.
*
* @return @c true, if lightning is enabled for the current map, for caller convenience.
*/
bool initForMap();

private:
DENG2_PRIVATE(d)
};

#endif // LIBHEXEN_PLAY_LIGHTNINGANIMATOR_H
241 changes: 241 additions & 0 deletions doomsday/plugins/hexen/src/lightninganimator.cpp
@@ -0,0 +1,241 @@
/** @file lightninganimator.cpp Animator for map-wide lightning effects.
*
* @authors Copyright © 2003-2014 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2005-2014 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 1999 Activision
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

#include "jhexen.h"
#include "lightninganimator.h"

#include "dmu_lib.h"
#include "gamesession.h"

using namespace de;

#define LIGHTNING_SPECIAL 198
#define LIGHTNING_SPECIAL2 199

static bool isLightningSector(Sector *sec)
{
xsector_t *xsec = P_ToXSector(sec);

if(xsec->special == LIGHTNING_SPECIAL || xsec->special == LIGHTNING_SPECIAL2)
return true;

if(P_GetIntp(P_GetPtrp(sec, DMU_CEILING_MATERIAL),
DMU_FLAGS) & MATF_SKYMASK)
return true;

if(P_GetIntp(P_GetPtrp(sec, DMU_FLOOR_MATERIAL),
DMU_FLAGS) & MATF_SKYMASK)
return true;

return false;
}

DENG2_PIMPL_NOREF(LightningAnimator)
{
int flash = 0;
int nextFlash = 0;
float *sectorLightLevels = 0; ///< Ambient light levels for each sector (if enabled).
};

LightningAnimator::LightningAnimator() : d(new Instance)
{}

bool LightningAnimator::enabled() const
{
return d->sectorLightLevels != 0;
}

void LightningAnimator::triggerFlash()
{
if(!enabled()) return;
d->nextFlash = 0;
}

void LightningAnimator::advanceTime()
{
if(!enabled()) return;

// Is it time for a lightning state change?
if(!(!d->nextFlash || d->flash))
{
d->nextFlash--;
return;
}

if(d->flash)
{
d->flash--;
float *tempLight = d->sectorLightLevels;

if(d->flash)
{
for(int i = 0; i < numsectors; ++i)
{
Sector *sec = (Sector *)P_ToPtr(DMU_SECTOR, i);
if(!isLightningSector(sec)) continue;

float lightLevel = P_GetFloat(DMU_SECTOR, i, DMU_LIGHT_LEVEL);
if(*tempLight < lightLevel - (4.f / 255))
{
P_SetFloat(DMU_SECTOR, i, DMU_LIGHT_LEVEL, lightLevel - (1.f / 255) * 4);
}
tempLight++;
}
}
else
{
// Remove the alternate lightning flash special.
for(int i = 0; i < numsectors; ++i)
{
Sector *sec = (Sector *)P_ToPtr(DMU_SECTOR, i);
if(!isLightningSector(sec)) continue;

P_SetFloatp(sec, DMU_LIGHT_LEVEL, *tempLight);
tempLight++;
}

if(!IS_DEDICATED)
{
R_SkyParams(1, DD_DISABLE, nullptr);
R_SkyParams(0, DD_ENABLE, nullptr);
}
}

return;
}

d->flash = (P_Random() & 7) + 8;

float const flashLight = (float) (200 + (P_Random() & 31)) / 255.0f;
float *tempLight = d->sectorLightLevels;
bool foundSec = false;
for(int i = 0; i < numsectors; ++i)
{
Sector *sec = (Sector *)P_ToPtr(DMU_SECTOR, i);
if(!isLightningSector(sec)) continue;

xsector_t *xsec = P_ToXSector(sec);
float newLevel = P_GetFloatp(sec, DMU_LIGHT_LEVEL);

*tempLight = newLevel;

if(xsec->special == LIGHTNING_SPECIAL)
{
newLevel += .25f;
if(newLevel > flashLight)
newLevel = flashLight;
}
else if(xsec->special == LIGHTNING_SPECIAL2)
{
newLevel += .125f;
if(newLevel > flashLight)
newLevel = flashLight;
}
else
{
newLevel = flashLight;
}

if(newLevel < *tempLight)
newLevel = *tempLight;

P_SetFloatp(sec, DMU_LIGHT_LEVEL, newLevel);
tempLight++;
foundSec = true;
}

if(foundSec)
{
mobj_t *plrmo = ::players[DISPLAYPLAYER].plr->mo;
mobj_t *clapSource = 0;

if(!IS_DEDICATED)
{
// Set the alternate (lightning) sky.
R_SkyParams(0, DD_DISABLE, nullptr);
R_SkyParams(1, DD_ENABLE, nullptr);
}

// If 3D sounds are active, position the clap somewhere above the player.
if(::cfg.snd3D && plrmo && !IS_NETGAME)
{
coord_t clapOrigin[] = {
plrmo->origin[VX] + (16 * (M_Random() - 127) << FRACBITS),
plrmo->origin[VY] + (16 * (M_Random() - 127) << FRACBITS),
plrmo->origin[VZ] + (4000 << FRACBITS)
};
clapSource = P_SpawnMobj(MT_CAMERA, clapOrigin, 0, 0);
if(clapSource)
{
clapSource->tics = 5 * TICSPERSEC; // Five seconds will do.
}
}

// Make it loud!
S_StartSound(SFX_THUNDER_CRASH | DDSF_NO_ATTENUATION, clapSource);
}

// Calculate the next lighting flash.
if(!d->nextFlash)
{
if(P_Random() < 50) // Immediate, quick flash.
{
d->nextFlash = (P_Random() & 15) + 16;
}
else if(P_Random() < 128 && !(mapTime & 32))
{
d->nextFlash = ((P_Random() & 7) + 2) * TICSPERSEC;
}
else
{
d->nextFlash = ((P_Random() & 15) + 5) * TICSPERSEC;
}
}
}

bool LightningAnimator::initForMap()
{
d->flash = 0;
d->nextFlash = 0;
Z_Free(d->sectorLightLevels); d->sectorLightLevels = 0;

Record const *mapInfo = COMMON_GAMESESSION->mapInfo();
if(mapInfo && !mapInfo->getb("lightning"))
{
int numLightningSectors = 0;
for(int i = 0; i < numsectors; ++i)
{
if(isLightningSector((Sector *)P_ToPtr(DMU_SECTOR, i)))
{
numLightningSectors++;
}
}
if(numLightningSectors > 0)
{
d->sectorLightLevels = (float *)Z_Malloc(numLightningSectors * sizeof(*d->sectorLightLevels), PU_MAP, nullptr);

// Don't flash immediately on entering the map.
d->nextFlash = ((P_Random() & 15) + 5) * TICSPERSEC;
}
}

return enabled();
}

0 comments on commit 37d15b9

Please sign in to comment.