Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion code/__DEFINES/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
#define DISABLE_DEATHRATTLE (1<<12)
#define DISABLE_ARRIVALRATTLE (1<<13)
#define COMBOHUD_LIGHTING (1<<14)
#define MUSIC_RADIO (1<<15)
// Gap in prefs between tg and fortune13 prefs.
#define SPLIT_ADMIN_TABS (1<<23)

#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS|SOUND_ANNOUNCEMENTS)
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|MUSIC_RADIO|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS|SOUND_ANNOUNCEMENTS)

//Chat toggles
#define CHAT_OOC (1<<0)
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/lists/objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ GLOBAL_LIST_EMPTY(money_piles)

GLOBAL_LIST_EMPTY(mob_nests) //list of all nests, /obj/structure/nest
GLOBAL_LIST_EMPTY(lamppost) //list of all lampposts
GLOBAL_LIST_EMPTY_TYPED(radio_list, /obj/item/radio) //For the radio station. See radio_station.dm
94 changes: 90 additions & 4 deletions code/game/objects/items/devices/PDA/PDA.dm
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ GLOBAL_LIST_EMPTY(PDAs)
var/font_index = 0 //This int tells DM which font is currently selected and lets DM know when the last font has been selected so that it can cycle back to the first font when "toggle font" is pressed again.
var/font_mode = "font-family:monospace;" //The currently selected font.
var/background_color = "#808000" //The currently selected background color.
var/mob/living/radio_holder = null
var/allow_music = FALSE

#define FONT_MONO "font-family:monospace;"
#define FONT_SHARE "font-family:\"Share Tech Mono\", monospace;letter-spacing:0px;"
Expand Down Expand Up @@ -98,6 +100,9 @@ GLOBAL_LIST_EMPTY(PDAs)
var/list/blocked_pdas

var/list/saved_frequencies = list("Common" = FREQ_COMMON)
var/music_channel
var/TimerID
var/obj/item/record_disk/R

/obj/item/pda/suicide_act(mob/living/carbon/user)
var/deathMessage = msg_input(user)
Expand All @@ -121,6 +126,11 @@ GLOBAL_LIST_EMPTY(PDAs)
set_light(f_lum, f_pow, f_col)

GLOB.PDAs += src
GLOB.radio_list += src //Big Iron. Adds the PDA to the global radio list
var/i
for(i = 1; i <= GLOB.radio_list.len; i++)
if(GLOB.radio_list[i] == src)
music_channel = i
if(default_cartridge)
cartridge = new default_cartridge(src)
if(inserted_item)
Expand Down Expand Up @@ -317,7 +327,10 @@ GLOBAL_LIST_EMPTY(PDAs)
dat += "<li><a href='byond://?src=[REF(src)];choice=1'>[PDAIMG(notes)]Notekeeper</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=2'>[PDAIMG(mail)]Messenger</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=99'>[PDAIMG(signaler)]Radio</a></li>"

if (R)
dat += "<li><a href='byond://?src=[REF(src)];choice=9'>Eject record disk</a></li>" //Big-iron
dat += "<li><a href='byond://?src=[REF(src)];choice=10'>Play record disk</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=11'>Stop record disk</a></li>"
if (cartridge)
if (cartridge.access & CART_MANIFEST)
dat += "<li><a href='byond://?src=[REF(src)];choice=41'>[PDAIMG(notes)]View Crew Manifest</a></li>"
Expand Down Expand Up @@ -394,7 +407,6 @@ GLOBAL_LIST_EMPTY(PDAs)
dat += "<a href='byond://?src=[REF(src)];choice=Toggle Messenger'>[PDAIMG(mail)]Send / Receive: [toff == 1 ? "Off" : "On"]</a> | "
dat += "<a href='byond://?src=[REF(src)];choice=Ringtone'>[PDAIMG(bell)]Set Ringtone</a> | "
dat += "<a href='byond://?src=[REF(src)];choice=21'>[PDAIMG(mail)]Messages</a><br>"

if(cartridge)
dat += cartridge.message_header()

Expand Down Expand Up @@ -465,6 +477,7 @@ GLOBAL_LIST_EMPTY(PDAs)
dat += "<a href='?src=[REF(src)];rfreq=2'>+</a>"
dat += "<a href='?src=[REF(src)];rfreq=10'>+</a>"
dat += " | <a href='?src=[REF(src)];rsavefreq=[radio.frequency]'>Save Frequency</a><br><br>"
dat += "Allow music: <a href='byond://?src=[REF(src)];allowmmusictoggle=1'>[allow_music?"Allowed":"disallowed"]</a><br>"

