diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 8266d470ff9..bebb0ce4c4c 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -696,6 +696,8 @@ proc/dd_sortedObjectList(list/incoming) /// Returns whether a numerical index is within a given list's bounds. Faster than isnull(LAZYACCESS(L, I)). #define ISINDEXSAFE(L, I) (I >= 1 && I <= length(L)) +///If the lazy list is currently initialized find item I in list L +#define LAZYIN(L, I) (L && (I in L)) //same, but returns nothing and acts on list in place /proc/shuffle_inplace(list/L) diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index 49bef9c90cd..ab8358a5db1 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -43,11 +43,6 @@ GLOBAL_VAR_INIT(fileaccess_timer, 0) GLOBAL_VAR_INIT(gametime_offset, 432000) // 12:00 in seconds -//printers shutdown if too much shit printed -GLOBAL_VAR_INIT(copier_items_printed, 0) -GLOBAL_VAR_INIT(copier_max_items, 300) -GLOBAL_VAR_INIT(copier_items_printed_logged, FALSE) - GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) // Station datacore, manifest, etc GLOBAL_LIST_EMPTY(ability_verbs) // Create-level abilities diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index b36df828017..6298a738f34 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -93,6 +93,9 @@ GLOBAL_LIST_EMPTY(fax_blacklist) 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 = 1 @@ -314,7 +317,7 @@ GLOBAL_LIST_EMPTY(fax_blacklist) sleep(20) if(istype(incoming, /obj/item/paper)) - copy(incoming) + papercopy(incoming) else if(istype(incoming, /obj/item/photo)) photocopy(incoming) else if(istype(incoming, /obj/item/paper_bundle)) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index e3355adfe76..c1b8a626977 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -1,10 +1,12 @@ -#define EMAG_DELAY 50 +#define PHOTOCOPIER_DELAY 15 +///Global limit on copied papers and photos, bundles are counted as a sum of their parts +#define MAX_COPIES_PRINTABLE 300 /obj/machinery/photocopier name = "photocopier" icon = 'icons/obj/library.dmi' icon_state = "bigscanner" - var/insert_anim = "bigscanner1" + anchored = 1 density = 1 use_power = IDLE_POWER_USE @@ -13,13 +15,31 @@ power_channel = EQUIP max_integrity = 300 integrity_failure = 100 - var/emag_cooldown atom_say_verb = "bleeps" - var/obj/item/copyitem = null //what's in the copier! - var/copies = 1 //how many copies to print! - var/toner = 60 //how much toner is left! woooooo~ - var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier! - var/mob/living/ass = null + + var/insert_anim = "bigscanner1" + ///Is the photocopier performing an action currently? + var/copying = FALSE + + ///Current obj stored in the copier to be copied + var/obj/item/copyitem = null + ///Current folder obj stored in the copier to copy into + var/obj/item/folder = null + ///Mob that is currently on the photocopier + var/mob/living/copymob = null + + var/copies = 1 + var/toner = 60 + ///Max number of copies that can be made at one time + var/maxcopies = 10 + var/max_saved_documents = 5 + + ///Lazy init list, Objs currently saved inside the photocopier for printing later + var/list/saved_documents + + ///Total copies printed from copymachines globally + var/static/total_copies = 0 + var/static/max_copies_reached = FALSE /obj/machinery/photocopier/attack_ai(mob/user) return attack_hand(user) @@ -28,167 +48,31 @@ return attack_hand(user) /obj/machinery/photocopier/attack_hand(mob/user) - user.set_machine(src) - - var/dat = "Photocopier

" - if(copyitem || (ass && (ass.loc == src.loc))) - dat += "Remove Item
" - if(toner) - dat += "Copy
" - dat += "Printing: [copies] copies." - dat += "- " - dat += "+

" - else if(toner) - dat += "Please insert something to copy.

" - if(istype(user,/mob/living/silicon)) - dat += "Print photo from database

