From 5c8ddf2a31bf09481f6ce079f8082e9032243477 Mon Sep 17 00:00:00 2001 From: Rob Nelson Date: Mon, 10 Mar 2014 23:17:18 -0700 Subject: [PATCH] YOOOOO0U. YOU GOT WHAT AH NEEEEEEEED Conflicts: code/__HELPERS/game.dm code/game/machinery/alarm.dm code/game/machinery/doors/firedoor.dm code/modules/client/preferences_toggles.dm code/setup.dm maps/tgstation.2.1.0.0.1.dmm --- code/__HELPERS/game.dm | 77 ++++++++++++++++++- code/_hooks/hooks.dm | 4 +- code/game/machinery/alarm.dm | 15 ++++ .../atmoalter/area_atmos_computer.dm | 4 +- code/game/machinery/doors/firedoor.dm | 4 +- code/game/objects/items/blueprints.dm | 3 +- code/modules/client/preferences_toggles.dm | 14 +++- code/modules/media/jukebox.dm | 64 +++++++++++---- code/modules/media/machinery.dm | 61 +++++++++++++-- code/modules/media/mediamanager.dm | 54 +++++++++---- code/modules/power/lighting.dm | 3 +- code/setup.dm | 3 +- code/world.dm | 1 + interface/skin.dmf | 26 +++++++ 14 files changed, 280 insertions(+), 53 deletions(-) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 0885a4ed180..81db855b15d 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -9,6 +9,12 @@ src:Topic(href, href_list) return null +/proc/get_area_master(O) + var/area/A = get_area(O) + if(A && A.master) + A = A.master + return A + /proc/get_area(O) var/atom/location = O var/i @@ -176,10 +182,10 @@ for(var/mob/M in range) hear += M - + var/list/objects = list() - for(var/obj/O in range) //Get a list of objects in hearing range. We'll check to see if any clients have their "eye" set to the object + for(var/obj/O in range) //Get a list of objects in hearing range. We'll check to see if any clients have their "eye" set to the object objects += O for(var/client/C in clients) @@ -196,7 +202,7 @@ if(C.eye in hear_and_objects) hear += C.mob - + else if(C.mob.loc in hear_and_objects) hear += C.mob else if(C.mob.loc.loc in hear_and_objects) @@ -376,3 +382,68 @@ proc/get_candidates(be_special_flag=0) sleep(duration) for(var/client/C in show_to) C.images -= I + +/proc/get_active_player_count() + // Get active players who are playing in the round + var/active_players = 0 + for(var/i = 1; i <= player_list.len; i++) + var/mob/M = player_list[i] + if(M && M.client) + if(istype(M, /mob/new_player)) // exclude people in the lobby + continue + else if(isobserver(M)) // Ghosts are fine if they were playing once (didn't start as observers) + var/mob/dead/observer/O = M + if(O.started_as_observer) // Exclude people who started as observers + continue + active_players++ + return active_players + +/datum/projectile_data + var/src_x + var/src_y + var/time + var/distance + var/power_x + var/power_y + var/dest_x + var/dest_y + +/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \ + var/power_x, var/power_y, var/dest_x, var/dest_y) + src.src_x = src_x + src.src_y = src_y + src.time = time + src.distance = distance + src.power_x = power_x + src.power_y = power_y + src.dest_x = dest_x + src.dest_y = dest_y + +/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power) + + // returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle], + // rotated at [rotation] and with the power of [power] + // Thanks to VistaPOWA for this function + + var/power_x = power * cos(angle) + var/power_y = power * sin(angle) + var/time = 2* power_y / 10 //10 = g + + var/distance = time * power_x + + var/dest_x = src_x + distance*sin(rotation); + var/dest_y = src_y + distance*cos(rotation); + + return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y) + + +/proc/mobs_in_area(var/area/the_area, var/client_needed=0, var/moblist=mob_list) + var/list/mobs_found[0] + var/area/our_area = get_area_master(the_area) + for(var/mob/M in moblist) + if(client_needed && !M.client) + continue + if(our_area != get_area_master(M)) + continue + mobs_found += M + return mobs_found diff --git a/code/_hooks/hooks.dm b/code/_hooks/hooks.dm index 30f5d892f39..51aea802165 100644 --- a/code/_hooks/hooks.dm +++ b/code/_hooks/hooks.dm @@ -32,14 +32,14 @@ var/global/list/hooks = list() for (var/hook_path in typesof(/hook)) var/hook/hook = new hook_path hooks[hook.name] = hook - //world.log << "Found hook: " + hook.name + world.log << "Found hook: " + hook.name for (var/hook_path in typesof(/hook_handler)) var/hook_handler/hook_handler = new hook_path for (var/name in hooks) if (hascall(hook_handler, "On" + name)) var/hook/hook = hooks[name] hook.handlers += hook_handler - //world.log << "Found hook handler for: " + name + world.log << "Found hook handler for: " + name for (var/hook/hook in hooks) hook.Setup() diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 1e42420be6d..271e2ff4a02 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -1043,6 +1043,13 @@ FIRE ALARM var/last_process = 0 var/wiresexposed = 0 var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone + var/area/master_area + +/obj/machinery/firealarm/New() + var/area/A = get_area_master(src) + if (!( istype(A, /area) )) + return + master_area=A /obj/machinery/firealarm/update_icon() @@ -1368,6 +1375,14 @@ Code shamelessly copied from apc_frame idle_power_usage = 2 active_power_usage = 6 + var/area/master_area + +/obj/machinery/partyalarm/New() + var/area/A = get_area_master(src) + if (!( istype(A, /area) )) + return + master_area=A + /obj/machinery/partyalarm/attack_paw(mob/user as mob) return attack_hand(user) diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm index fff75b24e3d..29834f1c943 100644 --- a/code/game/machinery/atmoalter/area_atmos_computer.dm +++ b/code/game/machinery/atmoalter/area_atmos_computer.dm @@ -164,9 +164,7 @@ var/turf/T = get_turf(src) if(!T.loc) return - var/area/A = T.loc - if (A.master) - A = A.master + var/area/A = get_area_master(T) for(var/obj/machinery/portable_atmospherics/scrubber/huge/scrubber in world ) var/turf/T2 = get_turf(scrubber) if(T2 && T2.loc) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 8e432e86289..9391bbb9d46 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -136,7 +136,7 @@ user << "\red \The [src] is welded solid!" return - var/area/A = get_area(src) + var/area/A = get_area_master(src) ASSERT(istype(A)) if(A.master) A = A.master @@ -273,4 +273,4 @@ /obj/machinery/door/firedoor/multi_tile/triple icon = 'icons/obj/doors/DoorHazard3x1.dmi' - width = 3 \ No newline at end of file + width = 3 diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index 92ed4e92447..9992c18340c 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -75,8 +75,7 @@ move an amendment to the drawing.

