2 //**************************************************************************
4 //** sn_sonix.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
13 // HEADER FILES ------------------------------------------------------------
19 // MACROS ------------------------------------------------------------------
21 #define SS_MAX_SCRIPTS 64
22 #define SS_TEMPBUFFER_SIZE 1024
23 #define SS_SEQUENCE_NAME_LENGTH 32
25 #define SS_SCRIPT_NAME "SNDSEQ"
26 #define SS_STRING_PLAY "play"
27 #define SS_STRING_PLAYUNTILDONE "playuntildone"
28 #define SS_STRING_PLAYTIME "playtime"
29 #define SS_STRING_PLAYREPEAT "playrepeat"
30 #define SS_STRING_DELAY "delay"
31 #define SS_STRING_DELAYRAND "delayrand"
32 #define SS_STRING_VOLUME "volume"
33 #define SS_STRING_END "end"
34 #define SS_STRING_STOPSOUND "stopsound"
36 // TYPES -------------------------------------------------------------------
42 SS_CMD_WAITUNTILDONE, // used by PLAYUNTILDONE
52 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
54 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
56 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
58 static void VerifySequencePtr(int *base, int *ptr);
59 static int GetSoundOffset(char *name);
61 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
63 extern sfxinfo_t S_sfx[];
65 // PUBLIC DATA DEFINITIONS -------------------------------------------------
67 // PRIVATE DATA DEFINITIONS ------------------------------------------------
71 char name[SS_SEQUENCE_NAME_LENGTH];
74 } SequenceTranslate[SEQ_NUMSEQ] =
77 { "Platform", 0, 0 }, // a 'heavy' platform is just a platform
78 { "PlatformMetal", 0, 0 },
79 { "Platform", 0, 0 }, // same with a 'creak' platform
85 { "PlatformMetal2", 0, 0 },
86 { "DoorNormal", 0, 0 },
87 { "DoorHeavy", 0, 0 },
88 { "DoorMetal", 0, 0 },
89 { "DoorCreak", 0, 0 },
95 { "DoorMetal2", 0, 0 },
99 static int *SequenceData[SS_MAX_SCRIPTS];
102 seqnode_t *SequenceListHead;
104 // CODE --------------------------------------------------------------------
106 //==========================================================================
110 // Verifies the integrity of the temporary ptr, and ensures that the ptr
111 // isn't exceeding the size of the temporary buffer
112 //==========================================================================
114 static void VerifySequencePtr(int *base, int *ptr)
116 if(ptr-base > SS_TEMPBUFFER_SIZE)
118 I_Error("VerifySequencePtr: tempPtr >= %d\n", SS_TEMPBUFFER_SIZE);
122 //==========================================================================
126 //==========================================================================
128 static int GetSoundOffset(char *name)
132 for(i = 0; i < NUMSFX; i++)
134 if(!strcasecmp(name, S_sfx[i].tagName))
139 SC_ScriptError("GetSoundOffset: Unknown sound name\n");
143 //==========================================================================
145 // SN_InitSequenceScript
147 //==========================================================================
149 void SN_InitSequenceScript(void)
153 int *tempDataStart = NULL; /* jim added initialiser */
154 int *tempDataPtr = NULL; /* jim added initialiser */
158 for(i = 0; i < SS_MAX_SCRIPTS; i++)
160 SequenceData[i] = NULL;
162 SC_Open(SS_SCRIPT_NAME);
163 while(SC_GetString())
165 if(*sc_String == ':')
169 SC_ScriptError("SN_InitSequenceScript: Nested Script Error");
171 tempDataStart = (int *)Z_Malloc(SS_TEMPBUFFER_SIZE,
173 memset(tempDataStart, 0, SS_TEMPBUFFER_SIZE);
174 tempDataPtr = tempDataStart;
175 for(i = 0; i < SS_MAX_SCRIPTS; i++)
177 if(SequenceData[i] == NULL)
182 if(i == SS_MAX_SCRIPTS)
184 I_Error("Number of SS Scripts >= SS_MAX_SCRIPTS");
186 for(j = 0; j < SEQ_NUMSEQ; j++)
188 if(!strcasecmp(SequenceTranslate[j].name, sc_String+1))
190 SequenceTranslate[j].scriptNum = i;
195 continue; // parse the next command
201 if(SC_Compare(SS_STRING_PLAYUNTILDONE))
203 VerifySequencePtr(tempDataStart, tempDataPtr);
205 *tempDataPtr++ = SS_CMD_PLAY;
206 *tempDataPtr++ = GetSoundOffset(sc_String);
207 *tempDataPtr++ = SS_CMD_WAITUNTILDONE;
209 else if(SC_Compare(SS_STRING_PLAY))
211 VerifySequencePtr(tempDataStart, tempDataPtr);
213 *tempDataPtr++ = SS_CMD_PLAY;
214 *tempDataPtr++ = GetSoundOffset(sc_String);
216 else if(SC_Compare(SS_STRING_PLAYTIME))
218 VerifySequencePtr(tempDataStart, tempDataPtr);
220 *tempDataPtr++ = SS_CMD_PLAY;
221 *tempDataPtr++ = GetSoundOffset(sc_String);
223 *tempDataPtr++ = SS_CMD_DELAY;
224 *tempDataPtr++ = sc_Number;
226 else if(SC_Compare(SS_STRING_PLAYREPEAT))
228 VerifySequencePtr(tempDataStart, tempDataPtr);
230 *tempDataPtr++ = SS_CMD_PLAYREPEAT;
231 *tempDataPtr++ = GetSoundOffset(sc_String);
233 else if(SC_Compare(SS_STRING_DELAY))
235 VerifySequencePtr(tempDataStart, tempDataPtr);
236 *tempDataPtr++ = SS_CMD_DELAY;
238 *tempDataPtr++ = sc_Number;
240 else if(SC_Compare(SS_STRING_DELAYRAND))
242 VerifySequencePtr(tempDataStart, tempDataPtr);
243 *tempDataPtr++ = SS_CMD_DELAYRAND;
245 *tempDataPtr++ = sc_Number;
247 *tempDataPtr++ = sc_Number;
249 else if(SC_Compare(SS_STRING_VOLUME))
251 VerifySequencePtr(tempDataStart, tempDataPtr);
252 *tempDataPtr++ = SS_CMD_VOLUME;
254 *tempDataPtr++ = sc_Number;
256 else if(SC_Compare(SS_STRING_END))
260 *tempDataPtr++ = SS_CMD_END;
261 dataSize = (tempDataPtr-tempDataStart)*sizeof(int);
262 SequenceData[i] = (int *)Z_Malloc(dataSize, PU_STATIC,
264 memcpy(SequenceData[i], tempDataStart, dataSize);
265 Z_Free(tempDataStart);
268 else if(SC_Compare(SS_STRING_STOPSOUND))
271 SequenceTranslate[inSequence].stopSound =
272 GetSoundOffset(sc_String);
273 *tempDataPtr++ = SS_CMD_STOPSOUND;
277 SC_ScriptError("SN_InitSequenceScript: Unknown commmand.\n");
282 //==========================================================================
286 //==========================================================================
288 void SN_StartSequence(mobj_t *mobj, int sequence)
292 SN_StopSequence(mobj); // Stop any previous sequence
293 node = (seqnode_t *)Z_Malloc(sizeof(seqnode_t), PU_STATIC, NULL);
294 node->sequencePtr = SequenceData[SequenceTranslate[sequence].scriptNum];
295 node->sequence = sequence;
298 node->stopSound = SequenceTranslate[sequence].stopSound;
299 node->volume = 127; // Start at max volume
301 if(!SequenceListHead)
303 SequenceListHead = node;
304 node->next = node->prev = NULL;
308 SequenceListHead->prev = node;
309 node->next = SequenceListHead;
311 SequenceListHead = node;
317 //==========================================================================
319 // SN_StartSequenceName
321 //==========================================================================
323 void SN_StartSequenceName(mobj_t *mobj, char *name)
327 for(i = 0; i < SEQ_NUMSEQ; i++)
329 if(!strcmp(name, SequenceTranslate[i].name))
331 SN_StartSequence(mobj, i);
337 //==========================================================================
341 //==========================================================================
343 void SN_StopSequence(mobj_t *mobj)
347 for(node = SequenceListHead; node; node = node->next)
349 if(node->mobj == mobj)
354 S_StartSoundAtVolume(mobj, node->stopSound, node->volume);
356 if(SequenceListHead == node)
358 SequenceListHead = node->next;
362 node->prev->next = node->next;
366 node->next->prev = node->prev;
374 //==========================================================================
376 // SN_UpdateActiveSequences
378 //==========================================================================
380 void SN_UpdateActiveSequences(void)
385 if(!ActiveSequences || paused)
386 { // No sequences currently playing/game is paused
389 for(node = SequenceListHead; node; node = node->next)
396 sndPlaying = S_GetSoundPlayingInfo(node->mobj, node->currentSoundID);
397 switch(*node->sequencePtr)
402 node->currentSoundID = *(node->sequencePtr+1);
403 S_StartSoundAtVolume(node->mobj, node->currentSoundID,
406 node->sequencePtr += 2;
408 case SS_CMD_WAITUNTILDONE:
412 node->currentSoundID = 0;
415 case SS_CMD_PLAYREPEAT:
418 node->currentSoundID = *(node->sequencePtr+1);
419 S_StartSoundAtVolume(node->mobj, node->currentSoundID,
424 node->delayTics = *(node->sequencePtr+1);
425 node->sequencePtr += 2;
426 node->currentSoundID = 0;
428 case SS_CMD_DELAYRAND:
429 node->delayTics = *(node->sequencePtr+1)+
430 M_Random()%(*(node->sequencePtr+2)-*(node->sequencePtr+1));
431 node->sequencePtr += 2;
432 node->currentSoundID = 0;
435 node->volume = (127*(*(node->sequencePtr+1)))/100;
436 node->sequencePtr += 2;
438 case SS_CMD_STOPSOUND:
439 // Wait until something else stops the sequence
442 SN_StopSequence(node->mobj);
450 //==========================================================================
452 // SN_StopAllSequences
454 //==========================================================================
456 void SN_StopAllSequences(void)
460 for(node = SequenceListHead; node; node = node->next)
462 node->stopSound = 0; // don't play any stop sounds
463 SN_StopSequence(node->mobj);
467 //==========================================================================
469 // SN_GetSequenceOffset
471 //==========================================================================
473 int SN_GetSequenceOffset(int sequence, int *sequencePtr)
475 return (sequencePtr-SequenceData[SequenceTranslate[sequence].scriptNum]);
478 //==========================================================================
482 // nodeNum zero is the first node
483 //==========================================================================
485 void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume,
492 node = SequenceListHead;
493 while(node && i < nodeNum)
499 { // reach the end of the list before finding the nodeNum-th node
502 node->delayTics = delayTics;
503 node->volume = volume;
504 node->sequencePtr += seqOffset;
505 node->currentSoundID = currentSoundID;