shithub: hexen

ref: 21f6a1501d32f541673f8226d4b2292aef920c2b
dir: /sn_sonix.c/

View raw version

//**************************************************************************
//**
//** sn_sonix.c : Heretic 2 : Raven Software, Corp.
//**
//** $Revision: 373 $
//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
//**
//**************************************************************************

// HEADER FILES ------------------------------------------------------------

#include "h2stdinc.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(const char *name);

// EXTERNAL DATA DECLARATIONS ----------------------------------------------

extern sfxinfo_t S_sfx[];

// PUBLIC DATA DEFINITIONS -------------------------------------------------

// PRIVATE DATA DEFINITIONS ------------------------------------------------

static struct
{
	const 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(const char *name)
{
	int i;

	for (i = 0; i < NUMSFX; i++)
	{
		if (!cistrcmp(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 = NULL; /* jim added initialiser */
	int *tempDataPtr   = NULL; /* jim added initialiser */

	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 (!cistrcmp(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, const 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;
}