From be575099c97079409e2c06756a2f74cea47a2560 Mon Sep 17 00:00:00 2001 From: Doubleumc Date: Sat, 6 Jul 2024 03:22:15 -0400 Subject: [PATCH] Sound Environment update (#6620) # About the pull request Changes to how a client's sound `environment` and `echo` is handled: https://www.byond.com/docs/ref/#/sound/var/environment https://www.byond.com/docs/ref/#/sound/var/echo A client's `soundOutput` now has sole control over environment and echo. The environment is updated when the mob moves into a different area, or if the mob's environment override is set. The echo is used to enable or disable the environmental reverb per-sound. # Explain why it's good for the game Issue: an environment applies to all sounds for that client, current and future, until another one is set. It applies to in-world sounds as well as, say, admin pings. Solution: since an echo is applied per-sound, by adjusting the echo's Room & RoomHF fields the environmental effects can be enabled or disabled (more accurately, made so quiet as to be inaudible). This is set to off by default, and is only enabled for positional sounds. Admin pings are safe. Idea from here: https://github.com/tgstation/tgstation/pull/55333 # Testing Photographs and Procedure Boots without issue. Sound environments change at appropriate points. Sound environments effect only positional sounds. # Changelog :cl: code: environmental reverb applies more reliably and only to positional sounds /:cl: --- code/__DEFINES/sounds.dm | 3 + code/datums/soundOutput.dm | 75 +++++++++++++++++++++---- code/game/sound.dm | 12 ++-- code/modules/mob/living/init_signals.dm | 2 + code/modules/mob/living/living.dm | 4 -- 5 files changed, 73 insertions(+), 23 deletions(-) diff --git a/code/__DEFINES/sounds.dm b/code/__DEFINES/sounds.dm index 541d95d28189..807305174b34 100644 --- a/code/__DEFINES/sounds.dm +++ b/code/__DEFINES/sounds.dm @@ -60,6 +60,9 @@ #define SOUND_ENVIRONMENT_DIZZY 24 #define SOUND_ENVIRONMENT_PSYCHOTIC 25 +#define SOUND_ECHO_REVERB_ON list(0, 0, 0, 0, 0, 0.0, 0, 0.25, 1.5, 1.0, 0, 1.0, 0, 0.0, 0.0, 0.0, 1.0, 0) +#define SOUND_ECHO_REVERB_OFF list(0, 0, -10000, -10000, 0, 0.0, 0, 0.25, 1.5, 1.0, 0, 1.0, 0, 0.0, 0.0, 0.0, 1.0, 0) //-10000 to Room & RoomHF makes enviromental reverb effectively inaudible + #define AMBIENCE_SHIP 'sound/ambience/shipambience.ogg' #define AMBIENCE_JUNGLE 'sound/ambience/ambienceLV624.ogg' #define AMBIENCE_RIVER 'sound/ambience/ambienceriver.ogg' diff --git a/code/datums/soundOutput.dm b/code/datums/soundOutput.dm index eb7339ceae51..6ebc32c7e41f 100644 --- a/code/datums/soundOutput.dm +++ b/code/datums/soundOutput.dm @@ -4,13 +4,25 @@ var/list/soundscape_playlist = list() //Updated on changing areas var/ambience = null //The file currently being played as ambience var/status_flags = 0 //For things like ear deafness, psychodelic effects, and other things that change how all sounds behave - var/list/echo -/datum/soundOutput/New(client/C) - if(!C) + + /// Currently applied environmental reverb. + VAR_PROTECTED/owner_environment = SOUND_ENVIRONMENT_NONE + +/datum/soundOutput/New(client/client) + if(!client) qdel(src) return - owner = C - . = ..() + owner = client + RegisterSignal(owner.mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_moved)) + RegisterSignal(owner.mob, COMSIG_MOB_LOGOUT, PROC_REF(on_mob_logout)) + RegisterSignal(owner, COMSIG_CLIENT_MOB_LOGGED_IN, PROC_REF(on_client_mob_logged_in)) + return ..() + +/datum/soundOutput/Destroy() + UnregisterSignal(owner.mob, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGOUT)) + UnregisterSignal(owner, COMSIG_CLIENT_MOB_LOGGED_IN) + owner = null + return ..() /datum/soundOutput/proc/process_sound(datum/sound_template/T) var/sound/S = sound(T.file, T.wait, T.repeat) @@ -22,7 +34,6 @@ S.frequency = T.frequency S.falloff = T.falloff S.status = T.status - S.echo = T.echo if(T.x && T.y && T.z) var/turf/owner_turf = get_turf(owner.mob) if(owner_turf) @@ -38,16 +49,12 @@ S.x = T.x - owner_turf.x S.y = 0 S.z = T.y - owner_turf.y - var/area/A = owner_turf.loc - S.environment = A.sound_environment S.y += T.y_s_offset S.x += T.x_s_offset + S.echo = SOUND_ECHO_REVERB_ON //enable environment reverb for positional sounds if(owner.mob.ear_deaf > 0) S.status |= SOUND_MUTE - if(owner.mob.sound_environment_override != SOUND_ENVIRONMENT_NONE) - S.environment = owner.mob.sound_environment_override - sound_to(owner,S) /datum/soundOutput/proc/update_ambience(area/target_area, ambience_override, force_update = FALSE) @@ -84,7 +91,6 @@ S.status = status_flags if(target_area) - S.environment = target_area.sound_environment var/muffle if(target_area.ceiling_muffle) switch(target_area.ceiling) @@ -128,6 +134,51 @@ S.status = SOUND_UPDATE sound_to(owner, S) +/// Pulls mob's area's sound_environment and applies if necessary and not overridden. +/datum/soundOutput/proc/update_area_environment() + var/area/owner_area = get_area(owner.mob) + var/new_environment = owner_area.sound_environment + + if(owner.mob.sound_environment_override != SOUND_ENVIRONMENT_NONE) //override in effect, can't apply + return + + set_owner_environment(new_environment) + +/// Pulls mob's sound_environment_override and applies if necessary. +/datum/soundOutput/proc/update_mob_environment_override() + var/new_environment_override = owner.mob.sound_environment_override + + if(new_environment_override == SOUND_ENVIRONMENT_NONE) //revert to area environment + update_area_environment() + return + + set_owner_environment(new_environment_override) + +/// Pushes new_environment to owner and updates owner_environment var. +/datum/soundOutput/proc/set_owner_environment(new_environment = SOUND_ENVIRONMENT_NONE) + if(new_environment ~= src.owner_environment) //no need to change + return + + var/sound/sound = sound() + sound.environment = new_environment + sound_to(owner, sound) + + src.owner_environment = new_environment + +/datum/soundOutput/proc/on_mob_moved(datum/source, atom/oldloc, direction, Forced) + SIGNAL_HANDLER //COMSIG_MOVABLE_MOVED + update_area_environment() + +/datum/soundOutput/proc/on_mob_logout(datum/source) + SIGNAL_HANDLER //COMSIG_MOB_LOGOUT + UnregisterSignal(owner.mob, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGOUT)) + +/datum/soundOutput/proc/on_client_mob_logged_in(datum/source, mob/new_mob) + SIGNAL_HANDLER //COMSIG_CLIENT_MOB_LOGGED_IN + RegisterSignal(owner.mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_moved)) + RegisterSignal(owner.mob, COMSIG_MOB_LOGOUT, PROC_REF(on_mob_logout)) + update_mob_environment_override() + /client/proc/adjust_volume_prefs(volume_key, prompt = "", channel_update = 0) volume_preferences[volume_key] = (tgui_input_number(src, prompt, "Volume", volume_preferences[volume_key]*100)) / 100 if(volume_preferences[volume_key] > 1) diff --git a/code/game/sound.dm b/code/game/sound.dm index 49ccb4eb9331..1ab8fc42f41a 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,3 +1,5 @@ +/sound + echo = SOUND_ECHO_REVERB_OFF //disable enviroment reverb by default, soundOutput re-enables for positional sounds /datum/sound_template //Basically a sound datum, but only serves as a way to carry info to soundOutput var/file //The sound itself @@ -11,7 +13,6 @@ var/falloff = 1 var/volume_cat = VOLUME_SFX var/range = 0 - var/list/echo var/x //Map coordinates, not sound coordinates var/y var/z @@ -35,7 +36,7 @@ //status: the regular 4 sound flags //falloff: max range till sound volume starts dropping as distance increases -/proc/playsound(atom/source, soundin, vol = 100, vary = FALSE, sound_range, vol_cat = VOLUME_SFX, channel = 0, status , falloff = 1, echo, y_s_offset,x_s_offset) +/proc/playsound(atom/source, soundin, vol = 100, vary = FALSE, sound_range, vol_cat = VOLUME_SFX, channel = 0, status , falloff = 1, y_s_offset,x_s_offset) if(isarea(source)) error("[source] is an area and is trying to make the sound: [soundin]") return FALSE @@ -53,7 +54,6 @@ S.falloff = falloff S.volume = vol S.volume_cat = vol_cat - S.echo = echo S.y_s_offset = y_s_offset S.x_s_offset = x_s_offset if(vary != FALSE) @@ -100,7 +100,7 @@ //This is the replacement for playsound_local. Use this for sending sounds directly to a client -/proc/playsound_client(client/client, soundin, atom/origin, vol = 100, random_freq, vol_cat = VOLUME_SFX, channel = 0, status, list/echo, y_s_offset, x_s_offset) +/proc/playsound_client(client/client, soundin, atom/origin, vol = 100, random_freq, vol_cat = VOLUME_SFX, channel = 0, status, y_s_offset, x_s_offset) if(!istype(client) || !client.soundOutput) return FALSE var/datum/sound_template/S = new() if(origin) @@ -123,7 +123,6 @@ S.volume_cat = vol_cat S.channel = channel S.status = status - S.echo = echo S.y_s_offset = y_s_offset S.x_s_offset = x_s_offset SSsound.queue(S, list(client)) @@ -154,13 +153,12 @@ /// Play sound for all on-map clients on a given Z-level. Good for ambient sounds. -/proc/playsound_z(z, soundin, volume = 100, vol_cat = VOLUME_SFX, echo, y_s_offset, x_s_offset) +/proc/playsound_z(z, soundin, volume = 100, vol_cat = VOLUME_SFX, y_s_offset, x_s_offset) var/datum/sound_template/S = new() S.file = soundin S.volume = volume S.channel = SOUND_CHANNEL_Z S.volume_cat = vol_cat - S.echo = echo S.y_s_offset = y_s_offset S.x_s_offset = x_s_offset var/list/hearers = list() diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index a2b92007d97e..825fa4dcc941 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -26,6 +26,7 @@ if(stat < UNCONSCIOUS) set_stat(UNCONSCIOUS) sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC + client?.soundOutput?.update_mob_environment_override() /// Called when [TRAIT_KNOCKEDOUT] is removed from the mob. /mob/living/proc/on_knockedout_trait_loss(datum/source) @@ -33,6 +34,7 @@ if(stat <= UNCONSCIOUS) update_stat() sound_environment_override = SOUND_ENVIRONMENT_NONE + client?.soundOutput?.update_mob_environment_override() /// Called when [TRAIT_IMMOBILIZED] is added to the mob. /mob/living/proc/on_immobilized_trait_gain(datum/source) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5f917cf6e0d5..27697a8938a7 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -503,12 +503,10 @@ if(CONSCIOUS) if(stat >= UNCONSCIOUS) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) - sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC add_traits(list(/*TRAIT_HANDS_BLOCKED, */ TRAIT_INCAPACITATED, TRAIT_FLOORED), STAT_TRAIT) if(UNCONSCIOUS) if(stat >= UNCONSCIOUS) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) //adding trait sources should come before removing to avoid unnecessary updates - sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC if(DEAD) SEND_SIGNAL(src, COMSIG_MOB_STAT_SET_ALIVE) // remove_from_dead_mob_list() @@ -518,12 +516,10 @@ if(CONSCIOUS) if(. >= UNCONSCIOUS) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) - sound_environment_override = SOUND_ENVIRONMENT_NONE remove_traits(list(/*TRAIT_HANDS_BLOCKED, */ TRAIT_INCAPACITATED, TRAIT_FLOORED, /*TRAIT_CRITICAL_CONDITION*/), STAT_TRAIT) if(UNCONSCIOUS) if(. >= UNCONSCIOUS) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) - sound_environment_override = SOUND_ENVIRONMENT_NONE if(DEAD) SEND_SIGNAL(src, COMSIG_MOB_STAT_SET_DEAD) // REMOVE_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)