Skip to content

Commit

Permalink
Playsound improvements (#16611)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lumipharon authored Oct 19, 2024
1 parent 6afd8a8 commit 197b04d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 42 deletions.
74 changes: 42 additions & 32 deletions code/controllers/subsystem/explosions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -137,38 +137,48 @@ SUBSYSTEM_DEF(explosions)
var/sound/far_explosion_sound = SFX_EXPLOSION_LARGE_DISTANT
var/sound/creak_sound = SFX_EXPLOSION_CREAK

for(var/MN in GLOB.player_list)
var/mob/M = MN
// Double check for client
var/turf/M_turf = get_turf(M)
if(M_turf && M_turf.z == epicenter.z)
var/dist = get_dist(M_turf, epicenter)
var/baseshakeamount
if(orig_max_distance - dist > 0)
baseshakeamount = sqrt((orig_max_distance - dist)*0.1)
if(devastation_range)
explosion_sound = SFX_EXPLOSION_LARGE
else if(heavy_impact_range)
explosion_sound = SFX_EXPLOSION_MED
else if(light_impact_range || weak_impact_range)
explosion_sound = SFX_EXPLOSION_SMALL
far_explosion_sound = SFX_EXPLOSION_SMALL_DISTANT
// If inside the blast radius + world.view - 2
if(dist <= round(max_range + world.view - 2, 1))
M.playsound_local(epicenter, explosion_sound, 75, 1, frequency, falloff = 5)
if(is_mainship_level(epicenter.z))
M.playsound_local(epicenter, creak_sound, 40, 1, frequency, falloff = 5)//ship groaning under explosion effect
if(baseshakeamount > 0)
shake_camera(M, 15, clamp(baseshakeamount, 0, 5))
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
var/far_volume = clamp(far_dist, 30, 60) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, far_explosion_sound, far_volume, 1, frequency, falloff = 5)
if(is_mainship_level(epicenter.z))
M.playsound_local(epicenter, creak_sound, far_volume*3, 1, frequency, falloff = 5)//ship groaning under explosion effect
if(baseshakeamount > 0)
shake_camera(M, 7, clamp(baseshakeamount*0.15, 0, 1.5))
if(devastation_range)
explosion_sound = SFX_EXPLOSION_LARGE
else if(heavy_impact_range)
explosion_sound = SFX_EXPLOSION_MED
else if(light_impact_range || weak_impact_range)
explosion_sound = SFX_EXPLOSION_SMALL
far_explosion_sound = SFX_EXPLOSION_SMALL_DISTANT
explosion_sound = sound(get_sfx(explosion_sound))
far_explosion_sound = sound(get_sfx(far_explosion_sound))
creak_sound = sound(get_sfx(creak_sound))

var/list/listeners = SSmobs.clients_by_zlevel[epicenter.z].Copy()
for(var/mob/ai_eye AS in GLOB.aiEyes)
var/turf/eye_turf = get_turf(ai_eye)
if(!eye_turf || eye_turf.z != epicenter.z)
continue
listeners += ai_eye

for(var/mob/listener AS in listeners|SSmobs.dead_players_by_zlevel[epicenter.z])
var/turf/M_turf = get_turf(listener)
var/dist = get_dist(M_turf, epicenter)
if(dist > far_dist)
continue
var/baseshakeamount
if(orig_max_distance - dist > 0)
baseshakeamount = sqrt((orig_max_distance - dist)*0.1)
// If inside the blast radius + world.view - 2
if(dist <= round(max_range + world.view - 2, 1))
listener.playsound_local(epicenter, explosion_sound, 75, 1, frequency, falloff = 5)
if(is_mainship_level(epicenter.z))
listener.playsound_local(epicenter, creak_sound, 40, 1, frequency, falloff = 5)//ship groaning under explosion effect
if(baseshakeamount > 0)
shake_camera(listener, 15, clamp(baseshakeamount, 0, 5))
continue
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
var/far_volume = clamp(far_dist, 30, 60) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
listener.playsound_local(epicenter, far_explosion_sound, far_volume, 1, frequency, falloff = 5)
if(is_mainship_level(epicenter.z))
listener.playsound_local(epicenter, creak_sound, far_volume*3, 1, frequency, falloff = 5)//ship groaning under explosion effect
if(baseshakeamount > 0)
shake_camera(listener, 7, clamp(baseshakeamount*0.15, 0, 1.5))

