Ports Bees ambience, reverb & sound system (#19559)

* ambience part 1

* almost there

* p3

* 420blazeit

* jesus christ im sorry

* virofix

* hm

* increase max time
This commit is contained in:
azzzertyy
2023-07-12 20:36:22 +01:00
committed by GitHub
parent 9790bdc966
commit 2b4079d1e5
49 changed files with 793 additions and 194 deletions

View File

@@ -0,0 +1,82 @@
/// The subsystem used to play ambience to users every now and then, makes them real excited.
SUBSYSTEM_DEF(ambience)
name = "Ambience"
flags = SS_BACKGROUND|SS_NO_INIT
priority = FIRE_PRIORITY_AMBIENCE
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
wait = 2
///Assoc list of listening client - next ambience time
var/list/ambience_listening_clients = list()
var/list/currentrun = list()
/datum/controller/subsystem/ambience/fire(resumed)
if(!resumed)
currentrun = ambience_listening_clients.Copy()
var/list/cached_clients = currentrun
for(var/client/client_iterator as anything in cached_clients)
if(isnull(client_iterator))
continue
if(isnewplayer(client_iterator.mob))
continue
process_ambience_client(client_iterator)
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/ambience/proc/process_ambience_client(client/to_process)
var/mob/current_mob = to_process.mob
var/area/current_area = get_area(current_mob)
if(!current_area) //Something's gone horribly wrong
stack_trace("[key_name(to_process)] has somehow ended up in nullspace. WTF did you do -xoxo ambience subsystem")
ambience_listening_clients -= to_process
return
if(current_area.ambient_buzz)
play_buzz(current_mob, current_area)
if(ambience_listening_clients[to_process] > world.time)
return //Not ready for the next sound
if(current_area.ambientsounds && length(current_area.ambientsounds))
var/ambi_fx = pick(current_area.ambientsounds)
play_ambience_effects(current_mob, ambi_fx, current_area)
if(current_area.ambientmusic && length(current_area.ambientmusic))
var/ambi_music = pick(current_area.ambientmusic)
play_ambience_music(current_mob, ambi_music, current_area)
ambience_listening_clients[to_process] = world.time + rand(current_area.min_ambience_cooldown, current_area.max_ambience_cooldown)
/datum/controller/subsystem/ambience/proc/add_ambience_client(client/to_add)
if(SSambience.ambience_listening_clients[to_add] > world.time)
return // If already properly set we don't want to reset the timer.
SSambience.ambience_listening_clients[to_add] = world.time + 10 SECONDS //Just wait 10 seconds before the next one aight mate? cheers.
/datum/controller/subsystem/ambience/proc/remove_ambience_client(client/to_remove)
ambience_listening_clients -= to_remove
currentrun -= to_remove
///Buzzing sound, the low ship drone that plays constantly, IC (requires the user to be able to hear)
/datum/controller/subsystem/ambience/proc/play_buzz(mob/M, area/A)
if (A.ambient_buzz && (M.client.prefs.toggles & SOUND_SHIP_AMBIENCE) && M.can_hear_ambience())
if (!M.client.buzz_playing || (A.ambient_buzz != M.client.buzz_playing))
SEND_SOUND(M, sound(A.ambient_buzz, repeat = 1, wait = 0, volume = A.ambient_buzz_vol, channel = CHANNEL_BUZZ))
M.client.buzz_playing = A.ambient_buzz // It's done this way so I can tell when the user switches to an area that has a different buzz effect, so we can seamlessly swap over to that one
return
if(M.client.buzz_playing) // If it's playing, and it shouldn't be, stop it
M.stop_sound_channel(CHANNEL_BUZZ)
M.client.buzz_playing = null
///Effect, random sounds that will play at random times, IC (requires the user to be able to hear)
/datum/controller/subsystem/ambience/proc/play_ambience_effects(mob/M, _ambi_fx, area/A)
if(M.can_hear_ambience() && !M.client?.channel_in_use(CHANNEL_AMBIENT_EFFECTS))
SEND_SOUND(M, sound(_ambi_fx, repeat = 0, wait = 0, volume = 45, channel = CHANNEL_AMBIENT_EFFECTS))
///Play background music, the more OOC ambience, like eerie space music
/datum/controller/subsystem/ambience/proc/play_ambience_music(mob/M, _ambi_music, area/A)
if(!M.client?.channel_in_use(CHANNEL_AMBIENT_MUSIC))
SEND_SOUND(M, sound(_ambi_music, repeat = 0, wait = 0, volume = 75, channel = CHANNEL_AMBIENT_MUSIC))

View File

@@ -0,0 +1,127 @@
/*
* Sound subsystem:
* Used for things that need constant updating (sound fading in / out)
*/
SUBSYSTEM_DEF(sound_effects)
name = "Sound"
wait = 1
priority = FIRE_PRIORITY_AMBIENCE
flags = SS_NO_INIT
//Note: Make sure you update this if you use sound fading pre-game
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/acting_effects = list() //key = sound, value = datum
var/list/currentrun = list()
/datum/controller/subsystem/sound_effects/fire(resumed = 0)
if (!resumed)
src.currentrun = acting_effects.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(LAZYLEN(currentrun))
var/datum/sound_effect/sound_effect = currentrun[currentrun[currentrun.len]]
currentrun.len--
sound_effect.update_effect()
if(world.time > sound_effect.end_tick)
sound_effect.end_effect()
acting_effects -= sound_effect.effect_id
if (MC_TICK_CHECK)
return
// ===== Sound effect procs =====
/proc/sound_fade(sound/S, start_volume = 100, end_volume = 0, time = 10, var/listeners)
//Check basics
if(!S)
CRASH("sound_fade called without a sound file.")
if(!listeners)
return
//Check in list format
var/listeners_list = listeners
if(!islist(listeners_list))
listeners_list = list(listeners)
//Create datum
new /datum/sound_effect/fade(S, listeners_list, time, start_volume, end_volume)
// ===== Sound effect datum =====
/datum/sound_effect
var/name = "null"
var/sound/sound
var/list/listeners
var/start_tick
var/end_tick
var/effect_id
/datum/sound_effect/New(S, list/_listeners, time)
. = ..()
sound = S
listeners = _listeners
start_tick = world.time
end_tick = world.time + time
effect_id = generate_id()
start_sound()
/datum/sound_effect/proc/generate_id()
var/id = "[name][sound.file]"
for(var/A in listeners)
id = "[id][REF(A)]"
return id
/datum/sound_effect/proc/send_sound()
for(var/receiver in listeners)
SEND_SOUND(receiver, sound)
/datum/sound_effect/proc/update_effect()
return //Not implemented
/datum/sound_effect/proc/end_effect()
return //Not implemented
// Send the sound to the person it's affecting and add it to the sound subsystem.
// Should be overridden to account for if an effect is already playing for that sound.
/datum/sound_effect/proc/start_sound()
send_sound()
SSsound_effects.acting_effects[effect_id] = src
//============== Fade =============
/datum/sound_effect/fade
name = "fade"
var/in_vol
var/out_vol
//Calculated
var/current_vol
/datum/sound_effect/fade/New(S, list/_listeners, time, start_vol, end_vol)
in_vol = start_vol
out_vol = end_vol
. = ..(S, _listeners, time)
/datum/sound_effect/fade/start_sound()
//If the sound is already playing, make it fade from the current point
if(SSsound_effects.acting_effects[effect_id])
var/datum/sound_effect/fade/old_sound = SSsound_effects.acting_effects[effect_id]
in_vol = old_sound.current_vol
else
send_sound()
SSsound_effects.acting_effects[effect_id] = src
/datum/sound_effect/fade/update_effect()
var/time_multiplier = clamp((world.time - start_tick) / (end_tick - start_tick), 0, 1)
current_vol = (time_multiplier * out_vol) + ((1-time_multiplier) * in_vol)
sound.status = SOUND_UPDATE
sound.volume = current_vol
for(var/receiver in listeners)
SEND_SOUND(receiver, sound)
/datum/sound_effect/fade/end_effect()
if(!out_vol)
sound.repeat = FALSE