/* HOW IT WORKS The radio_controller is a global object maintaining all radio transmissions, think about it as about "ether". Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way. procs: add_object(obj/device as obj, var/new_frequency as num, var/filter as text|null = null) Adds listening object. parameters: device - device receiving signals, must have proc receive_signal (see description below). one device may listen several frequencies, but not same frequency twice. new_frequency - see possibly frequencies below; filter - thing for optimization. Optional, but recommended. All filters should be consolidated in this file, see defines later. Device without listening filter will receive all signals (on specified frequency). Device with filter will receive any signals sent without filter. Device with filter will not receive any signals sent with different filter. returns: Reference to frequency object. remove_object (obj/device, old_frequency) Obliviously, after calling this proc, device will not receive any signals on old_frequency. Other frequencies will left unaffected. return_frequency(var/frequency as num) returns: Reference to frequency object. Use it if you need to send and do not need to listen. radio_frequency is a global object maintaining list of devices that listening specific frequency. procs: post_signal(obj/source as obj|null, datum/signal/signal, var/filter as text|null = null, var/range as num|null = null) Sends signal to all devices that wants such signal. parameters: source - object, emitted signal. Usually, devices will not receive their own signals. signal - see description below. filter - described above. range - radius of regular byond's square circle on that z-level. null means everywhere, on all z-levels. obj/proc/receive_signal(datum/signal/signal, var/receive_method as num, var/receive_param) Handler from received signals. By default does nothing. Define your own for your object. Avoid of sending signals directly from this proc, use spawn(-1). DO NOT use sleep() here or call procs that sleep please. If you must, use spawn() parameters: signal - see description below. Extract all needed data from the signal before doing sleep(), spawn() or return! receive_method - may be TRANSMISSION_WIRE or TRANSMISSION_RADIO. TRANSMISSION_WIRE is currently unused. receive_param - for TRANSMISSION_RADIO here comes frequency. datum/signal vars: source an object that emitted signal. Used for debug and bearing. data list with transmitting data. Usual use pattern: data["msg"] = "hello world" encryption Some number symbolizing "encryption key". Note that game actually do not use any cryptography here. If receiving object don't know right key, it must ignore encrypted signal in its receive_signal. */ var/const/DISPLAY_FREQ = 1435 //status displays var/const/ATMOS_FIRE_FREQ = 1437 //air alarms var/const/ENGINE_FREQ = 1438 //engine components var/const/ATMOS_VENTSCRUB = 1439 //vents, scrubbers, atmos control var/const/ATMOS_DISTRO_FREQ = 1443 //distro loop var/const/ATMOS_TANKS_FREQ = 1441 //atmos supply tanks var/const/BOT_BEACON_FREQ = 1445 //bot navigation beacons var/const/AIRLOCK_FREQ = 1449 //airlock controls, electropack, magnets var/const/RSD_FREQ = 1457 //radio signal device var/const/IMPL_FREQ = 1451 //tracking implant var/const/RADIO_LOW_FREQ = 1200 //minimum radio freq var/const/PUBLIC_LOW_FREQ = 1441 //minimum radio chat freq var/const/PUBLIC_HIGH_FREQ = 1489 //maximum radio chat freq var/const/RADIO_HIGH_FREQ = 1600 //maximum radio freq var/const/SYND_FREQ = 1213 var/const/SYNDTEAM_FREQ = 1244 var/const/DTH_FREQ = 1341 //Special Operations var/const/AI_FREQ = 1343 var/const/ERT_FREQ = 1345 var/const/COMM_FREQ = 1353 //Command var/const/BOT_FREQ = 1447 //mulebot, secbot, ed209 // department channels var/const/PUB_FREQ = 1459 //standard radio chat var/const/SEC_FREQ = 1359 //security var/const/ENG_FREQ = 1357 //engineering var/const/SCI_FREQ = 1351 //science var/const/MED_FREQ = 1355 //medical var/const/SUP_FREQ = 1347 //cargo var/const/SRV_FREQ = 1349 //service // internal department channels var/const/MED_I_FREQ = 1485 var/const/SEC_I_FREQ = 1475 var/list/radiochannels = list( "Common" = PUB_FREQ, "Science" = SCI_FREQ, "Command" = COMM_FREQ, "Medical" = MED_FREQ, "Engineering" = ENG_FREQ, "Security" = SEC_FREQ, "Response Team" = ERT_FREQ, "Special Ops" = DTH_FREQ, "Syndicate" = SYND_FREQ, "SyndTeam" = SYNDTEAM_FREQ, "Supply" = SUP_FREQ, "Service" = SRV_FREQ, "AI Private" = AI_FREQ, "Medical(I)" = MED_I_FREQ, "Security(I)" = SEC_I_FREQ ) // central command channels, i.e deathsquid & response teams var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ) // Antag channels, i.e. Syndicate var/list/ANTAG_FREQS = list(SYND_FREQ, SYNDTEAM_FREQ) //Department channels, arranged lexically var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ) #define TRANSMISSION_WIRE 0 #define TRANSMISSION_RADIO 1 /proc/frequency_span_class(var/frequency) // Antags! if(frequency in ANTAG_FREQS) return "syndradio" // centcomm channels (deathsquid and ert) if(frequency in CENT_FREQS) return "centradio" // command channel if(frequency == COMM_FREQ) return "comradio" // AI private channel if(frequency == AI_FREQ) return "airadio" // department radio formatting (poorly optimized, ugh) if(frequency == SEC_FREQ) return "secradio" if(frequency == ENG_FREQ) return "engradio" if(frequency == SCI_FREQ) return "sciradio" if(frequency == MED_FREQ) return "medradio" if(frequency == SUP_FREQ) return "supradio" if(frequency == SRV_FREQ) return "srvradio" if(frequency in DEPT_FREQS) return "deptradio" return "radio" /* filters */ //When devices register with the radio controller, they might register under a certain filter. //Other devices can then choose to send signals to only those devices that belong to a particular filter. //This is done for performance, so we don't send signals to lots of machines unnecessarily. //This filter is special because devices belonging to default also recieve signals sent to any other filter. var/const/RADIO_DEFAULT = "radio_default" var/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms var/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in recieving signals from air alarms var/const/RADIO_CHAT = "radio_telecoms" var/const/RADIO_ATMOSIA = "radio_atmos" var/const/RADIO_NAVBEACONS = "radio_navbeacon" var/const/RADIO_AIRLOCK = "radio_airlock" var/const/RADIO_SECBOT = "radio_secbot" var/const/RADIO_HONKBOT = "radio_honkbot" var/const/RADIO_MULEBOT = "radio_mulebot" var/const/RADIO_CLEANBOT = "10" var/const/RADIO_FLOORBOT = "11" var/const/RADIO_MEDBOT = "12" var/const/RADIO_MAGNETS = "radio_magnet" var/const/RADIO_LOGIC = "radio_logic" var/global/datum/controller/radio/radio_controller /hook/startup/proc/createRadioController() radio_controller = new /datum/controller/radio() return 1 //callback used by objects to react to incoming radio signals /obj/proc/receive_signal(datum/signal/signal, receive_method, receive_param) return null //The global radio controller /datum/controller/radio var/list/datum/radio_frequency/frequencies = list() /datum/controller/radio/proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null) var/f_text = num2text(new_frequency) var/datum/radio_frequency/frequency = frequencies[f_text] if(!frequency) frequency = new frequency.frequency = new_frequency frequencies[f_text] = frequency frequency.add_listener(device, filter) return frequency /datum/controller/radio/proc/remove_object(obj/device, old_frequency) var/f_text = num2text(old_frequency) var/datum/radio_frequency/frequency = frequencies[f_text] if(frequency) frequency.remove_listener(device) if(frequency.devices.len == 0) qdel(frequency) frequencies -= f_text return 1 /datum/controller/radio/proc/return_frequency(var/new_frequency as num) var/f_text = num2text(new_frequency) var/datum/radio_frequency/frequency = frequencies[f_text] if(!frequency) frequency = new frequency.frequency = new_frequency frequencies[f_text] = frequency return frequency /datum/radio_frequency var/frequency as num var/list/list/obj/devices = list() /datum/radio_frequency/proc/post_signal(obj/source as obj|null, datum/signal/signal, var/filter = null as text|null, var/range = null as num|null) var/turf/start_point if(range) start_point = get_turf(source) if(!start_point) qdel(signal) return 0 if(filter) send_to_filter(source, signal, filter, start_point, range) send_to_filter(source, signal, RADIO_DEFAULT, start_point, range) else //Broadcast the signal to everyone! for(var/next_filter in devices) send_to_filter(source, signal, next_filter, start_point, range) //Sends a signal to all machines belonging to a given filter. Should be called by post_signal() /datum/radio_frequency/proc/send_to_filter(obj/source, datum/signal/signal, var/filter, var/turf/start_point = null, var/range = null) if(range && !start_point) return for(var/obj/device in devices[filter]) if(device == source) continue if(range) var/turf/end_point = get_turf(device) if(!end_point) continue if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range) continue device.receive_signal(signal, TRANSMISSION_RADIO, frequency) /datum/radio_frequency/proc/add_listener(obj/device as obj, var/filter as text|null) if(!filter) filter = RADIO_DEFAULT //log_admin("add_listener(device=[device],filter=[filter]) frequency=[frequency]") var/list/obj/devices_line = devices[filter] if(!devices_line) devices_line = new devices[filter] = devices_line devices_line+=device // var/list/obj/devices_line___ = devices[filter_str] // var/l = devices_line___.len //log_admin("DEBUG: devices_line.len=[devices_line.len]") //log_admin("DEBUG: devices(filter_str).len=[l]") /datum/radio_frequency/proc/remove_listener(obj/device) for(var/devices_filter in devices) var/list/devices_line = devices[devices_filter] devices_line-=device while(null in devices_line) devices_line -= null if(devices_line.len==0) devices -= devices_filter qdel(devices_line) /datum/signal var/obj/source var/transmission_method = 0 //unused at the moment //0 = wire //1 = radio transmission //2 = subspace transmission var/list/data = list() var/encryption var/frequency = 0 /datum/signal/proc/copy_from(datum/signal/model) source = model.source transmission_method = model.transmission_method data = model.data encryption = model.encryption frequency = model.frequency /datum/signal/proc/debug_print() if(source) . = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n" else . = "signal = {source = '[source]' ()\n" for(var/i in data) . += "data\[\"[i]\"\] = \"[data[i]]\"\n" if(islist(data[i])) var/list/L = data[i] for(var/t in L) . += "data\[\"[i]\"\] list has: [t]" /datum/signal/proc/get_race(mob/M) if(ishuman(M)) var/mob/living/carbon/human/H = M . = H.dna.species.name else if(isbrain(M)) var/mob/living/carbon/brain/B = M . = B.get_race() else if(issilicon(M)) . = "Artificial Life" else if(isslime(M)) . = "Slime" else if(isbot(M)) . = "Bot" else if(isanimal(M)) . = "Domestic Animal" else . = "Unidentifiable"