From d368e4d49da1ccdd2eefb761054f4615c326d4bc Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Wed, 30 Jun 2021 17:51:35 -0700 Subject: [PATCH] Changes how weather sends sound to players, reduces sound loop overtime (#59284) * Converts looping sounds from a list of play locations to just the one * Updates all uses of looping sounds to match the new arg * Adds an area based sound manager that hooks into looping sounds to drive the actual audio. I'll be using this to redo how weather effects handle sound * Some structrual stuff to make everything else smoother Timers now properly return the time left for client based timers Weather sends global signals when it starts/stops Looping sounds now use their timerid var for all their sound related timers, not just the main loop * This is the painful part Adds an area sound manager component, it handles the logic of moving into new areas potentially creating new sound loops. We do some extra work to prevent stacking sound loops. Adds an ash storm listener element that adds a tailored area sound manager to clients on the lavaland z level. It's removed on logout. Adds the ash_storm_sounds assoc list, a reference to this is passed into area sound managers, and it's modified in a manner that doesn't break the reference in ash_storm (This is what I hate) * Hooks ash storm listener into cliented mobs and possessed objects * Documents the odd ref stuff, adds an ignore start var to looping sounds, fixes some errors and lint issues * Applies kyler's review banging Co-authored-by: Kylerace * Cleans up some var names, reduces the amount of looping we do in some areas * Makes the code compile, redoes the movement listener to be more general * fuck * We don't need to detach on del if we're just removing signals on detach * Should? work * if(direct) memes Co-authored-by: Kylerace --- code/__DEFINES/dcs/signals.dm | 5 ++ code/__DEFINES/weather.dm | 2 + code/controllers/subsystem/timer.dm | 4 +- code/controllers/subsystem/weather.dm | 17 ++-- code/datums/components/acid.dm | 2 +- code/datums/components/area_sound_manager.dm | 77 +++++++++++++++++++ code/datums/elements/weather_listener.dm | 45 +++++++++++ code/datums/looping_sounds/_looping_sound.dm | 59 ++++++++------ code/datums/looping_sounds/weather.dm | 3 - code/datums/weather/weather.dm | 50 +++++++----- .../datums/weather/weather_types/ash_storm.dm | 50 +++++------- code/game/machinery/fat_sucker.dm | 2 +- code/game/machinery/roulette_machine.dm | 2 +- .../machinery/telecomms/telecomunications.dm | 2 +- .../objects/items/devices/geiger_counter.dm | 2 +- .../items/devices/reverse_bear_trap.dm | 4 +- .../objects/items/devices/taperecorder.dm | 2 +- code/game/objects/structures/shower.dm | 2 +- code/modules/admin/verbs/possess.dm | 3 +- .../eldritch_cult/knowledge/void_lore.dm | 2 +- .../machinery/components/fusion/hfr_procs.dm | 2 +- code/modules/clothing/head/helmet.dm | 2 +- code/modules/clothing/spacesuits/hardsuit.dm | 2 +- .../kitchen_machinery/deep_fryer.dm | 2 +- .../kitchen_machinery/griddle.dm | 2 +- .../kitchen_machinery/grill.dm | 2 +- .../kitchen_machinery/microwave.dm | 2 +- code/modules/mob/login.dm | 3 + .../computers/item/computer.dm | 2 +- code/modules/power/gravitygenerator.dm | 2 +- code/modules/power/port_gen.dm | 2 +- code/modules/power/supermatter/supermatter.dm | 2 +- tgstation.dme | 3 + 33 files changed, 253 insertions(+), 110 deletions(-) create mode 100644 code/__DEFINES/weather.dm create mode 100644 code/datums/components/area_sound_manager.dm create mode 100644 code/datums/elements/weather_listener.dm diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 3162a671da2..e43df0a561b 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -40,6 +40,11 @@ #define LINKED_UP (1<<0) /// an obj/item is created! (obj/item/created_item) #define COMSIG_GLOB_NEW_ITEM "!new_item" +/// a weather event of some kind occured +#define COMSIG_WEATHER_TELEGRAPH(event_type) "!weather_telegraph [event_type]" +#define COMSIG_WEATHER_START(event_type) "!weather_start [event_type]" +#define COMSIG_WEATHER_WINDDOWN(event_type) "!weather_winddown [event_type]" +#define COMSIG_WEATHER_END(event_type) "!weather_end [event_type]" /// signals from globally accessible objects diff --git a/code/__DEFINES/weather.dm b/code/__DEFINES/weather.dm new file mode 100644 index 00000000000..4840ef976fc --- /dev/null +++ b/code/__DEFINES/weather.dm @@ -0,0 +1,2 @@ +//A reference to this list is passed into area sound managers, and it's modified in a manner that preserves that reference in ash_storm.dm +GLOBAL_LIST_EMPTY(ash_storm_sounds) diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index 290554819f1..09dede4e01e 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -632,7 +632,9 @@ SUBSYSTEM_DEF(timer) timer_subsystem = timer_subsystem || SStimer //id is string var/datum/timedevent/timer = timer_subsystem.timer_id_dict[id] - return (timer && !timer.spent) ? timer.timeToRun - world.time : null + if(!timer || timer.spent) + return null + return timer.timeToRun - (timer.flags & TIMER_CLIENT_TIME ? REALTIMEOFDAY : world.time) #undef BUCKET_LEN #undef BUCKET_POS diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index f162e291bc0..bf55397eb64 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -16,22 +16,21 @@ SUBSYSTEM_DEF(weather) /datum/controller/subsystem/weather/fire() // process active weather for(var/V in processing) - var/datum/weather/W = V - if(W.aesthetic || W.stage != MAIN_STAGE) + var/datum/weather/our_event = V + if(our_event.aesthetic || our_event.stage != MAIN_STAGE) continue - for(var/i in GLOB.mob_living_list) - var/mob/living/L = i - if(W.can_weather_act(L)) - W.weather_act(L) + for(var/mob/act_on as anything in GLOB.mob_living_list) + if(our_event.can_weather_act(act_on)) + our_event.weather_act(act_on) // start random weather on relevant levels for(var/z in eligible_zlevels) var/possible_weather = eligible_zlevels[z] - var/datum/weather/W = pickweight(possible_weather) - run_weather(W, list(text2num(z))) + var/datum/weather/our_event = pickweight(possible_weather) + run_weather(our_event, list(text2num(z))) eligible_zlevels -= z var/randTime = rand(3000, 6000) - next_hit_by_zlevel["[z]"] = addtimer(CALLBACK(src, .proc/make_eligible, z, possible_weather), randTime + initial(W.weather_duration_upper), TIMER_UNIQUE|TIMER_STOPPABLE) //Around 5-10 minutes between weathers + next_hit_by_zlevel["[z]"] = addtimer(CALLBACK(src, .proc/make_eligible, z, possible_weather), randTime + initial(our_event.weather_duration_upper), TIMER_UNIQUE|TIMER_STOPPABLE) //Around 5-10 minutes between weathers /datum/controller/subsystem/weather/Initialize(start_timeofday) for(var/V in subtypesof(/datum/weather)) diff --git a/code/datums/components/acid.dm b/code/datums/components/acid.dm index 8f960950740..cea68d80641 100644 --- a/code/datums/components/acid.dm +++ b/code/datums/components/acid.dm @@ -50,7 +50,7 @@ var/atom/parent_atom = parent RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/on_update_overlays) parent_atom.update_appearance() - sizzle = new(list(parent), TRUE) + sizzle = new(parent, TRUE) START_PROCESSING(SSacid, src) /datum/component/acid/Destroy(force, silent) diff --git a/code/datums/components/area_sound_manager.dm b/code/datums/components/area_sound_manager.dm new file mode 100644 index 00000000000..50bb77772f7 --- /dev/null +++ b/code/datums/components/area_sound_manager.dm @@ -0,0 +1,77 @@ +///Allows you to set a theme for a set of areas without tying them to looping sounds explicitly +/datum/component/area_sound_manager + ///area -> looping sound type + var/list/area_to_looping_type = list() + ///Current sound loop + var/datum/looping_sound/our_loop + ///A list of "acceptable" z levels to be on. If you leave this, we're gonna delete ourselves + var/list/accepted_zs + ///The timer id of our current start delay, if it exists + var/timerid + +/datum/component/area_sound_manager/Initialize(area_loop_pairs, change_on, remove_on, acceptable_zs) + if(!ismovable(parent)) + return + area_to_looping_type = area_loop_pairs + accepted_zs = acceptable_zs + change_the_track() + + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/react_to_move) + RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, .proc/react_to_z_move) + RegisterSignal(parent, change_on, .proc/handle_change) + RegisterSignal(parent, remove_on, .proc/handle_removal) + +/datum/component/area_sound_manager/Destroy(force, silent) + QDEL_NULL(our_loop) + . = ..() + +/datum/component/area_sound_manager/proc/react_to_move(datum/source, atom/oldloc, dir, forced) + SIGNAL_HANDLER + var/list/loop_lookup = area_to_looping_type + if(loop_lookup[get_area(oldloc)] == loop_lookup[get_area(parent)]) + return + change_the_track(TRUE) + +/datum/component/area_sound_manager/proc/react_to_z_move(datum/source, old_z, new_z) + SIGNAL_HANDLER + if(!length(accepted_zs) || (new_z in accepted_zs)) + return + qdel(src) + +/datum/component/area_sound_manager/proc/handle_removal(datum/source) + SIGNAL_HANDLER + qdel(src) + +/datum/component/area_sound_manager/proc/handle_change(datum/source) + SIGNAL_HANDLER + change_the_track() + +/datum/component/area_sound_manager/proc/change_the_track(skip_start = FALSE) + var/time_remaining = 0 + + if(our_loop) + var/our_id = our_loop.timerid || timerid + if(our_id) + time_remaining = timeleft(our_id, SSsound_loops) || 0 + //Time left will sometimes return negative values, just ignore them and start a new sound loop now + time_remaining = max(time_remaining, 0) + QDEL_NULL(our_loop) + + var/area/our_area = get_area(parent) + var/new_loop_type = area_to_looping_type[our_area] + if(!new_loop_type) + return + + our_loop = new new_loop_type(parent, FALSE, TRUE, skip_start) + + //If we're still playing, wait a bit before changing the sound so we don't double up + if(time_remaining) + timerid = addtimer(CALLBACK(src, .proc/start_looping_sound), time_remaining, TIMER_UNIQUE | TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_NO_HASH_WAIT | TIMER_DELETE_ME, SSsound_loops) + return + timerid = null + our_loop.start() + +/datum/component/area_sound_manager/proc/start_looping_sound() + timerid = null + if(our_loop) + our_loop.start() diff --git a/code/datums/elements/weather_listener.dm b/code/datums/elements/weather_listener.dm new file mode 100644 index 00000000000..956a355d97b --- /dev/null +++ b/code/datums/elements/weather_listener.dm @@ -0,0 +1,45 @@ +///This element just handles creating and destroying an area sound manager that's hooked into weather stuff +/datum/element/weather_listener + element_flags = ELEMENT_BESPOKE + id_arg_index = 2 + var/weather_type + //What events to change the track on + var/list/sound_change_signals + //The weather type we're working with + var/weather_trait + //The playlist of sounds to draw from. Pass by ref + var/list/playlist + + +/datum/element/weather_listener/Attach(datum/target, w_type, trait, weather_playlist) + . = ..() + if(!weather_type) + weather_type = w_type + sound_change_signals = list( + COMSIG_WEATHER_TELEGRAPH(weather_type), + COMSIG_WEATHER_START(weather_type), + COMSIG_WEATHER_WINDDOWN(weather_type), + COMSIG_WEATHER_END(weather_type) + ) + weather_trait = trait + playlist = weather_playlist + + RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, .proc/handle_z_level_change) + RegisterSignal(target, COMSIG_MOB_LOGOUT, .proc/handle_logout) + +/datum/element/weather_listener/Detach(datum/source) + . = ..() + UnregisterSignal(source, COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGOUT) + +/datum/element/weather_listener/proc/handle_z_level_change(datum/source, old_z, new_z) + SIGNAL_HANDLER + var/list/fitting_z_levels = SSmapping.levels_by_trait(weather_trait) + if(!(new_z in fitting_z_levels)) + return + var/datum/component/our_comp = source.AddComponent(/datum/component/area_sound_manager, playlist, list(), COMSIG_MOB_LOGOUT, fitting_z_levels) + our_comp.RegisterSignal(SSdcs, sound_change_signals, /datum/component/area_sound_manager/proc/handle_change) + +/datum/element/weather_listener/proc/handle_logout(datum/source) + SIGNAL_HANDLER + source.RemoveElement(/datum/element/weather_listener, weather_type, weather_trait, playlist) + diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm index eba6b558d4d..e8c6bc4d22f 100644 --- a/code/datums/looping_sounds/_looping_sound.dm +++ b/code/datums/looping_sounds/_looping_sound.dm @@ -15,7 +15,7 @@ direct (bool) If true plays directly to provided atoms instead of from them */ /datum/looping_sound - var/list/atom/output_atoms + var/atom/parent var/mid_sounds var/mid_length ///Override for volume of start sound @@ -34,38 +34,46 @@ var/falloff_exponent var/timerid var/falloff_distance + var/skip_starting_sounds = FALSE + var/loop_started = FALSE -/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE) +/datum/looping_sound/New(_parent, start_immediately=FALSE, _direct=FALSE, _skip_starting_sounds = FALSE) if(!mid_sounds) WARNING("A looping sound datum was created without sounds to play.") return - output_atoms = _output_atoms + set_parent(_parent) direct = _direct + skip_starting_sounds = _skip_starting_sounds if(start_immediately) start() /datum/looping_sound/Destroy() - stop() - output_atoms = null + stop(TRUE) return ..() -/datum/looping_sound/proc/start(atom/add_thing) - if(add_thing) - output_atoms |= add_thing +/datum/looping_sound/proc/start(on_behalf_of) + if(on_behalf_of) + set_parent(on_behalf_of) if(timerid) return on_start() -/datum/looping_sound/proc/stop(atom/remove_thing) - if(remove_thing) - output_atoms -= remove_thing +/datum/looping_sound/proc/stop(null_parent) + if(null_parent) + set_parent(null) if(!timerid) return on_stop() deltimer(timerid, SSsound_loops) timerid = null + loop_started = FALSE + +/datum/looping_sound/proc/start_sound_loop() + loop_started = TRUE + sound_loop() + timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP | TIMER_DELETE_ME, SSsound_loops) /datum/looping_sound/proc/sound_loop(starttime) if(max_loops && world.time >= starttime + mid_length * max_loops) @@ -73,21 +81,15 @@ return if(!chance || prob(chance)) play(get_sound(starttime)) - if(!timerid) - timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP, SSsound_loops) /datum/looping_sound/proc/play(soundfile, volume_override) - var/list/atoms_cache = output_atoms var/sound/S = sound(soundfile) if(direct) S.channel = SSsounds.random_available_channel() S.volume = volume_override || volume //Use volume as fallback if theres no override - for(var/i in 1 to atoms_cache.len) - var/atom/thing = atoms_cache[i] - if(direct) - SEND_SOUND(thing, S) - else - playsound(thing, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance) + SEND_SOUND(parent, S) + else + playsound(parent, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance) /datum/looping_sound/proc/get_sound(starttime, _mid_sounds) . = _mid_sounds || mid_sounds @@ -96,11 +98,22 @@ /datum/looping_sound/proc/on_start() var/start_wait = 0 - if(start_sound) + if(start_sound && !skip_starting_sounds) play(start_sound, start_volume) start_wait = start_length - addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME, SSsound_loops) + timerid = addtimer(CALLBACK(src, .proc/start_sound_loop), start_wait, TIMER_CLIENT_TIME | TIMER_DELETE_ME | TIMER_STOPPABLE, SSsound_loops) /datum/looping_sound/proc/on_stop() - if(end_sound) + if(end_sound && loop_started) play(end_sound, end_volume) + +/datum/looping_sound/proc/set_parent(new_parent) + if(parent) + UnregisterSignal(parent, COMSIG_PARENT_QDELETING) + parent = new_parent + if(parent) + RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/handle_parent_del) + +/datum/looping_sound/proc/handle_parent_del(datum/source) + SIGNAL_HANDLER + set_parent(null) diff --git a/code/datums/looping_sounds/weather.dm b/code/datums/looping_sounds/weather.dm index 93debec49ce..6576cfb4e8d 100644 --- a/code/datums/looping_sounds/weather.dm +++ b/code/datums/looping_sounds/weather.dm @@ -51,6 +51,3 @@ mid_length = 1669 // exact length of the music in ticks volume = 100 extra_range = 30 - -/datum/looping_sound/void_loop/start(atom/add_thing) - . = ..() diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index c875dbfbd61..95cf6c96b9b 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -94,6 +94,7 @@ /datum/weather/proc/telegraph() if(stage == STARTUP_STAGE) return + SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_TELEGRAPH(type)) stage = STARTUP_STAGE var/list/affectareas = list() for(var/V in get_areas(area_type)) @@ -109,13 +110,15 @@ weather_duration = rand(weather_duration_lower, weather_duration_upper) START_PROCESSING(SSweather, src) update_areas() - for(var/M in GLOB.player_list) - var/turf/mob_turf = get_turf(M) - if(mob_turf && (mob_turf.z in impacted_z_levels)) + for(var/z_level in impacted_z_levels) + for(var/mob/player as anything in SSmobs.clients_by_zlevel[z_level]) + var/turf/mob_turf = get_turf(player) + if(!mob_turf) + continue if(telegraph_message) - to_chat(M, telegraph_message) + to_chat(player, telegraph_message) if(telegraph_sound) - SEND_SOUND(M, sound(telegraph_sound)) + SEND_SOUND(player, sound(telegraph_sound)) addtimer(CALLBACK(src, .proc/start), telegraph_duration) /** @@ -128,15 +131,18 @@ /datum/weather/proc/start() if(stage >= MAIN_STAGE) return + SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_START(type)) stage = MAIN_STAGE update_areas() - for(var/M in GLOB.player_list) - var/turf/mob_turf = get_turf(M) - if(mob_turf && (mob_turf.z in impacted_z_levels)) + for(var/z_level in impacted_z_levels) + for(var/mob/player as anything in SSmobs.clients_by_zlevel[z_level]) + var/turf/mob_turf = get_turf(player) + if(!mob_turf) + continue if(weather_message) - to_chat(M, weather_message) + to_chat(player, weather_message) if(weather_sound) - SEND_SOUND(M, sound(weather_sound)) + SEND_SOUND(player, sound(weather_sound)) if(!perpetual) addtimer(CALLBACK(src, .proc/wind_down), weather_duration) @@ -150,15 +156,18 @@ /datum/weather/proc/wind_down() if(stage >= WIND_DOWN_STAGE) return + SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_WINDDOWN(type)) stage = WIND_DOWN_STAGE update_areas() - for(var/M in GLOB.player_list) - var/turf/mob_turf = get_turf(M) - if(mob_turf && (mob_turf.z in impacted_z_levels)) + for(var/z_level in impacted_z_levels) + for(var/mob/player as anything in SSmobs.clients_by_zlevel[z_level]) + var/turf/mob_turf = get_turf(player) + if(!mob_turf) + continue if(end_message) - to_chat(M, end_message) + to_chat(player, end_message) if(end_sound) - SEND_SOUND(M, sound(end_sound)) + SEND_SOUND(player, sound(end_sound)) addtimer(CALLBACK(src, .proc/end), end_duration) /** @@ -170,7 +179,8 @@ */ /datum/weather/proc/end() if(stage == END_STAGE) - return 1 + return + SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_END(type)) stage = END_STAGE STOP_PROCESSING(SSweather, src) update_areas() @@ -179,13 +189,13 @@ * Returns TRUE if the living mob can be affected by the weather * */ -/datum/weather/proc/can_weather_act(mob/living/L) - var/turf/mob_turf = get_turf(L) +/datum/weather/proc/can_weather_act(mob/living/act_on) + var/turf/mob_turf = get_turf(act_on) if(mob_turf && !(mob_turf.z in impacted_z_levels)) return - if(immunity_type in L.weather_immunities) + if(immunity_type in act_on.weather_immunities) return - if(!(get_area(L) in impacted_areas)) + if(!(get_area(act_on) in impacted_areas)) return return TRUE diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 53d9f4805ba..1a16e91889c 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -25,55 +25,41 @@ probability = 90 barometer_predictable = TRUE - - var/datum/looping_sound/active_outside_ashstorm/sound_ao = new(list(), FALSE, TRUE) - var/datum/looping_sound/active_inside_ashstorm/sound_ai = new(list(), FALSE, TRUE) - var/datum/looping_sound/weak_outside_ashstorm/sound_wo = new(list(), FALSE, TRUE) - var/datum/looping_sound/weak_inside_ashstorm/sound_wi = new(list(), FALSE, TRUE) + var/list/weak_sounds = list() + var/list/strong_sounds = list() /datum/weather/ash_storm/telegraph() - . = ..() - var/list/inside_areas = list() - var/list/outside_areas = list() var/list/eligible_areas = list() for (var/z in impacted_z_levels) eligible_areas += SSmapping.areas_in_z["[z]"] for(var/i in 1 to eligible_areas.len) var/area/place = eligible_areas[i] if(place.outdoors) - outside_areas += place + weak_sounds[place] = /datum/looping_sound/weak_outside_ashstorm + strong_sounds[place] = /datum/looping_sound/active_outside_ashstorm else - inside_areas += place + weak_sounds[place] = /datum/looping_sound/weak_inside_ashstorm + strong_sounds[place] = /datum/looping_sound/active_inside_ashstorm CHECK_TICK - sound_ao.output_atoms = outside_areas - sound_ai.output_atoms = inside_areas - sound_wo.output_atoms = outside_areas - sound_wi.output_atoms = inside_areas - - sound_wo.start() - sound_wi.start() + //We modify this list instead of setting it to weak/stron sounds in order to preserve things that hold a reference to it + //It's essentially a playlist for a bunch of components that chose what sound to loop based on the area a player is in + GLOB.ash_storm_sounds += weak_sounds + return ..() /datum/weather/ash_storm/start() - . = ..() - sound_wo.stop() - sound_wi.stop() - - sound_ao.start() - sound_ai.start() + GLOB.ash_storm_sounds -= weak_sounds + GLOB.ash_storm_sounds += strong_sounds + return ..() /datum/weather/ash_storm/wind_down() - . = ..() - sound_ao.stop() - sound_ai.stop() - - sound_wo.start() - sound_wi.start() + GLOB.ash_storm_sounds -= strong_sounds + GLOB.ash_storm_sounds += weak_sounds + return ..() /datum/weather/ash_storm/end() - . = ..() - sound_wo.stop() - sound_wi.stop() + GLOB.ash_storm_sounds -= weak_sounds + return ..() /datum/weather/ash_storm/proc/is_ash_immune(atom/L) while (L && !isturf(L)) diff --git a/code/game/machinery/fat_sucker.dm b/code/game/machinery/fat_sucker.dm index 1bc77b547ab..6cb7c0a99db 100644 --- a/code/game/machinery/fat_sucker.dm +++ b/code/game/machinery/fat_sucker.dm @@ -29,7 +29,7 @@ /obj/machinery/fat_sucker/Initialize() . = ..() - soundloop = new(list(src), FALSE) + soundloop = new(src, FALSE) update_appearance() /obj/machinery/fat_sucker/Destroy() diff --git a/code/game/machinery/roulette_machine.dm b/code/game/machinery/roulette_machine.dm index e9276876cc2..2d5aabe327e 100644 --- a/code/game/machinery/roulette_machine.dm +++ b/code/game/machinery/roulette_machine.dm @@ -51,7 +51,7 @@ /obj/machinery/roulette/Initialize() . = ..() - jackpot_loop = new(list(src), FALSE) + jackpot_loop = new(src, FALSE) wires = new /datum/wires/roulette(src) /obj/machinery/roulette/Destroy() diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 7cece0bc6ff..2dee715a23d 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -84,7 +84,7 @@ GLOBAL_LIST_EMPTY(telecomms_list) /obj/machinery/telecomms/Initialize(mapload) . = ..() - soundloop = new(list(src), on) + soundloop = new(src, on) GLOB.telecomms_list += src if(mapload && autolinkers.len) return INITIALIZE_HINT_LATELOAD diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index 97cc3b1fedf..d2c5cabc548 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -32,7 +32,7 @@ . = ..() START_PROCESSING(SSobj, src) - soundloop = new(list(src), FALSE) + soundloop = new(src, FALSE) /obj/item/geiger_counter/Destroy() STOP_PROCESSING(SSobj, src) diff --git a/code/game/objects/items/devices/reverse_bear_trap.dm b/code/game/objects/items/devices/reverse_bear_trap.dm index eebda33c916..9ea79b56ef8 100644 --- a/code/game/objects/items/devices/reverse_bear_trap.dm +++ b/code/game/objects/items/devices/reverse_bear_trap.dm @@ -23,8 +23,8 @@ /obj/item/reverse_bear_trap/Initialize() . = ..() - soundloop = new(list(src)) - soundloop2 = new(list(src)) + soundloop = new(src) + soundloop2 = new(src) /obj/item/reverse_bear_trap/Destroy() QDEL_NULL(soundloop) diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index ec451f512db..9eada837962 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -36,7 +36,7 @@ . = ..() if(starting_tape_type) mytape = new starting_tape_type(src) - soundloop = new(list(src)) + soundloop = new(src) update_appearance() /obj/item/taperecorder/Destroy() diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index 50670d12daa..ab3b413c1ae 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -38,7 +38,7 @@ . = ..() create_reagents(reagent_capacity) reagents.add_reagent(reagent_id, reagent_capacity) - soundloop = new(list(src), FALSE) + soundloop = new(src, FALSE) AddComponent(/datum/component/plumbing/simple_demand) var/static/list/loc_connections = list( COMSIG_ATOM_ENTERED = .proc/on_entered, diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm index 3edc1a3e0de..2ae5cba6d32 100644 --- a/code/modules/admin/verbs/possess.dm +++ b/code/modules/admin/verbs/possess.dm @@ -23,6 +23,7 @@ usr.name = O.name usr.reset_perspective(O) usr.control_object = O + O.AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds) SSblackbox.record_feedback("tally", "admin_verb", 1, "Possess Object") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /proc/release() @@ -38,7 +39,7 @@ var/mob/living/carbon/human/H = usr H.name = H.get_visible_name() - + usr.control_object.RemoveElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds) usr.forceMove(get_turf(usr.control_object)) usr.reset_perspective() usr.control_object = null diff --git a/code/modules/antagonists/eldritch_cult/knowledge/void_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/void_lore.dm index 1a4d10c21ac..34cadbfc5b2 100644 --- a/code/modules/antagonists/eldritch_cult/knowledge/void_lore.dm +++ b/code/modules/antagonists/eldritch_cult/knowledge/void_lore.dm @@ -191,7 +191,7 @@ waltzing.client?.give_award(/datum/award/achievement/misc/void_ascension, waltzing) priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# The nobleman of void [waltzing.real_name] has arrived, step along the Waltz that ends worlds! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", ANNOUNCER_SPANOMALIES) - sound_loop = new(list(user),TRUE,TRUE) + sound_loop = new(user, TRUE, TRUE) return ..() /datum/eldritch_knowledge/final/void_final/on_death() diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm index 7f617d0a87f..da2c5688f93 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm @@ -103,7 +103,7 @@ corner.active = TRUE corner.update_appearance() RegisterSignal(corner, COMSIG_PARENT_QDELETING, .proc/unregister_signals) - soundloop = new(list(src), TRUE) + soundloop = new(src, TRUE) soundloop.volume = 5 /** diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index d2bf6568282..2f239b2eb28 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -158,7 +158,7 @@ /obj/item/clothing/head/helmet/justice/Initialize() . = ..() - weewooloop = new(list(src), FALSE, FALSE) + weewooloop = new(src, FALSE, FALSE) /obj/item/clothing/head/helmet/justice/Destroy() QDEL_NULL(weewooloop) diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 2cc51ab9bbb..26f7d49e3ae 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -27,7 +27,7 @@ /obj/item/clothing/head/helmet/space/hardsuit/Initialize() . = ..() - soundloop = new(list(), FALSE, TRUE) + soundloop = new(src, FALSE, TRUE) soundloop.volume = 5 START_PROCESSING(SSobj, src) diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index d1ccbb96d8c..bce31ca452a 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -39,7 +39,7 @@ GLOBAL_LIST_INIT(oilfry_blacklisted_items, typecacheof(list( . = ..() create_reagents(50, OPENCONTAINER) reagents.add_reagent(/datum/reagent/consumable/cooking_oil, 25) - fry_loop = new(list(src), FALSE) + fry_loop = new(src, FALSE) /obj/machinery/deepfryer/Destroy() QDEL_NULL(fry_loop) diff --git a/code/modules/food_and_drinks/kitchen_machinery/griddle.dm b/code/modules/food_and_drinks/kitchen_machinery/griddle.dm index 3337d5d161a..ce44c882693 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/griddle.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/griddle.dm @@ -24,7 +24,7 @@ /obj/machinery/griddle/Initialize() . = ..() - grill_loop = new(list(src), FALSE) + grill_loop = new(src, FALSE) if(isnum(variant)) variant = rand(1,3) RegisterSignal(src, COMSIG_ATOM_EXPOSE_REAGENT, .proc/on_expose_reagent) diff --git a/code/modules/food_and_drinks/kitchen_machinery/grill.dm b/code/modules/food_and_drinks/kitchen_machinery/grill.dm index 811bd3232af..c0ca70a6213 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/grill.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/grill.dm @@ -18,7 +18,7 @@ /obj/machinery/grill/Initialize() . = ..() - grill_loop = new(list(src), FALSE) + grill_loop = new(src, FALSE) /obj/machinery/grill/Destroy() QDEL_NULL(grill_loop) diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm index 1aa75330ec1..29ef502ad03 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm @@ -36,7 +36,7 @@ . = ..() wires = new /datum/wires/microwave(src) create_reagents(100) - soundloop = new(list(src), FALSE) + soundloop = new(src, FALSE) /obj/machinery/microwave/Destroy() eject() diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index a8f06200af0..ba1b4ed28d3 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -20,6 +20,7 @@ * * grant any actions the mob has to the client * * calls [auto_deadmin_on_login](mob.html#proc/auto_deadmin_on_login) * * send signal COMSIG_MOB_CLIENT_LOGIN + * * attaches the ash listener element so clients can hear weather * client can be deleted mid-execution of this proc, chiefly on parent calls, with lag */ /mob/Login() @@ -94,6 +95,8 @@ SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client) client.init_verbs() + AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds) + return TRUE diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 7d346086689..eb1e67a25a8 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -61,7 +61,7 @@ comp_light_color = "#FFFFFF" idle_threads = list() if(looping_sound) - soundloop = new(list(src), enabled) + soundloop = new(src, enabled) update_appearance() /obj/item/modular_computer/Destroy() diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 6fd37f0ff32..cefb3a72f22 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -32,7 +32,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne /obj/machinery/gravity_generator/main/Initialize() . = ..() - soundloop = new(list(src), TRUE) + soundloop = new(src, TRUE) /obj/machinery/gravity_generator/main/Destroy() . = ..() diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 7e2c02e0dbc..ddd83003844 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -19,7 +19,7 @@ /obj/machinery/power/port_gen/Initialize() . = ..() - soundloop = new(list(src), active) + soundloop = new(src, active) /obj/machinery/power/port_gen/Destroy() QDEL_NULL(soundloop) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index fd4e8ecf641..1eca5d94bd7 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -242,7 +242,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) AddElement(/datum/element/bsa_blocker) RegisterSignal(src, COMSIG_ATOM_BSA_BEAM, .proc/call_explode) - soundloop = new(list(src), TRUE) + soundloop = new(src, TRUE) if(ispath(psyOverlay)) psyOverlay = new psyOverlay() else diff --git a/tgstation.dme b/tgstation.dme index 40e4fe0ee0a..2c145200383 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -151,6 +151,7 @@ #include "code\__DEFINES\vehicles.dm" #include "code\__DEFINES\vv.dm" #include "code\__DEFINES\wall_dents.dm" +#include "code\__DEFINES\weather.dm" #include "code\__DEFINES\wiremod.dm" #include "code\__DEFINES\wires.dm" #include "code\__DEFINES\wounds.dm" @@ -486,6 +487,7 @@ #include "code\datums\components\acid.dm" #include "code\datums\components\anti_magic.dm" #include "code\datums\components\aquarium.dm" +#include "code\datums\components\area_sound_manager.dm" #include "code\datums\components\areabound.dm" #include "code\datums\components\armor_plate.dm" #include "code\datums\components\bane.dm" @@ -737,6 +739,7 @@ #include "code\datums\elements\volatile_gas_storage.dm" #include "code\datums\elements\waddling.dm" #include "code\datums\elements\weapon_description.dm" +#include "code\datums\elements\weather_listener.dm" #include "code\datums\elements\decals\_decal.dm" #include "code\datums\elements\decals\blood.dm" #include "code\datums\elements\food\dunkable.dm"