if(saved_frequencies)
dat += "<b>Saved Frequencies</b>"
Expand All @@ -473,6 +486,25 @@ GLOBAL_LIST_EMPTY(PDAs)
dat += "<li><a href='?src=[REF(src)];rloadfreq=[saved_frequencies[freq]]'>[freq] ([format_frequency(saved_frequencies[freq])])</a>"
dat += " (<a href='?src=[REF(src)];rdelfreq=[saved_frequencies[freq]]'>Delete</a> | <a href='?src=[REF(src)];rrenfreq=[saved_frequencies[freq]]'>Rename</a>)</li>"
dat += "</ul>"
if(9)
if(R)
stopMusic(user)
radio_holder = null
R.forceMove(get_turf(src))
playsound(src, 'sound/effects/plastic_click.ogg', 100, 0)
R = null
else
to_chat(src.loc, "<span class='danger'>No record disk inserted!</span>")
mode = 0

if(10)
playMusiclocal(user)
mode = 0

if(11)
stopMusic(user)
radio_holder = null
mode = 0

else//Else it links to the cart menu proc. Although, it really uses menu hub 4--menu 4 doesn't really exist as it simply redirects to hub.
dat += cartridge.generate_menu()
Expand Down Expand Up @@ -751,7 +783,10 @@ GLOBAL_LIST_EMPTY(PDAs)
if(href_list["rspktoggle"])
radio.listening = !radio.listening
Boop()

if(href_list["allowmmusictoggle"])
allow_music = !allow_music
stopMusic(radio_holder)
Boop()
if(href_list["rfreq"])
var/new_frequency = (radio.frequency + text2num(href_list["rfreq"]))
if (!radio.freerange || (radio.frequency < MIN_FREE_FREQ || radio.frequency > MAX_FREE_FREQ))
Expand Down Expand Up @@ -897,7 +932,7 @@ GLOBAL_LIST_EMPTY(PDAs)
if (!signal.data["done"])
to_chat(user, span_notice("ERROR: Server isn't responding."))
if (!silent)
playsound(src, 'sound/machines/terminal_error.ogg', 15, 1)
playsound(src, 'sound/machines/terminal_error.ogg', 35, channel = music_channel)
return

var/target_text = signal.format_target()
Expand Down Expand Up @@ -1090,6 +1125,15 @@ GLOBAL_LIST_EMPTY(PDAs)
to_chat(user, span_notice("You insert [cartridge] into [src]."))
update_icon()
playsound(src, 'sound/machines/button.ogg', 50, 1)
if(istype(C, /obj/item/record_disk))
if(R)
to_chat(user, "<span class='danger'>A record disk is already inserted!</span>")
return
else
R = C
C.forceMove(src)
playsound(src, 'sound/effects/plastic_click.ogg', 100, 0)
playMusiclocal(user)

else if(istype(C, /obj/item/card/id))
var/obj/item/card/id/idcard = C
Expand Down Expand Up @@ -1216,6 +1260,9 @@ GLOBAL_LIST_EMPTY(PDAs)

/obj/item/pda/Destroy()
GLOB.PDAs -= src
GLOB.radio_list -= src //Big iron. Removes from global radio list
stopMusic(radio_holder)
radio_holder = null
if(istype(id))
QDEL_NULL(id)
if(istype(cartridge))
Expand Down Expand Up @@ -1315,6 +1362,45 @@ GLOBAL_LIST_EMPTY(PDAs)
continue
. += P

/obj/item/pda/proc/playMusiclocal(mob/living/user)
if(istype(src.loc, /mob/living))
user = src.loc
if(item_flags & IN_INVENTORY)
if(allow_music)
playsound(user, R.R.song_path, 100, channel = music_channel) //plays the music to the user
radio_holder = user
to_chat(user, "<span class='notice'>You play the [R] on your PDA.</span>")
else
to_chat(user, "<span class='warning'>The [src] is not allowed to play music!</span>")
else
to_chat(user, "<span class='warning'>The [src] must be in your inventory to play music!</span>")

/obj/item/pda/proc/playmusic(music_filepath, name_of_music, music_volume) //Plays music at src using the filepath to the audio file. This proc is directly working with the bluespace radio station at radio_station.dm
var/atom/loc_layer = loc
while(istype(loc_layer, /atom/movable))
if(!istype(loc_layer, /mob/living))
loc_layer = loc_layer.loc
else
radio_holder = loc_layer
break
if(!loc_layer) //if loc is null then this proc doesn't need to continue
return
if(!istype(loc_layer, /mob/living)) //doesn't need to continue if not on a mob
return

if(allow_music) //Music player is on
var/mob/living/M = loc_layer
if(istype(M) && M.client)
var/client/C = M.client
if(!(C.prefs.toggles & MUSIC_RADIO))
return
stopMusic(radio_holder) //stop the previously playing song to make way for the new one
playsound(radio_holder, music_filepath, music_volume, channel = music_channel) //plays the music to the user
to_chat(radio_holder, "<span class='robot'><b>[src]</b> beeps into your ears, 'Now playing: <i>[name_of_music]</i>.' </span>")

