This thread contains a patchset. You're looking at the original emails,
but you may wish to use the patch review UI.
Review patch
3
[PATCH 0/3] sounds.lst
This adds an ability for mods developers to override hardcoded sounds
with custom ones.
Alibek Omarov (3):
engine: add basic sounds.lst implementation
engine: client: use soundlist to acquire random sounds for temp
entities
engine: server: use soundlist to acquire random sounds for physics
Documentation/extensions/sounds.lst.md | 66 ++++++
engine/client/cl_tent.c | 124 ++++++-----
engine/common/common.h | 28 +++
engine/common/host.c | 2 +
engine/common/sounds.c | 272 +++++++++++++++++++++++++
engine/server/sv_move.c | 36 +---
engine/server/sv_phys.c | 8 +-
7 files changed, 438 insertions(+), 98 deletions(-)
create mode 100644 Documentation/extensions/sounds.lst.md
create mode 100644 engine/common/sounds.c
--
2.34.1
[PATCH 1/3] engine: add basic sounds.lst implementation
---
Documentation/extensions/sounds.lst.md | 66 ++++++
engine/common/common.h | 28 +++
engine/common/host.c | 2 +
engine/common/sounds.c | 272 +++++++++++++++++++++++++
4 files changed, 368 insertions(+)
create mode 100644 Documentation/extensions/sounds.lst.md
create mode 100644 engine/common/sounds.c
diff --git a/Documentation/extensions/sounds.lst.md b/Documentation/extensions/sounds.lst.md
new file mode 100644
index 00000000..77104d44
--- /dev/null
+++ b/Documentation/extensions/sounds.lst.md
@@ -0,0 +1,66 @@
+# sounds.lst.md
+
+Using sounds.lst located in scripts folder, modder can override some of the hardcoded sounds in temp entities and server physics.
+
+File format:
+```
+<group name>
+{
+ <path1>
+ <path2>
+ <path3>
+}
+
+<group2 name> <path with %d> <min number> <max number>
+```
+
+* Sounds can use any supported sound format (WAV or MP3).
+* The path must be relative to the sounds/ folder in the game or base directory root, addon folder, or archive root.
+* Groups can be empty or omitted from the file to load no sound.
+* Groups can either list a set of files or specify a format string and a range.
+* Anything after // will be considered a comment and ignored.
+* Behavior is undefined if the group was listed multiple times.
+
+Currently supported groups are:
+|Group name|Usage|
+|----------|-----|
+|`BouncePlayerShell`|Used for BOUNCE_SHELL tempentity hitsound|
+|`BounceWeaponShell`|Used for BOUCNE_SHOTSHELL tempentity hitsound|
+|`BounceConcrete`|Used for BOUNCE_CONCRETE tempentity hitsound|
+|`BounceGlass`|Used for BOUCNE_GLASS|
+|`BounceMetal`|Used for BOUNCE_METAL|
+|`BounceFlesh`|Used for BOUNCE_FLESH|
+|`BounceWood`|Used for BOUNCE_WOOD|
+|`Ricochet`|Used for BOUNCE_SHRAP and ricochet tempentities|
+|`Explode`|Used for tempentity explosions|
+|`EntityWaterEnter`|Used for entity entering water|
+|`EntityWaterExit`|Used for entity exiting water|
+|`PlayerWaterEnter`|Used for player entering water|
+|`PlayerWaterExit`|Used for player exiting water|
+
+## Example
+
+This example is based on defaults sounds used in Half-Life:
+
+```
+BouncePlayerShell "player/pl_shell%d.wav" 1 3
+BounceWeaponShell "weapons/sshell%d.wav" 1 3
+BounceConcrete "debris/concrete%d.wav" 1 3
+BounceGlass "debris/glass%d.wav" 1 4
+BounceMetal "debris/metal%d.wav" 1 6
+BounceFlesh "debris/flesh%d.wav" 1 7
+BounceWood "debris/wood%d.wav" 1 4
+Ricochet "weapons/ric%d.wav" 1 5
+Explode "weapons/explode%d" 3 5
+EntityWaterEnter "player/pl_wade%d.wav" 1 4
+EntityWaterExit "player/pl_wade%d.wav" 1 4
+PlayerWaterEnter
+{
+ "player/pl_wade1.wav"
+}
+
+PlayerWaterExit
+{
+ "player/pl_wade2.wav"
+}
+```
diff --git a/engine/common/common.h b/engine/common/common.h
index 26c02c62..31f1bc8c 100644
--- a/engine/common/common.h
+++ b/engine/common/common.h
@@ -815,6 +815,34 @@ void NET_MasterClear( void );
void NET_MasterShutdown( void );
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
+//
+// sounds.c
+//
+typedef enum soundlst_group_e
+{
+ BouncePlayerShell = 0,
+ BounceWeaponShell,
+ BounceConcrete,
+ BounceGlass,
+ BounceMetal,
+ BounceFlesh,
+ BounceWood,
+ Ricochet,
+ Explode,
+ PlayerWaterEnter,
+ PlayerWaterExit,
+ EntityWaterEnter,
+ EntityWaterExit,
+
+ SoundList_Groups // must be last
+} soundlst_group_t;
+
+int SoundList_Count( soundlst_group_t group );
+const char *SoundList_GetRandom( soundlst_group_t group );
+const char *SoundList_Get( soundlst_group_t group, int idx );
+void SoundList_Init( void );
+void SoundList_Shutdown( void );
+
#ifdef REF_DLL
#error "common.h in ref_dll"
#endif
diff --git a/engine/common/host.c b/engine/common/host.c
index f990f1cc..65ae4267 100644
--- a/engine/common/host.c
+++ b/engine/common/host.c
@@ -1310,6 +1310,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
HTTP_Init();
ID_Init();
+ SoundList_Init();
if( Host_IsDedicated() )
{
@@ -1412,6 +1413,7 @@ void EXPORT Host_Shutdown( void )
SV_ShutdownFilter();
CL_Shutdown();
+ SoundList_Shutdown();
Mod_Shutdown();
NET_Shutdown();
HTTP_Shutdown();
diff --git a/engine/common/sounds.c b/engine/common/sounds.c
new file mode 100644
index 00000000..b1e3ed27
--- /dev/null
+++ b/engine/common/sounds.c
@@ -0,0 +1,272 @@
+/*
+sounds.c - sounds.lst parser
+Copyright (C) 2024 Alibek Omarov
+
+This program 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 3 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.
+*/
+#include "common.h"
+
+enum soundlst_type_e
+{
+ SoundList_None,
+ SoundList_Range,
+ SoundList_List
+};
+
+static const char *soundlst_groups[SoundList_Groups] =
+{
+ "BouncePlayerShell",
+ "BounceWeaponShell",
+ "BounceConcrete",
+ "BounceGlass",
+ "BounceMetal",
+ "BounceFlesh",
+ "BounceWood",
+ "Ricochet",
+ "Explode",
+ "PlayerWaterEnter",
+ "PlayerWaterExit",
+ "EntityWaterEnter",
+ "EntityWaterExit",
+};
+
+typedef struct soundlst_s
+{
+ enum soundlst_type_e type;
+ char *snd;
+ int min; // the string length if type is group
+ int max; // the string count if type is group
+} soundlst_t;
+
+soundlst_t soundlst[SoundList_Groups];
+
+static void SoundList_Free( soundlst_t *lst )
+{
+ if( lst->snd )
+ {
+ Mem_Free( lst->snd );
+ lst->snd = NULL;
+ }
+
+ lst->min = lst->max = 0;
+ lst->type = SoundList_None;
+}
+
+void SoundList_Shutdown( void )
+{
+ int i;
+
+ for( i = 0; i < SoundList_Groups; i++ )
+ SoundList_Free( &soundlst[i] );
+}
+
+int SoundList_Count( enum soundlst_group_e group )
+{
+ soundlst_t *lst = &soundlst[group];
+
+ switch( lst->type )
+ {
+ case SoundList_Range:
+ return lst->max - lst->min + 1;
+ case SoundList_List:
+ return lst->max;
+ }
+
+ return 0;
+}
+
+const char *SoundList_Get( enum soundlst_group_e group, int i )
+{
+ static string temp;
+ soundlst_t *lst = &soundlst[group];
+
+ if( i < 0 || i >= SoundList_Count( group ))
+ return NULL;
+
+ switch( lst->type )
+ {
+ case SoundList_Range:
+ Q_snprintf( temp, sizeof( temp ), lst->snd, lst->min + i );
+ return temp;
+ case SoundList_List:
+ return &lst->snd[i * lst->min];
+ }
+
+ return NULL;
+}
+
+const char *SoundList_GetRandom( enum soundlst_group_e group )
+{
+ int count = SoundList_Count( group );
+ int idx = COM_RandomLong( 0, count - 1 );
+
+ return SoundList_Get( group, idx );
+}
+
+static qboolean SoundList_ParseGroup( soundlst_t *lst, char **file )
+{
+ string token;
+ int count = 0, slen = 0, i;
+ char *p;
+
+ p = *file;
+
+ for( ; p && *p; count++, p = COM_ParseFile( p, token, sizeof( token )))
+ {
+ int len = Q_strlen( token ) + 1;
+ if( slen < len )
+ slen = len;
+
+ if( !Q_strcmp( token, "}" ))
+ break;
+
+ if( !Q_strcmp( token, "{" ))
+ {
+ Con_Printf( "%s: expected '}' but got '{' during group list parse\n", __func__ );
+ return false;
+ }
+ else if( !COM_CheckStringEmpty( token ))
+ {
+ Con_Printf( "%s: expected '}' but got EOF during group list parse\n", __func__ );
+ return false;
+ }
+ }
+
+ lst->type = SoundList_List;
+ lst->min = slen;
+ lst->max = count;
+ lst->snd = Mem_Malloc( host.mempool, count * slen ); // allocate single buffer for the whole group
+
+ for( i = 0; i < count; i++ )
+ {
+ *file = COM_ParseFile( *file, token, sizeof( token ));
+
+ Q_strncpy( &lst->snd[i * slen], token, slen );
+ }
+
+ return true;
+}
+
+static qboolean SoundList_ParseRange( soundlst_t *lst, char **file )
+{
+ string token, snd;
+ char *p;
+ int i;
+
+ lst->type = SoundList_Range;
+ *file = COM_ParseFile( *file, snd, sizeof( snd ));
+
+ // validate format string
+ for( i = 0, p = snd; p; i++, p = Q_strchr( p, '%' ));
+ if( i != 1 )
+ {
+ Con_Printf( "%s: invalid range string %s\n", __func__, snd );
+ return false;
+ }
+
+ *file = COM_ParseFile( *file, token, sizeof( token ));
+ if( !Q_isdigit( token ))
+ {
+ Con_Printf( "%s: %s must be a digit\n", __func__, token );
+ return false;
+ }
+ lst->min = Q_atoi( token );
+
+ *file = COM_ParseFile( *file, token, sizeof( token ));
+ if( !Q_isdigit( token ))
+ {
+ Con_Printf( "%s: %s must be a digit\n", __func__, token );
+ return false;
+ }
+ lst->max = Q_atoi( token );
+ lst->snd = copystring( snd );
+
+ return true;
+}
+
+static qboolean SoundList_Parse( char *file )
+{
+ string token;
+ string name;
+ int i;
+
+ while( file && *file )
+ {
+ const char *group;
+ soundlst_t *lst = NULL;
+ file = COM_ParseFile( file, token, sizeof( token ));
+
+ for( i = 0; i < SoundList_Groups; i++ )
+ {
+ if( !Q_strcmp( token, soundlst_groups[i] ))
+ lst = &soundlst[i];
+ }
+
+ if( !lst )
+ {
+ Con_Printf( "%s: unexpected token %s, must be group name\n", __func__, token );
+ goto cleanup;
+ }
+
+ file = COM_ParseFile( file, token, sizeof( token ));
+
+ // group is a range
+ if( Q_strcmp( token, "{" ))
+ {
+ if( !SoundList_ParseRange( lst, &file ))
+ goto cleanup;
+ }
+ else
+ {
+ if( !SoundList_ParseGroup( lst, &file ))
+ goto cleanup;
+ }
+ }
+
+ return true;
+
+cleanup:
+ SoundList_Shutdown();
+ return false;
+}
+
+// I wish we had #embed already
+static const char default_sounds_lst[] =
+"BouncePlayerShell \"player/pl_shell%d.wav\" 1 3\n"
+"BounceWeaponShell \"weapons/sshell%d.wav\" 1 3\n"
+"BounceConcrete \"debris/concrete%d.wav\" 1 3\n"
+"BounceGlass \"debris/glass%d.wav\" 1 4\n"
+"BounceMetal \"debris/metal%d.wav\" 1 6\n"
+"BounceFlesh \"debris/flesh%d.wav\" 1 7\n"
+"BounceWood \"debris/wood%d.wav\" 1 4\n"
+"Ricochet \"weapons/ric%d.wav\" 1 5\n"
+"Explode \"weapons/explode%d\" 3 5\n"
+"EntityWaterEnter \"player/pl_wade%d.wav\" 1 4\n"
+"EntityWaterExit \"player/pl_wade%d.wav\" 1 4\n"
+"PlayerWaterEnter\n"
+"{\n"
+" \"player/pl_wade1.wav\"\n"
+"}\n"
+"\n"
+"PlayerWaterExit\n"
+"{\n"
+" \"player/pl_wade2.wav\"\n"
+"}\n";
+
+void SoundList_Init( void )
+{
+ char *pfile;
+
+ pfile = FS_LoadFile( "scripts/sounds.lst", NULL, false );
+
+ if( !pfile || !SoundList_Parse( pfile ))
+ SoundList_Parse( (char *)default_sounds_lst );
+}
--
2.34.1
[PATCH 2/3] engine: client: use soundlist to acquire random sounds for temp entities
---
engine/client/cl_tent.c | 124 +++++++++++++++++++---------------------
1 file changed, 58 insertions(+), 66 deletions(-)
diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c
index 7023a7f9..86235c3d 100644
--- a/engine/client/cl_tent.c
+++ b/engine/client/cl_tent.c
@@ -57,36 +57,6 @@ const char *cl_default_sprites[] =
"sprites/shellchrome.spr",
};
-const char *cl_player_shell_sounds[] =
-{
- "player/pl_shell1.wav",
- "player/pl_shell2.wav",
- "player/pl_shell3.wav",
-};
-
-const char *cl_weapon_shell_sounds[] =
-{
- "weapons/sshell1.wav",
- "weapons/sshell2.wav",
- "weapons/sshell3.wav",
-};
-
-const char *cl_ricochet_sounds[] =
-{
- "weapons/ric1.wav",
- "weapons/ric2.wav",
- "weapons/ric3.wav",
- "weapons/ric4.wav",
- "weapons/ric5.wav",
-};
-
-const char *cl_explode_sounds[] =
-{
- "weapons/explode3.wav",
- "weapons/explode4.wav",
- "weapons/explode5.wav",
-};
-
static void CL_PlayerDecal( int playerIndex, int textureIndex, int entityIndex, float *pos );
/*
@@ -148,6 +118,7 @@ client resources not precached by server
*/
void CL_AddClientResources( void )
{
+ const char *snd;
char filepath[MAX_QPATH];
int i;
@@ -163,37 +134,37 @@ void CL_AddClientResources( void )
}
// then check sounds
- for( i = 0; i < ARRAYSIZE( cl_player_shell_sounds ); i++ )
+ for( i = 0; ( snd = SoundList_Get( BouncePlayerShell, i )); i++ )
{
- Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_player_shell_sounds[i] );
+ Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
- CL_AddClientResource( cl_player_shell_sounds[i], t_sound );
+ CL_AddClientResource( snd, t_sound );
}
- for( i = 0; i < ARRAYSIZE( cl_weapon_shell_sounds ); i++ )
+ for( i = 0; ( snd = SoundList_Get( BounceWeaponShell, i )); i++ )
{
- Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_weapon_shell_sounds[i] );
+ Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
- CL_AddClientResource( cl_weapon_shell_sounds[i], t_sound );
+ CL_AddClientResource( snd, t_sound );
}
- for( i = 0; i < ARRAYSIZE( cl_explode_sounds ); i++ )
+ for( i = 0; ( snd = SoundList_Get( Explode, i )); i++ )
{
- Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_explode_sounds[i] );
+ Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
- CL_AddClientResource( cl_explode_sounds[i], t_sound );
+ CL_AddClientResource( snd, t_sound );
}
#if 0 // ric sounds was precached by server-side
- for( i = 0; i < ARRAYSIZE( cl_ricochet_sounds ); i++ )
+ for( i = 0; ( snd = SoundList_Get( Ricochet, i )); i++ )
{
- Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_ricochet_sounds[i] );
+ Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
- CL_AddClientResource( cl_ricochet_sounds[i], t_sound );
+ CL_AddClientResource( snd, t_sound );
}
#endif
}
@@ -301,7 +272,7 @@ play collide sound
static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
{
float fvol;
- char soundname[32];
+ const char *soundname = NULL;
qboolean isshellcasing = false;
int zvel;
@@ -312,36 +283,39 @@ static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
switch( pTemp->hitSound )
{
case BOUNCE_GLASS:
- Q_snprintf( soundname, sizeof( soundname ), "debris/glass%i.wav", COM_RandomLong( 1, 4 ));
+ soundname = SoundList_GetRandom( BounceGlass );
break;
case BOUNCE_METAL:
- Q_snprintf( soundname, sizeof( soundname ), "debris/metal%i.wav", COM_RandomLong( 1, 6 ));
+ soundname = SoundList_GetRandom( BounceMetal );
break;
case BOUNCE_FLESH:
- Q_snprintf( soundname, sizeof( soundname ), "debris/flesh%i.wav", COM_RandomLong( 1, 7 ));
+ soundname = SoundList_GetRandom( BounceFlesh );
break;
case BOUNCE_WOOD:
- Q_snprintf( soundname, sizeof( soundname ), "debris/wood%i.wav", COM_RandomLong( 1, 4 ));
+ soundname = SoundList_GetRandom( BounceWood );
break;
case BOUNCE_SHRAP:
- Q_strncpy( soundname, cl_ricochet_sounds[COM_RandomLong( 0, 4 )], sizeof( soundname ) );
+ soundname = SoundList_GetRandom( Ricochet );
break;
case BOUNCE_SHOTSHELL:
- Q_strncpy( soundname, cl_weapon_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) );
+ soundname = SoundList_GetRandom( BounceWeaponShell );
isshellcasing = true; // shell casings have different playback parameters
fvol = 0.5f;
break;
case BOUNCE_SHELL:
- Q_strncpy( soundname, cl_player_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) );
+ soundname = SoundList_GetRandom( BouncePlayerShell );
isshellcasing = true; // shell casings have different playback parameters
break;
case BOUNCE_CONCRETE:
- Q_snprintf( soundname, sizeof( soundname ), "debris/concrete%i.wav", COM_RandomLong( 1, 3 ));
+ soundname = SoundList_GetRandom( BounceConcrete );
break;
default: // null sound
return;
}
+ if( !soundname )
+ return;
+
zvel = abs( pTemp->entity.baseline.origin[2] );
// only play one out of every n
@@ -1491,7 +1465,7 @@ void GAME_EXPORT R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
===============
R_SparkEffect
-Create a streaks + richochet sprite
+Create a streaks + ricochet sprite
===============
*/
void GAME_EXPORT R_SparkEffect( const vec3_t pos, int count, int velocityMin, int velocityMax )
@@ -1507,18 +1481,25 @@ R_RicochetSound
Make a random ricochet sound
==============
*/
-static void R_RicochetSound_( const vec3_t pos, int sound )
+static void R_RicochetSoundByName( const vec3_t pos, const char *name )
{
- sound_t handle;
-
- handle = S_RegisterSound( cl_ricochet_sounds[sound] );
-
+ sound_t handle;
+ handle = S_RegisterSound( name );
S_StartSound( pos, 0, CHAN_AUTO, handle, VOL_NORM, 1.0, 100, 0 );
}
+static void R_RicochetSoundByIndex( const vec3_t pos, int idx )
+{
+ const char *name = SoundList_Get( Ricochet, idx );
+ if( name )
+ R_RicochetSoundByName( pos, name );
+}
+
void GAME_EXPORT R_RicochetSound( const vec3_t pos )
{
- R_RicochetSound_( pos, COM_RandomLong( 0, 4 ));
+ const char *name = SoundList_GetRandom( Ricochet );
+ if( name )
+ R_RicochetSoundByName( pos, name );
}
/*
@@ -1665,8 +1646,12 @@ void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerat
if( !FBitSet( flags, TE_EXPLFLAG_NOSOUND ))
{
- hSound = S_RegisterSound( cl_explode_sounds[COM_RandomLong( 0, 2 )] );
- S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
+ const char *name = SoundList_GetRandom( Explode );
+ if( name )
+ {
+ hSound = S_RegisterSound( name );
+ S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
+ }
}
}
@@ -1909,6 +1894,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
cl_entity_t *pEnt;
dlight_t *dl;
sound_t hSound;
+ const char *name;
if( cls.legacymode )
iSize = MSG_ReadByte( msg );
@@ -1968,8 +1954,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
pos[2] = MSG_ReadCoord( &buf );
R_BlobExplosion( pos );
- hSound = S_RegisterSound( cl_explode_sounds[0] );
- S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
+ if(( name = SoundList_Get( Explode, 0 )))
+ {
+ hSound = S_RegisterSound( name );
+ S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
+ }
break;
case TE_SMOKE:
pos[0] = MSG_ReadCoord( &buf );
@@ -2022,8 +2011,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
dl->die = cl.time + 0.5;
dl->decay = 300;
- hSound = S_RegisterSound( cl_explode_sounds[0] );
- S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 );
+ if(( name = SoundList_Get( Explode, 0 )))
+ {
+ hSound = S_RegisterSound( name );
+ S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
+ }
break;
case TE_BSPDECAL:
case TE_DECAL:
@@ -2251,8 +2243,8 @@ void CL_ParseTempEntity( sizebuf_t *msg )
CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, 0, pos, 0 );
R_BulletImpactParticles( pos );
flags = COM_RandomLong( 0, 0x7fff );
- if( flags < 0x3fff )
- R_RicochetSound_( pos, flags % 5 );
+ if( flags < 0x3fff && ( count = SoundList_Count( Ricochet )))
+ R_RicochetSoundByIndex( pos, flags % count );
break;
case TE_SPRAY:
case TE_SPRITE_SPRAY:
--
2.34.1
[PATCH 3/3] engine: server: use soundlist to acquire random sounds for physics
---
engine/server/sv_move.c | 36 ++++++------------------------------
engine/server/sv_phys.c | 8 ++++++--
2 files changed, 12 insertions(+), 32 deletions(-)
diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c
index e62bfd46..25cd894a 100644
--- a/engine/server/sv_move.c
+++ b/engine/server/sv_move.c
@@ -150,21 +150,9 @@ void SV_WaterMove( edict_t *ent )
if( flags & FL_INWATER )
{
// leave the water.
- switch( COM_RandomLong( 0, 3 ))
- {
- case 0:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- case 1:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- case 2:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- case 3:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- }
+ const char *snd = SoundList_GetRandom( EntityWaterExit );
+ if( snd )
+ SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
ent->v.flags = flags & ~FL_INWATER;
}
@@ -197,21 +185,9 @@ void SV_WaterMove( edict_t *ent )
if( watertype == CONTENTS_WATER )
{
// entering the water
- switch( COM_RandomLong( 0, 3 ))
- {
- case 0:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- case 1:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- case 2:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- case 3:
- SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
- break;
- }
+ const char *snd = SoundList_GetRandom( EntityWaterEnter );
+ if( snd )
+ SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
}
ent->v.flags = flags | FL_INWATER;
diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c
index 29fd6a9f..f65954fd 100644
--- a/engine/server/sv_phys.c
+++ b/engine/server/sv_phys.c
@@ -1384,7 +1384,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
if( ent->v.watertype == CONTENTS_EMPTY )
{
// just crossed into water
- SV_StartSound( ent, CHAN_AUTO, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
+ const char *snd = SoundList_GetRandom( PlayerWaterEnter );
+ if( snd )
+ SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
ent->v.velocity[2] *= 0.5f;
}
@@ -1418,7 +1420,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
if( ent->v.watertype != CONTENTS_EMPTY )
{
// just crossed into water
- SV_StartSound( ent, CHAN_AUTO, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
+ const char *snd = SoundList_GetRandom( PlayerWaterExit );
+ if( snd )
+ SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
}
ent->v.watertype = CONTENTS_EMPTY;
ent->v.waterlevel = 0;
--
2.34.1