/obj/item/blueprints/proc/get_area() var/turf/T = get_turf_loc(usr) - var/area/A = T.loc - A = A.master + var/area/A = get_area_master(T) return A /obj/item/blueprints/proc/get_area_type(var/area/A = get_area()) diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index fc52d59c6ee..91babc9f7c3 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -183,11 +183,21 @@ I.color = UI_style_color_new I.alpha = UI_style_alpha_new - - if(alert("Like it? Save changes?",,"Yes", "No") == "Yes") prefs.UI_style = UI_style_new prefs.UI_style_alpha = UI_style_alpha_new prefs.UI_style_color = UI_style_color_new prefs.save_preferences() usr << "UI was saved" + +/client/verb/toggle_media() + set name = "Hear/Silence Streaming" + set category = "Preferences" + set desc = "Toggle hearing streaming media (radios, jukeboxes, etc)" + + prefs.toggles ^= SOUND_STREAMING + prefs.save_preferences() + usr << "You will [(prefs.toggles & SOUND_STREAMING) ? "now" : "no longer"] hear streamed media." + // Restart. + media.stop_music() + media.update_music() diff --git a/code/modules/media/jukebox.dm b/code/modules/media/jukebox.dm index 22c07e9b6f0..67d6eebfeba 100644 --- a/code/modules/media/jukebox.dm +++ b/code/modules/media/jukebox.dm @@ -9,6 +9,8 @@ #define JUKEMODE_PLAY_ONCE 3 // Play, then stop. #define JUKEMODE_COUNT 3 +#define JUKEBOX_RELOAD_COOLDOWN 600 // 60s + // Represents a record returned. /datum/song_info var/title = "" @@ -43,30 +45,40 @@ var/global/loopModeNames=list( anchored = 1 luminosity = 4 // Why was this 16 + playing=0 + var/loop_mode = JUKEMODE_SHUFFLE // /datum/song_info var/list/playlist - var/current_song=0 + var/current_song = 0 + var/autoplay = 0 + var/last_reload = 0 /obj/machinery/media/jukebox/attack_ai() return /obj/machinery/media/jukebox/attack_paw() return - +/obj/machinery/media/jukebox/proc/check_reload() + return world.time > last_reload + JUKEBOX_RELOAD_COOLDOWN /obj/machinery/media/jukebox/attack_hand(var/mob/user) var/t = "

Jukebox Interface

