var/GLOBAL_RADIO_TYPE = 1 // radio type to use // 0 = old radios // 1 = new radios (subspace technology) /obj/item/device/radio icon = 'radio.dmi' name = "station bounced radio" suffix = "\[3\]" icon_state = "walkietalkie" item_state = "walkietalkie" var/on = 1 // 0 for off var/last_transmission var/frequency = 1459 //common chat var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies var/canhear_range = 3 // the range which mobs can hear this radio from var/obj/item/device/radio/patch_link = null var/obj/item/device/uplink/traitorradio = null var/wires = WIRE_SIGNAL | WIRE_RECEIVE | WIRE_TRANSMIT var/b_stat = 0 var/broadcasting = 0 var/listening = 1 var/freerange = 0 // 0 - Sanitize frequencies, 1 - Full range var/list/channels = list() //see communications.dm for full list. First channes is a "default" for :h var/subspace_transmission = 0 var/syndie = 0//Holder to see if it's a syndicate encrpyed radio var/maxf = 1499 // "Example" = FREQ_LISTENING|FREQ_BROADCASTING flags = FPRINT | CONDUCT | TABLEPASS slot_flags = SLOT_BELT throw_speed = 2 throw_range = 9 w_class = 2 g_amt = 25 m_amt = 75 var/const/WIRE_SIGNAL = 1 //sends a signal, like to set off a bomb or electrocute someone var/const/WIRE_RECEIVE = 2 var/const/WIRE_TRANSMIT = 4 var/const/TRANSMISSION_DELAY = 5 // only 2/second/radio var/const/FREQ_LISTENING = 1 //FREQ_BROADCASTING = 2 /obj/item/device/radio var/datum/radio_frequency/radio_connection var/list/datum/radio_frequency/secure_radio_connections = new proc/set_frequency(new_frequency) radio_controller.remove_object(src, frequency) frequency = new_frequency radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) /obj/item/device/radio/New() ..() if(radio_controller) initialize() // If intercom: do a local power check loop if(istype(src, /obj/item/device/radio/intercom)) spawn(5) checkpower() /obj/item/device/radio/initialize() if(freerange) if(frequency < 1200 || frequency > 1600) frequency = sanitize_frequency(frequency, maxf) // The max freq is higher than a regular headset to decrease the chance of people listening in, if you use the higher channels. else if (frequency < 1441 || frequency > maxf) world.log << "[src] ([type]) has a frequency of [frequency], sanitizing." frequency = sanitize_frequency(frequency, maxf) set_frequency(frequency) for (var/ch_name in channels) secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) /obj/item/device/radio/attack_self(mob/user as mob) user.machine = src interact(user) /obj/item/device/radio/proc/interact(mob/user as mob) if(!on) return var/dat = "[src]" if(!istype(src, /obj/item/device/radio/headset)) //Headsets dont get a mic button dat += "Microphone: [broadcasting ? "Engaged" : "Disengaged"]
" dat += {" Speaker: [listening ? "Engaged" : "Disengaged"]
Frequency: - - [format_frequency(frequency)] + +
"} for (var/ch_name in channels) dat+=text_sec_channel(ch_name, channels[ch_name]) dat+={"[text_wires()]
"} user << browse(dat, "window=radio") onclose(user, "radio") return /obj/item/device/radio/proc/text_wires() if (!b_stat) return "" return {"
Green Wire: [(wires & 4) ? "Cut" : "Mend"] Wire
Red Wire: [(wires & 2) ? "Cut" : "Mend"] Wire
Blue Wire: [(wires & 1) ? "Cut" : "Mend"] Wire
"} /obj/item/device/radio/proc/text_sec_channel(var/chan_name, var/chan_stat) var/list = !!(chan_stat&FREQ_LISTENING)!=0 return {" [chan_name]
Speaker: [list ? "Engaged" : "Disengaged"]
"} /obj/item/device/radio/proc/checkpower() // Simple loop, checks for power. Strictly for intercoms while(src) if(!src.loc) on = 0 else var/area/A = src.loc.loc if(!A || !isarea(A) || !A.master) on = 0 else on = A.master.powered(EQUIP) // set "on" to the power status if(!on) icon_state = "intercom-p" else icon_state = "intercom" sleep(30) /obj/item/device/radio/Topic(href, href_list) //..() if (usr.stat || !on) return if (!(issilicon(usr) || (usr.contents.Find(src) || ( in_range(src, usr) && istype(loc, /turf) )))) usr << browse(null, "window=radio") return usr.machine = src if (href_list["track"]) var/mob/target = locate(href_list["track"]) var/mob/living/silicon/ai/A = locate(href_list["track2"]) if(A && target) A.ai_actual_track(target) return else if (href_list["faketrack"]) var/mob/target = locate(href_list["track"]) var/mob/living/silicon/ai/A = locate(href_list["track2"]) if(A && target) A:cameraFollow = target A << text("Now tracking [] on camera.", target.name) if (usr.machine == null) usr.machine = usr while (usr:cameraFollow == target) usr << "Target is not on or near any active cameras on the station. We'll check again in 5 seconds (unless you use the cancel-camera verb)." sleep(40) continue return else if (href_list["freq"]) var/new_frequency = (frequency + text2num(href_list["freq"])) if (!freerange || (frequency < 1200 || frequency > 1600)) new_frequency = sanitize_frequency(new_frequency, maxf) set_frequency(new_frequency) if (traitor_frequency && frequency == traitor_frequency) usr.machine = null usr << browse(null, "window=radio") // now transform the regular radio, into a (disguised)syndicate uplink! var/obj/item/device/uplink/radio/T = traitorradio var/obj/item/device/radio/R = src usr.u_equip(R) R.loc = T if(usr.r_hand == R) usr.put_in_r_hand(T) else usr.put_in_l_hand(T) T.attack_self(usr) return else if (href_list["talk"]) broadcasting = text2num(href_list["talk"]) else if (href_list["listen"]) var/chan_name = href_list["ch_name"] if (!chan_name) listening = text2num(href_list["listen"]) else if (channels[chan_name] & FREQ_LISTENING) channels[chan_name] &= ~FREQ_LISTENING else channels[chan_name] |= FREQ_LISTENING else if (href_list["wires"]) var/t1 = text2num(href_list["wires"]) if (!( istype(usr.get_active_hand(), /obj/item/weapon/wirecutters) )) return if (wires & t1) wires &= ~t1 else wires |= t1 if (!( master )) if (istype(loc, /mob)) interact(loc) else updateDialog() else if (istype(master.loc, /mob)) interact(master.loc) else updateDialog() add_fingerprint(usr) /obj/item/device/radio/talk_into(mob/M as mob, message, channel) if(!on) return // the device has to be on /* Fix for permacell radios, but kinda eh about actually fixing them. if(!(src.wires & WIRE_TRANSMIT)) // The device has to have all its wires and shit intact return */ if(GLOBAL_RADIO_TYPE == 1) // NEW RADIO SYSTEMS: By Doohl /* Quick introduction: This new radio system uses a very robust FTL signaling technology unoriginally dubbed "subspace" which is somewhat similar to 'blue-space' but can't actually transmit large mass. Headsets are the only radio devices capable of sending subspace transmissions to the Communications Satellite. A headset sends a signal to a subspace listener/reciever elsewhere in space, the signal gets processed and logged, and an audible transmission gets sent to each individual headset. */ //#### Grab the connection datum ####// var/datum/radio_frequency/connection = null if(channel && channels && channels.len > 0) if (channel == "department") //world << "DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"" channel = channels[1] connection = secure_radio_connections[channel] else connection = radio_connection channel = null if (!istype(connection)) return if (!connection) return //#### Tagging the signal with all appropriate identity values ####// // ||-- The mob's name identity --|| var/displayname = M.name // grab the display name (name you get when you hover over someone's icon) var/real_name = M.real_name // mob's real name var/mobkey = "none" // player key associated with mob var/voicemask = 0 // the speaker is wearing a voice mask if(M.client) mobkey = M.key // assign the mob's key var/jobname // the mob's "job" // --- Human: use their actual job --- if (ishuman(M)) jobname = M:get_assignment() // --- Carbon Nonhuman --- else if (iscarbon(M)) // Nonhuman carbon mob jobname = "No id" // --- AI --- else if (isAI(M)) jobname = "AI" // --- Cyborg --- else if (isrobot(M)) jobname = "Cyborg" // --- Personal AI (pAI) --- else if (istype(M, /mob/living/silicon/pai)) jobname = "Personal AI" // --- Unidentifiable mob --- else jobname = "Unknown" // --- Modifications to the mob's identity --- // The mob is disguising their identity: if (istype(M.wear_mask, /obj/item/clothing/mask/gas/voice)) if(M.wear_mask:vchange) displayname = M.wear_mask:voice jobname = "Unknown" voicemask = 1 /* ###### Radio headsets can only broadcast through subspace ###### */ if(subspace_transmission) // First, we want to generate a new radio signal var/datum/signal/signal = new signal.transmission_method = 2 // 2 would be a subspace transmission. // transmission_method could probably be enumerated through #define. Would be neater. // --- Finally, tag the actual signal with the appropriate values --- signal.data = list( // Identity-associated tags: "mob" = M, // store a reference to the mob "mobtype" = M.type, // the mob's type "realname" = real_name, // the mob's real name "name" = displayname, // the mob's display name "job" = jobname, // the mob's job "key" = mobkey, // the mob's key "vmessage" = M.voice_message, // the message to display if the voice wasn't understood "vname" = M.voice_name, // the name to display if the voice wasn't understood "vmask" = voicemask, // 1 if the mob is using a voice gas mask // We store things that would otherwise be kept in the actual mob // so that they can be logged even AFTER the mob is deleted or something // Other tags: "compression" = rand(45,50), // compressed radio signal "message" = message, // the actual sent message "connection" = connection, // the radio connection to use "radio" = src, // stores the radio used for transmission "slow" = 0, // how much to sleep() before broadcasting - simulates net lag "traffic" = 0, // dictates the total traffic sum that the signal went through "type" = 0, // determines what type of radio input it is: normal broadcast "server" = null, // the last server to log this signal "reject" = 0 // if nonzero, the signal will not be accepted by any broadcasting machinery ) signal.frequency = connection.frequency // Quick frequency set //#### Sending the signal to all subspace receivers ####// for(var/obj/machinery/telecomms/receiver/R in world) R.receive_signal(signal) // Allinone can act as receivers. for(var/obj/machinery/telecomms/allinone/R in world) R.receive_signal(signal) // Receiving code can be located in Telecommunications.dm return /* ###### Intercoms and station-bounced radios ###### */ var/filter_type = 2 /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ if(istype(src, /obj/item/device/radio/intercom)) filter_type = 1 var/datum/signal/signal = new signal.transmission_method = 2 /* --- Try to send a normal subspace broadcast first */ signal.data = list( "mob" = M, // store a reference to the mob "mobtype" = M.type, // the mob's type "realname" = real_name, // the mob's real name "name" = displayname, // the mob's display name "job" = jobname, // the mob's job "key" = mobkey, // the mob's key "vmessage" = M.voice_message, // the message to display if the voice wasn't understood "vname" = M.voice_name, // the name to display if the voice wasn't understood "vmask" = voicemask, // 1 if the mob is using a voice gas mas "compression" = 0, // uncompressed radio signal "message" = message, // the actual sent message "connection" = connection, // the radio connection to use "radio" = src, // stores the radio used for transmission "slow" = 0, "traffic" = 0, "type" = 0, "server" = null, "reject" = 0 ) signal.frequency = connection.frequency // Quick frequency set for(var/obj/machinery/telecomms/receiver/R in world) R.receive_signal(signal) sleep(rand(10,25)) // wait a little... if(signal.data["done"]) // we're done here. return // Oh my god; the comms are down or something because the signal hasn't been broadcasted yet. // Send a mundane broadcast with limited targets: //THIS IS TEMPORARY. if(!connection) return //~Carn Broadcast_Message(connection, M, voicemask, M.voice_message, src, message, displayname, jobname, real_name, M.voice_name, filter_type, signal.data["compression"]) else // OLD RADIO SYSTEMS: By Goons? var/datum/radio_frequency/connection = null if(channel && channels && channels.len > 0) if (channel == "department") //world << "DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"" channel = channels[1] connection = secure_radio_connections[channel] else connection = radio_connection channel = null if (!istype(connection)) return var/display_freq = connection.frequency //world << "DEBUG: used channel=\"[channel]\" frequency= \"[display_freq]\" connection.devices.len = [connection.devices.len]" var/eqjobname if (ishuman(M)) eqjobname = M:get_assignment() else if (iscarbon(M)) eqjobname = "No id" //only humans can wear ID else if (isAI(M)) eqjobname = "AI" else if (isrobot(M)) eqjobname = "Cyborg"//Androids don't really describe these too well, in my opinion. else if (istype(M, /mob/living/silicon/pai)) eqjobname = "Personal AI" else eqjobname = "Unknown" if (!(wires & WIRE_TRANSMIT)) return var/list/receive = list() //for (var/obj/item/device/radio/R in radio_connection.devices) for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) // Modified for security headset code -- TLE //if(R.accept_rad(src, message)) receive |= R.send_hear(display_freq) //world << "DEBUG: receive.len=[receive.len]" var/list/heard_masked = list() // masked name or no real name var/list/heard_normal = list() // normal message var/list/heard_voice = list() // voice message var/list/heard_garbled = list() // garbled message for (var/mob/R in receive) if (R.client && R.client.STFU_radio) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. continue if (R.say_understands(M)) if (!ishuman(M) || istype(M.wear_mask, /obj/item/clothing/mask/gas/voice)) heard_masked += R else heard_normal += R else if (M.voice_message) heard_voice += R else heard_garbled += R if (length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled)) var/part_a = "" //var/part_b = " \icon[src]\[[format_frequency(frequency)]\] " var/freq_text switch(display_freq) if(SYND_FREQ) freq_text = "#unkn" if(COMM_FREQ) freq_text = "Command" if(1351) freq_text = "Science" if(1355) freq_text = "Medical" if(1357) freq_text = "Engineering" if(1359) freq_text = "Security" if(1349) freq_text = "Mining" if(1347) freq_text = "Cargo" //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO if(!freq_text) freq_text = format_frequency(display_freq) var/part_b = " \icon[src]\[[freq_text]\] " // Tweaked for security headsets -- TLE var/part_c = "" if (display_freq==SYND_FREQ) part_a = "" else if (display_freq==COMM_FREQ) part_a = "" else if (display_freq in DEPT_FREQS) part_a = "" var/quotedmsg = M.say_quote(message) //This following recording is intended for research and feedback in the use of department radio channels. var/part_blackbox_b = " \[[freq_text]\] " // Tweaked for security headsets -- TLE var/blackbox_msg = "[part_a][M.name][part_blackbox_b][quotedmsg][part_c]" //var/blackbox_admin_msg = "[part_a][M.name] (Real name: [M.real_name])[part_blackbox_b][quotedmsg][part_c]" for (var/obj/machinery/blackbox_recorder/BR in world) //BR.messages_admin += blackbox_admin_msg switch(display_freq) if(1459) BR.msg_common += blackbox_msg if(1351) BR.msg_science += blackbox_msg if(1353) BR.msg_command += blackbox_msg if(1355) BR.msg_medical += blackbox_msg if(1357) BR.msg_engineering += blackbox_msg if(1359) BR.msg_security += blackbox_msg if(1441) BR.msg_deathsquad += blackbox_msg if(1213) BR.msg_syndicate += blackbox_msg if(1349) BR.msg_mining += blackbox_msg if(1347) BR.msg_cargo += blackbox_msg else BR.messages += blackbox_msg //End of research and feedback code. if (length(heard_masked)) var/N = M.name var/J = eqjobname if (istype(M.wear_mask, /obj/item/clothing/mask/gas/voice)&&M.wear_mask:vchange) //To properly have the ninja show up on radio. Could also be useful for similar items. //Would not be necessary but the mob could be wearing a mask that is not a voice changer. N = M.wear_mask:voice J = "Unknown" var/rendered = "[part_a][N][part_b][quotedmsg][part_c]" for (var/mob/R in heard_masked) if(istype(R, /mob/living/silicon/ai)) R.show_message("[part_a][N] ([J]) [part_b][quotedmsg][part_c]", 2) else R.show_message(rendered, 2) if (length(heard_normal)) var/rendered = "[part_a][M.real_name][part_b][quotedmsg][part_c]" for (var/mob/R in heard_normal) if(istype(R, /mob/living/silicon/ai)) R.show_message("[part_a][M.real_name] ([eqjobname]) [part_b][quotedmsg][part_c]", 2) else R.show_message(rendered, 2) if (length(heard_voice)) var/rendered = "[part_a][M.voice_name][part_b][M.voice_message][part_c]" for (var/mob/R in heard_voice) if(istype(R, /mob/living/silicon/ai)) R.show_message("[part_a][M.voice_name] ([eqjobname]) [part_b][M.voice_message][part_c]", 2) else R.show_message(rendered, 2) if (length(heard_garbled)) quotedmsg = M.say_quote(stars(message)) var/rendered = "[part_a][M.voice_name][part_b][quotedmsg][part_c]" for (var/mob/R in heard_voice) if(istype(R, /mob/living/silicon/ai)) R.show_message("[part_a][M.voice_name][part_b][quotedmsg][part_c]", 2) else R.show_message(rendered, 2) /obj/item/device/radio/hear_talk(mob/M as mob, msg) if (broadcasting) talk_into(M, msg) /* /obj/item/device/radio/proc/accept_rad(obj/item/device/radio/R as obj, message) if ((R.frequency == frequency && message)) return 1 else if else return null return */ /obj/item/device/radio/proc/receive_range(freq) // check if this radio can receive on the given frequency, and if so, // what the range is in which mobs will hear the radio // returns: 0 if can't receive, range otherwise if (!(wires & WIRE_RECEIVE)) return 0 if(freq == SYND_FREQ) if(!(src.syndie))//Checks to see if it's allowed on that frequency, based on the encryption keys return 0 if (!on) return 0 if (!freq) //recieved on main frequency if (!listening) return 0 else var/accept = (freq==frequency && listening) if (!accept) for (var/ch_name in channels) var/datum/radio_frequency/RF = secure_radio_connections[ch_name] if (RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING)) accept = 1 break if (!accept) return 0 return canhear_range /obj/item/device/radio/proc/send_hear(freq) var/range = receive_range(freq) if(range > 0) return get_mobs_in_view(canhear_range, src) /obj/item/device/radio/examine() set src in view() ..() if ((in_range(src, usr) || loc == usr)) if (b_stat) usr.show_message("\blue \the [src] can be attached and modified!") else usr.show_message("\blue \the [src] can not be modified or attached!") return /obj/item/device/radio/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() user.machine = src if (!( istype(W, /obj/item/weapon/screwdriver) )) return b_stat = !( b_stat ) if(!istype(src, /obj/item/device/radio/beacon)) if (b_stat) user.show_message("\blue The radio can now be attached and modified!") else user.show_message("\blue The radio can no longer be modified or attached!") updateDialog() //Foreach goto(83) add_fingerprint(user) return else return /obj/item/device/radio/emp_act(severity) broadcasting = 0 listening = 0 for (var/ch_name in channels) channels[ch_name] = 0 ..()