Index: game/ai/AI.cpp
===================================================================
--- game/ai/AI.cpp	(revision 10520)
+++ game/ai/AI.cpp	(working copy)
@@ -6703,7 +6703,7 @@
 		sndShader = declManager->FindSound( sound.c_str() );
 		SetSoundVolume( sndShader->GetParms()->volume + GetMovementVolMod() );
 		StartSoundShader( sndShader, SND_CHANNEL_BODY, 0, false, NULL );
-		SetSoundVolume( 0.0f );
+		SetSoundVolume();
 
 		// propagate the suspicious sound to other AI
 		PropSoundDirect( localSound, true, false, 0.0f, 0 ); // grayman #3355
Index: game/Entity.cpp
===================================================================
--- game/Entity.cpp	(revision 10520)
+++ game/Entity.cpp	(working copy)
@@ -917,11 +917,22 @@
 
 	memset( refSound, 0, sizeof( *refSound ) );
 
-	refSound->parms.minDistance = args->GetFloat( "s_mindistance" );
-	refSound->parms.maxDistance = args->GetFloat( "s_maxdistance" );
-	refSound->parms.volume = args->GetFloat( "s_volume" );
-	refSound->parms.shakes = args->GetFloat( "s_shakes" );
+	auto ReadFloatParam = [&]( const char *spawnargName, int ssomFlag ) -> float {
+		// stgatilov #6346: mark parameter as overriding only when spawnarg is present and nonempty
+		// otherwise, parameter should not override anything (i.e. disabled)
+		const char *text;
+		if ( args->GetString( spawnargName, "", &text ) && text[0] ) {
+			refSound->parms.overrideMode |= ssomFlag;
+			return atof( text );
+		}
+		return 0.0f;
+	};
 
+	refSound->parms.minDistance = ReadFloatParam( "s_mindistance", SSOM_MIN_DISTANCE_OVERRIDE );
+	refSound->parms.maxDistance = ReadFloatParam( "s_maxdistance", SSOM_MAX_DISTANCE_OVERRIDE );
+	refSound->parms.volume = ReadFloatParam( "s_volume", SSOM_VOLUME_OVERRIDE );
+	refSound->parms.shakes = ReadFloatParam( "s_shakes", SSOM_SHAKES_OVERRIDE );
+
 	args->GetVector( "origin", "0 0 0", refSound->origin );
 
 	refSound->referenceSound  = NULL;
@@ -948,6 +959,7 @@
 		refSound->parms.soundShaderFlags |= SSF_UNCLAMPED;
 	}
 	refSound->parms.soundClass = args->GetInt( "s_soundClass" );