" t += "Power: [playing?"On":"Off"]
" t += "Play Mode: [loopModeNames[loop_mode]]
" - if(current_song) - var/datum/song_info/song=playlist[current_song] - t += "Current song: [song.artist] - [song.title]
" - t += "" - var/i - for(i = 1,i <= playlist.len,i++) - var/datum/song_info/song=playlist[i] - t += "" - t += "
Artist - TitleAlbum
#[i][song.artist] - [song.title][song.album]
" + if(playlist == null) + t += "\[DOWNLOADING PLAYLIST, PLEASE WAIT\]" + else + if(current_song) + var/datum/song_info/song=playlist[current_song] + t += "Current song: [song.artist] - [song.title]
" + if(check_reload()) + t += "\[Reload Playlist\]" + t += "" + var/i + for(i = 1,i <= playlist.len,i++) + var/datum/song_info/song=playlist[i] + t += "" + t += "
Artist - TitleAlbum
#[i][song.artist] - [song.title][song.album]
" user.set_machine(src) var/datum/browser/popup = new (user,"jukebox",name,420,700) popup.set_content(t) @@ -78,6 +90,16 @@ var/global/loopModeNames=list( ..() if (href_list["power"]) playing=!playing + update_music() + + if (href_list["reload"]) + if(!check_reload()) + usr << "\red You must wait 60 seconds between reloads." + return + last_reload=world.time + playlist=null + current_song=0 + update_music() if (href_list["song"]) current_song=Clamp(text2num(href_list["song"]),1,playlist.len) @@ -91,6 +113,7 @@ var/global/loopModeNames=list( /obj/machinery/media/jukebox/process() if(!playlist) var/url="[config.media_base_url]/index.php" + testing("[src] - Updating playlist from [url]...") var/response = world.Export(url) playlist=list() if(response) @@ -101,7 +124,9 @@ var/global/loopModeNames=list( var/songdata = reader.read_value() for(var/list/record in songdata) playlist += new /datum/song_info(record) + visible_message("\icon[src] \The [src] beeps, and the menu on its front fills with [playlist.len] items.","You hear a beep.") else + //testing("Failed to update playlist: Response null.") stat &= BROKEN update_icon() return @@ -119,13 +144,18 @@ var/global/loopModeNames=list( if(JUKEMODE_PLAY_ONCE) playing=0 return - if(!playing) return + if(!playing) + return update_music() /obj/machinery/media/jukebox/update_music() - var/datum/song_info/song = playlist[current_song] - media_url = song.url - media_start_time = world.time - visible_message("\icon[src] \The [src] begins to play \"[song.title]\", by [song.artist].","You hear music.") - visible_message("\icon[src] \The [src] warbles: [song.length]ds, [song.url]") + if(current_song) + var/datum/song_info/song = playlist[current_song] + media_url = song.url + media_start_time = world.time + visible_message("\icon[src] \The [src] begins to play \"[song.title]\", by [song.artist].","You hear music.") + //visible_message("\icon[src] \The [src] warbles: [song.length/10]s @ [song.url]") + else + media_url="" + media_start_time = 0 ..() \ No newline at end of file diff --git a/code/modules/media/machinery.dm b/code/modules/media/machinery.dm index 6778bfd988b..902c91b0330 100644 --- a/code/modules/media/machinery.dm +++ b/code/modules/media/machinery.dm @@ -4,12 +4,63 @@ var/media_url="" var/media_start_time=0 + var/area/master_area + // Notify everyone in the area of new music. // YOU MUST SET MEDIA_URL AND MEDIA_START_TIME YOURSELF! /obj/machinery/media/proc/update_music() - var/area/A = get_area(src) - if(A.master) - A=A.master - for(var/mob/M in A) + update_media_source() + + // Bail if we lost connection to master. + if(!master_area) + return + + // Send update to clients. + for(var/mob/M in mobs_in_area(master_area)) if(M && M.client) - M.update_music() \ No newline at end of file + M.update_music() + +/obj/machinery/media/proc/update_media_source() + var/area/A = get_area_master(src) + + // Check if there's a media source already. + if(A.media_source && A.media_source!=src) + master_area=null + return + + // Update Media Source. + if(!A.media_source) + A.media_source=src + + master_area=A + +/obj/machinery/media/proc/disconnect_media_source() + var/area/A = get_area_master(src) + + // Sanity + if(!A) + master_area=null + return + + // Check if there's a media source already. + if(A && A.media_source && A.media_source!=src) + master_area=null + return + + // Update Media Source. + A.media_source=null + + // Clients + for(var/mob/M in mobs_in_area(A)) + if(M && M.client) + M.update_music() + + master_area=null + +/obj/machinery/media/New() + ..() + update_media_source() + +/obj/machinery/media/Destroy() + disconnect_media_source() + ..() \ No newline at end of file diff --git a/code/modules/media/mediamanager.dm b/code/modules/media/mediamanager.dm index f895bcce5e4..ecb2771ef43 100644 --- a/code/modules/media/mediamanager.dm +++ b/code/modules/media/mediamanager.dm @@ -25,20 +25,24 @@ function SetMusic(url, time, volume) { /hook_handler/soundmanager // Set up player on login proc/OnLogin(var/list/args) + //testing("Received OnLogin.") var/client/C = args["client"] - C.media = new /datum/media_manager(C) + C.media = new /datum/media_manager(args["mob"]) C.media.open() + C.media.update_music() // Update when moving between areas. proc/OnMobAreaChange(var/list/args) + //testing("Received OnMobAreaChange.") var/mob/M = args["mob"] M.update_music() /mob/proc/update_music() - if (client) - if(client.media) - client.media.update_music() + if (client && client.media) + client.media.update_music() + //else + // testing("[src] - client: [client?"Y":"N"]; client.media: [client && client.media ? "Y":"N"]") /area // One media source per area. @@ -50,18 +54,31 @@ function SetMusic(url, time, volume) { var/volume = 100 var/client/owner + var/mob/mob + + var/const/window = "rpane.hosttracker" + //var/const/window = "mediaplayer" // For debugging. New(var/mob/holder) - src.owner=holder + src.mob=holder + owner=src.mob.client // Actually pop open the player in the background. proc/open() - owner << browse(PLAYER_HTML, "window=rpane.hosttracker") + owner << browse(PLAYER_HTML, "window=[window]") send_update() // Tell the player to play something via JS. proc/send_update() - owner << output(list2params(list(url, (world.timeofday - start_time) / 10, volume)), "rpane.hosttracker:SetMusic") + if(!(owner.prefs.toggles & SOUND_STREAMING)) + return // Nope. + //testing("Sending update to WMP...") + owner << output(list2params(list(url, (world.time - start_time) / 10, volume)), "[window]:SetMusic") + + proc/stop_music() + url="" + start_time=world.time + send_update() // Scan for media sources and use them. proc/update_music() @@ -69,16 +86,25 @@ function SetMusic(url, time, volume) { var/targetStartTime = 0 var/targetVolume = 100 - if (owner) - var/area/A = get_area() - var/obj/machinery/media/M = A.media_source - if(M.playing) - targetURL = M.media_url - targetStartTime = M.media_start_time + if (!owner) + //testing("owner is null") + return + + var/area/A = get_area_master(mob) + if(!A) + //testing("[owner] in [mob.loc]. Aborting.") + stop_music() + return + var/obj/machinery/media/M = A.media_source + if(M && M.playing) + targetURL = M.media_url + targetStartTime = M.media_start_time + //owner << "Found audio source: [M.media_url] @ [(world.time - start_time) / 10]s." + //else + // testing("M is not playing or null.") if (url != targetURL || abs(targetStartTime - start_time) > 1 || targetVolume != volume) url = targetURL start_time = targetStartTime volume = targetVolume - send_update() \ No newline at end of file diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 7ff2be8c2a2..1e7737bc406 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -611,8 +611,7 @@ // called when area power state changes /obj/machinery/light/power_change() spawn(10) - var/area/A = src.loc.loc - A = A.master + var/area/A = get_area_master(src) seton(A.lightswitch && A.power_light) // called when on fire diff --git a/code/setup.dm b/code/setup.dm index 44384aba264..efed8a48d8c 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -679,8 +679,9 @@ var/list/TAGGERLOCATIONS = list("Disposals", #define SOUND_AMBIENCE 4 #define SOUND_LOBBY 8 #define SOUND_VOICES 16 +#define SOUND_STREAMING 32 -#define SOUND_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY) +#define SOUND_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|SOUND_STREAMING) #define TOGGLES_DEFAULT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC) #define BE_TRAITOR 1 diff --git a/code/world.dm b/code/world.dm index bbc6a7cbddf..818c6583e10 100644 --- a/code/world.dm +++ b/code/world.dm @@ -40,6 +40,7 @@ appearance_loadbanfile() jobban_updatelegacybans() LoadBans() + SetupHooks() // /vg/ if(config && config.server_name != null && config.server_suffix && world.port > 0) // dumb and hardcoded but I don't care~ diff --git a/interface/skin.dmf b/interface/skin.dmf index 9cefbdf1d78..99e6ece48d4 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1541,6 +1541,32 @@ window "rpane" splitter = 50 show-splitter = true lock = none + elem "hosttracker" + type = BROWSER + pos = 392,25 + size = 1x1 + anchor1 = none + anchor2 = none + font-family = "" + font-size = 0 + font-style = "" + text-color = #000000 + background-color = none + is-visible = true + is-disabled = false + is-transparent = false + is-default = false + border = none + drop-zone = false + right-click = false + saved-params = "" + on-size = "" + show-history = false + show-url = false + auto-format = true + use-title = false + on-show = "" + on-hide = "" elem "rulesb" type = BUTTON pos = 278,0