From d9ecff2cb6a3d5fcc264be06ab1bb37546231651 Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Sat, 5 Jun 2021 01:47:27 -0400 Subject: [PATCH 1/3] PodZu Portable Music Player --- code/datums/chat_message.dm | 11 +- code/game/machinery/jukebox.dm | 43 +++--- code/modules/media/walkpod.dm | 268 +++++++++++++++++++++++++++++++++ icons/obj/device_vr.dmi | Bin 3998 -> 5460 bytes vorestation.dme | 1 + 5 files changed, 294 insertions(+), 29 deletions(-) create mode 100644 code/modules/media/walkpod.dm diff --git a/code/datums/chat_message.dm b/code/datums/chat_message.dm index c01c113c8d..a625d0cd58 100644 --- a/code/datums/chat_message.dm +++ b/code/datums/chat_message.dm @@ -325,10 +325,13 @@ var/list/runechat_image_cache = list() if(5) return rgb(c,m,x) -/atom/proc/runechat_message(message, range = world.view, italics, list/classes = list(), audible = TRUE) - var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src), range, remote_ghosts = FALSE) - - var/list/hearing_mobs = hear["mobs"] +/atom/proc/runechat_message(message, range = world.view, italics, list/classes = list(), audible = TRUE, list/specific_viewers) + var/hearing_mobs + if(islist(specific_viewers)) + hearing_mobs = specific_viewers.Copy() + else + var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src), range, remote_ghosts = FALSE) + hearing_mobs = hear["mobs"] for(var/mob in hearing_mobs) var/mob/M = mob diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm index ac24c962e4..395fe326bc 100644 --- a/code/game/machinery/jukebox.dm +++ b/code/game/machinery/jukebox.dm @@ -29,8 +29,6 @@ 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/max_queue_len = 3 // How many songs are we allowed to queue up? - var/list/queue = list() //VOREStation Add End var/datum/track/current_track @@ -60,29 +58,24 @@ // If the current track isn't finished playing, let it keep going if(current_track && world.time < media_start_time + current_track.duration) return - // Otherwise time to pick a new one! - if(queue.len > 0) - current_track = queue[1] - queue.Cut(1, 2) // Remove the item we just took off the list - else - // 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() + // 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() diff --git a/code/modules/media/walkpod.dm b/code/modules/media/walkpod.dm new file mode 100644 index 0000000000..8b1a2e2876 --- /dev/null +++ b/code/modules/media/walkpod.dm @@ -0,0 +1,268 @@ +// Mostly a jukebox copy-paste, given the vastly different paths though it seemed worth it. +// Would rather not have a bunch of /machinery baggage on our portable music player. + +/obj/item/device/walkpod + name = "\improper PodZu music player" + desc = "Portable music player! For when you need to ignore the rest of the world, there's only one choice: PodZu." + description_fluff = "A prestigious set: The ZuMan music player, and the HeadPods headphones, both 90th anniversary releases! Together they form the PodZu Music Player, famous in the local galactic cluster for pumping sick beats directly into your head." + description_info = "An easy way to access the menu while the player is in a pocket is Alt-Click. Wearing the headphones is not actually necessary to listen to music, but you can if you want, by right-clicking on the player and using 'Take HeadPods'." + + icon = 'icons/obj/device_vr.dmi' + icon_state = "podzu" // podzu_o, headpod, zuman + + var/loop_mode = JUKEMODE_PLAY_ONCE // Behavior when finished playing a song + var/datum/track/current_track // Current track playing + var/mob/living/listener // Person whomst is listening to us + + var/playing = 0 + var/volume = 1 + + var/media_url = "" + var/media_start_time + + var/obj/item/device/headpods/deployed_headpods + + w_class = ITEMSIZE_COST_SMALL + +/obj/item/device/walkpod/Destroy() + remove_listener() + return ..() + +// Icon +/obj/item/device/walkpod/update_icon() + if(listener) + if(deployed_headpods) + icon_state = "zuman_on" + else + icon_state = "[initial(icon_state)]_on" + else + if(deployed_headpods) + icon_state = "zuman" + else + icon_state = "[initial(icon_state)]" + +// Listener handling +/obj/item/device/walkpod/proc/check_listener() + if(loc == listener) + return TRUE + return FALSE + +/obj/item/device/walkpod/proc/remove_listener() + if(playing) + StopPlaying() + STOP_PROCESSING(SSobj, src) + if(deployed_headpods) + restore_headpods() + to_chat(listener, "You are no longer wearing the [src]'s headphones.") + listener = null + update_icon() + +/obj/item/device/walkpod/proc/set_listener(mob/living/L) + if(listener) + remove_listener() + listener = L + START_PROCESSING(SSobj, src) + to_chat(L, "You put the [src]'s headphones on and power it up, preparing to listen to some sick tunes.") + update_icon() + +/obj/item/device/walkpod/proc/update_music() + listener?.force_music(media_url, media_start_time, volume) // Calling this with "" url (when we aren't playing) helpfully disables forced music + +/obj/item/device/walkpod/AltClick(mob/living/L) + if(L == listener && check_listener()) + tgui_interact(L) + else if(loc == L) // at least they're holding it + to_chat(L, "Turn on the [src] first.") + +/obj/item/device/walkpod/attack_self(mob/living/L) + if(!istype(L) || loc != L) + return + if(!listener) + set_listener(L) + tgui_interact(L) + +// Process ticks to ensure our listener remains valid and we do music-ing +/obj/item/device/walkpod/process() + if(!check_headpods()) + restore_headpods() + if(!check_listener()) + remove_listener() + return + if(!playing) + 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() + +// Track/music internals +/obj/item/device/walkpod/proc/start_stop_song() + if(current_track && playing) + media_url = current_track.url + media_start_time = world.time + runechat_message("* [current_track.display()] *", specific_viewers = list(listener)) + else + media_url = "" + media_start_time = 0 + update_music() + +/obj/item/device/walkpod/proc/StopPlaying() + playing = 0 + start_stop_song() + +/obj/item/device/walkpod/proc/StartPlaying() + if(!current_track) + return + playing = 1 + start_stop_song() + updateDialog() + +// Advance to the next track - Don't start playing it unless we were already playing +/obj/item/device/walkpod/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() + +// Unadvance to the notnext track - Don't start playing it unless we were already playing +/obj/item/device/walkpod/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() + +// UI +/obj/item/device/walkpod/proc/getTracksList() + return SSmedia_tracks.jukebox_tracks + +/obj/item/device/walkpod/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Jukebox", "PodZu Music Player") + ui.open() + +/obj/item/device/walkpod/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 + + return data + +/obj/item/device/walkpod/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(current_track == null) + to_chat(usr, "No track selected.") + else + StartPlaying() + return TRUE + +// Silly verb +/obj/item/device/walkpod/verb/take_headpods() + set name = "Take HeadPods" + set desc = "Grab the pair of HeadPods." + + var/mob/living/L = usr + if(!istype(L)) + return + if(deployed_headpods) + to_chat(usr, "The HeadPods are already deployed!") + return + deployed_headpods = new () + L.put_in_any_hand_if_possible(deployed_headpods) + update_icon() + +/obj/item/device/walkpod/attackby(obj/item/W, mob/user) + if(W == deployed_headpods) + restore_headpods(user) + return + return ..() + +/obj/item/device/walkpod/proc/restore_headpods(mob/living/potential_holder) + if(!deployed_headpods) + return + + if(listener) + to_chat(listener, "The headphone cable reunites the [deployed_headpods] with the [src] by retracting inwards.") + + if(istype(potential_holder)) + potential_holder.unEquip(deployed_headpods, force = TRUE) + qdel_null(deployed_headpods) + update_icon() + +/obj/item/device/walkpod/proc/check_headpods() + if(deployed_headpods && deployed_headpods.loc != loc) + return FALSE + return TRUE + +/obj/item/device/headpods + name = "\improper pair of HeadPods" + desc = "Portable listening in Hi-Fi!" + icon = 'icons/obj/device_vr.dmi' + icon_state = "headpods" + item_state = "headphones_on" + w_class = ITEMSIZE_SMALL + slot_flags = SLOT_HEAD diff --git a/icons/obj/device_vr.dmi b/icons/obj/device_vr.dmi index 200443e04636ac1e5a9dedc3d0178f131ab5b8f0..e33e6e93da0e96a09755d587c7e712e678d55c04 100644 GIT binary patch literal 5460 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 literal 3998 zcmb7Hc{r49+rP(_U6hb&2=O$Sp`>~=BSfWTQjcUWTgp~;#*8gggv2z7p~aF=_AN8o zhNwwl5QfCq#$aqS#>{*BdcW`Zj_>*2<9Odc?(4da^SJNxI^i1iQ^VF;7kUeJaI8_wAXQS0;dlV7wm#8JObTrdItn~`}+Yv*yGI97TH*YbOQCq z`TYS}mS2_Ojmk+QK)LDE!wPpqg-o(P3nD6~toEj=jYe{bs?((HPdsSt4NuN&fQV5B zbMF`GI*Cfl%4=n&rGAo$3!V@`%=uMxHl4rv((1$?DWYQPTA^{(%3S%e3G}3uc86G% z>8v|^-1y9c2WBHu$`&nlD1!#S^v1D3;fn#!OLZ=e;+&CZZ7(CvpGV&<`&l=$GSb71 zn*WULO4LkM|6;=xYtqle_sB(}0YLV_35%l_!X7hoqI|Y6c2Y?C8U_;aU3KbB-nXt@ z+v=_1OViITxOM8gonk?!trPk$i36n$4XDj|d(J6VB<+_!nQm`;y5v}OY3H+~8VM5^2g8AFU(?QpRpFB6AxV^LRN|0k4T>7rOh2;n za}61DzVJ+p+J&)QBvsSRSTj*m9T`O+fByv_{u>&y`K0-O8(iiZA+}W^`?X53f^S23 z;imGyh|>k@Mn>7YZd;zsS!$=op5#XtNnQRCGV^ULk#5pD=$+DYui#gI@QQlw!%m!% zu8t7ksG?%M*1xH_%Cm)~@6_~ZNxgNE*5$+fBf4@@(zJqDyt)v^flrX8<;it#uXmv; zodnrGcH7z8B)@fqeB?)Lm(y0LTaB}lKilCNe&Uawvc|JG=gY4E0AX}QLajP&_WhPR zM40H)*XJH&;z#nQWPs?btSomgFYWV@`vqC_rIE-FA6DCXDDkUwoFL8|_*RB7T*Kv! zflFCVpWy0Z7qy~P;3(?qI9XCsf^Lq;;n((7%P%emxsAR{&F2%CQj+ntYCSzPSIu10 z&88*>amAA-q+K486F#N!dj+%T7kc!vueHkd3@f*%fQ{5}Plw(vBVd@xAd(GY_}~2@ zE;vUf|7k0U|3h!BO4QZ)HnN4*}vs@&}q+${(j9@pg!_r^m9v=-3R^+a2s<*l| zp5q%6GCZ%kTF%Rx^);7K1ZzoqO%Xpjt z!PPDlX;7@S2B=~7W+qc?6lvQ2m1k&w~7P^FQ(aEuf&H|5IW zRB*EMn|o7Jd!uTLFiVHum!+tM_=f6ZRh&eXpqlWSNDdU zRVXSI?T;D%I5=^5Zf^~%FLl$J>8K+Ad7}g?S^u};6 z2Q_5&;eduMXMuoPQTHX)!AV{djC7SGezRT>q5;q{hlg_gx~h$T*0R=j1~XHx`VFMS z1QrVq^7%&rsf!q9FBulOGJE<_BI&rM0s;=e2K*qGc)I1?wb4lKoBPx2j9n0Z(88}K zD;ZzfL~*}8=xj;@5*-dh0+@&ccfx$ctx};YO-n1WMS6Kkq@<03=x#2kzXy>eg(F`1 zQpz;@OI_Rtj4C#YmJe%w&8-&R-7~eR$sclTb#RAp(qiP%3xe=ehy}O4TzKLbg3>uk z5w^XE`wVXI0!6HjnM8!<-dgp+3~}7x4yNa@=U^lUl7q!EaqMukE(lT`rU7}xSWc`8 z*Uy>>Nr~?Igj-ylkDhVL1q+{$Al80mfVOm{qRB)A;C3ICUn4uOJFmpN;U2qxcRe&% zt2a5ER>V@;gcfv!fPj-a)IJ(NzliTPv#aJiKfouBN2N<{j@me7X=<%J*$m)Q{ETu zF)(tH29BS)_cH~xLm2o$F?$x$o(wBKp3IDK$M-R;1RiU?p)tGDkCQRl&D&1rmj>A* z8@HjaE1s6Aqb4d%uDqSQCGqkS)QmZPcx$E@VjrO@iZ?fiH>nTn&-i1%i_>~mRTO-$ z%rH@b3;#|$pll6hE=49&ec&|#(;{a$xC=&a+Y$vt_kRvL+$3d5YS4QN2PPIwa+184V}Wr~b#I=gS&$33kciBhU5~mmq0shitOu zeW8R_igLe9FN9eC_T;^|wCf!hVwOg1>w!Zlrp~;3lV4vjM%k}g(f2*_J93`4J!?-2 zvHd7X>VH4YxMM~8`lPtD=B+(4(!`)r4eH$Gm!?V*ui6Kl)Oj2^Q(O)iZ!S>JK2`rR zB)9{_t2F8&r08KP)Y19QnAUUUoE(dz-YPY?6@wtbXfjg+C{`*+W~MU@*LV{oACem+ zC@4rInKLt<8Q|=O*R=$D>#Y`{^{tu#syR71F;_1L4(KR7;S~#fBjRat&&qW7C`b$( zT#cg>Z@3#|{h+&ZJFPYMS8to zcBvtbZvr{xcU$v6CDz}#c%w-}7bJgMc@2I3-Yf8D#XZc!V75cZZ=uiHc58&a_%ChJ zDb#m;G?MWy!^M|0s*i5|uNCV2-gr7^weKgDg2C(}(c4`Th{eFnLf^hjdH*rvf_Tmd z6_3Hd`IuE6;T~k>TX=PHSV^mCI$_C{-@w)L-Z$mJ`2OeEX!{Jx8reKECg;AwpiX)1 z1q$ONN+h=uF2VOfhf;`IP&$k6^^KT9M3vCH#mNc^FvCh`Ph^ugse4;5i{HM;cnf|P zY9!RGwsOg2!0nu*@eUN6@ zjVEd-jt7@u8IAdps7>m}QiNJpFkuTN%t8(X)H~HH|B2{5O5RFtiQ81l+TM0U35Kn` z&0EH9-*EH4WwQc{1qzp2gD!FGTr^&s{)M0RYS69=keFKlyD?ZR2M{N)tTN9|#M5fV z_@ZxXh)NW8iO5^vsSu#9K0eZVdU|iq+)`n2@k~SRHhk7dePQjhs0W>U7TVcf>pWnx zU${-blErR2*L1_ZjC3H?kUif9A0lpH3-?xQpLe%LlIYk+P_l5Xr(bxau<#kC{A2}t z-g7k4I|Ho!dmiv)y$O7mbL6vJnru2}&ht07Uw6o)~@OynQJpya2&x9%kb(n_Y~f#SNE1$X!gVZ2g-MVKZph}T zx-*HMCngPl8bOC(hCJ=Fiw4iD+vZl5cC|l55pQJ5mX3`UntLKmHt39rP-|q*dr%2! zaB%{Zd`)!mPbe~j@6$oSAMrA49=;~xN>F>t!h{j{j;;T+g=3>Lw7C_AP{AavG2lI@ zD+H{mBe-!`vv%*S9hrsU#k!)W);DsAFaqNsmnVD Date: Sat, 5 Jun 2021 02:49:53 -0400 Subject: [PATCH 2/3] BoomTown jukebox remote speakers --- code/game/machinery/jukebox.dm | 6 ++ code/modules/media/juke_remote.dm | 111 ++++++++++++++++++++++++++++++ icons/obj/device_vr.dmi | Bin 5460 -> 7682 bytes vorestation.dme | 1 + 4 files changed, 118 insertions(+) create mode 100644 code/modules/media/juke_remote.dm diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm index 395fe326bc..c8683e0d00 100644 --- a/code/game/machinery/jukebox.dm +++ b/code/game/machinery/jukebox.dm @@ -29,6 +29,7 @@ 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/device/juke_remote/remotes //VOREStation Add End var/datum/track/current_track @@ -89,6 +90,11 @@ media_url = "" media_start_time = 0 update_music() + //VOREStation Add + for(var/rem in remotes) + var/obj/item/device/juke_remote/remote = rem + remote.update_music() + //VOREStation Add End /obj/machinery/media/jukebox/proc/set_hacked(var/newhacked) if(hacked == newhacked) diff --git a/code/modules/media/juke_remote.dm b/code/modules/media/juke_remote.dm new file mode 100644 index 0000000000..416db7a792 --- /dev/null +++ b/code/modules/media/juke_remote.dm @@ -0,0 +1,111 @@ +/obj/item/device/juke_remote + name = "\improper BoomTown cordless speaker" + desc = "Once paired with a jukebox, this speaker can relay the tunes elsewhere!" + + description_fluff = "The BoomTown cordless speaker is capable of maintaining a high-quality 49kbps audio stream from a stationary jukebox and relaying the sound locally. It's like magic!" + description_info = "Hit it on a jukebox to pair, then set it down to play tunes. Does nothing while held, it has to be stationary, visible in the world. Keep in mind music is done by AREA, not within a certain range. You will need more than one to cover a department." + + icon = 'icons/obj/device_vr.dmi' + icon_state = "bspeaker" + + var/obj/machinery/media/jukebox/paired_juke + var/area/our_area + +/* +/obj/item/device/juke_remote/Initialize() + . = ..() + flags |= NOBLUDGEON +*/ +// Pairing +/obj/item/device/juke_remote/proc/pair_juke(obj/machinery/media/jukebox/juke, mob/user) + if(paired_juke) + to_chat(user, "The [src] is already paired to [paired_juke == juke ? "that" : "a different"] jukebox.") + return + paired_juke = juke + LAZYDISTINCTADD(paired_juke.remotes, src) + to_chat(user, "You pair the [src] to the [juke].") + icon_state = "[initial(icon_state)]_ready" + +/obj/item/device/juke_remote/proc/unpair_juke(mob/user) + if(!paired_juke) + to_chat(user, "The [src] isn't paired to anything.") + return + LAZYREMOVE(paired_juke.remotes, src) + paired_juke = null + icon_state = initial(icon_state) + unanchor() + detach_area() + to_chat(user, "You unpair the [src].") + icon_state = "[initial(icon_state)]" + +/obj/item/device/juke_remote/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(istype(target, /obj/machinery/media/jukebox)) + pair_juke(target, user) + return + return ..() + +/obj/item/device/juke_remote/verb/reset() + set name = "Reset Pairing" + set desc = "Unpair this speaker from a jukebox." + + unpair_juke(usr) + +// Deploying +/obj/item/device/juke_remote/Moved(atom/old_loc, direction, forced) + . = ..() + if(paired_juke && !anchored && isturf(loc)) + anchor() + +/obj/item/device/juke_remote/attack_hand(mob/living/user) + if(anchored) + unanchor() + return ..() + +/obj/item/device/juke_remote/proc/anchor() + if(anchored) + return + anchored = TRUE + if(attach_area()) + visible_message("[src] attaches to the nearest surface and bounces happily, ready to pump tunes.", runemessage = "clank") + if(paired_juke) // we were able to claim the area + icon_state = "[initial(icon_state)]_playing" + else + icon_state = "[initial(icon_state)]" + +/obj/item/device/juke_remote/proc/unanchor() + detach_area() + anchored = FALSE + visible_message("[src] detaches from it's mounting surface, able to be moved once again.", runemessage = "clunk") + if(paired_juke) + icon_state = "[initial(icon_state)]_ready" + else + icon_state = "[initial(icon_state)]" + +// Area handling +/obj/item/device/juke_remote/proc/attach_area() + var/area/A = get_area(src) + if(!A || !paired_juke) + error("Jukebox remote at [x],[y],[z] without paired juke tried to bind to an area.") + return FALSE + if(A.media_source) + return FALSE // Already has a media source, won't overpower it with porta speaker + our_area = A + A.media_source = paired_juke + update_music() + return TRUE + +/obj/item/device/juke_remote/proc/detach_area() + if(!our_area || (paired_juke && our_area.media_source != paired_juke)) + return + our_area.media_source = null + update_music() + our_area = null + +// Music handling +/obj/item/device/juke_remote/proc/update_music() + if(!our_area || !paired_juke) + return + // Send update to clients. + for(var/mob/M in mobs_in_area(our_area)) + if(M?.client) + M.update_music() \ No newline at end of file diff --git a/icons/obj/device_vr.dmi b/icons/obj/device_vr.dmi index e33e6e93da0e96a09755d587c7e712e678d55c04..d74e254079dfa432fa64b8a5f15681e32275dcd1 100644 GIT binary patch literal 7682 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 diff --git a/vorestation.dme b/vorestation.dme index 59506646fe..3b344e3491 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2524,6 +2524,7 @@ #include "code\modules\materials\sheets\organic\tanning\hide_hairless.dm" #include "code\modules\materials\sheets\organic\tanning\leather_wet.dm" #include "code\modules\materials\sheets\organic\tanning\tanning_rack.dm" +#include "code\modules\media\juke_remote.dm" #include "code\modules\media\media_machinery.dm" #include "code\modules\media\media_player_html5.dm" #include "code\modules\media\media_player_vlc.dm" From 12197dc1cf57e72316277bae69490832b2862427 Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Sat, 5 Jun 2021 03:00:04 -0400 Subject: [PATCH 3/3] Make both obtainable --- code/datums/supplypacks/misc_vr.dm | 19 ++++++++++++++++++- code/game/machinery/vending_machines_vr.dm | 8 ++++++-- code/modules/research/designs/misc_vr.dm | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/code/datums/supplypacks/misc_vr.dm b/code/datums/supplypacks/misc_vr.dm index 94f23fb61c..005658d414 100644 --- a/code/datums/supplypacks/misc_vr.dm +++ b/code/datums/supplypacks/misc_vr.dm @@ -110,4 +110,21 @@ access = list(access_explorer, access_eva, access_pilot) - one_access = TRUE \ No newline at end of file + one_access = TRUE + +/datum/supply_pack/misc/music_players + name = "music players (3)" + contains = list( + /obj/item/device/walkpod = 3 + ) + cost = 150 + containername = "portable music players crate" + +/datum/supply_pack/misc/juke_remotes + name = "jukebox remote speakers (2)" + contains = list( + /obj/item/device/juke_remote = 2 + ) + cost = 300 + containername = "cordless jukebox speakers crate" + \ No newline at end of file diff --git a/code/game/machinery/vending_machines_vr.dm b/code/game/machinery/vending_machines_vr.dm index 563fc5eb4a..278bc08231 100644 --- a/code/game/machinery/vending_machines_vr.dm +++ b/code/game/machinery/vending_machines_vr.dm @@ -1029,7 +1029,9 @@ /obj/item/device/radio/headset = 10, /obj/item/device/flashlight = 5, /obj/item/device/laser_pointer = 3, - /obj/item/clothing/glasses/omnihud = 10) + /obj/item/clothing/glasses/omnihud = 10, + /obj/item/device/walkpod = 5, + /obj/item/device/juke_remote = 1) prices = list(/obj/item/clothing/suit/circuitry = 100, /obj/item/clothing/head/circuitry = 100, /obj/item/clothing/shoes/circuitry = 100, @@ -1049,7 +1051,9 @@ /obj/item/device/radio/headset = 50, /obj/item/device/flashlight = 100, /obj/item/device/laser_pointer = 200, - /obj/item/clothing/glasses/omnihud = 100) + /obj/item/clothing/glasses/omnihud = 100, + /obj/item/device/walkpod = 300, + /obj/item/device/juke_remote = 1000) premium = list(/obj/item/device/perfect_tele/one_beacon = 1) contraband = list(/obj/item/weapon/disk/nifsoft/compliance = 1) diff --git a/code/modules/research/designs/misc_vr.dm b/code/modules/research/designs/misc_vr.dm index 518a0d8201..859834b447 100644 --- a/code/modules/research/designs/misc_vr.dm +++ b/code/modules/research/designs/misc_vr.dm @@ -53,3 +53,18 @@ build_path = /obj/item/weapon/mining_scanner/advanced sort_string = "FBAAB" +/datum/design/item/general/walkpod + name = "PodZu Music Player" + id = "walkpod" + req_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 3) + materials = list(DEFAULT_WALL_MATERIAL = 2000, MAT_GLASS = 2000) + build_path = /obj/item/device/walkpod + sort_string = "TCVAD" + +/datum/design/item/general/juke_remote + name = "BoomTown Cordless Speaker" + id = "juke_remote" + req_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 4, TECH_BLUESPACE = 1) + materials = list(DEFAULT_WALL_MATERIAL = 4000, MAT_GLASS = 4000, MAT_URANIUM = 2000) + build_path = /obj/item/device/juke_remote + sort_string = "TCVAE"