ref: aa5529bc6cbd5424c33f624d8a33fc482d18c489
dir: /src/hexen/p_anim.c/
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2008 Simon Howard
//
// 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., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//-----------------------------------------------------------------------------
// HEADER FILES ------------------------------------------------------------
#include "h2def.h"
#include "m_random.h"
#include "i_system.h"
#include "p_local.h"
#include "s_sound.h"
// MACROS ------------------------------------------------------------------
#define ANIM_SCRIPT_NAME "ANIMDEFS"
#define MAX_ANIM_DEFS 20
#define MAX_FRAME_DEFS 96
#define ANIM_FLAT 0
#define ANIM_TEXTURE 1
#define SCI_FLAT "flat"
#define SCI_TEXTURE "texture"
#define SCI_PIC "pic"
#define SCI_TICS "tics"
#define SCI_RAND "rand"
#define LIGHTNING_SPECIAL 198
#define LIGHTNING_SPECIAL2 199
#define SKYCHANGE_SPECIAL 200
// TYPES -------------------------------------------------------------------
typedef struct
{
int index;
int tics;
} frameDef_t;
typedef struct
{
int type;
int index;
int tics;
int currentFrameDef;
int startFrameDef;
int endFrameDef;
} animDef_t;
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void P_LightningFlash(void);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern fixed_t Sky1ColumnOffset;
extern fixed_t Sky2ColumnOffset;
extern int Sky1Texture;
extern boolean DoubleSky;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
fixed_t Sky1ScrollDelta;
fixed_t Sky2ScrollDelta;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static animDef_t AnimDefs[MAX_ANIM_DEFS];
static frameDef_t FrameDefs[MAX_FRAME_DEFS];
static int AnimDefCount;
static boolean LevelHasLightning;
static int NextLightningFlash;
static int LightningFlash;
static int *LightningLightLevels;
// CODE --------------------------------------------------------------------
//==========================================================================
//
// P_AnimateSurfaces
//
//==========================================================================
void P_AnimateSurfaces(void)
{
int i;
animDef_t *ad;
line_t *line;
// Animate flats and textures
for (i = 0; i < AnimDefCount; i++)
{
ad = &AnimDefs[i];
ad->tics--;
if (ad->tics == 0)
{
if (ad->currentFrameDef == ad->endFrameDef)
{
ad->currentFrameDef = ad->startFrameDef;
}
else
{
ad->currentFrameDef++;
}
ad->tics = FrameDefs[ad->currentFrameDef].tics;
if (ad->tics > 255)
{ // Random tics
ad->tics = (ad->tics >> 16)
+ P_Random() % ((ad->tics & 0xff00) >> 8);
}
if (ad->type == ANIM_FLAT)
{
flattranslation[ad->index] =
FrameDefs[ad->currentFrameDef].index;
}
else
{ // Texture
texturetranslation[ad->index] =
FrameDefs[ad->currentFrameDef].index;
}
}
}
// Update scrolling textures
for (i = 0; i < numlinespecials; i++)
{
line = linespeciallist[i];
switch (line->special)
{
case 100: // Scroll_Texture_Left
sides[line->sidenum[0]].textureoffset += line->arg1 << 10;
break;
case 101: // Scroll_Texture_Right
sides[line->sidenum[0]].textureoffset -= line->arg1 << 10;
break;
case 102: // Scroll_Texture_Up
sides[line->sidenum[0]].rowoffset += line->arg1 << 10;
break;
case 103: // Scroll_Texture_Down
sides[line->sidenum[0]].rowoffset -= line->arg1 << 10;
break;
}
}
// Update sky column offsets
Sky1ColumnOffset += Sky1ScrollDelta;
Sky2ColumnOffset += Sky2ScrollDelta;
if (LevelHasLightning)
{
if (!NextLightningFlash || LightningFlash)
{
P_LightningFlash();
}
else
{
NextLightningFlash--;
}
}
}
//==========================================================================
//
// P_LightningFlash
//
//==========================================================================
static void P_LightningFlash(void)
{
int i;
sector_t *tempSec;
int *tempLight;
boolean foundSec;
int flashLight;
if (LightningFlash)
{
LightningFlash--;
if (LightningFlash)
{
tempLight = LightningLightLevels;
tempSec = sectors;
for (i = 0; i < numsectors; i++, tempSec++)
{
if (tempSec->ceilingpic == skyflatnum
|| tempSec->special == LIGHTNING_SPECIAL
|| tempSec->special == LIGHTNING_SPECIAL2)
{
if (*tempLight < tempSec->lightlevel - 4)
{
tempSec->lightlevel -= 4;
}
tempLight++;
}
}
}
else
{ // remove the alternate lightning flash special
tempLight = LightningLightLevels;
tempSec = sectors;
for (i = 0; i < numsectors; i++, tempSec++)
{
if (tempSec->ceilingpic == skyflatnum
|| tempSec->special == LIGHTNING_SPECIAL
|| tempSec->special == LIGHTNING_SPECIAL2)
{
tempSec->lightlevel = *tempLight;
tempLight++;
}
}
Sky1Texture = P_GetMapSky1Texture(gamemap);
}
return;
}
LightningFlash = (P_Random() & 7) + 8;
flashLight = 200 + (P_Random() & 31);
tempSec = sectors;
tempLight = LightningLightLevels;
foundSec = false;
for (i = 0; i < numsectors; i++, tempSec++)
{
if (tempSec->ceilingpic == skyflatnum
|| tempSec->special == LIGHTNING_SPECIAL
|| tempSec->special == LIGHTNING_SPECIAL2)
{
*tempLight = tempSec->lightlevel;
if (tempSec->special == LIGHTNING_SPECIAL)
{
tempSec->lightlevel += 64;
if (tempSec->lightlevel > flashLight)
{
tempSec->lightlevel = flashLight;
}
}
else if (tempSec->special == LIGHTNING_SPECIAL2)
{
tempSec->lightlevel += 32;
if (tempSec->lightlevel > flashLight)
{
tempSec->lightlevel = flashLight;
}
}
else
{
tempSec->lightlevel = flashLight;
}
if (tempSec->lightlevel < *tempLight)
{
tempSec->lightlevel = *tempLight;
}
tempLight++;
foundSec = true;
}
}
if (foundSec)
{
Sky1Texture = P_GetMapSky2Texture(gamemap); // set alternate sky
S_StartSound(NULL, SFX_THUNDER_CRASH);
}
// Calculate the next lighting flash
if (!NextLightningFlash)
{
if (P_Random() < 50)
{ // Immediate Quick flash
NextLightningFlash = (P_Random() & 15) + 16;
}
else
{
if (P_Random() < 128 && !(leveltime & 32))
{
NextLightningFlash = ((P_Random() & 7) + 2) * 35;
}
else
{
NextLightningFlash = ((P_Random() & 15) + 5) * 35;
}
}
}
}
//==========================================================================
//
// P_ForceLightning
//
//==========================================================================
void P_ForceLightning(void)
{
NextLightningFlash = 0;
}
//==========================================================================
//
// P_InitLightning
//
//==========================================================================
void P_InitLightning(void)
{
int i;
int secCount;
if (!P_GetMapLightning(gamemap))
{
LevelHasLightning = false;
LightningFlash = 0;
return;
}
LightningFlash = 0;
secCount = 0;
for (i = 0; i < numsectors; i++)
{
if (sectors[i].ceilingpic == skyflatnum
|| sectors[i].special == LIGHTNING_SPECIAL
|| sectors[i].special == LIGHTNING_SPECIAL2)
{
secCount++;
}
}
if (secCount)
{
LevelHasLightning = true;
}
else
{
LevelHasLightning = false;
return;
}
LightningLightLevels = (int *) Z_Malloc(secCount * sizeof(int), PU_LEVEL,
NULL);
NextLightningFlash = ((P_Random() & 15) + 5) * 35; // don't flash at level start
}
//==========================================================================
//
// P_InitFTAnims
//
// Initialize flat and texture animation lists.
//
//==========================================================================
void P_InitFTAnims(void)
{
int base;
int mod;
int fd;
animDef_t *ad;
boolean ignore;
boolean done;
fd = 0;
ad = AnimDefs;
AnimDefCount = 0;
SC_Open(ANIM_SCRIPT_NAME);
while (SC_GetString())
{
if (AnimDefCount == MAX_ANIM_DEFS)
{
I_Error("P_InitFTAnims: too many AnimDefs.");
}
if (SC_Compare(SCI_FLAT))
{
ad->type = ANIM_FLAT;
}
else if (SC_Compare(SCI_TEXTURE))
{
ad->type = ANIM_TEXTURE;
}
else
{
SC_ScriptError(NULL);
}
SC_MustGetString(); // Name
ignore = false;
if (ad->type == ANIM_FLAT)
{
if (W_CheckNumForName(sc_String) == -1)
{
ignore = true;
}
else
{
ad->index = R_FlatNumForName(sc_String);
}
}
else
{ // Texture
if (R_CheckTextureNumForName(sc_String) == -1)
{
ignore = true;
}
else
{
ad->index = R_TextureNumForName(sc_String);
}
}
ad->startFrameDef = fd;
done = false;
while (done == false)
{
if (SC_GetString())
{
if (SC_Compare(SCI_PIC))
{
if (fd == MAX_FRAME_DEFS)
{
I_Error("P_InitFTAnims: too many FrameDefs.");
}
SC_MustGetNumber();
if (ignore == false)
{
FrameDefs[fd].index = ad->index + sc_Number - 1;
}
SC_MustGetString();
if (SC_Compare(SCI_TICS))
{
SC_MustGetNumber();
if (ignore == false)
{
FrameDefs[fd].tics = sc_Number;
fd++;
}
}
else if (SC_Compare(SCI_RAND))
{
SC_MustGetNumber();
base = sc_Number;
SC_MustGetNumber();
if (ignore == false)
{
mod = sc_Number - base + 1;
FrameDefs[fd].tics = (base << 16) + (mod << 8);
fd++;
}
}
else
{
SC_ScriptError(NULL);
}
}
else
{
SC_UnGet();
done = true;
}
}
else
{
done = true;
}
}
if ((ignore == false) && (fd - ad->startFrameDef < 2))
{
I_Error("P_InitFTAnims: AnimDef has framecount < 2.");
}
if (ignore == false)
{
ad->endFrameDef = fd - 1;
ad->currentFrameDef = ad->endFrameDef;
ad->tics = 1; // Force 1st game tic to animate
AnimDefCount++;
ad++;
}
}
SC_Close();
}