This code from Shock might be useful?
// note: theoretically, this add-on is not compatible with any other add-on (e.g. a gamemode) which uses the setTimescale() function (*not* serverCmdTimescale()).
// any add-on which uses setTimescale() must set $oldTimescale before calling it, or else any future playPitchedSound event that is activated is going to
// reset it back to the previous ($oldTimescale) timescale.
//
// if I could package setTimescale() to add another arg to make this more compatible, I would,
// but setTimescale() isn't packageable.
function pitchedSoundLegibility(%obj, %sound) {
if(!isObject(%obj) || !isObject(%sound) || %sound.getClassName() !$= "AudioProfile")
return false;
if(%sound.description.isLooping)
return false;
if($oldTimescale $= "")
$oldTimescale = getTimescale();
return true;
}
function FxDTSBrick::playPitchedSound(%brick, %sound, %pitch) {
if(!pitchedSoundLegibility(%brick, %sound))
return;
setTimescale(%pitch);
serverPlay3D(%sound, %brick.getPosition());
setTimescale($oldTimescale);
}
registerOutputEvent("FxDTSBrick", "playPitchedSound", "dataBlock Sound" TAB "float 0.2 2 0.01 1", 0);
function GameConnection::playPitchedSound(%client, %sound, %pitch) {
if(!pitchedSoundLegibility(%client, %sound))
return;
setTimescale(%pitch);
%client.play2D(%sound);
setTimescale($oldTimescale);
}
registerOutputEvent("GameConnection", "playPitchedSound", "dataBlock Sound" TAB "float 0.2 2 0.01 1", 0);
if(isPackage(playPitchedSound))
deactivatePackage(playPitchedSound);
package playPitchedSound {
function serverCmdTimescale(%client, %timescale) {
if(%client.isAdmin)
$oldTimescale = mClampF(%timescale, 0.2, 2.0);
parent::serverCmdTimescale(%client, %timescale);
}
function disconnectedCleanup(%doReconnect) { // non-dedis
$oldTimescale = "";
parent::disconnectedCleanup(%doReconnect);
}
function disconnect(%doReconnect) { // non-dedis
$oldTimescale = "";
parent::disconnect(%doReconnect);
}
};
activatePackage(playPitchedSound);