" - dat += "Current toner level: [toner]" - if(!toner) - dat +="
Please insert a new toner cartridge!" - var/datum/browser/popup = new(user, "copier", name, 400, 400) - popup.set_content(dat) - popup.open(0) - onclose(user, "copier") - return - -/obj/machinery/photocopier/Topic(href, href_list) if(..()) - return 1 + return TRUE + ui_interact(user) - if(href_list["copy"]) - if(stat & (BROKEN|NOPOWER)) - return - - if(emag_cooldown > world.time) - to_chat(usr, "[src] is busy, try again in a few seconds.") - return - - playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) - for(var/i = 0, i < copies, i++) - if(toner <= 0) - break - - if(GLOB.copier_items_printed >= GLOB.copier_max_items) //global vars defined in misc.dm - if(prob(10)) - visible_message("The printer screen reads \"PC LOAD LETTER\".") - else - visible_message("The printer screen reads \"PHOTOCOPIER NETWORK OFFLINE, PLEASE CONTACT SYSTEM ADMINISTRATOR\".") - if(!GLOB.copier_items_printed_logged) - message_admins("Photocopier cap of [GLOB.copier_max_items] papers reached, all photocopiers are now disabled. This may be the cause of any lag.") - GLOB.copier_items_printed_logged = TRUE - break - - if(istype(copyitem, /obj/item/paper)) - copy(copyitem) - sleep(15) - else if(istype(copyitem, /obj/item/photo)) - photocopy(copyitem) - sleep(15) - else if(istype(copyitem, /obj/item/paper_bundle)) - var/obj/item/paper_bundle/C = copyitem - if(toner < (C.amount + 1)) - visible_message("A yellow light on [src] flashes, indicating there's not enough toner for the operation.") // It is better to prevent partial bundle than to produce broken paper bundle - return - var/obj/item/paper_bundle/B = bundlecopy(copyitem) - if(!B) - return - sleep(15*B.amount) - else if(ass && ass.loc == loc) - copyass() - sleep(15) - else - to_chat(usr, "\The [copyitem] can't be copied by \the [src].") - break - GLOB.copier_items_printed++ - use_power(active_power_usage) - updateUsrDialog() - else if(href_list["remove"]) - if(copyitem) - copyitem.forceMove(get_turf(src)) - if(ishuman(usr)) - if(!usr.get_active_hand()) - usr.put_in_hands(copyitem) - to_chat(usr, "You take \the [copyitem] out of \the [src].") - copyitem = null - updateUsrDialog() - else if(check_ass()) - to_chat(ass, "You feel a slight pressure on your ass.") - atom_say("Attention: Unable to remove large object!") - updateUsrDialog() - else if(href_list["min"]) - if(copies > 1) - copies-- - updateUsrDialog() - else if(href_list["add"]) - if(copies < maxcopies) - copies++ - updateUsrDialog() - else if(href_list["aipic"]) - if(!istype(usr,/mob/living/silicon)) return - if(stat & (BROKEN|NOPOWER)) return - - if(toner >= 5) - var/mob/living/silicon/tempAI = usr - var/obj/item/camera/siliconcam/camera = tempAI.aiCamera - - if(!camera) - return - var/datum/picture/selection = camera.selectpicture() - if(!selection) - return - - playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) - var/obj/item/photo/p = new /obj/item/photo (src.loc) - p.construct(selection) - if(p.desc == "") - p.desc += "Copied by [tempAI.name]" - else - p.desc += " - Copied by [tempAI.name]" - toner -= 5 - sleep(15) - updateUsrDialog() - -/obj/machinery/photocopier/attackby(obj/item/O as obj, mob/user as mob, params) - if(istype(O, /obj/item/paper) || istype(O, /obj/item/photo) || istype(O, /obj/item/paper_bundle)) - if(!copyitem) - user.drop_item() - copyitem = O - O.forceMove(src) - to_chat(user, "You insert \the [O] into \the [src].") - flick(insert_anim, src) - updateUsrDialog() - else - to_chat(user, "There is already something in \the [src].") - else if(istype(O, /obj/item/toner)) - if(toner <= 10) //allow replacing when low toner is affecting the print darkness - user.drop_item() - to_chat(user, "You insert the toner cartridge into \the [src].") - var/obj/item/toner/T = O - toner += T.toner_amount - qdel(O) - updateUsrDialog() - else - to_chat(user, "This cartridge is not yet ready for replacement! Use up the rest of the toner.") - else if(istype(O, /obj/item/grab)) //For ass-copying. - var/obj/item/grab/G = O - if(ismob(G.affecting) && G.affecting != ass) - var/mob/GM = G.affecting - visible_message("[usr] drags [GM.name] onto the photocopier!") - GM.forceMove(get_turf(src)) - ass = GM - if(copyitem) - copyitem.forceMove(get_turf(src)) - copyitem = null - updateUsrDialog() - else - return ..() - -/obj/machinery/photocopier/wrench_act(mob/user, obj/item/I) - . = TRUE - default_unfasten_wrench(user, I) - -/obj/machinery/photocopier/proc/copy(obj/item/paper/copy) +/** + * Public proc for copying paper objs + * + * Takes a paper object and makes a copy of it. This proc specifically does not change toner which allows more versatile use for child objects + * returns null if paper failed to be copied and returns the new copied paper obj if succesful + * Arguments: + * * obj/item/paper/copy - The paper obj to be copied + * * scanning - If true, the photo is stored inside the photocopier and we do not check for toner + * * bundled - If true the photo is stored inside the photocopier, used by bundlecopy() to construct paper bundles + */ +/obj/machinery/photocopier/proc/papercopy(obj/item/paper/copy, scanning = FALSE, bundled = FALSE) + if(!scanning) + if(toner < 1) + visible_message("A yellow light on [src] flashes, indicating there's not enough toner to finish the operation.") + return null + total_copies++ var/obj/item/paper/c = new /obj/item/paper (loc) + if(scanning || bundled) + c.forceMove(src) + else if(folder) + c.forceMove(folder) c.header = copy.header c.info = copy.info c.footer = copy.footer @@ -213,61 +97,77 @@ img.pixel_y = copy.offset_y[j] c.overlays += img c.updateinfolinks() - toner-- - if(toner == 0) - visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") return c +/** + * Public proc for copying photo objs + * + * Takes a photo object and makes a copy of it. This proc specifically does not change toner which allows more versatile use for child objects + * returns null if photo failed to be copied and returns the new copied photo object if succesful + * Arguments: + * * obj/item/photo/photocopy - The photo obj to be copied + * * scanning - If true, the photo is stored inside the photocopier and we do not check for toner + * * bundled - If true the photo is stored inside the photocopier, used by bundlecopy() to construct paper bundles + */ +/obj/machinery/photocopier/proc/photocopy(obj/item/photo/photocopy, scanning = FALSE, bundled = FALSE) + if(!scanning) //If we're just storing this as a file inside the copier then we don't expend toner + if(toner < 5) + visible_message("A yellow light on [src] flashes, indicating there's not enough toner to finish the operation.") + return null + total_copies++ -/obj/machinery/photocopier/proc/photocopy(obj/item/photo/photocopy) var/obj/item/photo/p = new /obj/item/photo (loc) + if(scanning || bundled) + p.forceMove(src) + else if(folder) + p.forceMove(folder) p.name = photocopy.name p.icon = photocopy.icon p.tiny = photocopy.tiny p.img = photocopy.img p.desc = photocopy.desc - p.pixel_x = photocopy.pixel_x - p.pixel_y = photocopy.pixel_y + p.pixel_x = rand(-10, 10) + p.pixel_y = rand(-10, 10) if(photocopy.scribble) p.scribble = photocopy.scribble - toner -= 5 - if(toner < 0) - toner = 0 - visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") return p -/obj/machinery/photocopier/proc/copyass() +/obj/machinery/photocopier/proc/copyass(scanning = FALSE) + if(!scanning) //If we're just storing this as a file inside the copier then we don't expend toner + if(toner < 5) + visible_message("A yellow light on [src] flashes, indicating there's not enough toner to finish the operation.") + return null + total_copies++ + var/icon/temp_img - if(!check_ass()) //You have to be sitting on the copier and either be a xeno or a human without clothes on. - return - atom_say("Attention: Posterior Placed on Printing Plaque!") + if(emagged) - if(ishuman(ass)) - var/mob/living/carbon/human/H = ass - to_chat(H, "Something smells toasty...") + if(ishuman(copymob)) + var/mob/living/carbon/human/H = copymob var/obj/item/organ/external/G = H.get_organ("groin") G.receive_damage(0, 30) - spawn(20) - H.emote("scream") - emag_cooldown = world.time + EMAG_DELAY + H.emote("scream") else - to_chat(ass, "Something smells toasty...") - ass.apply_damage(30, BURN) - emag_cooldown = world.time + EMAG_DELAY - if(ishuman(ass)) //Suit checks are in check_ass - var/mob/living/carbon/human/H = ass + copymob.apply_damage(30, BURN) + to_chat(copymob, "Something smells toasty...") + if(ishuman(copymob)) //Suit checks are in check_mob + var/mob/living/carbon/human/H = copymob temp_img = icon('icons/obj/butts.dmi', H.dna.species.butt_sprite) - else if(istype(ass,/mob/living/silicon/robot/drone)) + else if(istype(copymob,/mob/living/silicon/robot/drone)) temp_img = icon('icons/obj/butts.dmi', "drone") - else if(istype(ass,/mob/living/simple_animal/diona)) + else if(istype(copymob,/mob/living/simple_animal/diona)) temp_img = icon('icons/obj/butts.dmi', "nymph") - else if(isalien(ass) || istype(ass,/mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro. + else if(isalien(copymob) || istype(copymob,/mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro. temp_img = icon('icons/obj/butts.dmi', "xeno") else return var/obj/item/photo/p = new /obj/item/photo (loc) - p.desc = "You see [ass]'s ass on the photo." + if(scanning) + p.forceMove(src) + else if(folder) + p.forceMove(folder) + p.desc = "You see [copymob]'s ass on the photo." p.pixel_x = rand(-10, 10) p.pixel_y = rand(-10, 10) p.img = temp_img @@ -276,39 +176,313 @@ small_img.Scale(8, 8) ic.Blend(small_img,ICON_OVERLAY, 10, 13) p.icon = ic - toner -= 5 - if(toner < 0) - toner = 0 - visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") return p -//If need_toner is 0, the copies will still be lightened when low on toner, however it will not be prevented from printing. TODO: Implement print queues for fax machines and get rid of need_toner -/obj/machinery/photocopier/proc/bundlecopy(obj/item/paper_bundle/bundle, need_toner=1) +/** + * A public proc for copying bundles of paper + * + * It iterates through each object in the bundle and calls papercopy() and photocopy() and stores the produce photo/paper in the bundle + * Arguments: + * * bundle - The paper bundle object being copied + * * scanning - If true, the paper bundle is stored inside the photocopier + * * use_toner - If true, this operation uses toner, this is not done in copy() because partial bundles would be impossible otherwise + */ +/obj/machinery/photocopier/proc/bundlecopy(obj/item/paper_bundle/bundle, scanning = FALSE, use_toner = FALSE) var/obj/item/paper_bundle/P = new /obj/item/paper_bundle (src, default_papers = FALSE) + P.forceMove(src) //Bundle is initially inside copier to give copier time to build the bundle before the player can pick it up for(var/obj/item/W in bundle) - if(toner <= 0 && need_toner) - toner = 0 - visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") - break - if(istype(W, /obj/item/paper)) - W = copy(W) + W = papercopy(W, bundled = TRUE) + if(use_toner && W) + toner-- //In order to allow partial bundles we have to handle toner +- inside the proc else if(istype(W, /obj/item/photo)) - W = photocopy(W) + W = photocopy(W, bundled = TRUE) + if(use_toner && W) + toner -= 5 + if (!W) + break W.forceMove(P) P.amount++ - if(!P.amount) + P.amount-- //amount variable should be the number of pages in addition to the first (#pages - 1) this avoids runtimes from index errors + if(!P.amount) //if we did not have enough toner to complete the second page, delete the bundle qdel(P) - return null - P.amount-- - P.forceMove(get_turf(src)) + return FALSE + if(!scanning) + total_copies++ + if(folder) //Since bundle is still inside the copier, we need to finally move it out + P.forceMove(folder) + else + P.forceMove(loc) + P.update_icon() + P.icon_state = "paper_words" P.name = bundle.name P.pixel_y = rand(-8, 8) P.pixel_x = rand(-9, 9) return P +/obj/machinery/photocopier/proc/remove_document() + if(copying) + to_chat(usr, "[src] is busy, try again in a few seconds.") + return + if(copyitem) + copyitem.forceMove(get_turf(src)) + if(ishuman(usr)) + usr.put_in_hands(copyitem) + to_chat(usr, "You take \the [copyitem] out of \the [src].") + copyitem = null + + else if(check_mob()) + to_chat(copymob, "You feel a slight pressure on your ass.") + atom_say("Attention: Unable to remove large object!") + +/obj/machinery/photocopier/proc/remove_folder() + if(copying) + to_chat(usr, "[src] is busy, try again in a few seconds.") + return + if(folder) + folder.forceMove(get_turf(src)) + if(ishuman(usr)) + usr.put_in_hands(folder) + to_chat(usr, "You take \the [folder] out of \the [src].") + folder = null + +/** + * An internal proc for checking if a photocopier is able to copy an object + * + * It performs early checks/returns to see if the copier has any toner, if the copier is powered/working, + * if the copier is currently perfoming an action, or if we've hit the global copy limit. Used to inform + * the player in-game if they're using the photocopier incorrectly (no toner, no item inside, etc) + * Arguments: + * * scancopy - If TRUE, cancopy does not check for an item on/inside the copier to copy, used for copying stored files + */ +/obj/machinery/photocopier/proc/cancopy(scancopy = FALSE) //are we able to make a copy of a doc? + if(stat & (BROKEN|NOPOWER)) + return + if(copying) //are we in the process of copying something already? + to_chat(usr, "[src] is busy, try again in a few seconds.") + return + if(!scancopy && toner <= 0) //if we're not scanning lets check early that we actually have toner + visible_message("A yellow light on [src] flashes, indicating there's not enough toner for the operation.") + return + if(max_copies_reached) + visible_message("The printer screen reads \"MAX COPIES REACHED, PHOTOCOPIER NETWORK OFFLINE: PLEASE CONTACT SYSTEM ADMINISTRATOR\".") + return + if(total_copies >= MAX_COPIES_PRINTABLE) + visible_message("The printer screen reads \"MAX COPIES REACHED, PHOTOCOPIER NETWORK OFFLINE: PLEASE CONTACT SYSTEM ADMINISTRATOR\".") + message_admins("Photocopier cap of [MAX_COPIES_PRINTABLE] paper copies reached, all photocopiers are now disabled.") + max_copies_reached = TRUE + if(!check_mob() && (!copyitem && !scancopy)) //is there anything in or ontop of the machine? If not, is this a scanned file? + visible_message("A red light on [src] flashes, indicating there's nothing in [src] to copy.") + return + return TRUE + +/** + * Public proc for copying items + * + * Determines what item needs to be copied whether it's a mob's ass, paper, bundle, or photo and then calls the respective + * proc for it. Most toner var changing happens here so that the faxmachine child obj does not need to worry about toner + * Arguments: + * * obj/item/C - The item stored inside the photocopier to be copied (obj/paper, obj/photo, obj/paper_bundle) + * * scancopy - Indicates that obj/item/C is a stored file, we need to pass this on to cancopy() so it passes the check + */ +/obj/machinery/photocopier/proc/copy(obj/item/C, scancopy = FALSE) + if(!cancopy(scancopy)) + return + copying = TRUE + playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) + if(istype(C, /obj/item/paper)) + for(var/i in copies to 1 step -1) + if(!papercopy(C)) + break + toner -= 1 + use_power(active_power_usage) + sleep(PHOTOCOPIER_DELAY) + else if(istype(C, /obj/item/photo)) + for(var/i in copies to 1 step -1) + if(!photocopy(C)) + break + toner -= 5 + use_power(active_power_usage) + sleep(PHOTOCOPIER_DELAY) + else if(istype(C, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = C + for(var/i in copies to 1 step -1) + if(!bundlecopy(C, use_toner = TRUE)) + break + use_power(active_power_usage) + sleep(PHOTOCOPIER_DELAY * (B.amount + 1)) + else if(check_mob()) //Once we've scanned the copy_mob's ass we do not need to again + for(var/i in copies to 1 step -1) + if(!copyass()) + break + toner -= 5 + else + to_chat(usr, "\The [copyitem] can't be copied by \the [src], ejecting.") + copyitem.forceMove(loc) //fuckery detected! get off my photocopier... shitbird! + + copying = FALSE + +/obj/machinery/photocopier/proc/scan_document() //scan a document into a file + if(!cancopy()) + return + if(length(saved_documents) >= max_saved_documents) + to_chat(usr, "\The [copyitem] can't be scanned because the max file limit has been reached. Please delete a file to make room.") + return + copying = TRUE + var/obj/item/O + //Instead of calling copy() we jump ahead and use the procs that do the heavy lifting to avoid using toner since we're only scanning + if(istype(copyitem, /obj/item/paper)) + O = papercopy(copyitem, scanning = TRUE) + else if(istype(copyitem, /obj/item/photo)) + O = photocopy(copyitem, scanning = TRUE) + else if(istype(copyitem, /obj/item/paper_bundle)) + O = bundlecopy(copyitem, scanning = TRUE, use_toner = FALSE) + else if(copymob && copymob.loc == loc) + O = copyass(scanning = TRUE) + else + to_chat(usr, "\The [copyitem] can't be scanned by \the [src].") + copying = FALSE + return + use_power(active_power_usage) + sleep(PHOTOCOPIER_DELAY) + LAZYADD(saved_documents, O) + copying = FALSE + playsound(loc, 'sound/machines/ping.ogg', 50, 0) + atom_say("Document succesfully scanned!") + +/obj/machinery/photocopier/proc/delete_file(uid) + var/document = locateUID(uid) + if(LAZYIN(saved_documents, document)) //double checking that the list exists b4 we find document + LAZYREMOVE(saved_documents, document) + qdel(document) + +/obj/machinery/photocopier/proc/file_copy(uid) + var/document = locateUID(uid) + if(LAZYIN(saved_documents, document)) + copy(document, scancopy = TRUE) + + +/obj/machinery/photocopier/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "Photocopier", name, 402, 368, master_ui, state) + ui.open() + +/obj/machinery/photocopier/ui_data(mob/user) + var/list/data = list() + data["copynumber"] = copies + data["toner"] = toner + data["copyitem"] = (copyitem ? copyitem.name : null) + data["folder"] = (folder ? folder.name : null) + data["mob"] = (copymob ? copymob.name : null) + data["files"] = list() + if(LAZYLEN(saved_documents)) + for(var/obj/item/O in saved_documents) + var/list/document_data = list( + name = O.name, + uid = O.UID() + ) + data["files"] += list(document_data) + return data + +/obj/machinery/photocopier/ui_act(action, list/params) + if(..()) + return + add_fingerprint(usr) + switch(action) + if("copy") + copy(copyitem) + if("removedocument") + remove_document() + if("removefolder") + remove_folder() + if("add") + if(copies < maxcopies) + copies++ + if("minus") + if(copies > 0) + copies-- + if("scandocument") + scan_document() + if("filecopy") + file_copy(params["uid"]) + if("deletefile") + delete_file(params["uid"]) + update_icon() + return TRUE + +/obj/machinery/photocopier/proc/aipic() + if(!issilicon(usr)) + return + if(stat & (BROKEN|NOPOWER)) + return + + if(toner >= 5) + var/mob/living/silicon/tempAI = usr + var/obj/item/camera/siliconcam/camera = tempAI.aiCamera + + if(!camera) + return + var/datum/picture/selection = camera.selectpicture() + if(!selection) + return + + playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) + var/obj/item/photo/p = new /obj/item/photo(loc) + p.construct(selection) + if(p.desc == "") + p.desc += "Copied by [tempAI.name]" + else + p.desc += " - Copied by [tempAI.name]" + toner -= 5 + sleep(15) + +/obj/machinery/photocopier/attackby(obj/item/O, mob/user, params) + if(istype(O, /obj/item/paper) || istype(O, /obj/item/photo) || istype(O, /obj/item/paper_bundle)) + if(!copyitem) + user.drop_item() + copyitem = O + O.forceMove(src) + to_chat(user, "You insert \the [O] into \the [src].") + flick(insert_anim, src) + else + to_chat(user, "There is already something in \the [src].") + else if(istype(O, /obj/item/toner)) + if(toner <= 10) //allow replacing when low toner is affecting the print darkness + user.drop_item() + to_chat(user, "You insert the toner cartridge into \the [src].") + var/obj/item/toner/T = O + toner += T.toner_amount + qdel(O) + else + to_chat(user, "This cartridge is not yet ready for replacement! Use up the rest of the toner.") + else if(istype(O, /obj/item/folder)) + if(!folder) //allow replacing when low toner is affecting the print darkness + user.drop_item() + to_chat(user, "You slide the [O] into \the [src].") + folder = O + O.forceMove(src) + else + to_chat(user, "This cartridge is not yet ready for replacement! Use up the rest of the toner.") + else if(istype(O, /obj/item/grab)) //For ass-copying. + var/obj/item/grab/G = O + if(ismob(G.affecting) && G.affecting != copymob) + var/mob/GM = G.affecting + visible_message("[usr] drags [GM.name] onto the photocopier!") + GM.forceMove(get_turf(src)) + copymob = GM + if(copyitem) + copyitem.forceMove(get_turf(src)) + copyitem = null + else + return ..() + +/obj/machinery/photocopier/wrench_act(mob/user, obj/item/I) + . = TRUE + default_unfasten_wrench(user, I) + /obj/machinery/photocopier/obj_break(damage_flag) if(!(flags & NODECONSTRUCT)) if(toner > 0) @@ -316,7 +490,9 @@ toner = 0 /obj/machinery/photocopier/MouseDrop_T(mob/target, mob/user) - if(!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai) || target == ass) + if(!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai)) + return + if(check_mob()) //is target mob or another mob on this photocopier already? return src.add_fingerprint(user) if(target == user && !user.incapacitated()) @@ -326,23 +502,31 @@ if(!ishuman(user)) return visible_message("[usr] drags [target.name] onto [src]!") target.forceMove(get_turf(src)) - ass = target + copymob = target if(copyitem) copyitem.forceMove(get_turf(src)) - visible_message("[copyitem] is shoved out of the way by [ass]!") + visible_message("[copyitem] is shoved out of the way by [copymob]!") copyitem = null - updateUsrDialog() + playsound(loc, 'sound/machines/ping.ogg', 50, 0) + atom_say("Attention: Posterior Placed on Printing Plaque!") + SStgui.update_uis(src) -/obj/machinery/photocopier/proc/check_ass() //I'm not sure whether I made this proc because it's good form or because of the name. - if(!ass) - return 0 - if(ass.loc != src.loc) - ass = null - updateUsrDialog() - return 0 +/obj/machinery/photocopier/Destroy() + QDEL_LIST(saved_documents) + return ..() + +/** + * Internal proc for checking the Mob on top of the copier + * Reports FALSE if there is no copymob or if the copymob is in a diff location than the copy machine, otherwise reports TRUE + */ +/obj/machinery/photocopier/proc/check_mob() + if(!copymob) + return FALSE + if(copymob.loc != loc) + copymob = null + return FALSE else - playsound(loc, 'sound/machines/ping.ogg', 50, 0) - return 1 + return TRUE /obj/machinery/photocopier/emag_act(user as mob) if(!emagged) @@ -351,10 +535,14 @@ else to_chat(user, "[src]'s laser printing mechanism is already overloaded!") + +//TODO: Add an emp_act effect for photocopiers -sirryan + /obj/item/toner name = "toner cartridge" icon = 'icons/obj/device.dmi' icon_state = "tonercartridge" var/toner_amount = 30 -#undef EMAG_DELAY +#undef PHOTOCOPIER_DELAY +#undef MAX_COPIES_PRINTABLE diff --git a/tgui/packages/tgui/interfaces/Photocopier.js b/tgui/packages/tgui/interfaces/Photocopier.js new file mode 100644 index 00000000000..7848e27d002 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Photocopier.js @@ -0,0 +1,117 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Box, Button, Flex, LabeledList, Section } from '../components'; +import { Window } from '../layouts'; + +export const Photocopier = (props, context) => { + const { act, data } = useBackend(context); + return ( + + +
+ + + + {data.copynumber} + +
+
+ +
+ +
+
+ ); +}; + +const Actions = (props, context) => { + const { act, data } = useBackend(context); + return ( + +