507 lines
12 KiB
C++
507 lines
12 KiB
C++
|
|
||
|
//**************************************************************************
|
||
|
//**
|
||
|
//** 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;
|
||
|
}
|