diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 8d6949ccf85..dc543c5ccd9 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -1033,7 +1033,7 @@ SUBSYSTEM_DEF(job) if(!id_safe_code) CRASH("Cannot promote [new_captain.real_name] to Captain, there is no id_safe_code.") - var/paper = new /obj/item/folder/biscuit/confidental/spare_id_safe_code() + var/paper = new /obj/item/folder/biscuit/confidential/spare_id_safe_code() var/list/slots = list( LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, @@ -1059,7 +1059,7 @@ SUBSYSTEM_DEF(job) /// Send a drop pod containing a piece of paper with the spare ID safe code to loc /datum/controller/subsystem/job/proc/send_spare_id_safe_code(loc) - new /obj/effect/pod_landingzone(loc, /obj/structure/closet/supplypod/centcompod, new /obj/item/folder/biscuit/confidental/emergency_spare_id_safe_code()) + new /obj/effect/pod_landingzone(loc, /obj/structure/closet/supplypod/centcompod, new /obj/item/folder/biscuit/confidential/emergency_spare_id_safe_code()) safe_code_timer_id = null safe_code_request_loc = null diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 6de10258990..bf78c8c7cc3 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -52,7 +52,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN if(H.has_status_effect(/datum/status_effect/neck_slice)) - return + return INVOKE_ASYNC(src, PROC_REF(startNeckSlice), source, H, user) return COMPONENT_CANCEL_ATTACK_CHAIN diff --git a/code/modules/cargo/packs/general.dm b/code/modules/cargo/packs/general.dm index c97dc288e22..e5d62e8bdb6 100644 --- a/code/modules/cargo/packs/general.dm +++ b/code/modules/cargo/packs/general.dm @@ -300,9 +300,11 @@ SKYRAT REMOVAL END */ /datum/supply_pack/misc/papercutter name = "Paper Cutters Crate" - desc = "Contains 3 office duty paper cutters.\ - Those are equipped with sharp blades that can cut any paper into two slick paper slips.\ - Blade can be removed from the cutter using screwdriver for cleaning and sharpening of course." - cost = CARGO_CRATE_VALUE * 3.2 - contains = list(/obj/item/papercutter = 3) + desc = "Contains 3 office-grade paper cutters, equipped with sharp blades that can cut any paper into two thin slips.\ + Comes with one replacement blade." + cost = CARGO_CRATE_VALUE * 3.5 + contains = list( + /obj/item/papercutter = 3, + /obj/item/hatchet/cutterblade = 1, + ) crate_name = "paper cutters crate" diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index 01f0c95b8da..5ee1f658c23 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -15,6 +15,8 @@ /obj/item/documents, /obj/item/paperwork, )) + /// Do we hide the contents on examine? + var/contents_hidden = FALSE /obj/item/folder/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] begins filing an imaginary death warrant! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -33,8 +35,8 @@ /obj/item/folder/examine() . = ..() - if(length(contents)) - . += span_notice("Right-click to remove [contents[1]].") + if(length(contents) && !contents_hidden) + . += span_notice("Right-click to remove [contents[1]].") /obj/item/folder/proc/rename(mob/user, obj/item/writing_instrument) if(!user.can_write(writing_instrument)) diff --git a/code/modules/paperwork/paper_biscuit.dm b/code/modules/paperwork/paper_biscuit.dm index 3393b30a3f1..30b70f5c6ed 100644 --- a/code/modules/paperwork/paper_biscuit.dm +++ b/code/modules/paperwork/paper_biscuit.dm @@ -1,28 +1,41 @@ /obj/item/folder/biscuit - name = "\proper biscuit card" - desc = "An biscuit card. Has label which says DO NOT DIGEST." + name = "biscuit card" + desc = "A biscuit card. On the back, DO NOT DIGEST is printed in large lettering." icon_state = "paperbiscuit" bg_color = "#ffffff" w_class = WEIGHT_CLASS_TINY max_integrity = 130 drop_sound = 'sound/items/handling/disk_drop.ogg' pickup_sound = 'sound/items/handling/disk_pickup.ogg' + contents_hidden = TRUE /// Is biscuit cracked open or not? var/cracked = FALSE + /// The paper slip inside, if there is one + var/obj/item/paper/paperslip/contained_slip + +/obj/item/folder/biscuit/Initialize(mapload) + . = ..() + if(!isnull(contained_slip)) + contained_slip = new contained_slip(src) + +/obj/item/folder/biscuit/Destroy() + if(contained_slip) + QDEL_NULL(contained_slip) + return ..() /obj/item/folder/biscuit/suicide_act(mob/living/user) - user.visible_message(span_suicide("[user] tries to eat the paper biscuit! [user.p_theyre()] trying to commit suicide!")) + user.visible_message(span_suicide("[user] tries to eat [src]! [user.p_theyre()] trying to commit suicide!")) playsound(get_turf(user), 'sound/effects/wounds/crackandbleed.ogg', 40, TRUE) //Don't eat plastic cards kids, they get really sharp if you chew on them. return BRUTELOSS /obj/item/folder/biscuit/update_overlays() . = ..() - if(contents.len) //This is to prevent the not-sealed biscuit to have the folder_paper overlay when it gets sealed + if(contents.len) //This is to prevent the unsealed biscuit from having the folder_paper overlay when it gets sealed . -= "folder_paper" - if(cracked) //Shows overlay only when it has content and is cracked open + if(cracked) //Shows overlay only when it has contents and is cracked open . += "paperbiscuit_paper" -///Checks if the biscuit has been already cracked. If its not then it dipsplays "unopened!" ballon alert. If it is cracked then it lets the code continue. +///Checks if the biscuit has been already cracked. /obj/item/folder/biscuit/proc/crack_check(mob/user) if (cracked) return TRUE @@ -31,10 +44,14 @@ /obj/item/folder/biscuit/examine() . = ..() - if(!cracked) - . += span_notice("To reach contents you need to crack it open.") + if(cracked) + . += span_notice("It's been cracked open.") + else + . += span_notice("You'll need to crack it open to access its contents.") + if(contained_slip) + . += "This one contains [contained_slip.name]." -//All next is done so you can't reach contents, or put any new contents when its not cracked open +//The next few checks are done to prevent you from reaching the contents or putting anything inside when it's not cracked open /obj/item/folder/biscuit/remove_item(obj/item/item, mob/user) if (!crack_check(user)) return @@ -59,67 +76,63 @@ if (tgui_alert(user, "Do you want to crack it open?", "Biscuit Cracking", list("Yes", "No")) != "Yes") return cracked = TRUE + contents_hidden = FALSE playsound(get_turf(user), 'sound/effects/wounds/crack1.ogg', 60) icon_state = "[icon_state]_cracked" update_appearance() ui_interact(user) -//Corporate "confidental" biscuit cards -/obj/item/folder/biscuit/confidental - name = "\proper confidental biscuit card" - desc = "An confidental biscuit card. In a tasteful blue color with NT logo, looks like a chocolate bar. Has label which says DO NOT DIGEST." + +//Corporate "confidential" biscuit cards +/obj/item/folder/biscuit/confidential + name = "confidential biscuit card" + desc = "A confidential biscuit card. The tasteful blue color and NT logo on the front makes it look a little like a chocolate bar. \ + On the back, DO NOT DIGEST is printed in large lettering." icon_state = "paperbiscuit_secret" bg_color = "#355e9f" -/obj/item/folder/biscuit/confidental/spare_id_safe_code - name = "\proper spare ID safe code biscuit card" - desc = "An biscuit card containing confidental spare ID safe code. In a tasteful blue color with NT logo, looks like a chocolate bar. Has label which says DO NOT DIGEST." +/obj/item/folder/biscuit/confidential/spare_id_safe_code + name = "spare ID safe code biscuit card" + contained_slip = /obj/item/paper/paperslip/corporate/fluff/spare_id_safe_code -/obj/item/folder/biscuit/confidental/spare_id_safe_code/Initialize(mapload) - . = ..() - new /obj/item/paper/paperslip/corporate/fluff/spare_id_safe_code(src) +/obj/item/folder/biscuit/confidential/emergency_spare_id_safe_code + name = "spare emergency ID safe code biscuit card" + contained_slip = /obj/item/paper/paperslip/corporate/fluff/emergency_spare_id_safe_code -/obj/item/folder/biscuit/confidental/emergency_spare_id_safe_code - name = "\proper spare emergency ID safe code biscuit card" - desc = "An biscuit card containing not so confidental emergency spare ID safe code. In a tasteful blue color with NT logo, looks like a chocolate bar. Has label which says DO NOT DIGEST." - -/obj/item/folder/biscuit/confidental/emergency_spare_id_safe_code/Initialize(mapload) - . = ..() - new /obj/item/paper/paperslip/corporate/fluff/emergency_spare_id_safe_code(src) - -//Biscuits which start not-sealed/cracked initially for the crafting, printing and such +//Biscuits which start open. Used for crafting, printing, and such /obj/item/folder/biscuit/unsealed - name = "\proper biscuit card" - desc = "An biscuit card. Has label which says DO NOT DIGEST." + name = "biscuit card" + desc = "A biscuit card. On the back, DO NOT DIGEST is printed in large lettering." icon_state = "paperbiscuit_cracked" + contents_hidden = FALSE cracked = TRUE - ///Was the biscuit already sealed by players? To prevent several tgui alerts - var/sealed = FALSE - ///What is the sprite for when its not cracked? As it starts already cracked, and for re-sealing needs to have a sprite - var/not_cracked_icon = "paperbiscuit" + ///Was the biscuit already sealed by players? Prevents re-sealing after use + var/has_been_sealed = FALSE + ///What is the sprite for when it's sealed? It starts unsealed, so needs a sprite for when it's sealed. + var/sealed_icon = "paperbiscuit" /obj/item/folder/biscuit/unsealed/examine() . = ..() - if(!sealed) - . += span_notice("This one have not been sealed yet. You many insert anything to seal it by pressing it in hand. Once sealed, the contents are inaccessible until cracked open (irreversible).") + if(!has_been_sealed) + . += span_notice("This one could be sealed in hand. Once sealed, the contents are inaccessible until cracked open again - but once opened this is irreversible.") -//Asks if you want to seal the biscuit, after you do that it behaves like normal paper biscuit. +//Asks if you want to seal the biscuit, after you do that it behaves like a normal paper biscuit. /obj/item/folder/biscuit/unsealed/attack_self(mob/user) add_fingerprint(user) - if (!sealed) - if (tgui_alert(user, "Do you want to seal it? You must crack it open to reach the contents again!", "Biscuit Sealing", list("Yes", "No")) != "Yes") - return - cracked = FALSE - sealed = TRUE - playsound(get_turf(user), 'sound/items/duct_tape_snap.ogg', 60) - icon_state = "[not_cracked_icon]" - update_appearance() + if(!cracked) + return ..() + if(tgui_alert(user, "Do you want to seal it? This can only be done once.", "Biscuit Sealing", list("Yes", "No")) != "Yes") + return + cracked = FALSE + has_been_sealed = TRUE + contents_hidden = TRUE + playsound(get_turf(user), 'sound/items/duct_tape_snap.ogg', 60) + icon_state = "[sealed_icon]" + update_appearance() - return ..() - -/obj/item/folder/biscuit/unsealed/confidental - name = "\proper confidental biscuit card" - desc = "An confidental biscuit card. In a tasteful blue color with NT logo, looks like a chocolate bar. To reach contents you need to crack it open. Has label which says DO NOT DIGEST." +/obj/item/folder/biscuit/unsealed/confidential + name = "confidential biscuit card" + desc = "A confidential biscuit card. The tasteful blue color and NT logo on the front makes it look a little like a chocolate bar. On the back, DO NOT DIGEST is printed in large lettering." icon_state = "paperbiscuit_secret_cracked" bg_color = "#355e9f" - not_cracked_icon = "paperbiscuit_secret" + sealed_icon = "paperbiscuit_secret" diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 2a304d138ac..4c124ca3ad9 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -6,108 +6,160 @@ force = 5 throwforce = 5 w_class = WEIGHT_CLASS_NORMAL - var/obj/item/paper/storedpaper = null - var/obj/item/hatchet/cutterblade/storedcutter = null - var/cuttersecured = TRUE pass_flags = PASSTABLE - + /// The paper currently loaded inside the cutter + var/obj/item/paper/stored_paper + /// The blade currently loaded inside the cutter + var/obj/item/hatchet/cutterblade/stored_blade + /// Whether the cutter blade is secured or not. + var/blade_secured = TRUE + /// The chance for a clumsy person to cut themselves on the blade + /// Should probably be low-ish to prevent people spamming it quite so easily + var/cut_self_chance = 5 /obj/item/papercutter/Initialize(mapload) . = ..() - storedcutter = new /obj/item/hatchet/cutterblade(src) + stored_blade = new /obj/item/hatchet/cutterblade(src) update_appearance() +/obj/item/papercutter/Destroy(force) + if(stored_paper) + stored_paper.forceMove(get_turf(src)) + stored_paper = null + if(stored_blade) + stored_blade.forceMove(get_turf(src)) + stored_blade = null + return ..() + +/obj/item/papercutter/examine(mob/user) + . = ..() + . += "Right-Click to cut paper once it's inside." + if(stored_blade) + . += "The blade could be [blade_secured ? "un" : ""]secured with a screwdriver[blade_secured ? "" : " or removed with an empty hand"]." /obj/item/papercutter/suicide_act(mob/living/user) - if(storedcutter) - user.visible_message(span_suicide("[user] is beheading [user.p_them()]self with [src.name]! It looks like [user.p_theyre()] trying to commit suicide!")) - if(iscarbon(user)) - var/mob/living/carbon/C = user - var/obj/item/bodypart/BP = C.get_bodypart(BODY_ZONE_HEAD) - if(BP) - BP.drop_limb() - playsound(loc, SFX_DESECRATION ,50, TRUE, -1) - return BRUTELOSS - else - user.visible_message(span_suicide("[user] repeatedly bashes [src.name] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")) - playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1) + if(iscarbon(user) && stored_blade) + var/mob/living/carbon/carbon_user = user + var/obj/item/bodypart/user_head = carbon_user.get_bodypart(BODY_ZONE_HEAD) + if(isnull(user_head)) // So no head? + user.visible_message(span_suicide("[user] tries to behead [user.p_them()]self with [src], but [user.p_they()] [user.p_were()] already missing it! How embarassing!")) + return SHAME + user.visible_message(span_suicide("[user] is beheading [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) + user_head.drop_limb() + playsound(loc, SFX_DESECRATION, 50, TRUE, -1) return BRUTELOSS + // If we have no blade, just beat ourselves up + user.visible_message(span_suicide("[user] repeatedly bashes [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to commit suicide!")) + playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1) + return BRUTELOSS /obj/item/papercutter/update_icon_state() - icon_state = (storedcutter ? "[initial(icon_state)]-cutter" : "[initial(icon_state)]") + icon_state = (stored_blade ? "[initial(icon_state)]-cutter" : "[initial(icon_state)]") return ..() /obj/item/papercutter/update_overlays() . =..() - if(storedpaper) + if(stored_paper) . += "paper" /obj/item/papercutter/screwdriver_act(mob/living/user, obj/item/tool) - if(!storedcutter) + if(!stored_blade && !blade_secured) + balloon_alert(user, "no blade to secure!") return tool.play_tool_sound(src) - to_chat(user, span_notice("[storedcutter] has been [cuttersecured ? "unsecured" : "secured"].")) - cuttersecured = !cuttersecured + balloon_alert(user, "blade [blade_secured ? "un" : ""]secured") + blade_secured = !blade_secured return TOOL_ACT_TOOLTYPE_SUCCESS -/obj/item/papercutter/attackby(obj/item/P, mob/user, params) - if(istype(P, /obj/item/paper) && !storedpaper && !istype(P, /obj/item/paper/paperslip)) - if(!user.transferItemToLoc(P, src)) +/obj/item/papercutter/attackby(obj/item/inserted_item, mob/user, params) + if(istype(inserted_item, /obj/item/paper) && !istype(inserted_item, /obj/item/paper/paperslip)) + if(stored_paper) + balloon_alert(user, "already paper inside!") + if(!user.transferItemToLoc(inserted_item, src)) return playsound(loc, SFX_PAGE_TURN, 60, TRUE) - to_chat(user, span_notice("You place [P] in [src].")) - storedpaper = P - update_appearance() - return - if(istype(P, /obj/item/hatchet/cutterblade) && !storedcutter) - if(!user.transferItemToLoc(P, src)) + balloon_alert(user, "paper inserted") + stored_paper = inserted_item + + if(istype(inserted_item, /obj/item/hatchet/cutterblade)) + if(stored_blade) + balloon_alert(user, "already a blade inside!") return - to_chat(user, span_notice("You replace [src]'s [P].")) - P.forceMove(src) - storedcutter = P - update_appearance() - return - ..() + if(!user.transferItemToLoc(inserted_item, src)) + return + balloon_alert(user, "blade inserted") + inserted_item.forceMove(src) + stored_blade = inserted_item + + update_appearance() + + return ..() /obj/item/papercutter/attack_hand(mob/user, list/modifiers) - . = ..() - if(.) - return add_fingerprint(user) - if(!storedcutter) - to_chat(user, span_warning("The cutting blade is gone! You can't use [src] now.")) - return - if(!cuttersecured) - to_chat(user, span_notice("You remove [src]'s [storedcutter].")) - user.put_in_hands(storedcutter) - storedcutter = null - update_appearance() + if(!stored_blade && stored_paper) + balloon_alert(user, "no blade!") + return COMPONENT_CANCEL_ATTACK_CHAIN - if(storedpaper) - playsound(src.loc, 'sound/weapons/slash.ogg', 50, TRUE) - to_chat(user, span_notice("You neatly cut [storedpaper].")) - storedpaper = null - qdel(storedpaper) - new /obj/item/paper/paperslip(get_turf(src)) - new /obj/item/paper/paperslip(get_turf(src)) + else if(!blade_secured) + balloon_alert(user, "blade removed") + user.put_in_hands(stored_blade) + stored_blade = null update_appearance() + return COMPONENT_CANCEL_ATTACK_CHAIN + + else if(stored_paper) + balloon_alert(user, "paper removed") + user.put_in_hands(stored_paper) + stored_paper = null + update_appearance() + return COMPONENT_CANCEL_ATTACK_CHAIN + + // If there's a secured blade but no paper, just pick it up + return ..() + +/obj/item/papercutter/attack_hand_secondary(mob/user, list/modifiers) + if(!stored_blade) + balloon_alert(user, "no blade!") + else if(!blade_secured) + balloon_alert(user, "blade unsecured!") + else if(!stored_paper) + balloon_alert(user, "nothing to cut!") + else + cut_paper(user) + + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/item/papercutter/proc/cut_paper(mob/user) + playsound(src.loc, 'sound/weapons/slash.ogg', 50, TRUE) + var/clumsy = (iscarbon(user) && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(cut_self_chance)) + to_chat(user, span_userdanger("You neatly cut [stored_paper][clumsy ? "... and your finger in the process!" : "."]")) + if(clumsy) + var/obj/item/bodypart/finger = user.get_active_hand() + var/datum/wound/slash/moderate/papercut = new + papercut.apply_wound(finger) + stored_paper = null + qdel(stored_paper) + new /obj/item/paper/paperslip(get_turf(src)) + new /obj/item/paper/paperslip(get_turf(src)) + update_appearance() /obj/item/papercutter/MouseDrop(atom/over_object) . = ..() - var/mob/M = usr - if(M.incapacitated() || !Adjacent(M)) + var/mob/user = usr + if(user.incapacitated() || !Adjacent(user)) return - if(over_object == M) - M.put_in_hands(src) + if(over_object == user) + user.put_in_hands(src) else if(istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/H = over_object - M.putItemFromInventoryInHandIfPossible(src, H.held_index) - add_fingerprint(M) + var/atom/movable/screen/inventory/hand/target_hand = over_object + user.putItemFromInventoryInHandIfPossible(src, target_hand.held_index) + add_fingerprint(user) /obj/item/paper/paperslip name = "paper slip" @@ -120,7 +172,7 @@ /obj/item/paper/paperslip/corporate //More fancy and sturdy paper slip which is a "plastic card", used for things like spare ID safe code name = "corporate plastic card" - desc = "A plastic card for confidental corporate matters. Can be written on with pen somehow." + desc = "A plastic card for confidential corporate matters. Can be written on with pen somehow." icon_state = "corppaperslip" grind_results = list(/datum/reagent/plastic_polymers = 1.5) //It's a plastic card after all max_integrity = 130 //Slightly more sturdy because of being made out of a plastic @@ -130,7 +182,7 @@ throw_speed = 2 /obj/item/hatchet/cutterblade - name = "paper cutter" + name = "paper cutter blade" desc = "The blade of a paper cutter. Most likely removed for polishing or sharpening." icon = 'icons/obj/bureaucracy.dmi' icon_state = "cutterblade" diff --git a/code/modules/research/designs/autolathe/multi-department_designs.dm b/code/modules/research/designs/autolathe/multi-department_designs.dm index 0b74791718c..cef0bb8b773 100644 --- a/code/modules/research/designs/autolathe/multi-department_designs.dm +++ b/code/modules/research/designs/autolathe/multi-department_designs.dm @@ -564,13 +564,13 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO -/datum/design/paper_biscuit_confidental - name = "Confidental Paper Biscuit" - desc = "An paper biscuit which can seal in itself paperwork, this one is used for confidental Nanotrasen documents. After sealing it the only way to open is through cracking it, cracking is irreversible and makes it permamently open. Not actually a biscuit." - id = "confidental_biscuit" +/datum/design/paper_biscuit_confidential + name = "Confidential Paper Biscuit" + desc = "An paper biscuit which can seal in itself paperwork, this one is used for confidential Nanotrasen documents. After sealing it the only way to open is through cracking it, cracking is irreversible and makes it permamently open. Not actually a biscuit." + id = "confidential_biscuit" build_type = PROTOLATHE | AWAY_LATHE | AUTOLATHE materials = list(/datum/material/plastic = 30) - build_path = /obj/item/folder/biscuit/unsealed/confidental + build_path = /obj/item/folder/biscuit/unsealed/confidential category = list( RND_CATEGORY_HACKED, RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_SERVICE,