mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-09 16:12:17 +00:00
463 lines
14 KiB
Plaintext
463 lines
14 KiB
Plaintext
//
|
|
// Media Player Jukebox
|
|
// Rewritten by Leshana from existing Polaris code, merging in D2K5 and N3X15 work
|
|
//
|
|
|
|
/obj/machinery/media/jukebox
|
|
name = "space jukebox"
|
|
desc = "Filled with songs both past and present!"
|
|
icon = 'icons/obj/jukebox.dmi'
|
|
icon_state = "jukebox-nopower"
|
|
var/state_base = "jukebox"
|
|
anchored = TRUE
|
|
density = TRUE
|
|
power_channel = EQUIP
|
|
use_power = USE_POWER_IDLE
|
|
idle_power_usage = 10
|
|
active_power_usage = 100
|
|
circuit = /obj/item/circuitboard/jukebox
|
|
clicksound = 'sound/machines/buttonbeep.ogg'
|
|
volume = 0.5 //CHOMPEdit
|
|
|
|
// Vars for hacking
|
|
var/datum/wires/jukebox/wires = null
|
|
var/hacked = 0 // Whether to show the hidden songs or not
|
|
var/freq = 0 // Currently no effect, will return in phase II of mediamanager.
|
|
//VOREStation Add
|
|
var/loop_mode = JUKEMODE_PLAY_ONCE // Behavior when finished playing a song
|
|
var/list/obj/item/juke_remote/remotes
|
|
//VOREStation Add End
|
|
var/datum/track/current_track
|
|
|
|
/obj/machinery/media/jukebox/Initialize(mapload)
|
|
. = ..()
|
|
default_apply_parts()
|
|
wires = new/datum/wires/jukebox(src)
|
|
update_icon()
|
|
if(!LAZYLEN(getTracksList()))
|
|
stat |= BROKEN
|
|
AddElement(/datum/element/climbable)
|
|
|
|
/obj/machinery/media/jukebox/Destroy()
|
|
qdel(wires)
|
|
wires = null
|
|
return ..()
|
|
|
|
/obj/machinery/media/jukebox/proc/getTracksList()
|
|
return hacked ? SSmedia_tracks.all_tracks : SSmedia_tracks.jukebox_tracks
|
|
|
|
/obj/machinery/media/jukebox/process()
|
|
if(!playing)
|
|
return
|
|
if(inoperable())
|
|
disconnect_media_source()
|
|
playing = 0
|
|
return
|
|
// If the current track isn't finished playing, let it keep going
|
|
if(current_track && world.time < media_start_time + current_track.duration)
|
|
return
|
|
// Oh... nothing in queue? Well then pick next according to our rules
|
|
var/list/tracks = getTracksList()
|
|
switch(loop_mode)
|
|
if(JUKEMODE_NEXT)
|
|
var/curTrackIndex = max(1, tracks.Find(current_track))
|
|
var/newTrackIndex = (curTrackIndex % tracks.len) + 1 // Loop back around if past end
|
|
current_track = tracks[newTrackIndex]
|
|
if(JUKEMODE_RANDOM)
|
|
var/previous_track = current_track
|
|
do
|
|
current_track = pick(tracks)
|
|
while(current_track == previous_track && tracks.len > 1)
|
|
if(JUKEMODE_REPEAT_SONG)
|
|
current_track = current_track
|
|
if(JUKEMODE_PLAY_ONCE)
|
|
current_track = null
|
|
playing = 0
|
|
update_icon()
|
|
updateDialog()
|
|
start_stop_song()
|
|
|
|
// Tells the media manager to start or stop playing based on current settings.
|
|
/obj/machinery/media/jukebox/proc/start_stop_song()
|
|
if(current_track && playing)
|
|
media_url = current_track.url
|
|
media_start_time = world.time
|
|
audible_message(span_notice("\The [src] begins to play [current_track.display()]."), runemessage = "[current_track.display()]")
|
|
else
|
|
media_url = ""
|
|
media_start_time = 0
|
|
update_music()
|
|
//VOREStation Add
|
|
for(var/obj/item/juke_remote/remote as anything in remotes)
|
|
remote.update_music()
|
|
//VOREStation Add End
|
|
|
|
/obj/machinery/media/jukebox/proc/set_hacked(var/newhacked)
|
|
if(hacked == newhacked)
|
|
return
|
|
hacked = newhacked
|
|
updateDialog()
|
|
|
|
/obj/machinery/media/jukebox/attackby(obj/item/W as obj, mob/user as mob)
|
|
src.add_fingerprint(user)
|
|
|
|
if(default_deconstruction_screwdriver(user, W))
|
|
return
|
|
if(default_deconstruction_crowbar(user, W))
|
|
return
|
|
if(W.has_tool_quality(TOOL_WIRECUTTER))
|
|
return wires.Interact(user)
|
|
if(istype(W, /obj/item/multitool))
|
|
return wires.Interact(user)
|
|
if(W.has_tool_quality(TOOL_WRENCH))
|
|
if(playing)
|
|
StopPlaying()
|
|
user.visible_message(span_warning("[user] has [anchored ? "un" : ""]secured \the [src]."), span_notice("You [anchored ? "un" : ""]secure \the [src]."))
|
|
anchored = !anchored
|
|
playsound(src, W.usesound, 50, 1)
|
|
power_change()
|
|
update_icon()
|
|
if(!anchored)
|
|
playing = 0
|
|
disconnect_media_source()
|
|
else
|
|
update_media_source()
|
|
return
|
|
return ..()
|
|
|
|
/obj/machinery/media/jukebox/power_change()
|
|
if(!powered(power_channel) || !anchored)
|
|
stat |= NOPOWER
|
|
else
|
|
stat &= ~NOPOWER
|
|
|
|
if(stat & (NOPOWER|BROKEN) && playing)
|
|
StopPlaying()
|
|
update_icon()
|
|
|
|
/obj/machinery/media/jukebox/update_icon()
|
|
cut_overlays()
|
|
if(stat & (NOPOWER|BROKEN) || !anchored)
|
|
if(stat & BROKEN)
|
|
icon_state = "[state_base]-broken"
|
|
else
|
|
icon_state = "[state_base]-nopower"
|
|
return
|
|
icon_state = state_base
|
|
if(playing)
|
|
if(emagged)
|
|
add_overlay("[state_base]-emagged")
|
|
else
|
|
add_overlay("[state_base]-running")
|
|
if (panel_open)
|
|
add_overlay("panel_open")
|
|
|
|
/obj/machinery/media/jukebox/interact(mob/user)
|
|
if(inoperable())
|
|
to_chat(user, "\The [src] doesn't appear to function.")
|
|
return
|
|
tgui_interact(user)
|
|
|
|
/obj/machinery/media/jukebox/tgui_status(mob/user)
|
|
if(inoperable())
|
|
to_chat(user, span_warning("[src] doesn't appear to function."))
|
|
return STATUS_CLOSE
|
|
if(!anchored)
|
|
to_chat(user, span_warning("You must secure [src] first."))
|
|
return STATUS_CLOSE
|
|
. = ..()
|
|
|
|
/obj/machinery/media/jukebox/tgui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "Jukebox", "RetroBox - Space Style")
|
|
ui.open()
|
|
|
|
/obj/machinery/media/jukebox/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
|
var/list/data = ..()
|
|
|
|
data["playing"] = playing
|
|
data["loop_mode"] = loop_mode
|
|
data["volume"] = volume
|
|
data["current_track_ref"] = null
|
|
data["current_track"] = null
|
|
data["current_genre"] = null
|
|
if(current_track)
|
|
data["current_track_ref"] = "\ref[current_track]" // Convenient shortcut
|
|
data["current_track"] = current_track.toTguiList()
|
|
data["current_genre"] = current_track.genre
|
|
data["percent"] = playing ? min(100, round(world.time - media_start_time) / current_track.duration) : 0;
|
|
|
|
var/list/tgui_tracks = list()
|
|
for(var/datum/track/T in getTracksList())
|
|
tgui_tracks.Add(list(T.toTguiList()))
|
|
data["tracks"] = tgui_tracks
|
|
data["admin"] = is_admin(user)
|
|
|
|
return data
|
|
|
|
/obj/machinery/media/jukebox/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
|
if(..())
|
|
return TRUE
|
|
|
|
switch(action)
|
|
if("change_track")
|
|
var/datum/track/T = locate(params["change_track"]) in getTracksList()
|
|
if(istype(T))
|
|
current_track = T
|
|
StartPlaying()
|
|
return TRUE
|
|
if("loopmode")
|
|
var/newval = text2num(params["loopmode"])
|
|
loop_mode = sanitize_inlist(newval, list(JUKEMODE_NEXT, JUKEMODE_RANDOM, JUKEMODE_REPEAT_SONG, JUKEMODE_PLAY_ONCE), loop_mode)
|
|
return TRUE
|
|
if("volume")
|
|
var/newval = text2num(params["val"])
|
|
volume = clamp(newval, 0, 1)
|
|
update_music() // To broadcast volume change without restarting song
|
|
return TRUE
|
|
if("stop")
|
|
StopPlaying()
|
|
return TRUE
|
|
if("play")
|
|
if(emagged)
|
|
playsound(src, 'sound/items/AirHorn.ogg', 100, 1)
|
|
for(var/mob/living/carbon/M in ohearers(6, src))
|
|
if(M.get_ear_protection() >= 2)
|
|
continue
|
|
M.SetSleeping(0)
|
|
M.stuttering += 20
|
|
M.ear_deaf += 30
|
|
M.deaf_loop.start() // CHOMPStation Add: Ear Ringing/Deafness
|
|
M.Weaken(3)
|
|
if(prob(30))
|
|
M.Stun(10)
|
|
M.Paralyse(4)
|
|
else
|
|
M.make_jittery(500)
|
|
spawn(15)
|
|
explode()
|
|
else if(current_track == null)
|
|
to_chat(ui.user, "No track selected.")
|
|
else
|
|
StartPlaying()
|
|
return TRUE
|
|
if("add_new_track")
|
|
SSmedia_tracks.add_track(ui.user, params["url"], params["title"], text2num(params["duration"]) * 10, params["artist"], params["genre"], text2num(params["secret"]), text2num(params["lobby"]))
|
|
if("remove_new_track")
|
|
var/datum/track/track_to_remove = locate(params["ref"]) in getTracksList()
|
|
if(track_to_remove == current_track && playing)
|
|
StopPlaying()
|
|
SSmedia_tracks.remove_track(ui.user, track_to_remove)
|
|
|
|
/obj/machinery/media/jukebox/attack_ai(mob/user as mob)
|
|
return src.attack_hand(user)
|
|
|
|
/obj/machinery/media/jukebox/attack_hand(var/mob/user as mob)
|
|
interact(user)
|
|
|
|
/obj/machinery/media/jukebox/proc/explode()
|
|
walk_to(src,0)
|
|
src.visible_message(span_danger("\The [src] blows apart!"), 1)
|
|
|
|
explosion(src.loc, 0, 0, 1, rand(1,2), 1)
|
|
|
|
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
|
s.set_up(3, 1, src)
|
|
s.start()
|
|
|
|
new /obj/effect/decal/cleanable/blood/oil(src.loc)
|
|
qdel(src)
|
|
|
|
/obj/machinery/media/jukebox/attackby(obj/item/W as obj, mob/user as mob)
|
|
src.add_fingerprint(user)
|
|
|
|
if(default_deconstruction_screwdriver(user, W))
|
|
return
|
|
if(default_deconstruction_crowbar(user, W))
|
|
return
|
|
if(W.has_tool_quality(TOOL_WRENCH))
|
|
if(playing)
|
|
StopPlaying()
|
|
user.visible_message(span_warning("[user] has [anchored ? "un" : ""]secured \the [src]."), span_notice("You [anchored ? "un" : ""]secure \the [src]."))
|
|
anchored = !anchored
|
|
playsound(src, W.usesound, 50, 1)
|
|
power_change()
|
|
update_icon()
|
|
return
|
|
return ..()
|
|
|
|
/obj/machinery/media/jukebox/emag_act(var/remaining_charges, var/mob/user)
|
|
if(!emagged)
|
|
emagged = 1
|
|
StopPlaying()
|
|
visible_message(span_danger("\The [src] makes a fizzling sound."))
|
|
update_icon()
|
|
return 1
|
|
|
|
/obj/machinery/media/jukebox/proc/StopPlaying()
|
|
playing = 0
|
|
update_use_power(USE_POWER_IDLE)
|
|
update_icon()
|
|
start_stop_song()
|
|
|
|
/obj/machinery/media/jukebox/proc/StartPlaying()
|
|
if(!current_track)
|
|
return
|
|
playing = 1
|
|
update_use_power(USE_POWER_ACTIVE)
|
|
update_icon()
|
|
start_stop_song()
|
|
updateDialog()
|
|
|
|
// Advance to the next track - Don't start playing it unless we were already playing
|
|
/obj/machinery/media/jukebox/proc/NextTrack()
|
|
var/list/tracks = getTracksList()
|
|
if(!tracks.len) return
|
|
var/curTrackIndex = max(1, tracks.Find(current_track))
|
|
var/newTrackIndex = (curTrackIndex % tracks.len) + 1 // Loop back around if past end
|
|
current_track = tracks[newTrackIndex]
|
|
if(playing)
|
|
start_stop_song()
|
|
updateDialog()
|
|
|
|
// Advance to the next track - Don't start playing it unless we were already playing
|
|
/obj/machinery/media/jukebox/proc/PrevTrack()
|
|
var/list/tracks = getTracksList()
|
|
if(!tracks.len) return
|
|
var/curTrackIndex = max(1, tracks.Find(current_track))
|
|
var/newTrackIndex = curTrackIndex == 1 ? tracks.len : curTrackIndex - 1
|
|
current_track = tracks[newTrackIndex]
|
|
if(playing)
|
|
start_stop_song()
|
|
updateDialog()
|
|
|
|
//Pre-hacked Jukebox, has the full sond list unlocked
|
|
/obj/machinery/media/jukebox/hacked
|
|
name = "DRM free space jukebox"
|
|
desc = "Filled with songs both past and present! Unlocked for your convenience!"
|
|
hacked = 1
|
|
|
|
// Ghostly jukebox for adminbuse
|
|
/obj/machinery/media/jukebox/ghost
|
|
name = "ghost jukebox"
|
|
desc = "A jukebox from the nether-realms! Spooky."
|
|
|
|
plane = PLANE_GHOSTS
|
|
invisibility = INVISIBILITY_OBSERVER
|
|
alpha = 127
|
|
|
|
icon_state = "jukebox2-virtual"
|
|
|
|
density = FALSE
|
|
hacked = TRUE
|
|
|
|
use_power = USE_POWER_OFF
|
|
circuit = null
|
|
|
|
var/list/custom_tracks = list()
|
|
|
|
// Just junk to make it sneaky - I wish a lot more stuff was on /obj/machinery/media instead of /jukebox so I could use that.
|
|
/obj/machinery/media/jukebox/ghost/is_incorporeal()
|
|
return TRUE
|
|
/obj/machinery/media/jukebox/ghost/audible_message(message, deaf_message, hearing_distance, radio_message, runemessage)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/visible_message(message, blind_message, list/exclude_mobs, range, runemessage)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/attackby(obj/item/W as obj, mob/user as mob)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/attack_ai(mob/user as mob)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/attack_hand(var/mob/user as mob)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/update_use_power(new_use_power)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/power_change()
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/emp_act(severity)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/emag_act(remaining_charges, mob/user)
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/explode()
|
|
return
|
|
/obj/machinery/media/jukebox/ghost/update_icon()
|
|
if(playing)
|
|
animate(src, alpha = 200, time = 5, loop = -1)
|
|
else
|
|
animate(src, alpha = initial(alpha), time = 10)
|
|
// End junk
|
|
|
|
/obj/machinery/media/jukebox/ghost/attack_ghost(var/mob/observer/dead/M)
|
|
if(!istype(M))
|
|
return
|
|
|
|
if(check_rights(R_FUN|R_ADMIN, show_msg=0))
|
|
interact(M)
|
|
else if(current_track)
|
|
to_chat(M, "\The [src] is playing [current_track.display()].")
|
|
else
|
|
to_chat(M, "\The [src] is not playing any music.")
|
|
|
|
/obj/machinery/media/jukebox/ghost/getTracksList()
|
|
return (custom_tracks + ..())
|
|
|
|
/obj/machinery/media/jukebox/ghost/proc/manual_track_add()
|
|
var/client/C = usr.client
|
|
if(!check_rights(R_FUN|R_ADMIN))
|
|
return
|
|
|
|
// Required
|
|
var/url = tgui_input_text(C, "REQUIRED: Provide URL for track", "Track URL")
|
|
if(!url)
|
|
return
|
|
|
|
var/title = tgui_input_text(C, "REQUIRED: Provide title for track", "Track Title")
|
|
if(!title)
|
|
return
|
|
|
|
var/duration = tgui_input_number(C, "REQUIRED: Provide duration for track (in deciseconds, aka seconds*10)", "Track Duration")
|
|
if(!duration)
|
|
return
|
|
|
|
// Optional
|
|
var/artist = tgui_input_text(C, "Optional: Provide artist for track", "Track Artist")
|
|
if(isnull(artist)) // Cancel rather than empty string
|
|
return
|
|
|
|
// So they're obvious and grouped
|
|
var/genre = "! Admin Loaded !"
|
|
|
|
custom_tracks += new /datum/track(url, title, duration, artist, genre)
|
|
|
|
/obj/machinery/media/jukebox/ghost/proc/manual_track_remove()
|
|
var/client/C = usr.client
|
|
if(!check_rights(R_FUN|R_ADMIN))
|
|
return
|
|
|
|
var/track = tgui_input_text(C, "Input track title or URL to remove (must be exact)", "Remove Track")
|
|
if(!track)
|
|
return
|
|
|
|
for(var/datum/track/T in custom_tracks)
|
|
if(T.title == track || T.url == track)
|
|
custom_tracks -= T
|
|
qdel(T)
|
|
return
|
|
|
|
to_chat(C, span_warning("Couldn't find a track matching the specified parameters."))
|
|
|
|
/obj/machinery/media/jukebox/ghost/vv_get_dropdown()
|
|
. = ..()
|
|
VV_DROPDOWN_OPTION("", "---")
|
|
VV_DROPDOWN_OPTION("add_track", "Add New Track")
|
|
VV_DROPDOWN_OPTION("remove_track", "Remove Track")
|
|
|
|
/obj/machinery/media/jukebox/ghost/vv_do_topic(list/href_list)
|
|
. = ..()
|
|
IF_VV_OPTION("add_track")
|
|
manual_track_add()
|
|
href_list[VV_HK_DATUM_REFRESH] = "\ref[src]"
|
|
IF_VV_OPTION("remove_track")
|
|
manual_track_remove()
|
|
href_list[VV_HK_DATUM_REFRESH] = "\ref[src]"
|