/obj/item/pda/proc/stopMusic(mob/user)
playsound(user, 'sound/machines/button.ogg', 50, channel = music_channel)
playsound(user, null, channel = music_channel)

#undef PDA_SCANNER_NONE
#undef PDA_SCANNER_MEDICAL
Expand Down
120 changes: 120 additions & 0 deletions code/game/objects/items/devices/radio/radio.dm
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
var/linked_faction = FALSE // Which faction the radio is linked to.
var/mob/living/carbon/linked_mob = null // Which mob the radio is checked out to.
//fortuna addition end. radio management.
var/music_channel = null //The sound channel the music is playing on.
var/radio_music_file = "" //The file path to the music's audio file
var/music_toggle = TRUE //Toggles whether music will play or not.
var/music_name = "" //Used to display the name of currently playing music.
var/music_playing = FALSE
var/mob/living/radio_holder //stopmusic() will apply to this person

/obj/item/radio/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!</span>")
Expand Down Expand Up @@ -97,13 +103,26 @@
LAZYREMOVE(GLOB.bos_radios, src)
if(FACTION_ENCLAVE)
LAZYREMOVE(GLOB.enclave_radios, src)
GLOB.radio_list -= src //Big-Iron, removes radio from radio list lmao
remove_radio_all(src) //Just to be sure
QDEL_NULL(wires)
QDEL_NULL(keyslot)
return ..()

/obj/item/radio/Initialize()
wires = new /datum/wires/radio(src)
var/obj/item/pda/pdloc = loc
if(!istype(src, /obj/item/radio/intercom) && !istype(pdloc)) //Intercoms playing music is useless
GLOB.radio_list += src //Big iron. Adds the radio to the global radio list for usage in radio_station.dm
var/i
for(i = 1; i <= GLOB.radio_list.len; i++)
if(GLOB.radio_list[i] == src)
music_channel = i //I hope that over 1,000 radios are never initialized.
/* Allow me to explain why. There are 1,024 usable channels. The top ~10
are preserved for ambience, admin music, etc. The other 1,000 are unused (to my knowledge)
and so to allow radios to play their own music without inferefering with other sounds, I give
each radio their own channel to play music on. This way the user can also stop the music
playing from their radio (headsets, etc.) without stopping the music of someone else's radio. */
if(prison_radio)
wires.cut(WIRE_TX) // OH GOD WHY
secure_radio_connections = new
Expand Down Expand Up @@ -161,6 +180,7 @@

data["broadcasting"] = broadcasting
data["listening"] = listening
data["music_toggle"] = music_toggle
data["frequency"] = frequency
data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ
data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ
Expand Down Expand Up @@ -228,6 +248,10 @@
else
recalculateChannels()
. = TRUE
if("streammusic")
music_toggle = !music_toggle
stopmusic(radio_holder)
. = TRUE

/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language)
if(HAS_TRAIT(M, TRAIT_SIGN_LANG)) //Forces Sign Language users to wear the translation gloves to speak over radios
Expand Down Expand Up @@ -410,6 +434,102 @@
to_chat(user, "<span class='notice'>The radio can no longer be modified or attached!</span>")
else
return ..()

/obj/item/radio/AltClick(mob/user) //Big Iron
..()
if(!istype(user) || !Adjacent(user) || user.incapacitated())
return
if(user.a_intent == INTENT_HARM)
if(music_toggle)
music_toggle = 0
stopmusic(radio_holder)
to_chat(user, "<span class ='notice'>[src]'s music player is now <b>OFF</b>. </span>")
else
music_toggle = 1
to_chat(user, "<span class ='notice'>[src]'s music player is now <b>ON</b>. </span>")
return

/obj/item/radio/proc/avoiding_a_sleep(mob/living/user, music_filepath, name_of_music, music_volume)
music_name = name_of_music
to_chat(user, "<span class='robot'><b>[src]</b> beeps into your ears, 'Now playing: <i>[music_name]</i>.' </span>")
if(user.client)
var/mob/M = user
var/client/C = M.client
if(!(C.prefs.toggles & MUSIC_RADIO))
to_chat(user, "<span class='robot'><b>[src]</b> your preferences stopped <i>[music_name]</i> from playing!.' </span>")
return
music_playing = TRUE
playsound(user, music_filepath, music_volume, channel = music_channel) //plays the music to the user
update_icon()

/obj/item/radio/proc/playmusic(music_filepath, name_of_music, music_volume) //Plays music at src using the filepath to the audio file. This proc is directly working with the bluespace radio station at radio_station.dm
radio_music_file = music_filepath

