Adds snowstorm sounds (#89463)

## About The Pull Request

Unfortunately, the sound only plays when you're outside, under the
storm. I would love for it to play when you're near a window or
something, but that would vastly over-complicate things. Maybe later.


https://github.com/user-attachments/assets/6ca4bdb8-b1da-4644-bb71-6ca18cf3daec

## Why It's Good For The Game

Some free immersion. And in particular in the dark sometimes I don't
notice a snowstorm is raging so it adds some nice feedback.

## Changelog

🆑 Melbert
sound: Snowstorms now have sounds associated.
/🆑
This commit is contained in:
MrMelbert
2025-02-20 08:15:54 -06:00
committed by Roxy
parent 60437c2896
commit 024ee4508d
22 changed files with 95 additions and 9 deletions

View File

@@ -11,9 +11,10 @@
#define CHANNEL_CHARGED_SPELL 1015
#define CHANNEL_ELEVATOR 1014
#define CHANNEL_ESCAPEMENU 1013
#define CHANNEL_WEATHER 1012
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
//KEEP IT UPDATED
#define CHANNEL_HIGHEST_AVAILABLE 1012
#define CHANNEL_HIGHEST_AVAILABLE 1011
#define MAX_INSTRUMENT_CHANNELS (128 * 6)

View File

@@ -1,5 +1,7 @@
//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)
/// Tracks where we should play snowstorm sounds for the area sound listener
GLOBAL_LIST_EMPTY(snowstorm_sounds)
#define STARTUP_STAGE 1
#define MAIN_STAGE 2

View File

@@ -1,5 +1,6 @@
///Allows you to set a theme for a set of areas without tying them to looping sounds explicitly
/datum/component/area_sound_manager
dupe_mode = COMPONENT_DUPE_ALLOWED
///area -> looping sound type
var/list/area_to_looping_type = list()
///Current sound loop

View File

@@ -70,6 +70,7 @@
user.reset_perspective(target)
target.AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
target.AddElement(/datum/element/weather_listener, /datum/weather/snow_storm, ZTRAIT_SNOWSTORM, GLOB.snowstorm_sounds)
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(end_possession))
return TRUE
@@ -82,6 +83,7 @@
var/mob/poltergeist = parent
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/snow_storm, ZTRAIT_SNOWSTORM, GLOB.snowstorm_sounds)
UnregisterSignal(possessed, COMSIG_QDELETING)
if(!isnull(stashed_name))

View File

@@ -28,6 +28,9 @@
RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(handle_z_level_change), override = TRUE)
RegisterSignal(target, COMSIG_MOB_LOGOUT, PROC_REF(handle_logout), override = TRUE)
var/mob/target_mob = target
handle_z_level_change(target_mob, null, target_mob.loc)
/datum/element/weather_listener/Detach(datum/source)
. = ..()
UnregisterSignal(source, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGOUT))

View File

@@ -217,7 +217,10 @@
if(start_sound && !skip_starting_sounds)
play(start_sound, start_volume)
start_wait = start_length
timer_id = addtimer(CALLBACK(src, PROC_REF(start_sound_loop)), start_wait, TIMER_CLIENT_TIME | TIMER_DELETE_ME | TIMER_STOPPABLE, SSsound_loops)
if(start_wait)
timer_id = addtimer(CALLBACK(src, PROC_REF(start_sound_loop)), start_wait, TIMER_CLIENT_TIME | TIMER_DELETE_ME | TIMER_STOPPABLE, SSsound_loops)
else
start_sound_loop()
/// Stops sound playing on current channel, if specified
/datum/looping_sound/proc/stop_current()

View File

@@ -51,3 +51,45 @@
mid_length = 166.9 SECONDS // exact length of the music in ticks
volume = 100
extra_range = 30
/datum/looping_sound/snowstorm
mid_sounds = list(
'sound/ambience/weather/snowstorm/snow1.ogg' = 1,
'sound/ambience/weather/snowstorm/snow2.ogg' = 1,
'sound/ambience/weather/snowstorm/snow3.ogg' = 1,
'sound/ambience/weather/snowstorm/snow4.ogg' = 1,
'sound/ambience/weather/snowstorm/snow5.ogg' = 1,
'sound/ambience/weather/snowstorm/snow6.ogg' = 1,
'sound/ambience/weather/snowstorm/snow7.ogg' = 1,
'sound/ambience/weather/snowstorm/snow8.ogg' = 1,
'sound/ambience/weather/snowstorm/snow9.ogg' = 1,
)
mid_length = 10 SECONDS
volume = 30
sound_channel = CHANNEL_WEATHER
/// Dynamically adjust the length of the sound to appropriate values
var/list/sound_to_length = list(
'sound/ambience/weather/snowstorm/snow1.ogg' = 11.3 SECONDS,
'sound/ambience/weather/snowstorm/snow2.ogg' = 9.7 SECONDS,
'sound/ambience/weather/snowstorm/snow3.ogg' = 9.7 SECONDS,
'sound/ambience/weather/snowstorm/snow4.ogg' = 7.3 SECONDS,
'sound/ambience/weather/snowstorm/snow5.ogg' = 7.3 SECONDS,
'sound/ambience/weather/snowstorm/snow6.ogg' = 8.8 SECONDS,
'sound/ambience/weather/snowstorm/snow7.ogg' = 11.6 SECONDS,
'sound/ambience/weather/snowstorm/snow8.ogg' = 11.6 SECONDS,
'sound/ambience/weather/snowstorm/snow9.ogg' = 7.3 SECONDS,
)
// hijacking sound loop code to run loops of varying length
// doing this because set_mid_length can't run DURING a soundloop, which means we can't variably adjust the length of the sound
/datum/looping_sound/snowstorm/start_sound_loop()
loop_started = TRUE
sound_loop()
/datum/looping_sound/snowstorm/sound_loop(start_time)
if(!loop_started)
return
var/picked_sound = get_sound()
play(picked_sound)
if(sound_to_length[picked_sound])
timer_id = addtimer(CALLBACK(src, PROC_REF(sound_loop)), sound_to_length[picked_sound], TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_DELETE_ME, SSsound_loops)

