Modular Tablets: Converting PDAs to the NtOS System (SKYRAT VERSION) (#12920)

* hot-patch 1

* hot patch 2

* hot patch 3

* slight issue
This commit is contained in:
magatsuchi
2022-04-20 10:55:49 -05:00
committed by GitHub
parent d7222be1a3
commit dc8adc2924
182 changed files with 2968 additions and 4053 deletions
@@ -3,7 +3,7 @@
filedesc = "Newscaster"
required_access = list(ACCESS_LIBRARY)
category = PROGRAM_CATEGORY_CREW
program_icon_state = "computer"
program_icon_state = "bountyboard"
extended_desc = "This program allows any user to access the Newscaster network from anywhere."
size = 2
requires_ntnet = TRUE
@@ -0,0 +1,29 @@
/datum/computer_file/program/notepad
filename = "notepad"
filedesc = "Notepad"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "generic"
extended_desc = "Jot down your work-safe thoughts and what not."
size = 2
tgui_id = "NtosNotepad"
program_icon = "book"
usage_flags = PROGRAM_TABLET
/datum/computer_file/program/notepad/ui_act(action, list/params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("UpdateNote")
var/obj/item/modular_computer/tablet/comp = computer
comp.note = params["newnote"]
return UI_UPDATE
/datum/computer_file/program/notepad/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/modular_computer/tablet/comp = computer
data["note"] = comp.note
return data
@@ -0,0 +1,366 @@
/datum/computer_file/program/messenger
filename = "nt_messenger"
filedesc = "Direct Messenger"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "command"
extended_desc = "This program allows old-school communication with other modular devices."
size = 8
usage_flags = PROGRAM_TABLET
ui_header = "ntnrc_idle.gif"
available_on_ntnet = TRUE
tgui_id = "NtosMessenger"
program_icon = "comment-alt"
alert_able = TRUE
/// The current ringtone (displayed in the chat when a message is received).
var/ringtone = "beep"
/// Whether or not the ringtone is currently on.
var/ringer_status = TRUE
/// Whether or not we're sending and receiving messages.
var/sending_and_receiving = TRUE
/// The messages currently saved in the app.
var/messages = list()
/// great wisdom from PDA.dm - "no spamming" (prevents people from spamming the same message over and over)
var/last_text
/// even more wisdom from PDA.dm - "no everyone spamming" (prevents people from spamming the same message over and over)
var/last_text_everyone
/// Scanned photo for sending purposes.
var/datum/picture/picture
/// Whether or not we allow emojis to be sent by the user.
var/allow_emojis = FALSE
/// Whether or not we're currently looking at the message list.
var/viewing_messages = FALSE
// Whether or not this device is currently hidden from the message monitor.
var/monitor_hidden = FALSE
// Whether or not we're sorting by job.
var/sort_by_job = TRUE
// Whether or not we're sending (or trying to send) a virus.
var/sending_virus = FALSE
/// The path for the current loaded image in rsc
var/photo_path
/// Whether or not this app is loaded on a silicon's tablet.
var/is_silicon = FALSE
/// Whether or not we're in a mime PDA.
var/mime_mode = FALSE
/datum/computer_file/program/messenger/proc/ScrubMessengerList()
var/list/dictionary = list()
for(var/obj/item/modular_computer/messenger in GetViewableDevices(sort_by_job))
if(messenger.saved_identification && messenger.saved_job && !(messenger == computer))
var/list/data = list()
data["name"] = messenger.saved_identification
data["job"] = messenger.saved_job
data["ref"] = REF(messenger)
//if(data["ref"] != REF(computer)) // you cannot message yourself (despite all my rage)
dictionary += list(data)
return dictionary
/proc/GetViewableDevices(sort_by_job = FALSE)
var/list/dictionary = list()
var/sortmode
if(sort_by_job)
sortmode = /proc/cmp_pdajob_asc
else
sortmode = /proc/cmp_pdaname_asc
for(var/obj/item/modular_computer/P in sort_list(GLOB.TabletMessengers, sortmode))
var/obj/item/computer_hardware/hard_drive/drive = P.all_components[MC_HDD]
if(!drive)
continue
for(var/datum/computer_file/program/messenger/app in drive.stored_files)
if(!P.saved_identification || !P.saved_job || P.invisible || app.monitor_hidden)
continue
dictionary += P
return dictionary
/datum/computer_file/program/messenger/proc/StringifyMessengerTarget(obj/item/modular_computer/messenger)
return "[messenger.saved_identification] ([messenger.saved_job])"
/datum/computer_file/program/messenger/proc/ProcessPhoto()
if(computer.saved_image)
var/icon/img = computer.saved_image.picture_image
var/deter_path = "tmp_msg_photo[rand(0, 99999)].png"
usr << browse_rsc(img, deter_path) // funny random assignment for now, i'll make an actual key later
photo_path = deter_path
/datum/computer_file/program/messenger/ui_state(mob/user)
if(istype(user, /mob/living/silicon))
return GLOB.reverse_contained_state
return GLOB.default_state
/datum/computer_file/program/messenger/ui_act(action, list/params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("PDA_ringSet")
var/t = tgui_input_text(usr, "Enter a new ringtone", "Ringtone", "", 20)
var/mob/living/usr_mob = usr
if(in_range(computer, usr_mob) && computer.loc == usr_mob && t)
if(SEND_SIGNAL(computer, COMSIG_TABLET_CHANGE_ID, usr_mob, t) & COMPONENT_STOP_RINGTONE_CHANGE)
return
else
ringtone = t
return(UI_UPDATE)
if("PDA_ringer_status")
ringer_status = !ringer_status
return(UI_UPDATE)
if("PDA_sAndR")
sending_and_receiving = !sending_and_receiving
return(UI_UPDATE)
if("PDA_viewMessages")
viewing_messages = !viewing_messages
return(UI_UPDATE)
if("PDA_clearMessages")
messages = list()
return(UI_UPDATE)
if("PDA_changeSortStyle")
sort_by_job = !sort_by_job
return(UI_UPDATE)
if("PDA_sendEveryone")
if(!sending_and_receiving)
to_chat(usr, span_notice("ERROR: Device has sending disabled."))
return
var/list/targets = list()
for(var/obj/item/modular_computer/mc in GetViewableDevices())
targets += mc
if(targets.len > 0)
send_message(usr, targets, TRUE)
return(UI_UPDATE)
if("PDA_sendMessage")
if(!sending_and_receiving)
to_chat(usr, span_notice("ERROR: Device has sending disabled."))
return
var/obj/item/modular_computer/target = locate(params["ref"])
if(!target)
return // we don't want tommy sending his messages to nullspace
if(!(target.saved_identification == params["name"] && target.saved_job == params["job"]))
to_chat(usr, span_notice("ERROR: User no longer exists."))
return
var/obj/item/computer_hardware/hard_drive/drive = target.all_components[MC_HDD]
for(var/datum/computer_file/program/messenger/app in drive.stored_files)
if(!app.sending_and_receiving && !sending_virus)
to_chat(usr, span_notice("ERROR: Device has receiving disabled."))
return
if(sending_virus)
var/obj/item/computer_hardware/hard_drive/role/virus/disk = computer.all_components[MC_HDD_JOB]
if(istype(disk))
disk.send_virus(target, usr)
return(UI_UPDATE)
send_message(usr, list(target))
return(UI_UPDATE)
if("PDA_clearPhoto")
computer.saved_image = null
photo_path = null
return(UI_UPDATE)
if("PDA_toggleVirus")
sending_virus = !sending_virus
return(UI_UPDATE)
/datum/computer_file/program/messenger/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/hard_drive/role/disk = computer.all_components[MC_HDD_JOB]
data["owner"] = computer.saved_identification
data["messages"] = messages
data["ringer_status"] = ringer_status
data["sending_and_receiving"] = sending_and_receiving
data["messengers"] = ScrubMessengerList()
data["viewing_messages"] = viewing_messages
data["sortByJob"] = sort_by_job
data["isSilicon"] = is_silicon
data["photo"] = photo_path
if(disk)
data["canSpam"] = disk.CanSpam()
data["virus_attach"] = istype(disk, /obj/item/computer_hardware/hard_drive/role/virus)
data["sending_virus"] = sending_virus
return data
////////////////////////
// MESSAGE HANDLING
////////////////////////
// How I Learned To Stop Being A PDA Bloat Chump And Learn To Embrace The Lightweight
// Gets the input for a message being sent.
/datum/computer_file/program/messenger/proc/msg_input(mob/living/U = usr, rigged = FALSE)
var/t = null
if(mime_mode)
t = emoji_sanitize(tgui_input_text(U, "Enter emojis", "NT Messaging"))
else
t = tgui_input_text(U, "Enter a message", "NT Messaging")
if (!t || !sending_and_receiving)
return
if(!U.canUseTopic(computer, BE_CLOSE))
return
return sanitize(t)
/datum/computer_file/program/messenger/proc/send_message(mob/living/user, list/obj/item/modular_computer/targets, everyone = FALSE, rigged = FALSE, fake_name = null, fake_job = null)
var/message = msg_input(user, rigged)
if(!message || !targets.len)
return FALSE
if((last_text && world.time < last_text + 10) || (everyone && last_text_everyone && world.time < last_text_everyone + 2 MINUTES))
return FALSE
var/turf/position = get_turf(computer)
for(var/obj/item/jammer/jammer as anything in GLOB.active_jammers)
var/turf/jammer_turf = get_turf(jammer)
if(position?.z == jammer_turf.z && (get_dist(position, jammer_turf) <= jammer.range))
return FALSE
var/list/filter_result = CAN_BYPASS_FILTER(user) ? null : is_ic_filtered_for_pdas(message)
if (filter_result)
REPORT_CHAT_FILTER_TO_USER(user, filter_result)
return FALSE
var/list/soft_filter_result = CAN_BYPASS_FILTER(user) ? null : is_soft_ic_filtered_for_pdas(message)
if (soft_filter_result)
if(tgui_alert(usr,"Your message contains \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[soft_filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to send it?", "Soft Blocked Word", list("Yes", "No")) != "Yes")
return FALSE
message_admins("[ADMIN_LOOKUPFLW(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term in PDA messages. Message: \"[html_encode(message)]\"")
log_admin_private("[key_name(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term in PDA messages. Message: \"[message]\"")
// Send the signal
var/list/string_targets = list()
for (var/obj/item/modular_computer/comp in targets)
if (comp.saved_identification && comp.saved_job) // != src is checked by the UI
string_targets += STRINGIFY_PDA_TARGET(comp.saved_identification, comp.saved_job)
if (!string_targets.len)
return FALSE
var/datum/signal/subspace/messaging/tablet_msg/signal = new(computer, list(
"name" = fake_name || computer.saved_identification,
"job" = fake_job || computer.saved_job,
"message" = html_decode(message),
"ref" = REF(computer),
"targets" = targets,
"emojis" = allow_emojis,
"rigged" = rigged,
"photo" = photo_path,
"automated" = FALSE,
))
if(rigged) //Will skip the message server and go straight to the hub so it can't be cheesed by disabling the message server machine
signal.data["rigged_user"] = REF(user) // Used for bomb logging
signal.server_type = /obj/machinery/telecomms/hub
signal.data["reject"] = FALSE // Do not refuse the message
signal.send_to_receivers()
// If it didn't reach, note that fact
if (!signal.data["done"])
to_chat(user, span_notice("ERROR: Server isn't responding."))
//if(!silent)
//playsound(src, 'sound/machines/terminal_error.ogg', 15, TRUE)
return FALSE
if(allow_emojis)
message = emoji_parse(message)//already sent- this just shows the sent emoji as one to the sender in the to_chat
signal.data["message"] = emoji_parse(signal.data["message"])
// Log it in our logs
var/list/message_data = list()
message_data["name"] = signal.data["name"]
message_data["job"] = signal.data["job"]
message_data["contents"] = html_decode(signal.data["message"])
message_data["outgoing"] = TRUE
message_data["ref"] = signal.data["ref"]
message_data["photo"] = signal.data["photo"]
// Show it to ghosts
var/ghost_message = span_name("[message_data["name"]] </span><span class='game say'>[rigged ? "Rigged" : ""] PDA Message</span> --> [span_name("[signal.format_target()]")]: <span class='message'>[signal.data["message"]]")
for(var/mob/M in GLOB.player_list)
if(isobserver(M) && (M.client?.prefs.chat_toggles & CHAT_GHOSTPDA))
to_chat(M, "[FOLLOW_LINK(M, user)] [ghost_message]")
// Log in the talk log
user.log_talk(message, LOG_PDA, tag="[rigged ? "Rigged" : ""] PDA: [initial(message_data["name"])] to [signal.format_target()]")
if(rigged)
log_bomber(user, "sent a rigged PDA message (Name: [message_data["name"]]. Job: [message_data["job"]]) to [english_list(string_targets)] [!is_special_character(user) ? "(SENT BY NON-ANTAG)" : ""]")
to_chat(user, span_info("PDA message sent to [signal.format_target()]: [signal.data["message"]]"))
if (ringer_status)
computer.send_sound()
last_text = world.time
if (everyone)
message_data["name"] = "Everyone"
message_data["job"] = ""
last_text_everyone = world.time
messages += list(message_data)
return TRUE
/datum/computer_file/program/messenger/proc/receive_message(datum/signal/subspace/messaging/tablet_msg/signal)
var/list/message_data = list()
message_data["name"] = signal.data["name"]
message_data["job"] = signal.data["job"]
message_data["contents"] = html_decode(signal.data["message"])
message_data["outgoing"] = FALSE
message_data["ref"] = signal.data["ref"]
message_data["automated"] = signal.data["automated"]
message_data["photo"] = signal.data["photo"]
messages += list(message_data)
var/mob/living/L = null
if(computer.loc && isliving(computer.loc))
L = computer.loc
//Maybe they are a pAI!
else
L = get(computer, /mob/living/silicon)
if(L && (L.stat == CONSCIOUS || L.stat == SOFT_CRIT))
var/reply = "(<a href='byond://?src=[REF(src)];choice=[signal.data["rigged"] ? "Mess_us_up" : "Message"];skiprefresh=1;target=[signal.data["ref"]]'>Reply</a>)"
var/hrefstart
var/hrefend
if (isAI(L))
hrefstart = "<a href='?src=[REF(L)];track=[html_encode(signal.data["name"])]'>"
hrefend = "</a>"
if(signal.data["automated"])
reply = "\[Automated Message\]"
var/inbound_message = signal.format_message()
if(signal.data["emojis"] == TRUE)//so will not parse emojis as such from pdas that don't send emojis
inbound_message = emoji_parse(inbound_message)
if(ringer_status)
to_chat(L, "<span class='infoplain'>[icon2html(src)] <b>PDA message from [hrefstart][signal.data["name"]] ([signal.data["job"]])[hrefend], </b>[inbound_message] [reply]</span>")
if (ringer_status)
computer.ring(ringtone)
/datum/computer_file/program/messenger/Topic(href, href_list)
..()
if(!href_list["close"] && usr.canUseTopic(computer, BE_CLOSE, FALSE, NO_TK))
switch(href_list["choice"])
if("Message")
send_message(usr, list(locate(href_list["target"])))
if("Mess_us_up")
if(!HAS_TRAIT(src, TRAIT_PDA_CAN_EXPLODE))
var/obj/item/modular_computer/tablet/comp = computer
comp.explode(usr, from_message_menu = TRUE)
return
@@ -0,0 +1,78 @@
/datum/computer_file/program/phys_scanner
filename = "phys_scanner"
filedesc = "Physical Scanner"
category = PROGRAM_CATEGORY_MISC
extended_desc = "This program allows the tablet to scan physical objects and display a data output."
size = 8
usage_flags = PROGRAM_TABLET
available_on_ntnet = FALSE
tgui_id = "NtosPhysScanner"
program_icon = "barcode"
var/current_mode = 0
var/available_modes = 0
var/last_record = ""
/datum/computer_file/program/phys_scanner/proc/ReadModes()
var/reads = list()
if(available_modes & DISK_CHEM)
reads += "Reagent"
if(available_modes & DISK_MED)
reads += "Health"
return reads
/datum/computer_file/program/phys_scanner/proc/ReadCurrent()
if(current_mode & DISK_CHEM)
return "Reagent"
if(current_mode & DISK_MED)
return "Health"
/datum/computer_file/program/phys_scanner/tap(atom/A, mob/living/user, params)
. = ..()
switch(current_mode)
if(DISK_CHEM)
if(!isnull(A.reagents))
if(A.reagents.reagent_list.len > 0)
var/reagents_length = A.reagents.reagent_list.len
last_record = "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found."
for (var/re in A.reagents.reagent_list)
last_record += "\t [re]"
else
last_record = "No active chemical agents found in [A]."
else
last_record = "No significant chemical agents found in [A]."
if(DISK_MED)
var/mob/living/carbon/carbon = A
if(istype(carbon))
carbon.visible_message(span_notice("[user] analyzes [A]'s vitals."))
last_record = healthscan(user, carbon, 1, tochat = FALSE)
/datum/computer_file/program/phys_scanner/ui_act(action, list/params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("selectMode")
switch(params["newMode"])
if("Reagent")
current_mode = DISK_CHEM
if("Health")
current_mode = DISK_MED
return UI_UPDATE
/datum/computer_file/program/phys_scanner/ui_data(mob/user)
var/list/data = get_header_data()
data["set_mode"] = ReadCurrent()
data["last_record"] = last_record
data["available_modes"] = ReadModes()
return data
@@ -0,0 +1,74 @@
/datum/computer_file/program/records
filename = "ntrecords"
filedesc = "Records"
extended_desc = "Allows the user to view several basic records from the crew."
category = PROGRAM_CATEGORY_MISC
program_icon = "clipboard"
program_icon_state = "crew"
tgui_id = "NtosRecords"
size = 4
usage_flags = PROGRAM_TABLET | PROGRAM_LAPTOP
available_on_ntnet = FALSE
var/mode
/datum/computer_file/program/records/medical
filedesc = "Medical Records"
filename = "medrecords"
program_icon = "book-medical"
extended_desc = "Allows the user to view several basic medical records from the crew."
transfer_access = list(ACCESS_MEDICAL, ACCESS_FLAG_COMMAND)
available_on_ntnet = TRUE
mode = "medical"
/datum/computer_file/program/records/security
filedesc = "Security Records"
filename = "secrecords"
extended_desc = "Allows the user to view several basic security records from the crew."
transfer_access = list(ACCESS_SECURITY, ACCESS_FLAG_COMMAND)
available_on_ntnet = TRUE
mode = "security"
/datum/computer_file/program/records/proc/GetRecordsReadable()
var/list/all_records = list()
switch(mode)
if("security")
for(var/datum/data/record/person in GLOB.data_core.general)
var/datum/data/record/security_person = find_record("id", person.fields["id"], GLOB.data_core.security)
var/list/current_record = list()
if(security_person)
current_record["wanted"] = security_person.fields["criminal"]
current_record["id"] = person.fields["id"]
current_record["name"] = person.fields["name"]
current_record["rank"] = person.fields["rank"]
current_record["gender"] = person.fields["gender"]
current_record["age"] = person.fields["age"]
current_record["species"] = person.fields["species"]
current_record["fingerprint"] = person.fields["fingerprint"]
all_records += list(current_record)
if("medical")
for(var/datum/data/record/person in GLOB.data_core.medical)
var/list/current_record = list()
current_record["name"] = person.fields["name"]
current_record["bloodtype"] = person.fields["blood_type"]
current_record["mi_dis"] = person.fields["mi_dis"]
current_record["ma_dis"] = person.fields["ma_dis"]
current_record["notes"] = person.fields["notes"]
current_record["cnotes"] = person.fields["notes_d"]
all_records += list(current_record)
return all_records
/datum/computer_file/program/records/ui_data(mob/user)
var/list/data = get_header_data()
data["records"] = GetRecordsReadable()
data["mode"] = mode
return data
@@ -13,6 +13,8 @@
var/botcount = 0
///Access granted by the used to summon robots.
var/list/current_access = list()
///Whether or not this is the cartridge program version.
var/cart_mode = FALSE
var/list/drone_ping_types = list(
"Low",
"Medium",
@@ -27,20 +29,23 @@
var/list/botlist = list()
var/list/mulelist = list()
var/obj/item/computer_hardware/hard_drive/role/job_disk = computer ? computer.all_components[MC_HDD_JOB] : null
var/obj/item/computer_hardware/card_slot/card_slot = computer ? computer.all_components[MC_CARD] : null
var/obj/item/card/id/id_card = card_slot?.stored_card
data["have_id_slot"] = !!card_slot
if(computer)
data["has_id"] = !!id_card
data["id_owner"] = id_card ? id_card.registered_name : "No Card Inserted."
data["access_on_card"] = id_card ? id_card.access : null
var/obj/item/card/id/id_card = card_slot ? card_slot.stored_card : ""
data["id_owner"] = id_card
if(cart_mode && job_disk)
data["id_owner"] = "JOB DISK OVERRIDE"
botcount = 0
for(var/mob/living/simple_animal/bot/simple_bot as anything in GLOB.bots_list)
if(simple_bot.z != zlevel || !(simple_bot.bot_mode_flags & BOT_MODE_REMOTE_ENABLED)) //Only non-emagged bots on the same Z-level are detected!
continue
if(computer && !simple_bot.check_access(user, id_card)) // Only check Bots we can access
if(computer && !simple_bot.check_access(user) && !cart_mode) // Only check Bots we can access)
continue
if(!(simple_bot.bot_type in job_disk.bot_access) && cart_mode)
continue
var/list/newbot = list(
"name" = simple_bot.name,
@@ -19,14 +19,16 @@
. = ..()
if (!.)
return
if(!computer?.get_modular_computer_part(MC_SIGNALER)) //Giving a clue to users why the program is spitting out zeros.
var/obj/item/computer_hardware/hard_drive/role/signal/disk = computer?.get_modular_computer_part(MC_HDD_JOB)
if(!(computer?.get_modular_computer_part(MC_SIGNALER) || istype(disk))) //Giving a clue to users why the program is spitting out zeros.
to_chat(user, span_warning("\The [computer] flashes an error: \"hardware\\signal_hardware\\startup.bin -- file not found\"."))
/datum/computer_file/program/signaler/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
if(sensor?.check_functionality())
var/obj/item/computer_hardware/hard_drive/role/signal/disk = computer?.get_modular_computer_part(MC_HDD_JOB)
if(sensor?.check_functionality() || istype(disk))
data["frequency"] = signal_frequency
data["code"] = signal_code
data["minFrequency"] = MIN_FREE_FREQ
@@ -38,7 +40,8 @@
if(.)
return
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
if(!(sensor?.check_functionality()))
var/obj/item/computer_hardware/hard_drive/role/signal/disk = computer?.get_modular_computer_part(MC_HDD_JOB)
if(!(sensor?.check_functionality() || istype(disk)))
playsound(src, 'sound/machines/scanbuzz.ogg', 100, FALSE)
return
switch(action)
@@ -65,18 +68,19 @@
return
var/time = time2text(world.realtime,"hh:mm:ss")
var/turf/T = get_turf(src)
var/turf/T = get_turf(computer)
var/logging_data
if(usr)
logging_data = "[time] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(signal_frequency)]/[signal_code]"
message_admins("usr is true")
logging_data = "[time] <B>:</B> [usr.key] used [computer] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(signal_frequency)]/[signal_code]"
GLOB.lastsignalers.Add(logging_data)
var/datum/signal/signal = new(list("code" = signal_code), logging_data = logging_data)
radio_connection.post_signal(src, signal)
radio_connection.post_signal(computer, signal)
/datum/computer_file/program/signaler/proc/set_frequency(new_frequency)
SSradio.remove_object(src, signal_frequency)
SSradio.remove_object(computer, signal_frequency)
signal_frequency = new_frequency
radio_connection = SSradio.add_object(src, signal_frequency, RADIO_SIGNALER)
radio_connection = SSradio.add_object(computer, signal_frequency, RADIO_SIGNALER)
return
@@ -0,0 +1,55 @@
/datum/computer_file/program/status
filename = "statusdisplay"
filedesc = "Status Display"
program_icon = "signal"
program_icon_state = "generic"
requires_ntnet = TRUE
size = 4
extended_desc = "An app used to change the message on the station status displays."
tgui_id = "NtosStatus"
usage_flags = PROGRAM_ALL
available_on_ntnet = FALSE
var/upper_text
var/lower_text
/datum/computer_file/program/status/proc/SendSignal()
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
if(!frequency)
return
var/datum/signal/status_signal = new(list("command" = "message"))
status_signal.data["msg1"] = reject_bad_text(upper_text || "", MAX_STATUS_LINE_LENGTH)
status_signal.data["msg2"] = reject_bad_text(lower_text || "", MAX_STATUS_LINE_LENGTH)
frequency.post_signal(computer, status_signal)
/datum/computer_file/program/status/proc/SetText(position, text)
switch(position)
if("upper")
upper_text = text
if("lower")
lower_text = text
/datum/computer_file/program/status/ui_act(action, list/params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("stat_send")
SendSignal()
if("stat_update")
SetText(params["position"], params["text"]) // i hate the player i hate the player
/datum/computer_file/program/status/ui_data(mob/user)
var/list/data = get_header_data()
data["upper"] = upper_text
data["lower"] = lower_text
return data