+	refSound->parms.overrideMode |= SSOM_FLAGS_OR;
 
 	temp = args->GetString( "s_shader" );
 	if ( temp[0] != '\0' ) {
@@ -3997,7 +4009,12 @@
 */
 void idEntity::SetSoundVolume( float volume ) {
 	refSound.parms.volume = volume;
+	refSound.parms.overrideMode |= SSOM_VOLUME_OVERRIDE;
 }
+void idEntity::SetSoundVolume( void ) {
+	refSound.parms.volume = 0.0f;
+	refSound.parms.overrideMode &= ~SSOM_VOLUME_OVERRIDE;
+}
 
 /*
 ================
Index: game/Entity.h
===================================================================
--- game/Entity.h	(revision 10520)
+++ game/Entity.h	(working copy)
@@ -586,7 +586,8 @@
 	bool					StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length, float propVolMod = 0, int msgTag = 0); // grayman #3355
 	bool					StartSoundShader( const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length);
 	void					StopSound( const s_channelType channel, bool broadcast );	// pass SND_CHANNEL_ANY to stop all sounds
-	void					SetSoundVolume( float volume );
+	void					SetSoundVolume( float volume );	// stgatilov #6346: set and enable override
+	void					SetSoundVolume( void );			// stgatilov #6346: disable override
 	void					UpdateSound( void ); // grayman #4337
 	int						GetListenerId( void ) const;
 	idSoundEmitter *		GetSoundEmitter( void ) const;
Index: game/gamesys/SaveGame.cpp
===================================================================
--- game/gamesys/SaveGame.cpp	(revision 10520)
+++ game/gamesys/SaveGame.cpp	(working copy)
@@ -433,6 +433,7 @@
 	WriteFloat( refSound.parms.shakes );
 	WriteInt( refSound.parms.soundShaderFlags );
 	WriteInt( refSound.parms.soundClass );
+	WriteInt( refSound.parms.overrideMode );
 }
 
 void idSaveGame::WriteRenderView( const renderView_t &view ) {
@@ -1035,6 +1036,7 @@
 	ReadFloat( refSound.parms.shakes );
 	ReadInt( refSound.parms.soundShaderFlags );
 	ReadInt( refSound.parms.soundClass );
+	ReadInt( refSound.parms.overrideMode );
 }
 
 void idRestoreGame::ReadRenderView( renderView_t &view ) {
Index: game/Moveable.cpp
===================================================================
--- game/Moveable.cpp	(revision 10520)
+++ game/Moveable.cpp	(working copy)
@@ -446,7 +446,7 @@
 					PropSoundS( NULL, sndPropName, f, 0 ); // grayman #3355
 				}
 			
-				SetSoundVolume(0.0f);
+				SetSoundVolume();
 
 				nextSoundTime = gameLocal.time + 500;
 			}
Index: game/Player.cpp
===================================================================
--- game/Player.cpp	(revision 10520)
+++ game/Player.cpp	(working copy)
@@ -5381,7 +5381,7 @@
 	const idSoundShader	*sndShader = declManager->FindSound( sound );
 	SetSoundVolume( sndShader->GetParms()->volume + volAdjust);
 	StartSoundShader( sndShader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
-	SetSoundVolume( 0.0f );
+	SetSoundVolume();
 
 	// propagate the suspicious sound to AI
 	PropSoundDirect( soundName, true, false, volAdjust, 0 );
@@ -11438,7 +11438,7 @@
 		const idSoundShader* sndShader = declManager->FindSound( sound );
 		SetSoundVolume( sndShader->GetParms()->volume + GetMovementVolMod() + crouchVolAdjust); // grayman #3485
 		StartSoundShader( sndShader, SND_CHANNEL_BODY, 0, false, NULL );
-		SetSoundVolume( 0.0f );
+		SetSoundVolume();
 
 		// propagate the suspicious sound to other AI
 		PropSoundDirect( localSound, true, false, crouchVolAdjust, 0 ); // grayman #3355, grayman #3485
Index: sound/snd_emitter.cpp
===================================================================
--- sound/snd_emitter.cpp	(revision 10520)
+++ sound/snd_emitter.cpp	(working copy)
@@ -415,43 +415,95 @@
 	memset( &parms, 0, sizeof( parms ) );
 }
 
+idCVar s_override_parms_mode(
+	"s_override_parms_mode", "0", CVAR_SOUND | CVAR_INTEGER,
+	"Implementation of sound params override:\n"
+	"  0 --- original mode where nonzero value means override\n"
+	"  1 --- new mode where override flag is stored separately\n"
+	"  2 --- compare original and new modes, warn when there is difference",
+	0, 2
+);
+
 /*
 ==================
 idSoundEmitterLocal::OverrideParms
 ==================
 */
-void idSoundEmitterLocal::OverrideParms( const soundShaderParms_t *base, 
-									  const soundShaderParms_t *over, soundShaderParms_t *out ) {
+void idSoundEmitterLocal::OverrideParms( const soundShaderParms_t *base, const soundShaderParms_t *over, soundShaderParms_t *out, const char *comment ) {
 	if ( !over ) {
+		// NULL override: nothing to do
 		*out = *base;
 		return;
 	}
-	if ( over->minDistance ) {
-		out->minDistance = over->minDistance;
-	} else {
-		out->minDistance = base->minDistance;
+
+	soundShaderParms_t resultOld, resultNew;
+
+	{
+		// original Doom 3 mode: override if overriding parameter is nonzero
+		resultOld = *base;
+		if ( over->minDistance ) {
+			resultOld.minDistance = over->minDistance;
+		}
+		if ( over->maxDistance ) {
+			resultOld.maxDistance = over->maxDistance;
+		}
+		if ( over->shakes ) {
+			resultOld.shakes = over->shakes;
+		}
+		if ( over->volume ) {
+			resultOld.volume = over->volume;
+		}
+		if ( over->soundClass ) {
+			resultOld.soundClass = over->soundClass;
+		}
+		// always OR flags
+		resultOld.soundShaderFlags |= over->soundShaderFlags;
 	}
-	if ( over->maxDistance ) {
-		out->maxDistance = over->maxDistance;
-	} else {
-		out->maxDistance = base->maxDistance;
+	{
+		// new mode: override depending on proper flags
+		resultNew = *base;
+		if ( over->overrideMode & SSOM_MIN_DISTANCE_OVERRIDE ) {
+			resultNew.minDistance = over->minDistance;
+		}
+		if ( over->overrideMode & SSOM_MAX_DISTANCE_OVERRIDE ) {
+			resultNew.maxDistance = over->maxDistance;
+		}
+		if ( over->overrideMode & SSOM_SHAKES_OVERRIDE ) {
+			resultNew.shakes = over->shakes;
+		}
+		if ( over->overrideMode & SSOM_VOLUME_OVERRIDE ) {
+			resultNew.volume = over->volume;
+		}
+		if ( over->overrideMode & SSOM_SOUND_CLASS_OVERRIDE ) {
+			resultNew.soundClass = over->soundClass;
+		}
+
+		if ( over->overrideMode & SSOM_FLAGS_OR ) {
+			resultNew.soundShaderFlags |= over->soundShaderFlags;
+		} else if ( over->overrideMode & SSOM_FLAGS_OVERRIDE ) {
+			resultNew.soundShaderFlags = over->soundShaderFlags;
+		}
 	}
-	if ( over->shakes ) {
-		out->shakes = over->shakes;
-	} else {
-		out->shakes = base->shakes;
+
+	if ( s_override_parms_mode.GetInteger() == 2 ) {
+		if ( memcmp( &resultOld, &resultNew, sizeof(resultOld) ) != 0 ) {
+			common->Warning( "OverrideParms: different result for '%s'", comment );
+			#define PRINTDIFF( member ) \
+				if ( resultOld.member != resultNew.member ) \
+					common->Printf("  %s: %s -> %s\n", #member, std::to_string(resultOld.member).c_str(), std::to_string(resultNew.member).c_str() );
+			PRINTDIFF( volume );
+			PRINTDIFF( minDistance );
+			PRINTDIFF( maxDistance );
+			PRINTDIFF( shakes );
+			PRINTDIFF( soundShaderFlags );
+			PRINTDIFF( soundClass );
+		}
 	}
-	if ( over->volume ) {
-		out->volume = over->volume;
+	if ( s_override_parms_mode.GetInteger() == 0 ) {
+		*out = resultOld;
 	} else {
-		out->volume = base->volume;
+		*out = resultNew;
 	}
-	if ( over->soundClass ) {
-		out->soundClass = over->soundClass;
-	} else {
-		out->soundClass = base->soundClass;
-	}
-	out->soundShaderFlags = base->soundShaderFlags | over->soundShaderFlags;
 }
 
 /*
@@ -745,6 +797,7 @@
 		soundWorld->writeDemo->WriteFloat( parms->shakes );
 		soundWorld->writeDemo->WriteInt( parms->soundShaderFlags );
 		soundWorld->writeDemo->WriteInt( parms->soundClass );
+		soundWorld->writeDemo->WriteInt( parms->overrideMode );
 	}
 
 	this->origin = origin;
@@ -849,7 +902,7 @@
 	soundShaderParms_t	chanParms;
 
 	chanParms = shader->parms;
-	OverrideParms( &chanParms, &this->parms, &chanParms );
+	OverrideParms( &chanParms, &this->parms, &chanParms, shader->GetName() );
 	chanParms.soundShaderFlags |= soundShaderFlags;
 
 	if ( chanParms.shakes > 0.0f ) {
@@ -1130,6 +1183,7 @@
 		soundWorld->writeDemo->WriteFloat( parms->shakes );
 		soundWorld->writeDemo->WriteInt( parms->soundShaderFlags );
 		soundWorld->writeDemo->WriteInt( parms->soundClass );
+		soundWorld->writeDemo->WriteInt( parms->overrideMode );
 	}
 
 	for ( int i = 0; i < SOUND_MAX_CHANNELS; i++ ) {
@@ -1142,7 +1196,7 @@
 			continue;
 		}
 
-		OverrideParms( &chan->parms, parms, &chan->parms );
+		OverrideParms( &chan->parms, parms, &chan->parms, (chan->soundShader ? chan->soundShader->GetName() : "???") );
 
 		if ( chan->parms.shakes > 0.0f && chan->soundShader != NULL ) {
 			chan->soundShader->CheckShakesAndOgg();
Index: sound/snd_local.h
===================================================================
--- sound/snd_local.h	(revision 10520)
+++ sound/snd_local.h	(working copy)
@@ -450,7 +450,7 @@
 
 	void				Clear( void );
 
-	void				OverrideParms( const soundShaderParms_t *base, const soundShaderParms_t *over, soundShaderParms_t *out );
+	void				OverrideParms( const soundShaderParms_t *base, const soundShaderParms_t *over, soundShaderParms_t *out, const char *comment );
 	void				CheckForCompletion( int current44kHzTime );
 	void				Spatialize( bool primary, idVec3 listenerPos, int listenerArea, idRenderWorld *rw ); // grayman #4882
 
Index: sound/snd_shader.cpp
===================================================================
--- sound/snd_shader.cpp	(revision 10520)
+++ sound/snd_shader.cpp	(working copy)
@@ -158,6 +158,7 @@
 	//this will results in missing sounds later, when soundCache is finally available
 	assert( soundSystemLocal.soundCache || soundSystemLocal.s_noSound.GetBool() );
 
+	memset( &parms, 0, sizeof(parms) );
 	parms.minDistance = 1;
 	parms.maxDistance = 10;
 	parms.volume = 1;
Index: sound/snd_world.cpp
===================================================================
--- sound/snd_world.cpp	(revision 10520)
+++ sound/snd_world.cpp	(working copy)
@@ -374,6 +374,7 @@
 			readDemo->ReadFloat( parms.shakes );
 			readDemo->ReadInt( parms.soundShaderFlags );
 			readDemo->ReadInt( parms.soundClass );
+			readDemo->ReadInt( parms.overrideMode );
 			EmitterForIndex( index )->UpdateEmitter( origin, listenerId, &parms );
 		}
 		break;
@@ -405,6 +406,7 @@
 			readDemo->ReadFloat( parms.shakes );
 			readDemo->ReadInt( parms.soundShaderFlags );
 			readDemo->ReadInt( parms.soundClass );
+			readDemo->ReadInt( parms.overrideMode );
 			EmitterForIndex( index )->ModifySound( (s_channelType)channel, &parms );
 		}
 		break;
@@ -1511,6 +1513,7 @@
 	saveGame->WriteFloat(params->shakes);
 	saveGame->WriteInt(params->soundShaderFlags);
 	saveGame->WriteInt(params->soundClass);
+	saveGame->WriteInt(params->overrideMode);
 }
 
 /*
@@ -1681,6 +1684,7 @@
 	saveGame->ReadFloat(params->shakes);
 	saveGame->ReadInt(params->soundShaderFlags);
 	saveGame->ReadInt(params->soundClass);
+	saveGame->ReadInt(params->overrideMode);
 }
 
 /*
Index: sound/sound.h
===================================================================
--- sound/sound.h	(revision 10520)
+++ sound/sound.h	(working copy)
@@ -45,6 +45,15 @@
 static const int	SSF_NO_DUPS =			BIT(9);	// try not to play the same sound twice in a row
 static const int	SSF_NO_EFX =			BIT(10);// do not apply EFX effect to the sound
 
+// stgatilov #6346: override mode for emitter/channel params
+static const int	SSOM_MIN_DISTANCE_OVERRIDE =	BIT(0);	// override corresponding parameter?
+static const int	SSOM_MAX_DISTANCE_OVERRIDE =	BIT(1);	// (if flag is missing, then new parameter is ignored)
+static const int	SSOM_VOLUME_OVERRIDE =			BIT(2);	// ...
+static const int	SSOM_SHAKES_OVERRIDE =			BIT(3);	// ...
+static const int	SSOM_SOUND_CLASS_OVERRIDE =		BIT(4);	// ...
+static const int	SSOM_FLAGS_OVERRIDE =			BIT(5);	// override soundShaderFlags with new ones?
+static const int	SSOM_FLAGS_OR =					BIT(6); // OR base and new parameters together?
+
 //stgatilov #2454: verbosity level of subtitles
 enum SubtitleLevel {
 	SUBL_IGNORE		= 0,		// auxilliary value for tdm_subtitles: don't show any subtitles regardless of level
@@ -62,6 +71,7 @@
 	float					shakes;
 	int						soundShaderFlags;		// SSF_* bit flags
 	int						soundClass;				// for global fading of sounds
+	int						overrideMode;			// stgatilov #6346: SSOM_* flags define how to override with these params
 } soundShaderParms_t;
 
 
