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