if(devastation_range > 0)
new /obj/effect/temp_visual/explosion(epicenter, max_range, color, FALSE, TRUE)
Expand Down
31 changes: 21 additions & 10 deletions code/game/sound.dm
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ A good representation is: 'byond applies a volume reduction to the sound every X
/proc/playsound(atom/source, soundin, vol, vary, sound_range, falloff, is_global, frequency, channel = 0, ambient_sound = FALSE)
var/turf/turf_source = get_turf(source)

if(!turf_source)
if (!turf_source || !soundin || !vol)
return

//allocate a channel if necessary now so its the same for everyone
Expand All @@ -61,29 +61,40 @@ A good representation is: 'byond applies a volume reduction to the sound every X
sound_range = round(0.5*vol) //if no specific range, the max range is equal to half the volume.

if(!frequency)
frequency = GET_RANDOM_FREQ // Same frequency for everybody
// Looping through the player list has the added bonus of working for mobs inside containers
frequency = GET_RANDOM_FREQ
var/sound/S = sound(get_sfx(soundin))
for(var/mob/listener AS in GLOB.player_list|GLOB.aiEyes)
if(!listener.client && !isAIeye(listener))

var/list/listeners = SSmobs.clients_by_zlevel[turf_source.z].Copy()
for(var/mob/ai_eye AS in GLOB.aiEyes)
var/turf/eye_turf = get_turf(ai_eye)
if(!eye_turf || eye_turf.z != turf_source.z)
continue
if(ambient_sound && !(listener.client?.prefs?.toggles_sound & SOUND_AMBIENCE))
listeners += ai_eye

for(var/mob/listener AS in listeners|SSmobs.dead_players_by_zlevel[turf_source.z])
if(get_dist(listener, turf_source) > sound_range)
continue
var/turf/T = get_turf(listener)
if(!T || T.z != turf_source.z || get_dist(listener, turf_source) > sound_range)
if(ambient_sound && !(listener.client?.prefs?.toggles_sound & SOUND_AMBIENCE))
continue
listener.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global, channel, S)


//We do tanks separately, since they are not actually on the source z, and we need some other stuff to get accurate directional sound
for(var/obj/vehicle/sealed/armored/armor AS in GLOB.tank_list)
if(!armor.interior || armor.z != turf_source.z || get_dist(armor.loc, turf_source) > sound_range)
continue
if(!length(armor.interior.occupants))
continue
var/turf/middle_turf = armor.interior.loaded_turfs[floor(length(armor.interior.loaded_turfs) * 0.5)]
var/turf/origin_point = locate(clamp(middle_turf.x - armor.x + turf_source.x, 1, world.maxx), clamp(middle_turf.y - armor.y + turf_source.y, 1, world.maxy), middle_turf.z)
//origin point is regardless of vehicle orientation for player QOL and simple sanity

for(var/mob/crew AS in armor.interior.occupants)
if(!crew.client)
continue
if(ambient_sound && !(crew.client.prefs.toggles_sound & SOUND_AMBIENCE))
continue
//turf source is null on purpose because it will not work properly since crew is on a different z
crew.playsound_local(null, soundin, vol*0.5, vary, frequency, falloff, is_global, channel, S)
crew.playsound_local(origin_point, soundin, vol*0.5, vary, frequency, falloff, is_global, channel, S)

/**
* Plays a sound locally
Expand Down

0 comments on commit 197b04d

Please sign in to comment.