//As a brief warning to all those who dare tread upon these grounds: //The bulk of this code here was written years ago, back in the days of 512. //We were incredibly drunk back then. And nowadays, we've found that being drunk is a hard requirement for working with this code. //So if you're here to make changes? Brandish a glass. There are many sins here, but it's exactly as engineered as it needs to be. //We physically won't be able to tell you what half of this code does. The only thing that'll help you here is the ballmer peak. //Bottoms up, friend. And be sure to drink responsibly. Be sure to fetch some water, too; it eases the hangover. - Bhijn & Myr // Jukelist indices #define JUKE_TRACK 1 #define JUKE_CHANNEL 2 #define JUKE_BOX 3 #define JUKE_FALLOFF 4 #define JUKE_SOUND 5 SUBSYSTEM_DEF(jukeboxes) name = "Jukeboxes" wait = 5 var/list/songs = list() var/list/activejukeboxes = list() var/list/freejukeboxchannels = 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, jukefalloff = 1) if(!istype(T)) CRASH("[src] tried to play a song with a nonexistant track") var/channeltoreserve = pick(freejukeboxchannels) if(!channeltoreserve) return FALSE var/sound/song_to_init = sound(T.song_path) freejukeboxchannels -= channeltoreserve var/list/youvegotafreejukebox = list(T, channeltoreserve, jukebox, jukefalloff, song_to_init) song_to_init.status = SOUND_MUTE song_to_init.environment = 7 song_to_init.channel = channeltoreserve song_to_init.volume = 1 song_to_init.falloff = jukefalloff song_to_init.echo = list(0, null, -10000, null, null, null, null, null, null, null, null, null, null, 1, 1, 1, null, null) activejukeboxes.len++ activejukeboxes[activejukeboxes.len] = youvegotafreejukebox for(var/mob/M in GLOB.player_list) if(!M.client) continue if(!(M.client.prefs.toggles & SOUND_INSTRUMENTS)) continue SEND_SOUND(M, song_to_init) return activejukeboxes.len //Updates jukebox by transferring to different object or modifying falloff. /datum/controller/subsystem/jukeboxes/proc/updatejukebox(IDtoupdate, obj/jukebox, jukefalloff) if(islist(activejukeboxes[IDtoupdate])) if(istype(jukebox)) activejukeboxes[IDtoupdate][JUKE_BOX] = jukebox if(!isnull(jukefalloff)) activejukeboxes[IDtoupdate][JUKE_FALLOFF] = jukefalloff /datum/controller/subsystem/jukeboxes/proc/removejukebox(IDtoremove) if(islist(activejukeboxes[IDtoremove])) var/jukechannel = activejukeboxes[IDtoremove][JUKE_CHANNEL] for(var/mob/M in GLOB.player_list) if(!M.client) continue M.stop_sound_channel(jukechannel) freejukeboxchannels |= jukechannel activejukeboxes.Cut(IDtoremove, IDtoremove+1) return TRUE else CRASH("Tried to remove jukebox with invalid ID") /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 for(var/i in CHANNEL_JUKEBOX_START to CHANNEL_JUKEBOX) freejukeboxchannels |= i return ..() /datum/controller/subsystem/jukeboxes/fire() if(!activejukeboxes.len) return for(var/list/jukeinfo in activejukeboxes) if(!jukeinfo.len) stack_trace("Active jukebox without any associated metadata.") continue var/datum/track/juketrack = jukeinfo[JUKE_TRACK] if(!istype(juketrack)) stack_trace("Invalid jukebox track datum.") continue var/obj/jukebox = jukeinfo[JUKE_BOX] if(!istype(jukebox)) stack_trace("Nonexistant or invalid object associated with jukebox.") continue var/list/audible_zlevels = get_multiz_accessible_levels(jukebox.z) //TODO - for multiz refresh, this should use the cached zlevel connections var in SSMapping. For now this is fine! var/sound/song_played = jukeinfo[JUKE_SOUND] var/turf/currentturf = get_turf(jukebox) var/area/currentarea = get_area(jukebox) var/list/hearerscache = hearers(7, jukebox) var/targetfalloff = jukeinfo[JUKE_FALLOFF] var/mixes = ((targetfalloff*250)-750) var/inrange var/pressure_factor var/datum/gas_mixture/source_env = (istype(currentturf) ? currentturf.return_air() : null) var/datum/gas_mixture/hearer_env //We init this var outside of the mob loop for the sake of performance var/turf/hearerturf //ditto var/source_pressure = (istype(source_env) ? source_env.return_pressure() : 0) song_played.falloff = targetfalloff song_played.volume = min((targetfalloff * 50), 100) for(var/mob/M in GLOB.player_list) if(!M.client) continue if(!(M.client.prefs.toggles & SOUND_INSTRUMENTS)) M.stop_sound_channel(jukeinfo[JUKE_CHANNEL]) continue inrange = FALSE song_played.status = SOUND_MUTE | SOUND_UPDATE if(source_pressure) hearerturf = get_turf(M) hearer_env = (istype(hearerturf) ? hearerturf.return_air() : null) if(istype(hearer_env)) pressure_factor = min(source_pressure, hearer_env.return_pressure()) if(pressure_factor && targetfalloff && M.can_hear() && (hearerturf.z in audible_zlevels)) if(get_area(hearerturf) == currentarea) inrange = TRUE else if(M in hearerscache) inrange = TRUE song_played.x = (currentturf.x - hearerturf.x) * SOUND_DEFAULT_DISTANCE_MULTIPLIER song_played.z = (currentturf.y - hearerturf.y) * SOUND_DEFAULT_DISTANCE_MULTIPLIER song_played.y = (((currentturf.z - hearerturf.z) * 10 * SOUND_DEFAULT_DISTANCE_MULTIPLIER) + ((currentturf.z < hearerturf.z) ? -5 : 5)) if(pressure_factor < ONE_ATMOSPHERE) song_played.volume = (min((targetfalloff * 50), 100) * max((pressure_factor - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 1)) song_played.echo[1] = (inrange ? 0 : -10000) song_played.echo[3] = (inrange ? mixes : max(mixes, 0)) song_played.status = SOUND_UPDATE SEND_SOUND(M, song_played) CHECK_TICK return #undef JUKE_TRACK #undef JUKE_CHANNEL #undef JUKE_BOX #undef JUKE_FALLOFF #undef JUKE_SOUND