diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1289c95a3..03fbfa73f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1164,7 +1164,6 @@ set (PCH_SOURCES g_shared/a_morph.cpp g_shared/a_quake.cpp g_shared/a_skies.cpp - g_shared/a_soundsequence.cpp g_shared/a_specialspot.cpp g_shared/hudmessages.cpp g_shared/sbarinfo.cpp diff --git a/src/g_shared/a_soundsequence.cpp b/src/g_shared/a_soundsequence.cpp deleted file mode 100644 index 1352e72de..000000000 --- a/src/g_shared/a_soundsequence.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* -** a_soundsequence.cpp -** Actors for independantly playing sound sequences in a map. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** A SoundSequence actor has two modes of operation: -** -** 1. If the sound sequence assigned to it has a slot, then a separate -** SoundSequenceSlot actor is spawned (if not already present), and -** this actor's sound sequence is added to its list of choices. This -** actor is then destroyed, never to be heard from again. The sound -** sequence for the slot is automatically played on the new -** SoundSequenceSlot actor, and it should at some point execute the -** randomsequence command so that it can pick one of the other -** sequences to play. The slot sequence should also end with restart -** so that more than one sequence will have a chance to play. -** -** In this mode, it is very much like world $ambient sounds defined -** in SNDINFO but more flexible. -** -** 2. If the sound sequence assigned to it has no slot, then it will play -** the sequence when activated and cease playing the sequence when -** deactivated. -** -** In this mode, it is very much like point $ambient sounds defined -** in SNDINFO but more flexible. -** -** To assign a sound sequence, set the SoundSequence's first argument to -** the ID of the corresponding environment sequence you want to use. If -** that sequence is a multiple-choice sequence, then the second argument -** selects which choice it picks. -*/ - -#include - -#include "actor.h" -#include "info.h" -#include "s_sound.h" -#include "m_random.h" -#include "s_sndseq.h" -#include "serializer.h" - -// SoundSequenceSlot -------------------------------------------------------- - -class ASoundSequenceSlot : public AActor -{ - DECLARE_CLASS (ASoundSequenceSlot, AActor) - HAS_OBJECT_POINTERS -public: - - void Serialize(FSerializer &arc); - - TObjPtr Sequence; -}; - -IMPLEMENT_CLASS(ASoundSequenceSlot, false, true) - -IMPLEMENT_POINTERS_START(ASoundSequenceSlot) - IMPLEMENT_POINTER(Sequence) -IMPLEMENT_POINTERS_END - -//========================================================================== -// -// ASoundSequenceSlot :: Serialize -// -//========================================================================== - -void ASoundSequenceSlot::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("sequence", Sequence); -} - -// SoundSequence ------------------------------------------------------------ - -class ASoundSequence : public AActor -{ - DECLARE_CLASS (ASoundSequence, AActor) -public: - void OnDestroy() override; - void PostBeginPlay (); - void Activate (AActor *activator); - void Deactivate (AActor *activator); - void MarkPrecacheSounds () const; -}; - -IMPLEMENT_CLASS(ASoundSequence, false, false) - -//========================================================================== -// -// ASoundSequence :: Destroy -// -//========================================================================== - -void ASoundSequence::OnDestroy () -{ - SN_StopSequence (this); - Super::OnDestroy(); -} - -//========================================================================== -// -// ASoundSequence :: PostBeginPlay -// -//========================================================================== - -void ASoundSequence::PostBeginPlay () -{ - FName slot = SN_GetSequenceSlot (args[0], SEQ_ENVIRONMENT); - - if (slot != NAME_None) - { // This is a slotted sound, so add it to the master for that slot - ASoundSequenceSlot *master; - TThinkerIterator locator; - - while (NULL != (master = locator.Next ())) - { - if (master->Sequence->GetSequenceName() == slot) - { - break; - } - } - if (master == NULL) - { - master = Spawn (); - master->Sequence = SN_StartSequence (master, slot, 0); - GC::WriteBarrier(master, master->Sequence); - } - master->Sequence->AddChoice (args[0], SEQ_ENVIRONMENT); - Destroy (); - } -} - -//========================================================================== -// -// ASoundSequence :: MarkPrecacheSounds -// -//========================================================================== - -void ASoundSequence::MarkPrecacheSounds() const -{ - Super::MarkPrecacheSounds(); - SN_MarkPrecacheSounds(args[0], SEQ_ENVIRONMENT); -} - -//========================================================================== -// -// ASoundSequence :: Activate -// -//========================================================================== - -void ASoundSequence::Activate (AActor *activator) -{ - SN_StartSequence (this, args[0], SEQ_ENVIRONMENT, args[1]); -} - -//========================================================================== -// -// ASoundSequence :: Deactivate -// -//========================================================================== - -void ASoundSequence::Deactivate (AActor *activator) -{ - SN_StopSequence (this); -} diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5d116f101..09f946fc7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4832,6 +4832,13 @@ void AActor::MarkPrecacheSounds() const CrushPainSound.MarkUsed(); } +DEFINE_ACTION_FUNCTION(AActor, MarkPrecacheSounds) +{ + PARAM_SELF_PROLOGUE(AActor); + self->MarkPrecacheSounds(); + return 0; +} + bool AActor::isFast() { if (flags5&MF5_ALWAYSFAST) return true; diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index c8e1ef599..6506f303b 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -425,11 +425,27 @@ void DSeqNode::AddChoice (int seqnum, seqtype_t type) } } +DEFINE_ACTION_FUNCTION(DSeqNode, AddChoice) +{ + PARAM_SELF_PROLOGUE(DSeqNode); + PARAM_NAME(seq); + PARAM_INT(mode); + self->AddChoice(seq, seqtype_t(mode)); + return 0; +} + + FName DSeqNode::GetSequenceName () const { return Sequences[m_Sequence]->SeqName; } +DEFINE_ACTION_FUNCTION(DSeqNode, GetSequenceName) +{ + PARAM_SELF_PROLOGUE(DSeqNode); + ACTION_RETURN_INT(self->GetSequenceName().GetIndex()); +} + IMPLEMENT_CLASS(DSeqActorNode, false, true) IMPLEMENT_POINTERS_START(DSeqActorNode) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 3a9ae5ea1..856156322 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -54,6 +54,7 @@ #include "d_player.h" #include "r_state.h" #include "g_levellocals.h" +#include "virtual.h" // MACROS ------------------------------------------------------------------ @@ -479,7 +480,16 @@ void S_PrecacheLevel () // Precache all sounds known to be used by the currently spawned actors. while ( (actor = iterator.Next()) != NULL ) { - actor->MarkPrecacheSounds(); + IFVIRTUALPTR(actor, AActor, MarkPrecacheSounds) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { actor }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else + { + actor->MarkPrecacheSounds(); + } } for (auto i : gameinfo.PrecachedSounds) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9ad6db85c..6e529220f 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -309,6 +309,7 @@ class Actor : Thinker native virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0); virtual native bool Slam(Actor victim); virtual native void Touch(Actor toucher); + virtual native void MarkPrecacheSounds(); // Called by PIT_CheckThing to check if two actos actually can collide. virtual bool CanCollideWith(Actor other, bool passive) diff --git a/wadsrc/static/zscript/shared/soundsequence.txt b/wadsrc/static/zscript/shared/soundsequence.txt index 97ff8e9aa..c5e2b2604 100644 --- a/wadsrc/static/zscript/shared/soundsequence.txt +++ b/wadsrc/static/zscript/shared/soundsequence.txt @@ -1,3 +1,62 @@ +/* +** a_soundsequence.cpp +** Actors for independantly playing sound sequences in a map. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** A SoundSequence actor has two modes of operation: +** +** 1. If the sound sequence assigned to it has a slot, then a separate +** SoundSequenceSlot actor is spawned (if not already present), and +** this actor's sound sequence is added to its list of choices. This +** actor is then destroyed, never to be heard from again. The sound +** sequence for the slot is automatically played on the new +** SoundSequenceSlot actor, and it should at some point execute the +** randomsequence command so that it can pick one of the other +** sequences to play. The slot sequence should also end with restart +** so that more than one sequence will have a chance to play. +** +** In this mode, it is very much like world $ambient sounds defined +** in SNDINFO but more flexible. +** +** 2. If the sound sequence assigned to it has no slot, then it will play +** the sequence when activated and cease playing the sequence when +** deactivated. +** +** In this mode, it is very much like point $ambient sounds defined +** in SNDINFO but more flexible. +** +** To assign a sound sequence, set the SoundSequence's first argument to +** the ID of the corresponding environment sequence you want to use. If +** that sequence is a multiple-choice sequence, then the second argument +** selects which choice it picks. +*/ class AmbientSound : Actor native { @@ -17,7 +76,7 @@ class AmbientSoundNoGravity : AmbientSound } } -class SoundSequenceSlot : Actor native +class SoundSequenceSlot : Actor { default { @@ -25,9 +84,11 @@ class SoundSequenceSlot : Actor native +NOBLOCKMAP +DONTSPLASH } + + SeqNode sequence; } -class SoundSequence : Actor native +class SoundSequence : Actor { default { @@ -35,6 +96,86 @@ class SoundSequence : Actor native +NOBLOCKMAP +DONTSPLASH } + + //========================================================================== + // + // ASoundSequence :: Destroy + // + //========================================================================== + + override void OnDestroy () + { + StopSoundSequence (); + Super.OnDestroy(); + } + + //========================================================================== + // + // ASoundSequence :: PostBeginPlay + // + //========================================================================== + + override void PostBeginPlay () + { + Name slot = SeqNode.GetSequenceSlot (args[0], SeqNode.ENVIRONMENT); + + if (slot != 'none') + { // This is a slotted sound, so add it to the master for that slot + SoundSequenceSlot master; + let locator = ThinkerIterator.Create("SoundSequenceSlot"); + + while ((master = SoundSequenceSlot(locator.Next ()))) + { + if (master.Sequence.GetSequenceName() == slot) + { + break; + } + } + if (master == NULL) + { + master = SoundSequenceSlot(Spawn("SoundSequenceSlot")); + master.Sequence = master.StartSoundSequence (slot, 0); + } + master.Sequence.AddChoice (args[0], SeqNode.ENVIRONMENT); + Destroy (); + } + } + + //========================================================================== + // + // ASoundSequence :: MarkPrecacheSounds + // + //========================================================================== + + override void MarkPrecacheSounds() + { + Super.MarkPrecacheSounds(); + SeqNode.MarkPrecacheSounds(args[0], SeqNode.ENVIRONMENT); + } + + //========================================================================== + // + // ASoundSequence :: Activate + // + //========================================================================== + + override void Activate (Actor activator) + { + StartSoundSequenceID (args[0], SeqNode.ENVIRONMENT, args[1]); + } + + //========================================================================== + // + // ASoundSequence :: Deactivate + // + //========================================================================== + + override void Deactivate (Actor activator) + { + StopSoundSequence (); + } + + } // Heretic Sound sequences ----------------------------------------------------------- diff --git a/wadsrc/static/zscript/sounddata.txt b/wadsrc/static/zscript/sounddata.txt index 3aff17c4c..2496b8f8d 100644 --- a/wadsrc/static/zscript/sounddata.txt +++ b/wadsrc/static/zscript/sounddata.txt @@ -12,6 +12,8 @@ class SeqNode native native bool AreModesSameID(int sequence, int type, int mode1); native bool AreModesSame(Name name, int mode1); + native Name GetSequenceName(); + native void AddChoice (int seqnum, int type); native static Name GetSequenceSlot (int sequence, int type); native static void MarkPrecacheSounds(int sequence, int type); }