GLOBAL_LIST_EMPTY(allfaxes) GLOBAL_LIST_INIT(admin_departments, list("Central Command")) GLOBAL_LIST_INIT(hidden_admin_departments, list("Syndicate")) GLOBAL_LIST_EMPTY(alldepartments) GLOBAL_LIST_EMPTY(hidden_departments) GLOBAL_LIST_EMPTY(fax_blacklist) /obj/machinery/photocopier/faxmachine name = "fax machine" desc = "Because just talking to your coworkers is too efficient." icon = 'icons/obj/library.dmi' icon_state = "fax" insert_anim = "faxsend" var/receive_anim = "faxsend" pass_flags = PASSTABLE var/fax_network = "Local Fax Network" /// If true, prevents fax machine from sending messages to NT machines var/syndie_restricted = FALSE /// Can we send messages off-station? var/long_range_enabled = FALSE req_one_access = list(ACCESS_INTERNAL_AFFAIRS, ACCESS_HEADS, ACCESS_ARMORY) idle_power_consumption = 30 active_power_consumption = 200 /// ID card inserted into the machine, used to log in with var/obj/item/card/id/scan = null /// Whether the machine is "logged in" or not var/authenticated = FALSE /// Next world.time at which this fax machine can send a message to CC/syndicate var/sendcooldown = 0 /// After sending a message to CC/syndicate, cannot send another to them for this many deciseconds var/cooldown_time = 1800 /// Our department, determines whether this machine gets faxes sent to a department var/department = "Unknown" /// Target department to send outgoing faxes to var/destination /obj/machinery/photocopier/faxmachine/Initialize(mapload) . = ..() GLOB.allfaxes += src update_network() /obj/machinery/photocopier/faxmachine/Destroy() GLOB.allfaxes -= src return ..() /obj/machinery/photocopier/faxmachine/examine(mob/user) . = ..() . += "Alt-Click [src] to remove its currently stored ID." /obj/machinery/photocopier/faxmachine/proc/update_network() if(department != "Unknown") if(!(("[department]" in GLOB.alldepartments) || ("[department]" in GLOB.hidden_departments) || ("[department]" in GLOB.admin_departments) || ("[department]" in GLOB.hidden_admin_departments))) GLOB.alldepartments |= department /obj/machinery/photocopier/faxmachine/longrange name = "long range fax machine" desc = "A fax machine of the ancient days, now using modern entanglement networks, all the better to snitch on your coworkers." fax_network = "Central Command Quantum Entanglement Network" long_range_enabled = TRUE /obj/machinery/photocopier/faxmachine/longrange/Initialize(mapload) . = ..() add_overlay("longfax") /obj/machinery/photocopier/faxmachine/longrange/syndie name = "syndicate long range fax machine" desc = "For requesting supplies from your benefactors, not that they'll send you any." emagged = TRUE syndie_restricted = TRUE req_one_access = list(ACCESS_SYNDICATE) //No point setting fax network, being emagged overrides that anyway. /obj/machinery/photocopier/faxmachine/longrange/syndie/Initialize(mapload) . = ..() add_overlay("syndiefax") /obj/machinery/photocopier/faxmachine/longrange/syndie/update_network() if(department != "Unknown") GLOB.hidden_departments |= department /obj/machinery/photocopier/faxmachine/attack_hand(mob/user) ui_interact(user) /obj/machinery/photocopier/faxmachine/attack_ghost(mob/user) ui_interact(user) /obj/machinery/photocopier/faxmachine/attackby(obj/item/item, mob/user, params) if(istype(item,/obj/item/card/id) && !scan) scan(item) else if(istype(item, /obj/item/paper) || istype(item, /obj/item/photo) || istype(item, /obj/item/paper_bundle)) ..() SStgui.update_uis(src) else if(istype(item, /obj/item/folder)) to_chat(user, "The [src] can't accept folders!") return //early return so the parent proc doesn't suck up and items that a photocopier would take else return ..() /obj/machinery/photocopier/faxmachine/MouseDrop_T() return //you should not be able to fax your ass without first copying it at an actual photocopier /obj/machinery/photocopier/faxmachine/emag_act(mob/user) if(!emagged) emagged = TRUE req_one_access = list() to_chat(user, "The transmitters realign to an unknown source!") return TRUE else to_chat(user, "You swipe the card through [src], but nothing happens.") /obj/machinery/photocopier/faxmachine/proc/is_authenticated(mob/user) if(authenticated) return TRUE else if(user.can_admin_interact()) return TRUE return FALSE /obj/machinery/photocopier/faxmachine/ui_state(mob/user) return GLOB.default_state /obj/machinery/photocopier/faxmachine/ui_interact(mob/user, datum/tgui/ui = null) ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "FaxMachine", name) ui.open() /obj/machinery/photocopier/faxmachine/ui_data(mob/user) var/list/data = list() data["authenticated"] = is_authenticated(user) data["realauth"] = authenticated data["scan_name"] = scan ? scan.name : FALSE data["nologin"] = !data["scan_name"] && !data["realauth"] if(!data["authenticated"]) data["network"] = "Disconnected" else if(!emagged) data["network"] = fax_network else data["network"] = "ERR*?*%!*" data["paper"] = copyitem ? copyitem.name : FALSE data["paperinserted"] = copyitem ? TRUE : FALSE data["destination"] = destination ? destination : FALSE data["sendError"] = FALSE if(stat & (BROKEN|NOPOWER)) data["sendError"] = "No Power" else if(!data["authenticated"]) data["sendError"] = "Not Logged In" else if(!data["paper"]) data["sendError"] = "Nothing Inserted" else if(!data["destination"]) data["sendError"] = "Destination Not Set" else if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments)) var/cooldown_seconds = cooldown_seconds() if(cooldown_seconds) data["sendError"] = "Re-aligning in [cooldown_seconds] seconds..." return data /obj/machinery/photocopier/faxmachine/ui_act(action, params) if(isnull(..())) // isnull(..()) here because the parent photocopier proc returns null as opposed to TRUE if the ui should not be interacted with. return var/is_authenticated = is_authenticated(usr) . = TRUE switch(action) if("scan") // insert/remove your ID card scan() if("auth") // log in/out if(!is_authenticated && scan) if(scan.registered_name in GLOB.fax_blacklist) to_chat(usr, "Login rejected: individual is blacklisted from fax network.") playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) . = FALSE else if(check_access(scan)) authenticated = TRUE else // ID doesn't have access to this machine to_chat(usr, "Login rejected: ID card does not have required access.") playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) . = FALSE else if(is_authenticated) authenticated = FALSE if("paper") // insert/eject paper/paperbundle/photo if(copyitem) copyitem.forceMove(get_turf(src)) if(ishuman(usr)) if(!usr.get_active_hand() && Adjacent(usr)) usr.put_in_hands(copyitem) to_chat(usr, "You eject [copyitem] from [src].") copyitem = null else var/obj/item/I = usr.get_active_hand() if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle)) usr.drop_item() copyitem = I I.forceMove(src) to_chat(usr, "You insert [I] into [src].") flick(insert_anim, src) else to_chat(usr, "[src] only accepts paper, paper bundles, and photos.") . = FALSE if("rename") // rename the item that is currently in the fax machine if(copyitem) var/n_name = tgui_input_text(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) if(!n_name) return if(copyitem && copyitem.loc == src && usr.stat == CONSCIOUS) if(istype(copyitem, /obj/item/paper)) copyitem.name = "[(n_name ? "[n_name]" : initial(copyitem.name))]" copyitem.desc = "This is a paper titled '" + copyitem.name + "'." else if(istype(copyitem, /obj/item/photo)) copyitem.name = "[(n_name ? "[n_name]" : "photo")]" else if(istype(copyitem, /obj/item/paper_bundle)) copyitem.name = "[(n_name ? "[n_name]" : "paper")]" else . = FALSE else . = FALSE else . = FALSE if("dept") // choose which department receives the fax if(is_authenticated) var/lastdestination = destination var/list/combineddepartments = GLOB.alldepartments.Copy() if(long_range_enabled) combineddepartments += GLOB.admin_departments.Copy() if(emagged) combineddepartments += GLOB.hidden_admin_departments.Copy() combineddepartments += GLOB.hidden_departments.Copy() if(syndie_restricted) combineddepartments = GLOB.hidden_admin_departments.Copy() combineddepartments += GLOB.hidden_departments.Copy() for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) if(F.emagged)//we can contact emagged faxes on the station combineddepartments |= F.department destination = tgui_input_list(usr, "To which department?", "Choose a department", combineddepartments) if(!destination) destination = lastdestination if("send") // actually send the fax if(!copyitem || !is_authenticated || !destination) return if(stat & (BROKEN|NOPOWER)) return if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments)) var/cooldown_seconds = cooldown_seconds() if(cooldown_seconds > 0) playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) to_chat(usr, "[src] is not ready for another [cooldown_seconds] seconds.") return send_admin_fax(usr, destination) sendcooldown = world.time + cooldown_time else sendfax(destination, usr) if(.) add_fingerprint(usr) /obj/machinery/photocopier/faxmachine/proc/scan(obj/item/card/id/card = null) if(scan) // Card is in machine if(ishuman(usr)) scan.forceMove(get_turf(src)) if(!usr.get_active_hand() && Adjacent(usr)) usr.put_in_hands(scan) scan = null else scan.forceMove(get_turf(src)) scan = null else if(Adjacent(usr)) if(!card) var/obj/item/I = usr.get_active_hand() if(istype(I, /obj/item/card/id)) usr.drop_item() I.forceMove(src) scan = I else if(istype(card)) usr.drop_item() card.forceMove(src) scan = card SStgui.update_uis(src) /obj/machinery/photocopier/faxmachine/AltClick(mob/user) if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user)) return if(scan) to_chat(user, "You remove [scan] from [src].") if(!user.get_active_hand()) user.put_in_hands(scan) else if(!user.put_in_inactive_hand(scan)) scan.forceMove(get_turf(src)) scan = null else to_chat(user, "There is nothing to remove from [src].") /obj/machinery/photocopier/faxmachine/proc/sendfax(destination, mob/sender) use_power(active_power_consumption) var/success = 0 for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) if(F.department == destination) success = F.receivefax(copyitem) if(success) var/datum/fax/F = new /datum/fax() F.name = copyitem.name F.from_department = department F.to_department = destination F.origin = src F.message = copyitem F.sent_by = sender F.sent_at = world.time visible_message("[src] beeps, \"Message transmitted successfully.\"") else visible_message("[src] beeps, \"Error transmitting message.\"") /obj/machinery/photocopier/faxmachine/proc/receivefax(obj/item/incoming) if(stat & (BROKEN|NOPOWER)) return FALSE if(department == "Unknown") return FALSE //You can't send faxes to "Unknown" flick(receive_anim, src) playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) addtimer(CALLBACK(src, PROC_REF(print_fax), incoming), 2 SECONDS) return TRUE /obj/machinery/photocopier/faxmachine/proc/print_fax(obj/item/incoming) if(istype(incoming, /obj/item/paper)) papercopy(incoming) else if(istype(incoming, /obj/item/photo)) photocopy(incoming) else if(istype(incoming, /obj/item/paper_bundle)) bundlecopy(incoming) else return use_power(active_power_consumption) /obj/machinery/photocopier/faxmachine/proc/log_fax(mob/sender, destination) // Logging for sending photos if(istype(copyitem, /obj/item/photo)) log_admin("[key_name(sender)] has sent a photo by fax to [destination]") return // Logging for single paper message if(istype(copyitem, /obj/item/paper)) var/obj/item/paper/fax_message = copyitem log_admin("[key_name(sender)] has sent a message by fax to [destination] reading [fax_message.info]") return // Logging for paper bundle messages if(istype(copyitem, /obj/item/paper_bundle)) var/obj/item/paper_bundle/paper_bundle = copyitem // Incremented by one for each paper in the bundle var/page_count = 1 // Loop through the contents of the paper bundle and grab the message from each page for(var/obj/item/paper/page in paper_bundle.contents) log_admin("[key_name(sender)] has sent a bundled message by fax to [destination] - Page [page_count]: [page.info]") page_count ++ return /obj/machinery/photocopier/faxmachine/proc/send_admin_fax(mob/sender, destination) use_power(active_power_consumption) if(!(istype(copyitem, /obj/item/paper) || istype(copyitem, /obj/item/paper_bundle) || istype(copyitem, /obj/item/photo))) visible_message("[src] beeps, \"Error transmitting message.\"") return var/datum/fax/admin/A = new /datum/fax/admin() A.name = copyitem.name A.from_department = department A.to_department = destination A.origin = src A.message = copyitem A.sent_by = sender A.sent_at = world.time //message badmins that a fax has arrived switch(destination) if("Central Command") message_admins(sender, "CENTCOM FAX", destination, copyitem, "#006100") if("Syndicate") message_admins(sender, "SYNDICATE FAX", destination, copyitem, "#DC143C") for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) if(F.department == destination) F.receivefax(copyitem) visible_message("[src] beeps, \"Message transmitted successfully.\"") log_fax(sender, destination) /obj/machinery/photocopier/faxmachine/proc/cooldown_seconds() if(sendcooldown < world.time) return 0 return round((sendcooldown - world.time) / 10) /obj/machinery/photocopier/faxmachine/proc/message_admins(mob/sender, faxname, faxtype, obj/item/sent, font_colour="#9A04D1") var/msg = "[faxname]: [key_name_admin(sender)] | REPLY: (RADIO) (FAX) ([ADMIN_SM(sender,"SM")]) | REJECT: (TEMPLATE) ([ADMIN_BSA(sender,"BSA")]) (EVILFAX) : Receiving '[sent.name]' via secure connection... view message" var/fax_sound = sound('sound/effects/adminhelp.ogg') for(var/client/C in GLOB.admins) if(check_rights(R_EVENT, 0, C.mob)) to_chat(C, msg) if(C.prefs.sound & SOUND_ADMINHELP) SEND_SOUND(C, fax_sound) /obj/machinery/photocopier/faxmachine/proc/become_mimic() if(scan) scan.forceMove(get_turf(src)) var/mob/living/simple_animal/hostile/mimic/copy/M = new(loc, src, null, 1) // it will delete src on creation and override any machine checks M.name = "angry fax machine"