hexen/Hexen Source/SN_SONIX.C

507 lines
12 KiB
C++
Raw Permalink Normal View History

2008-09-04 00:00:00 +00:00
//**************************************************************************
//**
//** sn_sonix.c : Heretic 2 : Raven Software, Corp.
//**
//** $RCSfile: sn_sonix.c,v $
//** $Revision: 1.17 $
//** $Date: 95/10/05 18:25:44 $
//** $Author: paul $
//**
//**************************************************************************
// HEADER FILES ------------------------------------------------------------
#include <string.h>
#include "h2def.h"
#include "soundst.h"
// MACROS ------------------------------------------------------------------
#define SS_MAX_SCRIPTS 64
#define SS_TEMPBUFFER_SIZE 1024
#define SS_SEQUENCE_NAME_LENGTH 32
#define SS_SCRIPT_NAME "SNDSEQ"
#define SS_STRING_PLAY "play"
#define SS_STRING_PLAYUNTILDONE "playuntildone"
#define SS_STRING_PLAYTIME "playtime"
#define SS_STRING_PLAYREPEAT "playrepeat"
#define SS_STRING_DELAY "delay"
#define SS_STRING_DELAYRAND "delayrand"
#define SS_STRING_VOLUME "volume"
#define SS_STRING_END "end"
#define SS_STRING_STOPSOUND "stopsound"
// TYPES -------------------------------------------------------------------
typedef enum
{
SS_CMD_NONE,
SS_CMD_PLAY,
SS_CMD_WAITUNTILDONE, // used by PLAYUNTILDONE
SS_CMD_PLAYTIME,
SS_CMD_PLAYREPEAT,
SS_CMD_DELAY,
SS_CMD_DELAYRAND,
SS_CMD_VOLUME,
SS_CMD_STOPSOUND,
SS_CMD_END
} sscmds_t;
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void VerifySequencePtr(int *base, int *ptr);
static int GetSoundOffset(char *name);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern sfxinfo_t S_sfx[];
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static struct
{
char name[SS_SEQUENCE_NAME_LENGTH];
int scriptNum;
int stopSound;
} SequenceTranslate[SEQ_NUMSEQ] =
{
{ "Platform", 0, 0 },
{ "Platform", 0, 0 }, // a 'heavy' platform is just a platform
{ "PlatformMetal", 0, 0 },
{ "Platform", 0, 0 }, // same with a 'creak' platform
{ "Silence", 0, 0 },
{ "Lava", 0, 0 },
{ "Water", 0, 0 },
{ "Ice", 0, 0 },
{ "Earth", 0, 0 },
{ "PlatformMetal2", 0, 0 },
{ "DoorNormal", 0, 0 },
{ "DoorHeavy", 0, 0 },
{ "DoorMetal", 0, 0 },
{ "DoorCreak", 0, 0 },
{ "Silence", 0, 0 },
{ "Lava", 0, 0 },
{ "Water", 0, 0},
{ "Ice", 0, 0 },
{ "Earth", 0, 0},
{ "DoorMetal2", 0, 0 },
{ "Wind", 0, 0 }
};
static int *SequenceData[SS_MAX_SCRIPTS];
int ActiveSequences;
seqnode_t *SequenceListHead;
// CODE --------------------------------------------------------------------
//==========================================================================
//
// VerifySequencePtr
//
// Verifies the integrity of the temporary ptr, and ensures that the ptr
// isn't exceeding the size of the temporary buffer
//==========================================================================
static void VerifySequencePtr(int *base, int *ptr)
{
if(ptr-base > SS_TEMPBUFFER_SIZE)
{
I_Error("VerifySequencePtr: tempPtr >= %d\n", SS_TEMPBUFFER_SIZE);
}
}
//==========================================================================
//
// GetSoundOffset
//
//==========================================================================
static int GetSoundOffset(char *name)
{
int i;
for(i = 0; i < NUMSFX; i++)
{
if(!strcasecmp(name, S_sfx[i].tagName))
{
return i;
}
}
SC_ScriptError("GetSoundOffset: Unknown sound name\n");
return 0;
}
//==========================================================================
//
// SN_InitSequenceScript
//
//==========================================================================
void SN_InitSequenceScript(void)
{
int i, j;
int inSequence;
int *tempDataStart;
int *tempDataPtr;
inSequence = -1;
ActiveSequences = 0;
for(i = 0; i < SS_MAX_SCRIPTS; i++)
{
SequenceData[i] = NULL;
}
SC_Open(SS_SCRIPT_NAME);
while(SC_GetString())
{
if(*sc_String == ':')
{
if(inSequence != -1)
{
SC_ScriptError("SN_InitSequenceScript: Nested Script Error");
}
tempDataStart = (int *)Z_Malloc(SS_TEMPBUFFER_SIZE,
PU_STATIC, NULL);
memset(tempDataStart, 0, SS_TEMPBUFFER_SIZE);
tempDataPtr = tempDataStart;
for(i = 0; i < SS_MAX_SCRIPTS; i++)
{
if(SequenceData[i] == NULL)
{
break;
}
}
if(i == SS_MAX_SCRIPTS)
{
I_Error("Number of SS Scripts >= SS_MAX_SCRIPTS");
}
for(j = 0; j < SEQ_NUMSEQ; j++)
{
if(!strcasecmp(SequenceTranslate[j].name, sc_String+1))
{
SequenceTranslate[j].scriptNum = i;
inSequence = j;
break;
}
}
continue; // parse the next command
}
if(inSequence == -1)
{
continue;
}
if(SC_Compare(SS_STRING_PLAYUNTILDONE))
{
VerifySequencePtr(tempDataStart, tempDataPtr);
SC_MustGetString();
*tempDataPtr++ = SS_CMD_PLAY;
*tempDataPtr++ = GetSoundOffset(sc_String);
*tempDataPtr++ = SS_CMD_WAITUNTILDONE;
}
else if(SC_Compare(SS_STRING_PLAY))
{
VerifySequencePtr(tempDataStart, tempDataPtr);
SC_MustGetString();
*tempDataPtr++ = SS_CMD_PLAY;
*tempDataPtr++ = GetSoundOffset(sc_String);
}
else if(SC_Compare(SS_STRING_PLAYTIME))
{
VerifySequencePtr(tempDataStart, tempDataPtr);
SC_MustGetString();
*tempDataPtr++ = SS_CMD_PLAY;
*tempDataPtr++ = GetSoundOffset(sc_String);
SC_MustGetNumber();
*tempDataPtr++ = SS_CMD_DELAY;
*tempDataPtr++ = sc_Number;
}
else if(SC_Compare(SS_STRING_PLAYREPEAT))
{
VerifySequencePtr(tempDataStart, tempDataPtr);
SC_MustGetString();
*tempDataPtr++ = SS_CMD_PLAYREPEAT;
*tempDataPtr++ = GetSoundOffset(sc_String);
}
else if(SC_Compare(SS_STRING_DELAY))
{
VerifySequencePtr(tempDataStart, tempDataPtr);
*tempDataPtr++ = SS_CMD_DELAY;
SC_MustGetNumber();
*tempDataPtr++ = sc_Number;
}
else if(SC_Compare(SS_STRING_DELAYRAND))
{
VerifySequencePtr(tempDataStart, tempDataPtr);
*tempDataPtr++ = SS_CMD_DELAYRAND;
SC_MustGetNumber();
*tempDataPtr++ = sc_Number;
SC_MustGetNumber();
*tempDataPtr++ = sc_Number;
}
else if(SC_Compare(SS_STRING_VOLUME))
{
VerifySequencePtr(tempDataStart, tempDataPtr);
*tempDataPtr++ = SS_CMD_VOLUME;
SC_MustGetNumber();
*tempDataPtr++ = sc_Number;
}
else if(SC_Compare(SS_STRING_END))
{
int dataSize;
*tempDataPtr++ = SS_CMD_END;
dataSize = (tempDataPtr-tempDataStart)*sizeof(int);
SequenceData[i] = (int *)Z_Malloc(dataSize, PU_STATIC,
NULL);
memcpy(SequenceData[i], tempDataStart, dataSize);
Z_Free(tempDataStart);
inSequence = -1;
}
else if(SC_Compare(SS_STRING_STOPSOUND))
{
SC_MustGetString();
SequenceTranslate[inSequence].stopSound =
GetSoundOffset(sc_String);
*tempDataPtr++ = SS_CMD_STOPSOUND;
}
else
{
SC_ScriptError("SN_InitSequenceScript: Unknown commmand.\n");
}
}
}
//==========================================================================
//
// SN_StartSequence
//
//==========================================================================
void SN_StartSequence(mobj_t *mobj, int sequence)
{
seqnode_t *node;
SN_StopSequence(mobj); // Stop any previous sequence
node = (seqnode_t *)Z_Malloc(sizeof(seqnode_t), PU_STATIC, NULL);
node->sequencePtr = SequenceData[SequenceTranslate[sequence].scriptNum];
node->sequence = sequence;
node->mobj = mobj;
node->delayTics = 0;
node->stopSound = SequenceTranslate[sequence].stopSound;
node->volume = 127; // Start at max volume
if(!SequenceListHead)
{
SequenceListHead = node;
node->next = node->prev = NULL;
}
else
{
SequenceListHead->prev = node;
node->next = SequenceListHead;
node->prev = NULL;
SequenceListHead = node;
}
ActiveSequences++;
return;
}
//==========================================================================
//
// SN_StartSequenceName
//
//==========================================================================
void SN_StartSequenceName(mobj_t *mobj, char *name)
{
int i;
for(i = 0; i < SEQ_NUMSEQ; i++)
{
if(!strcmp(name, SequenceTranslate[i].name))
{
SN_StartSequence(mobj, i);
return;
}
}
}
//==========================================================================
//
// SN_StopSequence
//
//==========================================================================
void SN_StopSequence(mobj_t *mobj)
{
seqnode_t *node;
for(node = SequenceListHead; node; node = node->next)
{
if(node->mobj == mobj)
{
S_StopSound(mobj);
if(node->stopSound)
{
S_StartSoundAtVolume(mobj, node->stopSound, node->volume);
}
if(SequenceListHead == node)
{
SequenceListHead = node->next;
}
if(node->prev)
{
node->prev->next = node->next;
}
if(node->next)
{
node->next->prev = node->prev;
}
Z_Free(node);
ActiveSequences--;
}
}
}
//==========================================================================
//
// SN_UpdateActiveSequences
//
//==========================================================================
void SN_UpdateActiveSequences(void)
{
seqnode_t *node;
boolean sndPlaying;
if(!ActiveSequences || paused)
{ // No sequences currently playing/game is paused
return;
}
for(node = SequenceListHead; node; node = node->next)
{
if(node->delayTics)
{
node->delayTics--;
continue;
}
sndPlaying = S_GetSoundPlayingInfo(node->mobj, node->currentSoundID);
switch(*node->sequencePtr)
{
case SS_CMD_PLAY:
if(!sndPlaying)
{
node->currentSoundID = *(node->sequencePtr+1);
S_StartSoundAtVolume(node->mobj, node->currentSoundID,
node->volume);
}
node->sequencePtr += 2;
break;
case SS_CMD_WAITUNTILDONE:
if(!sndPlaying)
{
node->sequencePtr++;
node->currentSoundID = 0;
}
break;
case SS_CMD_PLAYREPEAT:
if(!sndPlaying)
{
node->currentSoundID = *(node->sequencePtr+1);
S_StartSoundAtVolume(node->mobj, node->currentSoundID,
node->volume);
}
break;
case SS_CMD_DELAY:
node->delayTics = *(node->sequencePtr+1);
node->sequencePtr += 2;
node->currentSoundID = 0;
break;
case SS_CMD_DELAYRAND:
node->delayTics = *(node->sequencePtr+1)+
M_Random()%(*(node->sequencePtr+2)-*(node->sequencePtr+1));
node->sequencePtr += 2;
node->currentSoundID = 0;
break;
case SS_CMD_VOLUME:
node->volume = (127*(*(node->sequencePtr+1)))/100;
node->sequencePtr += 2;
break;
case SS_CMD_STOPSOUND:
// Wait until something else stops the sequence
break;
case SS_CMD_END:
SN_StopSequence(node->mobj);
break;
default:
break;
}
}
}
//==========================================================================
//
// SN_StopAllSequences
//
//==========================================================================
void SN_StopAllSequences(void)
{
seqnode_t *node;
for(node = SequenceListHead; node; node = node->next)
{
node->stopSound = 0; // don't play any stop sounds
SN_StopSequence(node->mobj);
}
}
//==========================================================================
//
// SN_GetSequenceOffset
//
//==========================================================================
int SN_GetSequenceOffset(int sequence, int *sequencePtr)
{
return (sequencePtr-SequenceData[SequenceTranslate[sequence].scriptNum]);
}
//==========================================================================
//
// SN_ChangeNodeData
//
// nodeNum zero is the first node
//==========================================================================
void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume,
int currentSoundID)
{
int i;
seqnode_t *node;
i = 0;
node = SequenceListHead;
while(node && i < nodeNum)
{
node = node->next;
i++;
}
if(!node)
{ // reach the end of the list before finding the nodeNum-th node
return;
}
node->delayTics = delayTics;
node->volume = volume;
node->sequencePtr += seqOffset;
node->currentSoundID = currentSoundID;
}