1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: s_sndseq.cpp 4469 2014-01-03 23:38:29Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //  Sound Sequences
21 //
22 //-----------------------------------------------------------------------------
23 
24 #include <cstring>
25 #include <stdio.h>
26 
27 #include "doomtype.h"
28 #include "doomstat.h"
29 #include "sc_man.h"
30 #include "m_alloc.h"
31 #include "m_random.h"
32 #include "s_sound.h"
33 #include "s_sndseq.h"
34 #include "w_wad.h"
35 #include "z_zone.h"
36 #include "i_system.h"
37 #include "cmdlib.h"
38 #include "p_local.h"
39 
40 // MACROS ------------------------------------------------------------------
41 
42 #define MAX_SEQSIZE			256
43 #define GetCommand(a)		((a)>>24)
44 #define GetData(a)			( ((a) & 0xffffff) == 0xffffff ? ~0 : ((a) & 0xffffff) )
45 #define MakeCommand(a,b)	(((a) << 24)|((b) & 0xffffff))
46 #define HexenPlatSeq(a)		(a)
47 #define HexenDoorSeq(a)		((a) | 0x40)
48 #define HexenEnvSeq(a)		((a) | 0x80)
49 #define HexenLastSeq		(0xff)
50 
51 // TYPES -------------------------------------------------------------------
52 
53 typedef enum
54 {
55 	SS_STRING_PLAY,
56 	SS_STRING_PLAYUNTILDONE,
57 	SS_STRING_PLAYTIME,
58 	SS_STRING_PLAYREPEAT,
59 	SS_STRING_PLAYLOOP,
60 	SS_STRING_DELAY,
61 	SS_STRING_DELAYRAND,
62 	SS_STRING_VOLUME,
63 	SS_STRING_END,
64 	SS_STRING_STOPSOUND,
65 	SS_STRING_ATTENUATION,
66 	SS_STRING_DOOR,
67 	SS_STRING_PLATFORM,
68 	SS_STRING_ENVIRONMENT,
69 	SS_STRING_NOSTOPCUTOFF
70 } ssstrings_t;
71 
72 typedef enum
73 {
74 	SS_CMD_NONE,
75 	SS_CMD_PLAY,
76 	SS_CMD_WAITUNTILDONE, // used by PLAYUNTILDONE
77 	SS_CMD_PLAYTIME,
78 	SS_CMD_PLAYREPEAT,
79 	SS_CMD_PLAYLOOP,
80 	SS_CMD_DELAY,
81 	SS_CMD_DELAYRAND,
82 	SS_CMD_VOLUME,
83 	SS_CMD_STOPSOUND,
84 	SS_CMD_ATTENUATION,
85 	SS_CMD_END
86 } sscmds_t;
87 
88 typedef struct {
89 	const char		*name;
90 	byte			seqs[4];
91 } hexenseq_t;
92 
93 class DSeqActorNode : public DSeqNode
94 {
95 	DECLARE_SERIAL (DSeqActorNode, DSeqNode)
96 public:
97 	DSeqActorNode (AActor *actor, int sequence);
98 	~DSeqActorNode ();
MakeSound()99 	void MakeSound () { S_SoundID (m_Actor, CHAN_BODY, m_CurrentSoundID, m_Volume, m_Atten); }
MakeLoopedSound()100 	void MakeLoopedSound () { S_LoopedSoundID (m_Actor, CHAN_BODY, m_CurrentSoundID, m_Volume, m_Atten); }
IsPlaying()101 	bool IsPlaying () { return S_GetSoundPlayingInfo (m_Actor, m_CurrentSoundID); }
Source()102 	void *Source () { return m_Actor; }
103 	virtual void DestroyedPointer(DObject *obj);
104 private:
DSeqActorNode()105 	DSeqActorNode () {}
106 	AActor *m_Actor;
107 };
108 
109 class DSeqPolyNode : public DSeqNode
110 {
111 	DECLARE_SERIAL (DSeqPolyNode, DSeqNode)
112 public:
113 	DSeqPolyNode (polyobj_t *poly, int sequence);
114 	~DSeqPolyNode ();
MakeSound()115 	void MakeSound () { S_SoundID (&m_Poly->startSpot[0], CHAN_BODY, m_CurrentSoundID, m_Volume, m_Atten); }
MakeLoopedSound()116 	void MakeLoopedSound () { S_LoopedSoundID (&m_Poly->startSpot[0], CHAN_BODY, m_CurrentSoundID, m_Volume, m_Atten); }
IsPlaying()117 	bool IsPlaying () { return S_GetSoundPlayingInfo (&m_Poly->startSpot[0], m_CurrentSoundID); }
Source()118 	void *Source () { return m_Poly; }
119 private:
DSeqPolyNode()120 	DSeqPolyNode () {}
121 	polyobj_t *m_Poly;
122 };
123 
124 class DSeqSectorNode : public DSeqNode
125 {
126 	DECLARE_SERIAL (DSeqSectorNode, DSeqNode)
127 public:
128 	DSeqSectorNode (sector_t *sec, int sequence);
129 	~DSeqSectorNode ();
MakeSound()130 	void MakeSound () { S_SoundID (&m_Sector->soundorg[0], CHAN_BODY, m_CurrentSoundID, m_Volume, m_Atten); }
MakeLoopedSound()131 	void MakeLoopedSound () { S_LoopedSoundID (&m_Sector->soundorg[0], CHAN_BODY, m_CurrentSoundID, m_Volume, m_Atten); }
IsPlaying()132 	bool IsPlaying () { return S_GetSoundPlayingInfo (m_Sector->soundorg, m_CurrentSoundID); }
Source()133 	void *Source () { return m_Sector; }
134 private:
DSeqSectorNode()135 	DSeqSectorNode() {}
136 	sector_t *m_Sector;
137 };
138 
139 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
140 
141 static void VerifySeqPtr (int pos, int need);
142 static void AssignTranslations (int seq, seqtype_t type);
143 static void AssignHexenTranslations (void);
144 
145 // PRIVATE DATA DEFINITIONS ------------------------------------------------
146 
147 static const char *SSStrings[] = {
148 	"play",
149 	"playuntildone",
150 	"playtime",
151 	"playrepeat",
152 	"playloop",
153 	"delay",
154 	"delayrand",
155 	"volume",
156 	"end",
157 	"stopsound",
158 	"attenuation",
159 	"door",
160 	"platform",
161 	"environment",
162 	"nostopcutoff",
163 	NULL
164 };
165 static const char *Attenuations[] = {
166 	"none",
167 	"normal",
168 	"idle",
169 	"static",
170 	"surround",
171 	NULL
172 };
173 static const hexenseq_t HexenSequences[] = {
174 	{ "Platform",		{ HexenPlatSeq(0), HexenPlatSeq(1), HexenPlatSeq(3), HexenLastSeq } },
175 	{ "PlatformMetal",	{ HexenPlatSeq(2), HexenLastSeq } },
176 	{ "Silence",		{ HexenPlatSeq(4), HexenDoorSeq(4), HexenLastSeq } },
177 	{ "Lava",			{ HexenPlatSeq(5), HexenDoorSeq(5), HexenLastSeq } },
178 	{ "Water",			{ HexenPlatSeq(6), HexenDoorSeq(6), HexenLastSeq } },
179 	{ "Ice",			{ HexenPlatSeq(7), HexenDoorSeq(7), HexenLastSeq } },
180 	{ "Earth",			{ HexenPlatSeq(8), HexenDoorSeq(8), HexenLastSeq } },
181 	{ "PlatformMetal2",	{ HexenPlatSeq(9), HexenLastSeq } },
182 	{ "DoorNormal",		{ HexenDoorSeq(0), HexenLastSeq } },
183 	{ "DoorHeavy",		{ HexenDoorSeq(1), HexenLastSeq } },
184 	{ "DoorMetal",		{ HexenDoorSeq(2), HexenLastSeq } },
185 	{ "DoorCreak",		{ HexenDoorSeq(3), HexenLastSeq } },
186 	{ "DoorMetal2",		{ HexenDoorSeq(9), HexenLastSeq } },
187 	{ "Wind",			{ HexenEnvSeq(10), HexenLastSeq } },
188 	{ NULL, }
189 };
190 
191 static int SeqTrans[64*3];
192 static unsigned int *ScriptTemp;
193 static int ScriptTempSize;
194 
195 sndseq_t **Sequences;
196 int NumSequences;
197 int MaxSequences;
198 int ActiveSequences;
199 DSeqNode *DSeqNode::SequenceListHead;
200 
201 
202 // CODE --------------------------------------------------------------------
203 
SerializeSequences(FArchive & arc)204 void DSeqNode::SerializeSequences (FArchive &arc)
205 {
206 	if (arc.IsStoring ())
207 	{
208 		arc << SequenceListHead;
209 	}
210 	else
211 	{
212 		SN_StopAllSequences ();
213 		arc >> SequenceListHead;
214 	}
215 }
216 
IMPLEMENT_SERIAL(DSeqNode,DObject)217 IMPLEMENT_SERIAL (DSeqNode, DObject)
218 
219 DSeqNode::DSeqNode ()
220 {
221 	m_Next = m_Prev = NULL;
222 }
223 
Serialize(FArchive & arc)224 void DSeqNode::Serialize (FArchive &arc)
225 {
226 	Super::Serialize (arc);
227 	if (arc.IsStoring ())
228 	{
229 		arc << (DWORD)SN_GetSequenceOffset (m_Sequence, m_SequencePtr)
230 			<< m_DelayTics
231 			<< m_Volume
232 			<< m_Atten
233 			<< S_sfx[m_CurrentSoundID].name
234 			<< Sequences[m_Sequence]->name
235 			<< m_Next
236 			<< m_Prev;
237 	}
238 	else
239 	{
240 		std::string seqName, soundName;
241 		int seqOffset = 0, delayTics = 0;
242 		float volume;
243 		int atten = ATTN_NORM;
244 
245 		arc >> seqOffset
246 			>> delayTics
247 			>> volume
248 			>> atten
249 			>> soundName
250 			>> seqName
251 			>> m_Next
252 			>> m_Prev;
253 
254 		int i;
255 
256 		for (i = 0; i < NumSequences; i++)
257 		{
258 			if (!stricmp (seqName.c_str(), Sequences[i]->name))
259 			{
260 				ActivateSequence (i);
261 				break;
262 			}
263 		}
264 		if (i == NumSequences)
265 			I_Error ("Unknown sound sequence '%s'\n", seqName.c_str());
266 
267 		ChangeData (seqOffset, delayTics, volume, S_FindSound (soundName.c_str()));
268 	}
269 }
270 
IMPLEMENT_SERIAL(DSeqActorNode,DSeqNode)271 IMPLEMENT_SERIAL (DSeqActorNode, DSeqNode)
272 
273 void DSeqActorNode::DestroyedPointer(DObject *obj)
274 {
275 	if(obj == m_Actor)
276 		m_Actor = NULL;
277 }
278 
Serialize(FArchive & arc)279 void DSeqActorNode::Serialize (FArchive &arc)
280 {
281 	Super::Serialize (arc);
282 	if (arc.IsStoring ())
283 		arc << m_Actor;
284 	else
285 		arc >> m_Actor;
286 }
287 
IMPLEMENT_SERIAL(DSeqPolyNode,DSeqNode)288 IMPLEMENT_SERIAL (DSeqPolyNode, DSeqNode)
289 
290 void DSeqPolyNode::Serialize (FArchive &arc)
291 {
292 	Super::Serialize (arc);
293 	if (arc.IsStoring ())
294 		arc << (WORD)(m_Poly - polyobjs);
295 	else
296 	{
297 		WORD ofs;
298 		arc >> ofs;
299 		m_Poly = polyobjs + ofs;
300 	}
301 }
302 
IMPLEMENT_SERIAL(DSeqSectorNode,DSeqNode)303 IMPLEMENT_SERIAL (DSeqSectorNode, DSeqNode)
304 
305 void DSeqSectorNode::Serialize (FArchive &arc)
306 {
307 	Super::Serialize (arc);
308 	if (arc.IsStoring ())
309 		arc << m_Sector;
310 	else
311 		arc >> m_Sector;
312 }
313 
314 //==========================================================================
315 //
316 // VerifySequencePtr
317 //
318 //==========================================================================
319 
VerifySeqPtr(int pos,int need)320 static void VerifySeqPtr (int pos, int need)
321 {
322 	if (pos + need > ScriptTempSize)
323 	{
324 		ScriptTempSize *= 2;
325 		ScriptTemp = (unsigned int *)Realloc (ScriptTemp, ScriptTempSize * sizeof(*ScriptTemp));
326 	}
327 }
328 
329 //==========================================================================
330 //
331 // AssignTranslations
332 //
333 //==========================================================================
334 
AssignTranslations(int seq,seqtype_t type)335 static void AssignTranslations (int seq, seqtype_t type)
336 {
337 	sc_Crossed = false;
338 
339 	while (SC_GetString () && !sc_Crossed)
340 	{
341 		if (IsNum (sc_String))
342 		{
343 			SeqTrans[(atoi(sc_String) & 63) + type * 64] = seq;
344 		}
345 	}
346 
347 	SC_UnGet ();
348 }
349 
350 //==========================================================================
351 //
352 // AssignHexenTranslations
353 //
354 //==========================================================================
355 
AssignHexenTranslations(void)356 static void AssignHexenTranslations (void)
357 {
358 	int i, j, seq;
359 
360 	for (i = 0; HexenSequences[i].name; i++)
361 	{
362 		for (seq = 0; seq < NumSequences; seq++)
363 		{
364 			if (!stricmp (HexenSequences[i].name, Sequences[seq]->name))
365 				break;
366 		}
367 		if (seq == NumSequences)
368 			continue;
369 
370 		for (j = 0; j < 4 && HexenSequences[i].seqs[j] != HexenLastSeq; j++)
371 		{
372 			int trans;
373 
374 			if (HexenSequences[i].seqs[j] & 0x40)
375 				trans = 64;
376 			else if (HexenSequences[i].seqs[j] & 0x80)
377 				trans = 64*2;
378 			else
379 				trans = 0;
380 
381 			SeqTrans[trans + (HexenSequences[i].seqs[j] & 0x3f)] = seq;
382 		}
383 	}
384 }
385 
386 //==========================================================================
387 //
388 // S_ParseSndSeq
389 //
390 //==========================================================================
391 
S_ParseSndSeq(void)392 void S_ParseSndSeq (void)
393 {
394 	char name[MAX_SNDNAME+1];
395 	int stopsound;
396 	int cursize;
397 	int curseq = -1;
398 
399 	// denis - reboot safe
400 	if(Sequences)
401 	{
402 		free(Sequences);
403 		Sequences = 0;
404 		MaxSequences = 0;
405 	}
406 
407 	// be gone, compiler warnings
408 	cursize = 0;
409 	stopsound = -1;
410 
411 	memset (SeqTrans, -1, sizeof(SeqTrans));
412 	name[MAX_SNDNAME] = 0;
413 	ScriptTemp = (unsigned int *)Malloc (MAX_SEQSIZE * sizeof(*ScriptTemp));
414 	ScriptTempSize = MAX_SEQSIZE;
415 
416 	int lump = -1;
417 	while ((lump = W_FindLump("SNDSEQ", lump)) != -1)
418 	{
419 		SC_OpenLumpNum (lump, "SNDSEQ");
420 		while (SC_GetString ())
421 		{
422 			if (*sc_String == ':')
423 			{
424 				if (curseq != -1)
425 				{
426 					SC_ScriptError ("S_ParseSndSeq: Nested Script Error");
427 				}
428 				strncpy (name, sc_String + 1, MAX_SNDNAME);
429 				for (curseq = 0; curseq < NumSequences; curseq++)
430 				{
431 					if (stricmp (Sequences[curseq]->name, name) == 0)
432 					{
433 						Z_Free (Sequences[curseq]);
434 						Sequences[curseq] = NULL;
435 						break;
436 					}
437 				}
438 				if (curseq == NumSequences)
439 					NumSequences++;
440 				if (NumSequences > MaxSequences)
441 				{
442 					MaxSequences = MaxSequences ? MaxSequences * 2 : 64;
443 					Sequences = (sndseq_t **)Realloc (Sequences, MaxSequences * sizeof(*Sequences));
444 				}
445 				memset (ScriptTemp, 0, sizeof(*ScriptTemp) * ScriptTempSize);
446 				stopsound = -1;
447 				cursize = 0;
448 				continue;
449 			}
450 			if (curseq == -1)
451 			{
452 				continue;
453 			}
454 			switch (SC_MustMatchString (SSStrings))
455 			{
456 				case SS_STRING_PLAYUNTILDONE:
457 					VerifySeqPtr (cursize, 2);
458 					SC_MustGetString ();
459 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_PLAY, S_FindSound (sc_String));
460 					ScriptTemp[cursize++] = SS_CMD_WAITUNTILDONE << 24;
461 					break;
462 
463 				case SS_STRING_PLAY:
464 					VerifySeqPtr (cursize, 1);
465 					SC_MustGetString ();
466 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_PLAY, S_FindSound (sc_String));
467 					break;
468 
469 				case SS_STRING_PLAYTIME:
470 					VerifySeqPtr (cursize, 2);
471 					SC_MustGetString ();
472 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_PLAY, S_FindSound (sc_String));
473 					SC_MustGetNumber ();
474 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_DELAY, sc_Number);
475 					break;
476 
477 				case SS_STRING_PLAYREPEAT:
478 					VerifySeqPtr (cursize, 1);
479 					SC_MustGetString ();
480 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_PLAYREPEAT, S_FindSound (sc_String));
481 					break;
482 
483 				case SS_STRING_PLAYLOOP:
484 					VerifySeqPtr (cursize, 2);
485 					SC_MustGetString ();
486 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_PLAYLOOP, S_FindSound (sc_String));
487 					SC_MustGetNumber ();
488 					ScriptTemp[cursize++] = sc_Number;
489 					break;
490 
491 				case SS_STRING_DELAY:
492 					VerifySeqPtr (cursize, 1);
493 					SC_MustGetNumber ();
494 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_DELAY, sc_Number);
495 					break;
496 
497 				case SS_STRING_DELAYRAND:
498 					VerifySeqPtr (cursize, 2);
499 					SC_MustGetNumber ();
500 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_DELAYRAND, sc_Number);
501 					SC_MustGetNumber ();
502 					ScriptTemp[cursize++] = sc_Number;
503 					break;
504 
505 				case SS_STRING_VOLUME:
506 					VerifySeqPtr (cursize, 1);
507 					SC_MustGetNumber ();
508 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_VOLUME, sc_Number);
509 					break;
510 
511 				case SS_STRING_STOPSOUND:
512 					VerifySeqPtr (cursize, 1);
513 					SC_MustGetString ();
514 					stopsound = S_FindSound (sc_String);
515 					ScriptTemp[cursize++] = SS_CMD_STOPSOUND << 24;
516 					break;
517 
518 				case SS_STRING_NOSTOPCUTOFF:
519 					VerifySeqPtr (cursize, 1);
520 					stopsound = -2;
521 					ScriptTemp[cursize++] = SS_CMD_STOPSOUND << 24;
522 					break;
523 
524 				case SS_STRING_ATTENUATION:
525 					VerifySeqPtr (cursize, 1);
526 					SC_MustGetString ();
527 					ScriptTemp[cursize++] = MakeCommand (SS_CMD_ATTENUATION,
528 											SC_MustMatchString (Attenuations));
529 					break;
530 
531 				case SS_STRING_END:
532 					Sequences[curseq] = (sndseq_t *)Z_Malloc (sizeof(sndseq_t) + sizeof(int)*cursize, PU_STATIC, 0);
533 					strcpy (Sequences[curseq]->name, name);
534 					memcpy (Sequences[curseq]->script, ScriptTemp, sizeof(int)*cursize);
535 					Sequences[curseq]->script[cursize] = SS_CMD_END;
536 					Sequences[curseq]->stopsound = stopsound;
537 					curseq = -1;
538 					break;
539 
540 				case SS_STRING_PLATFORM:
541 					AssignTranslations (curseq, SEQ_PLATFORM);
542 					break;
543 
544 				case SS_STRING_DOOR:
545 					AssignTranslations (curseq, SEQ_DOOR);
546 					break;
547 
548 				case SS_STRING_ENVIRONMENT:
549 					AssignTranslations (curseq, SEQ_ENVIRONMENT);
550 					break;
551 			}
552 		}
553 		SC_Close ();
554 	}
555 
556 	free (ScriptTemp);
557 
558 	if (HexenHack)
559 		AssignHexenTranslations ();
560 }
561 
~DSeqNode()562 DSeqNode::~DSeqNode ()
563 {
564 	if (SequenceListHead == this)
565 		SequenceListHead = m_Next;
566 	if (m_Prev)
567 		m_Prev->m_Next = m_Next;
568 	if (m_Next)
569 		m_Next->m_Prev = m_Prev;
570 	ActiveSequences--;
571 }
572 
DSeqNode(int sequence)573 DSeqNode::DSeqNode (int sequence)
574 {
575 	ActivateSequence (sequence);
576 	if (!SequenceListHead)
577 	{
578 		SequenceListHead = this;
579 		m_Next = m_Prev = NULL;
580 	}
581 	else
582 	{
583 		SequenceListHead->m_Prev = this;
584 		m_Next = SequenceListHead;
585 		SequenceListHead = this;
586 		m_Prev = NULL;
587 	}
588 }
589 
ActivateSequence(int sequence)590 void DSeqNode::ActivateSequence (int sequence)
591 {
592 	m_SequencePtr = Sequences[sequence]->script;
593 	m_Sequence = sequence;
594 	m_DelayTics = 0;
595 	m_StopSound = Sequences[sequence]->stopsound;
596 	m_CurrentSoundID = -1;
597 	m_Volume = 1;			// Start at max volume...
598 	m_Atten = ATTN_IDLE;	// ...and idle attenuation
599 
600 	ActiveSequences++;
601 }
602 
DSeqActorNode(AActor * actor,int sequence)603 DSeqActorNode::DSeqActorNode (AActor *actor, int sequence)
604 	: DSeqNode (sequence)
605 {
606 	m_Actor = actor;
607 }
608 
DSeqPolyNode(polyobj_t * poly,int sequence)609 DSeqPolyNode::DSeqPolyNode (polyobj_t *poly, int sequence)
610 	: DSeqNode (sequence)
611 {
612 	m_Poly = poly;
613 }
614 
DSeqSectorNode(sector_t * sec,int sequence)615 DSeqSectorNode::DSeqSectorNode (sector_t *sec, int sequence)
616 	: DSeqNode (sequence)
617 {
618 	m_Sector = sec;
619 }
620 
621 //==========================================================================
622 //
623 //  SN_StartSequence
624 //
625 //==========================================================================
626 
TwiddleSeqNum(int & sequence,seqtype_t type)627 static bool TwiddleSeqNum (int &sequence, seqtype_t type)
628 {
629 	if (type < SEQ_NUMSEQTYPES)
630 		sequence = SeqTrans[sequence + type * 64];
631 
632 	// [SL] 2011-05-29 - Prevent a segfault if passed a bad sequence number
633 	// perhaps this should produce an error msg instead
634 	if (sequence >= NumSequences || sequence < 0)
635 		return false;
636 
637 	if (sequence == -1 || Sequences[sequence] == NULL)
638 		return false;
639 	else
640 		return true;
641 }
642 
SN_StartSequence(AActor * actor,int sequence,seqtype_t type)643 void SN_StartSequence (AActor *actor, int sequence, seqtype_t type)
644 {
645 	SN_StopSequence (actor); // Stop any previous sequence
646 	if (TwiddleSeqNum (sequence, type))
647 		new DSeqActorNode (actor, sequence);
648 }
649 
SN_StartSequence(sector_t * sector,int sequence,seqtype_t type)650 void SN_StartSequence (sector_t *sector, int sequence, seqtype_t type)
651 {
652 	SN_StopSequence (sector);
653 	if (TwiddleSeqNum (sequence, type))
654 		new DSeqSectorNode (sector, sequence);
655 }
656 
SN_StartSequence(polyobj_t * poly,int sequence,seqtype_t type)657 void SN_StartSequence (polyobj_t *poly, int sequence, seqtype_t type)
658 {
659 	SN_StopSequence (poly);
660 	if (TwiddleSeqNum (sequence, type))
661 		new DSeqPolyNode (poly, sequence);
662 }
663 
664 //==========================================================================
665 //
666 //  SN_StartSequence (named)
667 //
668 //==========================================================================
669 
SN_StartSequence(AActor * actor,const char * name)670 void SN_StartSequence (AActor *actor, const char *name)
671 {
672 	int i;
673 
674 	for (i = 0; i < NumSequences; i++)
675 	{
676 		if (!stricmp (name, Sequences[i]->name))
677 		{
678 			SN_StartSequence (actor, i, SEQ_NOTRANS);
679 			return;
680 		}
681 	}
682 }
683 
SN_StartSequence(sector_t * sec,const char * name)684 void SN_StartSequence (sector_t *sec, const char *name)
685 {
686 	int i;
687 
688 	for (i = 0; i < NumSequences; i++)
689 	{
690 		if (!stricmp (name, Sequences[i]->name))
691 		{
692 			SN_StartSequence (sec, i, SEQ_NOTRANS);
693 			return;
694 		}
695 	}
696 }
697 
SN_StartSequence(polyobj_t * poly,const char * name)698 void SN_StartSequence (polyobj_t *poly, const char *name)
699 {
700 	int i;
701 
702 	for (i = 0; i < NumSequences; i++)
703 	{
704 		if (!stricmp (name, Sequences[i]->name))
705 		{
706 			SN_StartSequence (poly, i, SEQ_NOTRANS);
707 			return;
708 		}
709 	}
710 }
711 
712 //==========================================================================
713 //
714 //  SN_StopSequence
715 //
716 //==========================================================================
717 
SN_StopSequence(AActor * actor)718 void SN_StopSequence (AActor *actor)
719 {
720 	SN_DoStop (actor);
721 }
722 
SN_StopSequence(sector_t * sector)723 void SN_StopSequence (sector_t *sector)
724 {
725 	SN_DoStop (sector);
726 }
727 
SN_StopSequence(polyobj_t * poly)728 void SN_StopSequence (polyobj_t *poly)
729 {
730 	SN_DoStop (poly);
731 }
732 
SN_DoStop(void * source)733 void SN_DoStop (void *source)
734 {
735 	DSeqNode *node;
736 
737 	for (node = DSeqNode::FirstSequence (); node; )
738 	{
739 		DSeqNode *next = node->NextSequence();
740 		if (node->Source() == source)
741 		{
742 			node->Destroy ();
743 		}
744 		node = next;
745 	}
746 }
747 
~DSeqActorNode()748 DSeqActorNode::~DSeqActorNode ()
749 {
750 	if (m_StopSound >= -1)
751 		S_StopSound (m_Actor, CHAN_BODY);
752 	if (m_StopSound >= 0)
753 		S_SoundID (m_Actor, CHAN_BODY, m_StopSound, m_Volume, m_Atten);
754 }
755 
~DSeqSectorNode()756 DSeqSectorNode::~DSeqSectorNode ()
757 {
758 	if (m_StopSound >= -1)
759 		S_StopSound (m_Sector->soundorg, CHAN_BODY);
760 	if (m_StopSound >= 0)
761 		S_SoundID (m_Sector->soundorg, CHAN_BODY, m_StopSound, m_Volume, m_Atten);
762 }
763 
~DSeqPolyNode()764 DSeqPolyNode::~DSeqPolyNode ()
765 {
766 	if (m_StopSound >= -1)
767 		S_StopSound (m_Poly->startSpot, CHAN_BODY);
768 	if (m_StopSound >= 0)
769 		S_SoundID (m_Poly->startSpot, CHAN_BODY, m_StopSound, m_Volume, m_Atten);
770 }
771 
772 //==========================================================================
773 //
774 //  SN_UpdateActiveSequences
775 //
776 //==========================================================================
777 
RunThink()778 void DSeqNode::RunThink ()
779 {
780 	if (m_DelayTics > 0)
781 	{
782 		m_DelayTics--;
783 		return;
784 	}
785 	bool sndPlaying = IsPlaying ();
786 	if (m_DelayTics < 0 && sndPlaying)
787 	{
788 		m_DelayTics++;
789 		return;
790 	}
791 	switch (GetCommand(*m_SequencePtr))
792 	{
793 	case SS_CMD_PLAY:
794 		if (!sndPlaying)
795 		{
796 			m_CurrentSoundID = GetData(*m_SequencePtr);
797 			MakeSound ();
798 		}
799 		m_SequencePtr++;
800 		break;
801 
802 	case SS_CMD_WAITUNTILDONE:
803 		if (!sndPlaying)
804 		{
805 			m_SequencePtr++;
806 			m_CurrentSoundID = -1;
807 		}
808 		break;
809 
810 	case SS_CMD_PLAYREPEAT:
811 		if (!sndPlaying)
812 		{
813 			// Does not advance sequencePtr, so it will repeat
814 			// as necessary
815 			m_CurrentSoundID = GetData(*m_SequencePtr);
816 			MakeLoopedSound ();
817 		}
818 		break;
819 
820 	case SS_CMD_PLAYLOOP:
821 		m_CurrentSoundID = GetData(*m_SequencePtr);
822 		MakeLoopedSound ();
823 		m_DelayTics = -(signed)GetData(*(m_SequencePtr+1));
824 		break;
825 
826 	case SS_CMD_DELAY:
827 		m_DelayTics = GetData(*m_SequencePtr);
828 		m_SequencePtr++;
829 		m_CurrentSoundID = -1;
830 		break;
831 
832 	case SS_CMD_DELAYRAND:
833 		m_DelayTics = GetData(*m_SequencePtr)+
834 			M_Random()%(*(m_SequencePtr+1)-GetData(*m_SequencePtr));
835 		m_SequencePtr += 2;
836 		m_CurrentSoundID = -1;
837 		break;
838 
839 	case SS_CMD_VOLUME:
840 		// volume is in range 0..100
841 		m_Volume = GetData(*m_SequencePtr)/100;
842 		m_SequencePtr++;
843 		break;
844 
845 	case SS_CMD_STOPSOUND:
846 		// Wait until something else stops the sequence
847 		break;
848 
849 	case SS_CMD_ATTENUATION:
850 		m_Atten = GetData(*m_SequencePtr);
851 		m_SequencePtr++;
852 		break;
853 
854 	case SS_CMD_END:
855 		Destroy ();
856 		break;
857 
858 	default:
859 		break;
860 	}
861 }
862 
SN_UpdateActiveSequences(void)863 void SN_UpdateActiveSequences (void)
864 {
865 	DSeqNode *node;
866 
867 	if (!ActiveSequences || paused)
868 	{ // No sequences currently playing/game is paused
869 		return;
870 	}
871 	for (node = DSeqNode::FirstSequence(); node; node = node->NextSequence())
872 	{
873 		node->RunThink ();
874 	}
875 }
876 
877 //==========================================================================
878 //
879 //  SN_StopAllSequences
880 //
881 //==========================================================================
882 
SN_StopAllSequences(void)883 void SN_StopAllSequences (void)
884 {
885 	DSeqNode *node;
886 
887 	for (node = DSeqNode::FirstSequence(); node; )
888 	{
889 		DSeqNode *next = node->NextSequence();
890 		node->m_StopSound = -1; // don't play any stop sounds
891 		node->Destroy ();
892 		node = next;
893 	}
894 }
895 
896 //==========================================================================
897 //
898 //  SN_GetSequenceOffset
899 //
900 //==========================================================================
901 
SN_GetSequenceOffset(int sequence,unsigned int * sequencePtr)902 ptrdiff_t SN_GetSequenceOffset (int sequence, unsigned int *sequencePtr)
903 {
904 	return sequencePtr - Sequences[sequence]->script;
905 }
906 
907 //==========================================================================
908 //
909 //  SN_ChangeNodeData
910 //
911 // 	nodeNum zero is the first node
912 //==========================================================================
913 
SN_ChangeNodeData(int nodeNum,int seqOffset,int delayTics,float volume,int currentSoundID)914 void SN_ChangeNodeData (int nodeNum, int seqOffset, int delayTics, float volume,
915 	int currentSoundID)
916 {
917 	int i;
918 	DSeqNode *node;
919 
920 	i = 0;
921 	node = DSeqNode::FirstSequence();
922 	while (node && i < nodeNum)
923 	{
924 		node = node->NextSequence();
925 		i++;
926 	}
927 	if (!node)
928 	{ // reached the end of the list before finding the nodeNum-th node
929 		return;
930 	}
931 	node->ChangeData (seqOffset, delayTics, volume, currentSoundID);
932 }
933 
ChangeData(int seqOffset,int delayTics,float volume,int currentSoundID)934 void DSeqNode::ChangeData (int seqOffset, int delayTics, float volume, int currentSoundID)
935 {
936 	m_DelayTics = delayTics;
937 	m_Volume = volume;
938 	m_SequencePtr += seqOffset;
939 	m_CurrentSoundID = currentSoundID;
940 }
941 
942 VERSION_CONTROL (s_sndseq_cpp, "$Id: s_sndseq.cpp 4469 2014-01-03 23:38:29Z dr_sean $")
943