2015-05-19 21:54:34 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 1997 , 2005 - 3 D Realms Entertainment
2019-12-19 00:20:43 +00:00
Copyright ( C ) 2019 Christoph Oelckers
2015-05-19 21:54:34 +00:00
This file is part of Shadow Warrior version 1.2
Shadow Warrior is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
Original Source : 1997 - Frank Maddin and Jim Norwood
Prepared for public release : 03 / 28 / 2005 - Charlie Wiederhold , 3 D Realms
*/
//-------------------------------------------------------------------------
2019-10-09 16:09:05 +00:00
# include "ns.h"
2015-05-19 21:54:34 +00:00
# include "build.h"
2019-12-17 22:25:07 +00:00
2015-05-19 21:54:34 +00:00
# include "names2.h"
# include "panel.h"
# include "game.h"
# include "sounds.h"
# include "ai.h"
2019-03-21 02:24:19 +00:00
# include "network.h"
2015-05-19 21:54:34 +00:00
2020-08-05 15:07:19 +00:00
# include "misc.h"
2020-08-05 22:18:45 +00:00
# include "misc.h"
2015-05-19 21:54:34 +00:00
# include "rts.h"
# include "menus.h"
2020-10-04 16:31:48 +00:00
# include "razemenu.h"
2020-04-12 06:07:48 +00:00
# include "raze_music.h"
2020-04-12 06:09:38 +00:00
# include "raze_sound.h"
2020-04-11 21:54:33 +00:00
# include "filesystem.h"
2020-02-23 16:13:18 +00:00
# include "serializer.h"
2020-08-05 15:07:19 +00:00
# include "gamecontrol.h"
2020-08-16 18:10:26 +00:00
# include "gamestate.h"
2021-04-28 22:56:36 +00:00
# include "vm.h"
2015-05-19 22:06:04 +00:00
2019-10-09 16:09:05 +00:00
BEGIN_SW_NS
2019-12-18 10:09:01 +00:00
enum EChanExFlags
{
2019-12-18 18:17:37 +00:00
CHANEXF_NODOPPLER = 0x20000000 ,
2019-12-19 00:20:43 +00:00
CHANEXF_DONTPAN = 0x40000000 ,
2019-12-18 10:09:01 +00:00
} ;
2015-05-19 21:54:34 +00:00
// Parentally locked sounds list
int PLocked_Sounds [ ] =
{
483 , 328 , 334 , 335 , 338 , 478 , 450 , 454 , 452 , 453 , 456 , 457 , 458 , 455 , 460 , 462 ,
461 , 464 , 466 , 465 , 467 , 463 , 342 , 371 , 254 , 347 , 350 , 432 , 488 , 489 , 490 , 76 , 339 ,
499 , 500 , 506 , 479 , 480 , 481 , 482 , 78 , 600 , 467 , 548 , 547 , 544 , 546 , 545 , 542 , 541 , 540 ,
539 , 536 , 529 , 525 , 522 , 521 , 515 , 516 , 612 , 611 , 589 , 625 , 570 , 569 , 567 , 565 ,
558 , 557
} ;
//
// Includes digi.h to build the table
//
# define DIGI_TABLE
2021-12-31 12:31:13 +00:00
VOCstruct voc [ ] =
2015-05-19 21:54:34 +00:00
{
# include "digi.h"
} ;
# undef DIGI_TABLE
//
// Includes ambient.h to build the table of ambient sounds for game
//
# define AMBIENT_TABLE
AMB_INFO ambarray [ ] =
{
# include "ambient.h"
} ;
# undef AMBIENT_TABLE
# define MAX_AMBIENT_SOUNDS 82
2019-12-18 21:13:19 +00:00
//==========================================================================
//
//
2015-05-19 21:54:34 +00:00
//
2019-12-17 22:25:07 +00:00
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-19 00:20:43 +00:00
float S_ConvertPitch ( int lpitch )
2015-05-19 21:54:34 +00:00
{
2021-05-12 14:50:20 +00:00
return powf ( 2 , lpitch / 1200.f ) ;
2015-05-19 21:54:34 +00:00
}
2019-12-17 22:25:07 +00:00
//==========================================================================
//
2019-12-18 18:17:37 +00:00
// Sound Distance Calculation
2019-12-17 22:25:07 +00:00
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-18 18:17:37 +00:00
enum
{
DECAY_CONST = 4000
} ;
2015-05-19 21:54:34 +00:00
2021-11-02 22:31:09 +00:00
const int MAXLEVLDIST = 19000 ; // The higher the number, the further away you can hear sound
2022-08-21 15:42:53 +00:00
short SoundDist ( const DVector3 & pos , int basedist )
2019-12-18 18:17:37 +00:00
{
double tx , ty , tz ;
2022-08-21 15:42:53 +00:00
double sqrdist ;
2019-12-18 18:17:37 +00:00
extern short screenpeek ;
2015-05-19 21:54:34 +00:00
2022-11-23 09:59:15 +00:00
double distance = ( Player [ screenpeek ] . actor - > getPosWithOffsetZ ( ) - pos ) . Length ( ) * 16 ;
2015-05-19 21:54:34 +00:00
2019-12-18 18:17:37 +00:00
if ( basedist < 0 ) // if basedist is negative
{
double decayshift = 2 ;
2022-08-21 15:42:53 +00:00
int decay = abs ( basedist ) / DECAY_CONST ;
2019-12-18 18:17:37 +00:00
for ( int i = 0 ; i < decay ; i + + )
decayshift * = 2 ;
2022-08-21 15:42:53 +00:00
if ( fabs ( double ( basedist ) / decayshift ) > = distance )
distance = 0 ;
2019-12-18 18:17:37 +00:00
else
2022-08-21 15:42:53 +00:00
distance * = decay ;
2019-12-18 18:17:37 +00:00
}
else
{
2022-08-21 15:42:53 +00:00
if ( basedist > distance )
distance = 0 ;
2019-12-18 18:17:37 +00:00
else
2022-08-21 15:42:53 +00:00
distance - = basedist ;
2019-12-18 18:17:37 +00:00
}
2019-12-17 22:25:07 +00:00
2022-08-21 15:42:53 +00:00
distance = distance * ( 256. / MAXLEVLDIST ) ;
2019-12-17 22:25:07 +00:00
2022-08-21 15:42:53 +00:00
if ( distance < 0 ) distance = 0 ;
if ( distance > 255 ) distance = 255 ;
2019-12-17 22:25:07 +00:00
2022-08-21 15:42:53 +00:00
return short ( distance ) ;
2019-12-18 18:17:37 +00:00
}
2019-12-17 22:25:07 +00:00
2019-12-18 18:17:37 +00:00
//==========================================================================
//
// Calculate rolloff info.
//
//==========================================================================
2019-12-17 22:25:07 +00:00
2019-12-18 18:17:37 +00:00
FRolloffInfo GetRolloff ( int basedist )
{
FRolloffInfo info ;
2019-12-17 22:25:07 +00:00
2019-12-18 18:17:37 +00:00
if ( basedist < 0 ) // if basedist is negative
{
double decayshift = 2 ;
2022-09-02 22:00:28 +00:00
int decay = abs ( basedist ) / DECAY_CONST ;
2019-12-17 22:25:07 +00:00
2019-12-18 18:17:37 +00:00
for ( int i = 0 ; i < decay ; i + + )
decayshift * = 2 ;
2019-12-17 22:25:07 +00:00
2019-12-18 18:17:37 +00:00
info . RolloffType = ROLLOFF_Doom ;
info . MinDistance = ( float ) ( - basedist / decayshift / 16. ) ;
info . MaxDistance = MAXLEVLDIST / 16.f / decay ;
}
else
{
info . RolloffType = ROLLOFF_Doom ;
info . MinDistance = basedist / 16.f ;
info . MaxDistance = info . MinDistance + MAXLEVLDIST / 16.f ;
}
return info ;
}
2019-12-17 22:25:07 +00:00
2019-12-19 00:20:43 +00:00
//==========================================================================
//
//
// Ambient sounds
//
//
//==========================================================================
struct AmbientSound
{
2021-12-24 23:36:05 +00:00
DSWActor * spot ;
2019-12-19 00:20:43 +00:00
int ambIndex ;
2022-11-24 16:46:39 +00:00
FSoundID vocIndex ;
2019-12-19 00:20:43 +00:00
int ChanFlags ;
int maxIndex ;
int curIndex ;
bool intermit ;
} ;
static TArray < AmbientSound * > ambients ;
//==========================================================================
//
//
//
//==========================================================================
void StopAmbientSound ( void )
{
2020-02-23 14:41:57 +00:00
for ( auto amb : ambients )
2019-12-19 00:20:43 +00:00
{
2020-02-23 14:41:57 +00:00
soundEngine - > StopSound ( SOURCE_Ambient , amb , - 1 ) ;
2020-02-23 16:13:18 +00:00
delete amb ;
2019-12-19 00:20:43 +00:00
}
ambients . Clear ( ) ;
}
//==========================================================================
//
// Play a sound
//
//==========================================================================
2021-11-02 22:08:59 +00:00
void InitAmbient ( int num , DSWActor * actor )
2019-12-19 00:20:43 +00:00
{
2021-12-31 12:31:13 +00:00
VOCstruct * vp ;
2019-12-19 00:20:43 +00:00
int pitch = 0 ;
short angle , sound_dist ;
int tx , ty , tz ;
uint8_t priority ;
int maxtics = 0 ;
if ( ! snd_ambience ) return ;
// Ambient sounds need special treatment
if ( num < 0 | | num > MAX_AMBIENT_SOUNDS )
{
2020-11-24 21:39:35 +00:00
if ( num ! = - 1 ) // skip message for -1 to allow using it for silencing buggy ambient sound sprites (there is one in SW level 9.)
{
sprintf ( ds , " Invalid or out of range ambient sound number %d \n " , num ) ;
PutStringInfo ( Player + screenpeek , ds ) ;
}
2019-12-19 00:20:43 +00:00
return ;
}
2022-11-24 16:46:39 +00:00
auto vnum = FSoundID : : fromInt ( ambarray [ num ] . diginame ) ;
2019-12-19 00:20:43 +00:00
if ( ! soundEngine - > isValidSoundId ( vnum ) )
{
return ; // linked sound does not exist.
}
auto amb = new AmbientSound ;
2021-12-24 23:36:05 +00:00
amb - > spot = actor ;
2019-12-19 00:20:43 +00:00
amb - > ambIndex = num ;
amb - > vocIndex = vnum ;
2020-02-23 16:13:18 +00:00
amb - > ChanFlags = CHANF_TRANSIENT ;
2019-12-19 00:20:43 +00:00
if ( ambarray [ num ] . ambient_flags & v3df_dontpan ) amb - > ChanFlags | = EChanFlags : : FromInt ( CHANEXF_DONTPAN ) ;
2022-11-24 16:46:39 +00:00
if ( voc [ vnum . index ( ) ] . voc_flags & vf_loop ) amb - > ChanFlags | = CHANF_LOOP ;
2020-02-29 16:55:31 +00:00
amb - > maxIndex = ambarray [ num ] . maxtics ;
2019-12-19 00:20:43 +00:00
amb - > curIndex = 0 ;
amb - > intermit = ! ! ( ambarray [ num ] . ambient_flags & v3df_intermit ) ;
ambients . Push ( amb ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void StartAmbientSound ( void )
{
2020-09-17 22:33:18 +00:00
if ( ! SoundEnabled ( ) ) return ;
2019-12-19 00:20:43 +00:00
2021-11-02 22:08:59 +00:00
SWStatIterator it ( STAT_AMBIENT ) ;
while ( auto actor = it . Next ( ) )
2019-12-19 00:20:43 +00:00
{
2021-12-24 23:45:19 +00:00
InitAmbient ( actor - > spr . lotag , actor ) ;
2019-12-19 00:20:43 +00:00
}
}
//==========================================================================
//
//
//
//==========================================================================
static void RestartAmbient ( AmbientSound * amb )
{
2020-11-22 17:16:08 +00:00
if ( ! SoundEnabled ( ) ) return ;
2022-11-24 16:46:39 +00:00
auto & vp = voc [ amb - > vocIndex . index ( ) ] ;
2019-12-19 00:20:43 +00:00
auto rolloff = GetRolloff ( vp . voc_distance ) ;
int pitch = 0 ;
if ( vp . pitch_hi < = vp . pitch_lo ) pitch = vp . pitch_lo ;
2021-12-25 15:30:22 +00:00
else pitch = vp . pitch_lo + ( StdRandomRange ( vp . pitch_hi - vp . pitch_lo ) ) ;
2020-09-02 16:59:56 +00:00
amb - > curIndex = PlayClock ;
2019-12-19 00:20:43 +00:00
2020-02-27 22:11:03 +00:00
if ( ! soundEngine - > IsSourcePlayingSomething ( SOURCE_Ambient , amb , CHAN_BODY , amb - > vocIndex ) )
soundEngine - > StartSound ( SOURCE_Ambient , amb , nullptr , CHAN_BODY , EChanFlags : : FromInt ( amb - > ChanFlags ) , amb - > vocIndex , 1.f , ATTN_NORM , & rolloff , S_ConvertPitch ( pitch ) ) ;
2019-12-19 00:20:43 +00:00
}
2019-12-18 21:13:19 +00:00
//==========================================================================
//
//
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-19 00:20:43 +00:00
static int RandomizeAmbientSpecials ( int handle )
2015-05-19 21:54:34 +00:00
{
2019-12-18 10:09:01 +00:00
# define MAXRNDAMB 12
2021-11-28 10:34:29 +00:00
static const uint8_t ambrand [ ] =
2015-05-19 21:54:34 +00:00
{
2019-12-18 10:09:01 +00:00
56 , 57 , 58 , 59 , 60 , 61 , 62 , 63 , 64 , 65 , 66 , 67
} ;
2019-12-18 21:13:19 +00:00
int i ;
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
// If ambient sound is found in the array, randomly pick a new sound
for ( i = 0 ; i < MAXRNDAMB ; i + + )
2015-05-19 21:54:34 +00:00
{
2020-02-29 16:55:31 +00:00
if ( handle = = ambrand [ i ] )
2021-12-25 15:30:22 +00:00
return ambrand [ StdRandomRange ( MAXRNDAMB - 1 ) ] ;
2015-05-19 21:54:34 +00:00
}
2019-12-18 21:13:19 +00:00
return - 1 ;
2015-05-19 21:54:34 +00:00
}
2019-12-18 21:13:19 +00:00
//==========================================================================
//
//
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-19 00:20:43 +00:00
static void DoTimedSound ( AmbientSound * amb )
2015-05-19 21:54:34 +00:00
{
2020-09-02 16:59:56 +00:00
if ( PlayClock > = amb - > curIndex + amb - > maxIndex )
2019-12-18 10:09:01 +00:00
{
2020-02-29 16:55:31 +00:00
if ( ! soundEngine - > IsSourcePlayingSomething ( SOURCE_Ambient , amb , CHAN_BODY ) )
2019-12-18 10:09:01 +00:00
{
2019-12-18 21:13:19 +00:00
// Check for special case ambient sounds. Since the sound is stopped and doesn't occupy a real channel at this time we can just swap out the sound ID before restarting it.
2020-02-29 16:55:31 +00:00
int ambid = RandomizeAmbientSpecials ( amb - > ambIndex ) ;
2019-12-18 21:13:19 +00:00
if ( ambid ! = - 1 )
2019-12-18 10:09:01 +00:00
{
2022-11-24 16:46:39 +00:00
amb - > vocIndex = FSoundID : : fromInt ( ambarray [ ambid ] . diginame ) ;
2021-12-25 15:30:22 +00:00
amb - > maxIndex = StdRandomRange ( ambarray [ ambid ] . maxtics ) ;
2019-12-19 00:20:43 +00:00
}
RestartAmbient ( amb ) ;
}
}
}
//==========================================================================
//
//
//
//==========================================================================
static void UpdateAmbients ( )
{
2020-11-22 17:16:08 +00:00
if ( ! SoundEnabled ( ) ) return ;
2019-12-19 00:20:43 +00:00
for ( auto & amb : ambients )
{
2021-12-24 23:36:05 +00:00
auto spot = amb - > spot ;
2022-11-24 16:46:39 +00:00
auto sdist = SoundDist ( spot - > spr . pos , voc [ amb - > vocIndex . index ( ) ] . voc_distance ) ;
2019-12-19 00:20:43 +00:00
2022-11-24 16:46:39 +00:00
if ( sdist < 255 & & amb - > vocIndex . index ( ) = = DIGI_WHIPME )
2019-12-19 00:20:43 +00:00
{
2021-12-31 14:59:11 +00:00
PLAYER * pp = Player + screenpeek ;
2022-11-23 09:59:15 +00:00
if ( ! FAFcansee ( spot - > spr . pos , spot - > sector ( ) , pp - > actor - > getPosWithOffsetZ ( ) , pp - > cursector ) )
2019-12-19 00:20:43 +00:00
{
sdist = 255 ;
2019-12-18 10:09:01 +00:00
}
2019-12-19 00:20:43 +00:00
}
if ( sdist < 255 )
{
if ( amb - > intermit ) DoTimedSound ( amb ) ;
else RestartAmbient ( amb ) ;
2019-12-18 21:13:19 +00:00
2019-12-19 00:20:43 +00:00
}
else
{
2020-02-23 14:41:57 +00:00
soundEngine - > StopSound ( SOURCE_Ambient , amb , - 1 ) ;
2019-12-18 10:09:01 +00:00
}
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
}
2015-05-19 21:54:34 +00:00
}
2019-12-19 00:20:43 +00:00
//==========================================================================
//
// end of ambient sounds
//
//==========================================================================
//==========================================================================
//
//
//
//==========================================================================
2021-11-28 09:24:42 +00:00
class SWSoundEngine : public RazeSoundEngine
2019-12-19 00:20:43 +00:00
{
// client specific parts of the sound engine go in this class.
void CalcPosVel ( int type , const void * source , const float pt [ 3 ] , int channum , int chanflags , FSoundID chanSound , FVector3 * pos , FVector3 * vel , FSoundChan * chan ) override ;
TArray < uint8_t > ReadSound ( int lumpnum ) override ;
public :
SWSoundEngine ( )
{
S_Rolloff . RolloffType = ROLLOFF_Doom ;
S_Rolloff . MinDistance = 0 ; // These are the default values, SW uses a few different rolloff settings.
S_Rolloff . MaxDistance = 1187 ;
}
2020-02-29 11:33:35 +00:00
2021-11-28 09:24:42 +00:00
bool SourceIsActor ( FSoundChan * chan ) override
{
return chan - > SourceType = = SOURCE_Actor | | chan - > SourceType = = SOURCE_Unattached ;
}
2020-02-29 11:33:35 +00:00
int SoundSourceIndex ( FSoundChan * chan ) override
{
2021-12-31 14:59:11 +00:00
if ( chan - > SourceType = = SOURCE_Player ) return int ( ( PLAYER * ) ( chan - > Source ) - Player ) ;
2020-02-29 11:33:35 +00:00
return 0 ;
}
void SetSource ( FSoundChan * chan , int index ) override
{
if ( chan - > SourceType = = SOURCE_Player )
{
if ( index < 0 | | index > = MAX_SW_PLAYERS_REG ) index = 0 ;
chan - > Source = & Player [ index ] ;
}
else chan - > Source = nullptr ;
}
2020-04-12 06:09:38 +00:00
void StopChannel ( FSoundChan * chan ) override
{
2021-07-10 12:25:18 +00:00
if ( chan & & chan - > SysChannel ! = nullptr & & ! ( chan - > ChanFlags & CHANF_EVICTED ) & & chan - > SourceType = = SOURCE_Actor )
2020-04-12 06:09:38 +00:00
{
2021-07-10 12:25:18 +00:00
chan - > Source = nullptr ;
2020-04-12 06:09:38 +00:00
chan - > SourceType = SOURCE_Unattached ;
}
SoundEngine : : StopChannel ( chan ) ;
}
2019-12-19 00:20:43 +00:00
} ;
//==========================================================================
//
//
//
//==========================================================================
TArray < uint8_t > SWSoundEngine : : ReadSound ( int lumpnum )
{
auto wlump = fileSystem . OpenFileReader ( lumpnum ) ;
return wlump . Read ( ) ;
}
//==========================================================================
//
//
//
//==========================================================================
2022-11-24 20:27:08 +00:00
void GameInterface : : StartSoundEngine ( )
{
soundEngine = new SWSoundEngine ;
}
2019-12-19 00:20:43 +00:00
void InitFX ( void )
{
auto & S_sfx = soundEngine - > GetSounds ( ) ;
S_sfx . Resize ( countof ( voc ) ) ;
for ( size_t i = 1 ; i < countof ( voc ) ; i + + )
{
auto & entry = voc [ i ] ;
2020-01-27 21:29:45 +00:00
auto lump = S_LookupSound ( entry . name ) ;
2019-12-19 00:20:43 +00:00
if ( lump > 0 )
{
auto & newsfx = S_sfx [ i ] ;
newsfx . name = entry . name ;
newsfx . lumpnum = lump ;
newsfx . NearLimit = 6 ;
newsfx . bTentative = false ;
}
}
soundEngine - > HashSounds ( ) ;
for ( auto & sfx : S_sfx )
{
soundEngine - > CacheSound ( & sfx ) ;
}
}
2015-05-19 21:54:34 +00:00
2019-12-18 21:13:19 +00:00
//==========================================================================
//
//
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-18 21:13:19 +00:00
void SWSoundEngine : : CalcPosVel ( int type , const void * source , const float pt [ 3 ] , int channum , int chanflags , FSoundID chanSound , FVector3 * pos , FVector3 * vel , FSoundChan * chan )
2019-12-18 10:09:01 +00:00
{
2019-12-18 21:13:19 +00:00
if ( pos ! = nullptr )
2015-05-19 21:54:34 +00:00
{
2021-12-31 14:59:11 +00:00
PLAYER * pp = Player + screenpeek ;
2022-11-23 09:59:15 +00:00
FVector3 campos = GetSoundPos ( pp - > actor ? pp - > actor - > getPosWithOffsetZ ( ) : DVector3 ( ) ) ;
2022-08-21 15:42:53 +00:00
DVector3 vPos = { } ;
2022-02-02 23:20:57 +00:00
bool pancheck = false ;
2015-05-19 21:54:34 +00:00
2019-12-18 21:13:19 +00:00
if ( vel ) vel - > Zero ( ) ;
2015-05-19 21:54:34 +00:00
2019-12-18 21:13:19 +00:00
if ( type = = SOURCE_Unattached )
2019-12-18 10:09:01 +00:00
{
2019-12-18 21:13:19 +00:00
pos - > X = pt [ 0 ] ;
pos - > Y = pt [ 1 ] ;
pos - > Z = pt [ 2 ] ;
2019-12-18 10:09:01 +00:00
}
2019-12-18 21:13:19 +00:00
else if ( type = = SOURCE_Actor | | type = = SOURCE_Player )
2019-12-18 10:09:01 +00:00
{
2022-11-23 09:59:15 +00:00
vPos = type = = SOURCE_Actor ? ( ( DSWActor * ) source ) - > spr . pos : ( ( PLAYER * ) source ) - > actor - > getPosWithOffsetZ ( ) ;
2022-02-02 23:20:57 +00:00
pancheck = true ;
2022-08-21 15:42:53 +00:00
FVector3 npos = GetSoundPos ( vPos ) ;
2019-12-19 00:20:43 +00:00
* pos = npos ;
2022-10-01 07:39:49 +00:00
#if 0
if ( vel )
2019-12-19 00:20:43 +00:00
{
2022-10-01 07:39:49 +00:00
// We do not do doppler effects because none of these old games are set up for it.
2019-12-19 00:20:43 +00:00
if ( chan & & ! ( chanflags & ( CHANF_JUSTSTARTED | CHANF_EVICTED ) ) )
{
* vel = ( npos - FVector3 ( pt [ 0 ] , pt [ 1 ] , pt [ 2 ] ) ) * 40 ; // SW ticks 40 times a second.
chan - > Point [ 0 ] = npos . X ;
chan - > Point [ 1 ] = npos . Y ;
chan - > Point [ 2 ] = npos . Z ;
}
}
2022-10-01 07:39:49 +00:00
# endif
2019-12-19 00:20:43 +00:00
}
else if ( type = = SOURCE_Ambient )
{
2021-12-24 23:36:05 +00:00
auto spot = ( ( AmbientSound * ) source ) - > spot ;
2022-08-21 15:42:53 +00:00
vPos = spot - > spr . pos ;
FVector3 npos = GetSoundPos ( vPos ) ;
2022-02-02 23:20:57 +00:00
pancheck = true ;
2015-05-19 21:54:34 +00:00
2019-12-18 21:13:19 +00:00
// Can the ambient sound see the player? If not, tone it down some.
2019-12-19 00:20:43 +00:00
if ( ( chanflags & CHANF_LOOP ) )
2019-12-18 10:09:01 +00:00
{
2022-11-23 09:59:15 +00:00
if ( ! FAFcansee ( vPos , spot - > sector ( ) , pp - > actor - > getPosWithOffsetZ ( ) , pp - > cursector ) )
2019-12-18 10:09:01 +00:00
{
2019-12-18 21:13:19 +00:00
auto distvec = npos - campos ;
npos = campos + distvec * 1.75f ; // Play more quietly
2019-12-18 10:09:01 +00:00
}
}
2019-12-19 00:20:43 +00:00
* pos = npos ;
}
2015-05-19 21:54:34 +00:00
2022-02-02 23:20:57 +00:00
if ( pancheck & & chanflags & CHANEXF_DONTPAN )
2019-12-19 00:20:43 +00:00
{
// For unpanned sounds the volume must be set directly and the position taken from the listener.
* pos = campos ;
2022-11-24 16:46:39 +00:00
auto sdist = SoundDist ( vPos , voc [ chanSound . index ( ) ] . voc_distance ) ;
2019-12-19 00:20:43 +00:00
if ( chan ) SetVolume ( chan , ( 255 - sdist ) * ( 1 / 255.f ) ) ;
2015-05-19 21:54:34 +00:00
}
2019-12-19 00:20:43 +00:00
2020-03-01 08:18:23 +00:00
if ( ( chanflags & CHANF_LISTENERZ ) & & type ! = SOURCE_None )
2019-12-18 10:09:01 +00:00
{
2019-12-18 21:13:19 +00:00
pos - > Y = campos . Y ;
2019-12-18 10:09:01 +00:00
}
}
2015-05-19 21:54:34 +00:00
}
2019-12-18 21:13:19 +00:00
//==========================================================================
//
// Main function to update 3D sound array
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2020-08-29 22:55:49 +00:00
void GameInterface : : UpdateSounds ( void )
2019-12-18 21:13:19 +00:00
{
2021-12-31 14:59:11 +00:00
PLAYER * pp = Player + screenpeek ;
2019-12-18 22:18:23 +00:00
SoundListener listener ;
2022-08-27 04:49:14 +00:00
DAngle tang ;
2021-12-13 12:24:33 +00:00
if ( pp - > sop_remote )
{
2021-12-24 23:45:19 +00:00
DSWActor * rsp = pp - > remoteActor ;
2021-12-13 12:24:33 +00:00
if ( TEST_BOOL1 ( rsp ) )
2022-08-28 03:15:31 +00:00
tang = rsp - > spr . angle ;
2021-12-13 12:24:33 +00:00
else
2022-11-23 07:20:46 +00:00
tang = ( pp - > sop_remote - > pmid . XY ( ) - pp - > actor - > spr . pos . XY ( ) ) . Angle ( ) ;
2021-12-13 12:24:33 +00:00
}
2022-08-27 13:09:22 +00:00
else tang = pp - > angle . ang ;
2021-12-13 12:24:33 +00:00
2022-08-27 04:49:14 +00:00
listener . angle = float ( - tang . Radians ( ) ) ;
2019-12-18 22:18:23 +00:00
listener . velocity . Zero ( ) ;
2022-11-23 09:59:15 +00:00
listener . position = GetSoundPos ( pp - > actor ? pp - > actor - > getPosWithOffsetZ ( ) : DVector3 ( ) ) ;
2019-12-18 22:18:23 +00:00
listener . underwater = false ;
// This should probably use a real environment instead of the pitch hacking in S_PlaySound3D.
// listenactor->waterlevel == 3;
//assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber);
listener . Environment = 0 ; // primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment;
listener . valid = true ;
listener . ListenerObject = pp ;
soundEngine - > SetListener ( listener ) ;
2019-12-19 00:20:43 +00:00
UpdateAmbients ( ) ;
2019-12-18 21:13:19 +00:00
}
2015-05-19 21:54:34 +00:00
2019-12-18 18:17:37 +00:00
//==========================================================================
//
2015-05-19 21:54:34 +00:00
// Play a sound
2019-12-18 18:17:37 +00:00
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2022-09-05 23:05:29 +00:00
int _PlaySound ( int num , DSWActor * actor , PLAYER * pp , const DVector3 * const ppos , int flags , int channel , EChanFlags cflags )
2015-05-19 21:54:34 +00:00
{
2022-11-24 16:46:39 +00:00
if ( Prediction | | ! SoundEnabled ( ) | | ! soundEngine - > isValidSoundId ( FSoundID : : fromInt ( num ) ) )
2019-12-19 00:20:43 +00:00
return - 1 ;
2015-05-19 21:54:34 +00:00
2021-11-28 10:34:29 +00:00
auto sps = actor ;
2022-09-05 23:05:29 +00:00
auto pos = ppos ? * ppos : DVector3 ( 0 , 0 , 0 ) ;
2015-05-19 21:54:34 +00:00
2019-12-19 00:20:43 +00:00
auto vp = & voc [ num ] ;
int sourcetype = SOURCE_None ;
2020-02-16 19:08:04 +00:00
cflags | = channel = = 8 ? CHANF_OVERLAP : CHANF_NONE ; // for the default channel we do not want to have sounds stopping each other.
2019-12-19 00:20:43 +00:00
void * source = nullptr ;
2022-10-01 07:39:49 +00:00
// If the sound is not supposed to be positioned, it may not be linked to the launching actor.
2022-10-01 14:09:53 +00:00
if ( ! ( flags & v3df_follow ) ) // use if this is so intermittent that using the flag would break 3D sound.
2015-05-19 21:54:34 +00:00
{
2022-02-01 23:00:54 +00:00
if ( actor & & ! ppos )
2019-12-18 10:09:01 +00:00
{
2022-09-05 23:05:29 +00:00
pos = actor - > spr . pos ;
2021-11-28 10:34:29 +00:00
actor = nullptr ;
2022-10-08 12:50:00 +00:00
sourcetype = SOURCE_Unattached ;
2019-12-18 10:09:01 +00:00
}
2022-02-01 23:00:54 +00:00
else if ( pp & & ! ppos )
2019-12-18 18:17:37 +00:00
{
2022-11-23 09:59:15 +00:00
pos = pp - > actor - > getPosWithOffsetZ ( ) ;
2019-12-19 00:20:43 +00:00
pp = nullptr ;
2022-10-08 12:50:00 +00:00
sourcetype = SOURCE_Unattached ;
2019-12-18 10:09:01 +00:00
}
2019-12-19 00:20:43 +00:00
}
2015-05-19 21:54:34 +00:00
2022-02-01 23:00:54 +00:00
if ( ppos ! = nullptr )
2019-12-19 00:20:43 +00:00
{
sourcetype = SOURCE_Unattached ;
}
2021-11-28 10:34:29 +00:00
else if ( actor ! = nullptr )
2019-12-19 00:20:43 +00:00
{
2021-11-28 10:34:29 +00:00
source = actor ;
2019-12-19 00:20:43 +00:00
sourcetype = SOURCE_Actor ;
}
else if ( pp ! = nullptr )
{
source = pp ;
sourcetype = SOURCE_Player ;
}
// Otherwise it's an unpositioned sound.
2019-12-18 18:17:37 +00:00
2022-10-01 07:39:49 +00:00
//if (flags & v3df_doppler) cflags |= EChanFlags::FromInt(CHANEXF_NODOPPLER); // intentionally not implemented
//if (flags & v3df_dontpan) cflags |= EChanFlags::FromInt(CHANEXF_DONTPAN); // disabled due to poor use
2019-12-19 00:20:43 +00:00
if ( vp - > voc_flags & vf_loop ) cflags | = CHANF_LOOP ; // with the new sound engine these can just be started and don't have to be stopped ever.
2015-05-19 21:54:34 +00:00
2019-12-19 00:20:43 +00:00
int pitch = 0 ;
if ( vp - > pitch_hi < = vp - > pitch_lo ) pitch = vp - > pitch_lo ;
2021-12-25 15:30:22 +00:00
else if ( vp - > pitch_hi ! = vp - > pitch_lo ) pitch = vp - > pitch_lo + ( StdRandomRange ( vp - > pitch_hi - vp - > pitch_lo ) ) ;
2015-05-19 21:54:34 +00:00
2019-12-19 00:20:43 +00:00
auto rolloff = GetRolloff ( vp - > voc_distance ) ;
2022-02-01 23:00:54 +00:00
FVector3 spos = GetSoundPos ( pos ) ;
2022-11-24 16:46:39 +00:00
auto chan = soundEngine - > StartSound ( sourcetype , source , & spos , channel , cflags , FSoundID : : fromInt ( num ) , 1.f , ATTN_NORM , & rolloff , S_ConvertPitch ( pitch ) ) ;
2020-03-01 12:10:07 +00:00
if ( chan & & sourcetype = = SOURCE_Unattached ) chan - > Source = sps ; // needed for sound termination.
2019-12-18 18:17:37 +00:00
return 1 ;
2019-12-18 10:09:01 +00:00
}
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
//==========================================================================
//
//
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
void PlaySoundRTS ( int rts_num )
{
2020-12-08 16:16:50 +00:00
if ( SoundEnabled ( ) & & RTS_IsInitialized ( ) & & snd_speech )
2019-12-18 10:09:01 +00:00
{
auto sid = RTS_GetSoundID ( rts_num - 1 ) ;
2022-11-24 16:46:39 +00:00
if ( sid . isvalid ( ) )
2015-05-19 21:54:34 +00:00
{
2019-12-18 10:09:01 +00:00
soundEngine - > StartSound ( SOURCE_Unattached , nullptr , nullptr , CHAN_VOICE , 0 , sid , 0.8f , ATTN_NONE ) ;
}
}
}
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
//==========================================================================
//
//
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
void COVER_SetReverb ( int amt )
{
FX_SetReverb ( amt ) ;
}
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
//==========================================================================
//
// Deletes vocs in the 3D sound queue with no owners
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2021-10-31 17:10:59 +00:00
void DeleteNoSoundOwner ( DSWActor * actor )
2019-12-18 10:09:01 +00:00
{
2019-12-25 10:26:19 +00:00
if ( ! soundEngine ) return ;
2019-12-18 10:09:01 +00:00
soundEngine - > EnumerateChannels ( [ = ] ( FSoundChan * chan )
2015-05-19 21:54:34 +00:00
{
2021-12-13 12:17:25 +00:00
if ( chan - > Source = = actor & & chan - > ChanFlags & CHANF_LOOP )
2015-05-19 21:54:34 +00:00
{
2019-12-18 10:09:01 +00:00
soundEngine - > StopChannel ( chan ) ;
2015-05-19 21:54:34 +00:00
}
2019-12-18 10:09:01 +00:00
return false ;
} ) ;
2022-10-18 22:02:36 +00:00
// also delete all ambients attached to this actor.
for ( int i = ambients . Size ( ) - 1 ; i > = 0 ; i - - )
{
auto amb = ambients [ i ] ;
if ( amb - > spot = = actor )
{
soundEngine - > StopSound ( SOURCE_Ambient , amb , - 1 ) ;
ambients . Delete ( i ) ;
}
}
2019-12-18 10:09:01 +00:00
}
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
//==========================================================================
//
2021-11-02 23:14:09 +00:00
// This is called from KillSprite to kill a follow sound with no valid sprite Owner
2019-12-18 21:13:19 +00:00
// Stops any active sound with the follow bit set, even play once sounds.
2019-12-18 10:09:01 +00:00
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2021-11-06 08:40:22 +00:00
void DeleteNoFollowSoundOwner ( DSWActor * actor )
2019-12-18 10:09:01 +00:00
{
2021-12-24 23:45:19 +00:00
soundEngine - > StopSound ( SOURCE_Actor , actor , - 1 ) ; // all non-follow sounds are SOURCE_Unattached
2019-12-18 10:09:01 +00:00
}
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
//==========================================================================
//
// Terminate the sounds list
//
//==========================================================================
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
void Terminate3DSounds ( void )
2015-05-19 21:54:34 +00:00
{
2019-12-18 10:09:01 +00:00
soundEngine - > EnumerateChannels ( [ ] ( FSoundChan * chan )
{
if ( chan - > SourceType = = SOURCE_Actor | | chan - > SourceType = = SOURCE_Unattached | |
( chan - > SourceType = = SOURCE_Player & & chan - > EntChannel ! = CHAN_VOICE ) )
{
soundEngine - > StopChannel ( chan ) ;
}
return false ;
} ) ;
}
2015-05-19 21:54:34 +00:00
2019-12-18 10:09:01 +00:00
//==========================================================================
//
2015-05-19 21:54:34 +00:00
// Play a sound using special sprite setup
2019-12-18 10:09:01 +00:00
//
//==========================================================================
2021-12-31 21:36:56 +00:00
void PlaySpriteSound ( DSWActor * actor , int attrib_ndx , int flags )
2015-05-19 21:54:34 +00:00
{
2021-10-31 09:54:52 +00:00
if ( actor - > hasU ( ) )
2021-12-23 22:45:39 +00:00
PlaySound ( actor - > user . Attrib - > Sounds [ attrib_ndx ] , actor , flags ) ;
2019-12-18 10:09:01 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
2021-12-31 14:59:11 +00:00
int _PlayerSound ( int num , PLAYER * pp )
2019-12-18 10:09:01 +00:00
{
int handle ;
2021-12-31 12:31:13 +00:00
VOCstruct * vp ;
2019-12-18 10:09:01 +00:00
if ( Prediction )
return 0 ;
if ( pp < Player | | pp > = Player + MAX_SW_PLAYERS )
{
return 0 ;
}
2022-11-24 16:46:39 +00:00
if ( num < 0 | | num > = DIGI_MAX | | ! soundEngine - > isValidSoundId ( FSoundID : : fromInt ( num ) ) | | ! SoundEnabled ( ) )
2019-12-18 10:09:01 +00:00
return 0 ;
2021-12-27 18:34:06 +00:00
if ( pp - > Flags & ( PF_DEAD ) ) return 0 ; // You're dead, no talking!
2019-12-18 10:09:01 +00:00
// If this is a player voice and he's already yacking, forget it.
vp = & voc [ num ] ;
// Not a player voice, bail.
2020-10-23 20:53:02 +00:00
if ( vp - > priority ! = PRI_PLAYERVOICE & & vp - > priority ! = PRI_PLAYERDEATH & & vp - > priority ! = PRI_PLAYERSPEECH )
return 0 ;
// Don't talk if not allowed to.
if ( vp - > priority = = PRI_PLAYERSPEECH & & ! snd_speech )
2019-12-18 10:09:01 +00:00
return 0 ;
2020-02-29 08:30:12 +00:00
// The surfacing sound should not block other player speech.
2022-11-24 16:46:39 +00:00
if ( soundEngine - > IsSourcePlayingSomething ( SOURCE_Player , pp , CHAN_VOICE , FSoundID : : fromInt ( DIGI_SURFACE ) ) )
2020-02-29 08:30:12 +00:00
{
soundEngine - > StopSound ( SOURCE_Player , pp , CHAN_VOICE ) ;
}
2019-12-18 10:09:01 +00:00
// He wasn't talking, but he will be now.
if ( ! soundEngine - > IsSourcePlayingSomething ( SOURCE_Player , pp , CHAN_VOICE ) )
{
2022-11-24 16:46:39 +00:00
soundEngine - > StartSound ( SOURCE_Player , pp , nullptr , CHAN_VOICE , 0 , FSoundID : : fromInt ( num ) , 1.f , ATTN_NORM ) ;
2019-12-18 10:09:01 +00:00
}
return 0 ;
2015-05-19 21:54:34 +00:00
}
2021-12-31 14:59:11 +00:00
void StopPlayerSound ( PLAYER * pp , int which )
2019-12-18 10:09:01 +00:00
{
2022-11-24 16:46:39 +00:00
soundEngine - > StopSound ( SOURCE_Player , pp , CHAN_VOICE , FSoundID : : fromInt ( which ) ) ;
2019-12-18 10:09:01 +00:00
}
2019-12-17 20:33:53 +00:00
2021-11-28 10:34:29 +00:00
bool SoundValidAndActive ( DSWActor * spr , int channel )
2019-12-18 18:17:37 +00:00
{
return soundEngine - > IsSourcePlayingSomething ( SOURCE_Actor , spr , channel ) ;
}
2019-12-17 20:33:53 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
=
= High level sound code ( not directly engine related )
=
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
int PlayerPainVocs [ ] =
{
DIGI_PLAYERPAIN1 ,
DIGI_PLAYERPAIN2 ,
DIGI_PLAYERPAIN3 ,
DIGI_PLAYERPAIN4 ,
DIGI_PLAYERPAIN5
} ;
// Don't have these sounds yet
int PlayerLowHealthPainVocs [ ] =
{
DIGI_HURTBAD1 ,
DIGI_HURTBAD2 ,
DIGI_HURTBAD3 ,
DIGI_HURTBAD4 ,
DIGI_HURTBAD5
} ;
int TauntAIVocs [ ] =
{
DIGI_TAUNTAI1 ,
DIGI_TAUNTAI2 ,
DIGI_TAUNTAI3 ,
DIGI_TAUNTAI4 ,
DIGI_TAUNTAI5 ,
DIGI_TAUNTAI6 ,
DIGI_TAUNTAI7 ,
DIGI_TAUNTAI8 ,
DIGI_TAUNTAI9 ,
DIGI_TAUNTAI10 ,
DIGI_COWABUNGA ,
DIGI_NOCHARADE ,
DIGI_TIMETODIE ,
DIGI_EATTHIS ,
DIGI_FIRECRACKERUPASS ,
DIGI_HOLYCOW ,
DIGI_HAHA2 ,
DIGI_HOLYPEICESOFCOW ,
DIGI_HOLYSHIT ,
DIGI_HOLYPEICESOFSHIT ,
DIGI_PAYINGATTENTION ,
DIGI_EVERYBODYDEAD ,
DIGI_KUNGFU ,
DIGI_HOWYOULIKEMOVE ,
DIGI_HAHA3 ,
DIGI_NOMESSWITHWANG ,
DIGI_RAWREVENGE ,
DIGI_YOULOOKSTUPID ,
DIGI_TINYDICK ,
DIGI_NOTOURNAMENT ,
DIGI_WHOWANTSWANG ,
DIGI_MOVELIKEYAK ,
DIGI_ALLINREFLEXES
} ;
int PlayerGetItemVocs [ ] =
{
DIGI_GOTITEM1 ,
DIGI_HAHA1 ,
DIGI_BANZAI ,
DIGI_COWABUNGA ,
DIGI_TIMETODIE
} ;
int PlayerYellVocs [ ] =
{
DIGI_PLAYERYELL1 ,
DIGI_PLAYERYELL2 ,
DIGI_PLAYERYELL3
} ;
2019-12-17 22:25:07 +00:00
//==========================================================================
//
// PLays music
//
//==========================================================================
2019-12-17 20:33:53 +00:00
2021-05-11 23:58:42 +00:00
bool PlaySong ( const char * song_file_name , int cdaudio_track , bool isThemeTrack ) //(nullptr, nullptr, -1, false) starts the normal level music.
2019-12-17 20:33:53 +00:00
{
// Play CD audio if enabled.
2021-02-26 17:58:13 +00:00
if ( cdaudio_track > = 0 & & ( mus_redbook | | ! song_file_name | | * song_file_name = = 0 ) )
2019-12-17 20:33:53 +00:00
{
2021-03-12 22:15:34 +00:00
FStringf trackname ( " shadow%02d.ogg " , cdaudio_track ) ;
2021-05-11 23:58:42 +00:00
if ( ! Mus_Play ( trackname , true ) )
2019-12-17 20:33:53 +00:00
{
2021-03-12 22:15:34 +00:00
trackname . Format ( " track%02d.ogg " , cdaudio_track ) ;
2021-05-11 23:58:42 +00:00
if ( ! Mus_Play ( trackname , true ) )
2021-03-12 22:15:34 +00:00
{
Printf ( " Can't find CD track %i! \n " , cdaudio_track ) ;
}
2019-12-17 20:33:53 +00:00
}
2020-02-08 20:36:57 +00:00
else return true ;
2019-12-17 20:33:53 +00:00
}
2021-02-26 17:58:13 +00:00
if ( ! song_file_name | | * song_file_name = = 0 )
{
return true ;
}
2021-05-11 23:58:42 +00:00
if ( ! Mus_Play ( song_file_name , true ) )
2019-12-26 12:04:29 +00:00
{
2020-05-22 21:02:25 +00:00
// try the CD track anyway if no MIDI could be found (the original game doesn't have any MIDI, it was CD Audio only, this avoids no music playing if mus_redbook is off.)
2021-03-12 22:15:34 +00:00
FStringf trackname ( " shadow%02d.ogg " , cdaudio_track ) ;
2021-05-11 23:58:42 +00:00
if ( ! Mus_Play ( trackname , true ) )
2021-03-12 22:15:34 +00:00
{
trackname . Format ( " track%02d.ogg " , cdaudio_track ) ;
2021-05-11 23:58:42 +00:00
if ( ! Mus_Play ( trackname , true ) ) return false ;
2021-03-12 22:15:34 +00:00
}
2019-12-26 12:04:29 +00:00
}
return true ;
2019-12-17 20:33:53 +00:00
}
2019-12-18 18:17:37 +00:00
void StopSound ( void )
{
2019-12-25 10:26:19 +00:00
// This gets also called on shutdown.
2020-02-13 23:52:57 +00:00
StopAmbientSound ( ) ;
2019-12-25 10:26:19 +00:00
if ( soundEngine ) soundEngine - > StopAllChannels ( ) ;
2019-12-18 18:17:37 +00:00
Mus_Stop ( ) ;
}
2020-02-11 18:28:25 +00:00
void StopFX ( )
{
2020-02-13 23:52:57 +00:00
StopAmbientSound ( ) ;
2020-02-11 18:28:25 +00:00
if ( soundEngine ) soundEngine - > StopAllChannels ( ) ;
}
2021-04-28 22:56:36 +00:00
DEFINE_ACTION_FUNCTION ( _SW , PlaySound )
{
PARAM_PROLOGUE ;
PARAM_INT ( sound ) ;
PARAM_INT ( vflags ) ;
PARAM_INT ( channel ) ;
PARAM_INT ( cflags ) ;
2021-12-31 21:36:56 +00:00
PlaySound ( sound , vflags , channel , EChanFlags : : FromInt ( cflags ) ) ;
2021-04-28 22:56:36 +00:00
return 0 ;
}
DEFINE_ACTION_FUNCTION_NATIVE ( _SW , StopSound , StopSound )
{
StopSound ( ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( _SW , IsSoundPlaying )
{
PARAM_PROLOGUE ;
PARAM_INT ( channel ) ;
ACTION_RETURN_BOOL ( soundEngine - > IsSourcePlayingSomething ( SOURCE_None , nullptr , channel ) ) ;
}
DEFINE_ACTION_FUNCTION ( _SW , PlaySong )
{
PARAM_PROLOGUE ;
PARAM_INT ( song ) ;
2021-05-11 23:58:42 +00:00
PlaySong ( ThemeSongs [ song ] , ThemeTrack [ song ] , true ) ;
2021-04-28 22:56:36 +00:00
return 0 ;
}
2019-12-17 20:33:53 +00:00
2019-10-09 16:09:05 +00:00
END_SW_NS