var/atom/loc_layer = loc
while(istype(loc_layer, /atom/movable))
if(!istype(loc_layer, /mob/living))
loc_layer = loc_layer.loc
else
radio_holder = loc_layer
break
if(!loc_layer) //if loc is null then this proc doesn't need to continue
return
if(!istype(loc_layer, /mob/living)) //doesn't need to continue if not on a mob
return

if(music_toggle == 1) //Music player is on
if(istype(src, /obj/item/radio/headset))
var/mob/living/carbon/wearer = radio_holder
if(!(wearer.ears == src)) //only want headsets to play music if they're equipped
return
stopmusic(radio_holder) //stop the previously playing song to make way for the new one
addtimer(CALLBACK(src, .proc/avoiding_a_sleep, radio_holder, music_filepath, name_of_music, music_volume), 10)

/obj/item/radio/proc/stopmusic(mob/living/user, music_turnoff_message_type)
if(music_playing)
music_playing = FALSE
update_icon()
playsound(user, null, channel = music_channel)
playsound(user, 'sound/machines/buzz-sigh.ogg', 50, channel = music_channel)
music_name = ""
switch(music_turnoff_message_type)
if(1)
audible_message("<span class='robot'><b>[src]</b> beeps, '[src] removed, turning off music.' </span>")
if(2)
src.audible_message("<span class='robot'><b>[src]</b> beeps, 'Music toggled off.' </span>") //Unused message
if(3)
src.audible_message("<span class='robot'><b>[src]</b> beeps, 'Signal interrupted.' </span>")
music_playing = FALSE

/obj/item/radio/dropped(mob/user)
..()
addtimer(CALLBACK(src, .proc/droppedStopMusic, user), 3)

/obj/item/radio/proc/droppedStopMusic(mob/user)
var/i
for(i = 1, i <= user.contents.len, i++)
if(user.contents[i] == src)
return
if(item_flags & IN_INVENTORY)
return
if(determineIfInMob(user) == TRUE)
return
stopmusic(user, 1)

/obj/item/radio/proc/determineIfInMob(mob/user)
var/obj/itemholder = src
var/mob/M = src.loc
while(M && !istype(M, /mob/living))
M = itemholder
if(!M)
return FALSE
itemholder = itemholder.loc
if(M == user)
return TRUE
else
return FALSE

//Big-iron end
/*
/obj/item/radio/emp_act(severity)
. = ..()
Expand Down
4 changes: 4 additions & 0 deletions code/modules/client/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ Records disabled until a use for them is found
dat += "<br>"
dat += "<b>Play Admin MIDIs:</b> <a href='?_src_=prefs;preference=hear_midis'>[(toggles & SOUND_MIDI) ? "Enabled":"Disabled"]</a><br>"
dat += "<b>Play Lobby Music:</b> <a href='?_src_=prefs;preference=lobby_music'>[(toggles & SOUND_LOBBY) ? "Enabled":"Disabled"]</a><br>"
dat += "<b>Stream radio music:</b> <a href='?_src_=prefs;preference=music_streaming'>[(toggles & MUSIC_RADIO) ? "Enabled":"Disabled"]</a><br>"
dat += "<b>See Pull Requests:</b> <a href='?_src_=prefs;preference=pull_requests'>[(chat_toggles & CHAT_PULLR) ? "Enabled":"Disabled"]</a><br>"
dat += "<br>"
if(user.client)
Expand Down Expand Up @@ -2542,6 +2543,9 @@ Records disabled until a use for them is found
if("ghost_ears")
chat_toggles ^= CHAT_GHOSTEARS

if("music_streaming")
toggles ^= MUSIC_RADIO

if("ghost_sight")
chat_toggles ^= CHAT_GHOSTSIGHT

Expand Down
13 changes: 13 additions & 0 deletions code/modules/client/preferences_toggles.dm
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,19 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggleprayersounds)()
C?.tgui_panel?.stop_music()
SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Stop Self Sounds")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggleradiomusic)()
set name = "Hear/Silence Radio Music"
set category = "Preferences"
set desc = "Hear music streamed by radio stations"
usr.client.prefs.toggles ^= MUSIC_RADIO
usr.client.prefs.save_preferences()
if(usr.client.prefs.toggles & MUSIC_RADIO)
to_chat(usr, "You will now hear songs through radios.")
else
to_chat(usr, "You will no longer hear sounds played in radios")
SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Toggle Radio Music", "[usr.client.prefs.toggles & MUSIC_RADIO ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/verbs/menu/Settings/Sound/toggleradiomusic/Get_checked(client/C)
return C.prefs.toggles & MUSIC_RADIO

TOGGLE_CHECKBOX(/datum/verbs/menu/Settings, listen_ooc)()
set name = "Show/Hide OOC"
Expand Down
Loading