View File

@@ -18,6 +18,8 @@
var/telegraph_duration = 30 SECONDS
/// The sound file played to everyone on an affected z-level
var/telegraph_sound
/// Volume of the telegraph sound
var/telegraph_sound_vol
/// The overlay applied to all tiles on the z-level
var/telegraph_overlay
@@ -42,6 +44,8 @@
var/end_duration = 30 SECONDS
/// Sound that plays while weather is ending
var/end_sound
/// Volume of the sound that plays while weather is ending
var/end_sound_vol
/// Area overlay while weather is ending
var/end_overlay
@@ -122,7 +126,7 @@
SSweather.processing |= src
update_areas()
if(telegraph_duration)
send_alert(telegraph_message, telegraph_sound)
send_alert(telegraph_message, telegraph_sound, telegraph_sound_vol)
addtimer(CALLBACK(src, PROC_REF(start)), telegraph_duration)
/**
@@ -157,7 +161,7 @@
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_WINDDOWN(type), src)
stage = WIND_DOWN_STAGE
update_areas()
send_alert(end_message, end_sound)
send_alert(end_message, end_sound, end_sound_vol)
addtimer(CALLBACK(src, PROC_REF(end)), end_duration)
/**
@@ -178,7 +182,7 @@
SEND_SIGNAL(impacted_area, COMSIG_WEATHER_ENDED_IN_AREA(type), src)
// handles sending all alerts
/datum/weather/proc/send_alert(alert_msg, alert_sfx)
/datum/weather/proc/send_alert(alert_msg, alert_sfx, alert_sfx_vol = 100)
for(var/z_level in impacted_z_levels)
for(var/mob/player as anything in SSmobs.clients_by_zlevel[z_level])
if(!can_get_alert(player))
@@ -186,7 +190,8 @@
if(alert_msg)
to_chat(player, alert_msg)
if(alert_sfx)
SEND_SOUND(player, sound(alert_sfx))
player.stop_sound_channel(CHANNEL_WEATHER)
SEND_SOUND(player, sound(alert_sfx, channel = CHANNEL_WEATHER, volume = alert_sfx_vol))
// the checks for if a mob should receive alerts, returns TRUE if can
/datum/weather/proc/can_get_alert(mob/player)

View File

@@ -6,6 +6,8 @@
telegraph_message = span_warning("Drifting particles of snow begin to dust the surrounding area..")
telegraph_duration = 30 SECONDS
telegraph_overlay = "light_snow"
telegraph_sound = 'sound/ambience/weather/snowstorm/snow_start.ogg'
telegraph_sound_vol = /datum/looping_sound/snowstorm::volume + 10
weather_message = span_userdanger("<i>Harsh winds pick up as dense snow begins to fall from the sky! Seek shelter!</i>")
weather_overlay = "snow_storm"
@@ -15,6 +17,8 @@
end_duration = 10 SECONDS
end_message = span_bolddanger("The snowfall dies down, it should be safe to go outside again.")
end_sound = 'sound/ambience/weather/snowstorm/snow_end.ogg'
end_sound_vol = /datum/looping_sound/snowstorm::volume + 10
area_type = /area
protect_indoors = TRUE
@@ -32,13 +36,23 @@
/datum/weather/snow_storm/weather_act(mob/living/living)
living.adjust_bodytemperature(-rand(cooling_lower, cooling_upper))
/datum/weather/snow_storm/start()
GLOB.snowstorm_sounds.Cut() // it's passed by ref
for(var/area/impacted_area as anything in impacted_areas)
GLOB.snowstorm_sounds[impacted_area] = /datum/looping_sound/snowstorm
return ..()
/datum/weather/snow_storm/end()
GLOB.snowstorm_sounds.Cut()
return ..()
// since snowstorm is on a station z level, add extra checks to not annoy everyone
/datum/weather/snow_storm/can_get_alert(mob/player)
if(!..())
return FALSE
if(!is_station_level(player.z))
return TRUE // bypass checks
return TRUE // bypass checks
if(isobserver(player))
return TRUE
@@ -49,7 +63,6 @@
if(istype(get_area(player), /area/mine))
return TRUE
for(var/area/snow_area in impacted_areas)
if(locate(snow_area) in view(player))
return TRUE
@@ -58,7 +71,7 @@
///A storm that doesn't stop storming, and is a bit stronger
/datum/weather/snow_storm/forever_storm
telegraph_duration = 0
telegraph_duration = 0 SECONDS
perpetual = TRUE
probability = 0

View File

@@ -131,6 +131,7 @@
client.init_verbs()
AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
AddElement(/datum/element/weather_listener, /datum/weather/snow_storm, ZTRAIT_SNOWSTORM, GLOB.snowstorm_sounds)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_LOGGED_IN, src)

View File

@@ -0,0 +1,13 @@
{
snow1.ogg
snow2.ogg
snow3.ogg
snow4.ogg
snow5.ogg
snow6.ogg
snow7.ogg
snow8.ogg
snow9.ogg
snow_start.ogg
snow_end.ogg
} Wind at door howling 4.ogg by Bosk1 -- https://freesound.org/s/217186/ -- License: Attribution 4.0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.