Jukebox rework + environment/reverb controls for sounds played via playsound_local (#7367)
* Reworks jukeboxes - Makes jukeboxes a subsystem, adds realtime directional jukebox audio, adds environment/reverb controls to sounds played with TG procs * fixes my stupidity, has no effect at all outside of boombox local branch * minor optimizations, fixes jukebox sound not updating at all when the source is on a different z-level
This commit is contained in:
+10
-9
@@ -3,21 +3,22 @@
|
||||
#define CHANNEL_ADMIN 1023
|
||||
#define CHANNEL_VOX 1022
|
||||
#define CHANNEL_JUKEBOX 1021
|
||||
#define CHANNEL_JUSTICAR_ARK 1020
|
||||
#define CHANNEL_HEARTBEAT 1019 //sound channel for heartbeats
|
||||
#define CHANNEL_AMBIENCE 1018
|
||||
#define CHANNEL_BUZZ 1017
|
||||
#define CHANNEL_BICYCLE 1016
|
||||
#define CHANNEL_JUKEBOX_START 1016
|
||||
#define CHANNEL_JUSTICAR_ARK 1015
|
||||
#define CHANNEL_HEARTBEAT 1014 //sound channel for heartbeats
|
||||
#define CHANNEL_AMBIENCE 1013
|
||||
#define CHANNEL_BUZZ 1012
|
||||
#define CHANNEL_BICYCLE 1011
|
||||
|
||||
//CIT CHANNELS - TRY NOT TO REGRESS
|
||||
#define CHANNEL_PRED 1015
|
||||
#define CHANNEL_DIGEST 1014
|
||||
#define CHANNEL_PREYLOOP 1013
|
||||
#define CHANNEL_PRED 1010
|
||||
#define CHANNEL_DIGEST 1009
|
||||
#define CHANNEL_PREYLOOP 1008
|
||||
|
||||
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
|
||||
//KEEP IT UPDATED
|
||||
|
||||
#define CHANNEL_HIGHEST_AVAILABLE 1012 //CIT CHANGE - COMPENSATES FOR VORESOUND CHANNELS
|
||||
#define CHANNEL_HIGHEST_AVAILABLE 1008 //CIT CHANGE - COMPENSATES FOR VORESOUND CHANNELS
|
||||
|
||||
|
||||
#define SOUND_MINIMUM_PRESSURE 10
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
SUBSYSTEM_DEF(jukeboxes)
|
||||
name = "Jukeboxes"
|
||||
wait = 5
|
||||
var/list/songs = list()
|
||||
var/list/activejukeboxes = list()
|
||||
|
||||
/datum/track
|
||||
var/song_name = "generic"
|
||||
var/song_path = null
|
||||
var/song_length = 0
|
||||
var/song_beat = 0
|
||||
var/song_associated_id = null
|
||||
|
||||
/datum/track/New(name, path, length, beat, assocID)
|
||||
song_name = name
|
||||
song_path = path
|
||||
song_length = length
|
||||
song_beat = beat
|
||||
song_associated_id = assocID
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/proc/addjukebox(obj/jukebox, datum/track/T)
|
||||
if(!istype(T))
|
||||
CRASH("[src] tried to play a song with a nonexistant track")
|
||||
var/channeltoreserve = CHANNEL_JUKEBOX_START + activejukeboxes.len - 1
|
||||
if(channeltoreserve > CHANNEL_JUKEBOX)
|
||||
return FALSE
|
||||
activejukeboxes.len++
|
||||
activejukeboxes[activejukeboxes.len] = list(T, channeltoreserve, jukebox)
|
||||
return activejukeboxes.len
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/proc/removejukebox(IDtoremove)
|
||||
if(islist(activejukeboxes[IDtoremove]))
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
M.stop_sound_channel(activejukeboxes[IDtoremove][2])
|
||||
activejukeboxes.Cut(IDtoremove, IDtoremove+1)
|
||||
return TRUE
|
||||
else
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. Tried to remove jukebox with invalid ID</span>")
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/proc/findjukeboxindex(obj/jukebox)
|
||||
if(activejukeboxes.len)
|
||||
for(var/list/jukeinfo in activejukeboxes)
|
||||
if(jukebox in jukeinfo)
|
||||
return activejukeboxes.Find(jukeinfo)
|
||||
return FALSE
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/Initialize()
|
||||
var/list/tracks = flist("config/jukebox_music/sounds/")
|
||||
for(var/S in tracks)
|
||||
var/datum/track/T = new()
|
||||
T.song_path = file("config/jukebox_music/sounds/[S]")
|
||||
var/list/L = splittext(S,"+")
|
||||
T.song_name = L[1]
|
||||
T.song_length = text2num(L[2])
|
||||
T.song_beat = text2num(L[3])
|
||||
T.song_associated_id = L[4]
|
||||
songs |= T
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/fire()
|
||||
if(!activejukeboxes.len)
|
||||
return
|
||||
for(var/list/jukeinfo in activejukeboxes)
|
||||
if(!jukeinfo.len)
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. Active jukebox without any associated metadata</span>")
|
||||
var/datum/track/juketrack = jukeinfo[1]
|
||||
if(!istype(juketrack))
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. After jukebox track grabbing</span>")
|
||||
continue
|
||||
var/obj/jukebox = jukeinfo[3]
|
||||
if(!istype(jukebox))
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. Nonexistant or invalid jukebox in active jukebox list")
|
||||
continue
|
||||
var/sound/song_played = sound(juketrack.song_path)
|
||||
var/area/currentarea = get_area(jukebox)
|
||||
var/turf/currentturf = get_turf(jukebox)
|
||||
var/list/hearerscache = hearers(7, jukebox)
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
if(!(M.client.prefs.toggles & SOUND_INSTRUMENTS))
|
||||
M.stop_sound_channel(jukeinfo[2])
|
||||
continue
|
||||
|
||||
var/inrange = FALSE
|
||||
if(jukebox.z == M.z) //todo - expand this to work with mining planet z-levels when robust jukebox audio gets merged to master
|
||||
song_played.status = SOUND_UPDATE
|
||||
if(get_area(M) == currentarea)
|
||||
inrange = TRUE
|
||||
else if(M in hearerscache)
|
||||
inrange = TRUE
|
||||
else
|
||||
song_played.status = SOUND_MUTE | SOUND_UPDATE //Setting volume = 0 doesn't let the sound properties update at all, which is lame.
|
||||
|
||||
M.playsound_local(currentturf, null, 100, channel = jukeinfo[2], S = song_played, envwet = (inrange ? -250 : 0), envdry = (inrange ? 0 : -10000))
|
||||
CHECK_TICK
|
||||
return
|
||||
@@ -9,7 +9,6 @@
|
||||
var/active = FALSE
|
||||
var/list/rangers = list()
|
||||
var/stop = 0
|
||||
var/list/songs = list()
|
||||
var/datum/track/selection = null
|
||||
|
||||
/obj/machinery/jukebox/disco
|
||||
@@ -29,34 +28,6 @@
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
flags_1 = NODECONSTRUCT_1
|
||||
|
||||
/datum/track
|
||||
var/song_name = "generic"
|
||||
var/song_path = null
|
||||
var/song_length = 0
|
||||
var/song_beat = 0
|
||||
|
||||
/datum/track/New(name, path, length, beat)
|
||||
song_name = name
|
||||
song_path = path
|
||||
song_length = length
|
||||
song_beat = beat
|
||||
|
||||
/obj/machinery/jukebox/Initialize()
|
||||
. = ..()
|
||||
var/list/tracks = flist("config/jukebox_music/sounds/")
|
||||
|
||||
for(var/S in tracks)
|
||||
var/datum/track/T = new()
|
||||
T.song_path = file("config/jukebox_music/sounds/[S]")
|
||||
var/list/L = splittext(S,"+")
|
||||
T.song_name = L[1]
|
||||
T.song_length = text2num(L[2])
|
||||
T.song_beat = text2num(L[3])
|
||||
songs |= T
|
||||
|
||||
if(songs.len)
|
||||
selection = pick(songs)
|
||||
|
||||
/obj/machinery/jukebox/Destroy()
|
||||
dance_over()
|
||||
return ..()
|
||||
@@ -91,7 +62,7 @@
|
||||
to_chat(user,"<span class='warning'>Error: Access Denied.</span>")
|
||||
user.playsound_local(src,'sound/misc/compiler-failure.ogg', 25, 1)
|
||||
return
|
||||
if(!songs.len)
|
||||
if(!SSjukeboxes.songs.len)
|
||||
to_chat(user,"<span class='warning'>Error: No music tracks have been authorized for your station. Petition Central Command to resolve this issue.</span>")
|
||||
playsound(src,'sound/misc/compiler-failure.ogg', 25, 1)
|
||||
return
|
||||
@@ -100,8 +71,11 @@
|
||||
dat += "<b><A href='?src=[REF(src)];action=toggle'>[!active ? "BREAK IT DOWN" : "SHUT IT DOWN"]<b></A><br>"
|
||||
dat += "</div><br>"
|
||||
dat += "<A href='?src=[REF(src)];action=select'> Select Track</A><br>"
|
||||
dat += "Track Selected: [selection.song_name]<br>"
|
||||
dat += "Track Length: [DisplayTimeText(selection.song_length)]<br><br>"
|
||||
if(istype(selection))
|
||||
dat += "Track Selected: [selection.song_name]<br>"
|
||||
dat += "Track Length: [DisplayTimeText(selection.song_length)]<br><br>"
|
||||
else
|
||||
dat += "Track Selected: None!<br><br>"
|
||||
var/datum/browser/popup = new(user, "vending", "[name]", 400, 350)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
@@ -120,8 +94,14 @@
|
||||
to_chat(usr, "<span class='warning'>Error: The device is still resetting from the last activation, it will be ready again in [DisplayTimeText(stop-world.time)].</span>")
|
||||
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
|
||||
return
|
||||
activate_music()
|
||||
START_PROCESSING(SSobj, src)
|
||||
if(!istype(selection))
|
||||
to_chat(usr, "<span class='warning'>Error: Severe user incompetence detected.</span>")
|
||||
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
|
||||
return
|
||||
if(!activate_music())
|
||||
to_chat(usr, "<span class='warning'>Error: Generic hardware failure.</span>")
|
||||
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
|
||||
return
|
||||
updateUsrDialog()
|
||||
else if(active)
|
||||
stop = 0
|
||||
@@ -132,7 +112,7 @@
|
||||
return
|
||||
|
||||
var/list/available = list()
|
||||
for(var/datum/track/S in songs)
|
||||
for(var/datum/track/S in SSjukeboxes.songs)
|
||||
available[S.song_name] = S
|
||||
var/selected = input(usr, "Choose your song", "Track:") as null|anything in available
|
||||
if(QDELETED(src) || !selected || !istype(available[selected], /datum/track))
|
||||
@@ -141,10 +121,15 @@
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/jukebox/proc/activate_music()
|
||||
active = TRUE
|
||||
update_icon()
|
||||
START_PROCESSING(SSobj, src)
|
||||
stop = world.time + selection.song_length
|
||||
var/jukeboxslottotake = SSjukeboxes.addjukebox(src, selection)
|
||||
if(jukeboxslottotake)
|
||||
active = TRUE
|
||||
update_icon()
|
||||
START_PROCESSING(SSobj, src)
|
||||
stop = world.time + selection.song_length
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/jukebox/disco/activate_music()
|
||||
..()
|
||||
@@ -433,23 +418,9 @@
|
||||
QDEL_LIST(sparkles)
|
||||
|
||||
/obj/machinery/jukebox/process()
|
||||
if(world.time < stop && active)
|
||||
var/sound/song_played = sound(selection.song_path)
|
||||
|
||||
for(var/mob/M in range(10,src))
|
||||
if(!M.client || !(M.client.prefs.toggles & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
if(!(M in rangers))
|
||||
rangers[M] = TRUE
|
||||
M.playsound_local(get_turf(M), null, 100, channel = CHANNEL_JUKEBOX, S = song_played)
|
||||
for(var/mob/L in rangers)
|
||||
if(get_dist(src,L) > 10)
|
||||
rangers -= L
|
||||
if(!L || !L.client)
|
||||
continue
|
||||
L.stop_sound_channel(CHANNEL_JUKEBOX)
|
||||
else if(active)
|
||||
if(active && world.time >= stop)
|
||||
active = FALSE
|
||||
SSjukeboxes.removejukebox(SSjukeboxes.findjukeboxindex(src))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
dance_over()
|
||||
playsound(src,'sound/machines/terminal_off.ogg',50,1)
|
||||
|
||||
+4
-1
@@ -26,7 +26,7 @@
|
||||
if(T && T.z == turf_source.z)
|
||||
M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S)
|
||||
|
||||
/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S)
|
||||
/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S, envwet = -10000, envdry = 0)
|
||||
if(!client || !can_hear())
|
||||
return
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
S.wait = 0 //No queue
|
||||
S.channel = channel || open_sound_channel()
|
||||
S.volume = vol
|
||||
S.environment = 7
|
||||
|
||||
if(vary)
|
||||
if(frequency)
|
||||
@@ -64,6 +65,8 @@
|
||||
else //space
|
||||
pressure_factor = 0
|
||||
|
||||
S.echo = list(envdry, null, envwet, null, null, null, null, null, null, null, null, null, null, 1, 1, 1, null, null)
|
||||
|
||||
if(distance <= 1)
|
||||
pressure_factor = max(pressure_factor, 0.15) //touching the source of the sound
|
||||
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
#include "code\controllers\subsystem\input.dm"
|
||||
#include "code\controllers\subsystem\ipintel.dm"
|
||||
#include "code\controllers\subsystem\job.dm"
|
||||
#include "code\controllers\subsystem\jukeboxes.dm"
|
||||
#include "code\controllers\subsystem\language.dm"
|
||||
#include "code\controllers\subsystem\lighting.dm"
|
||||
#include "code\controllers\subsystem\machines.dm"
|
||||
|
||||
Reference in New Issue
Block a user