From ff4dcc1c53cd2befd7249a2a1b0689276e3386a1 Mon Sep 17 00:00:00 2001 From: HWSensum <121913313+HWSensum@users.noreply.github.com> Date: Sun, 28 May 2023 23:39:37 +0300 Subject: [PATCH] New traitor item: Mail Counterfeit Devices (#75390) ## About The Pull Request This PR will add new (antag) device, that will allow players to counterfeit mails, putting (almost) anything they want and arming it, if they liked to. Upon activation this device will give you multiple choices like: - Is it gonna be an envelope or a normal mail? - Is it gonna be armed? - Who is gonna be a recipient? - If it is a non private mail, then what title it is gonna have? Those devices can put any single normal sized item inside a mail, that is gonna be activated upon opening if mail armed. Mail creator and other ditalis will be shown to admins upon activation for admin purposes. By activation i mean `attack_self` proc of an item. Armed mail can be disarmed by using, BUT! Only owner can disarm it with 100% success rate. Other people will have 50% chance of fail, that will activate a trap. Those devices also have few more admin-only variations: ``` /obj/item/storage/mail_counterfeit_device/advanced /obj/item/storage/mail_counterfeit_device/bluespace ``` They can put more items inside a mail. ### How to get those naughty devices? - Those devices can be purchased in uplink. One device goes for one TC. - QM and Cargo Technicians have special kits that costs 2 TC and have 6 devices. And yeah, i also fixed issue with envelopes, they actually have 2 items inside, but player were given only first one. Proof of testing: ![dreamseeker_ngVIMHxdQf](https://github.com/tgstation/tgstation/assets/121913313/2bd997a9-8de6-4c32-878b-b13438f1a51e) (minibomb was set to instant detonation before recording) ## Why It's Good For The Game This PR will give a lot of new possibilities for traitors. Those mails can be used not only as bombing tools, but also for contraband and other purposes. Also those mails can be used for (b)admin stuff. ## Changelog :cl: add: added a mail counterfeit device that can make custom (and also armed) mails. Traitors have those devices in their uplinks. add: added new kit for QM and Cargo Technicians that have multiple mail counterfeit devices for neat price. fix: fixed envelopes that were giving only their first item, even tho they had two items insede. image: added new icon for mail counterfeit device. /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com> Co-authored-by: ShizCalev --- code/game/objects/items/mail.dm | 186 +++++++++++++++++- .../game/objects/items/storage/uplink_kits.dm | 8 + code/modules/unit_tests/_unit_tests.dm | 1 + .../unit_tests/traitor_mail_content_check.dm | 10 + code/modules/uplink/uplink_items/job.dm | 9 + .../uplink/uplink_items/stealthy_tools.dm | 7 + icons/obj/device_syndie.dmi | Bin 797 -> 1025 bytes 7 files changed, 213 insertions(+), 8 deletions(-) create mode 100644 code/modules/unit_tests/traitor_mail_content_check.dm diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm index 149e4968402..c9fddbe19d6 100644 --- a/code/game/objects/items/mail.dm +++ b/code/game/objects/items/mail.dm @@ -107,25 +107,45 @@ var/tag = uppertext(GLOB.TAGGERLOCATIONS[destination_tag.currTag]) to_chat(user, span_notice("*[tag]*")) sort_tag = destination_tag.currTag - playsound(loc, 'sound/machines/twobeep_high.ogg', 100, TRUE) + playsound(loc, 'sound/machines/twobeep_high.ogg', vol = 100, vary = TRUE) + +/obj/item/mail/multitool_act(mob/living/user, obj/item/tool) + if(user.get_inactive_held_item() == src) + balloon_alert(user, "nothing to disable!") + return TRUE + balloon_alert(user, "hold it!") + return FALSE + /obj/item/mail/attack_self(mob/user) + if(!unwrap(user)) + return FALSE + return after_unwrap(user) + +/// proc for unwrapping a mail. Goes just for an unwrapping procces, returns FALSE if it fails. +/obj/item/mail/proc/unwrap(mob/user) if(recipient_ref) var/datum/mind/recipient = recipient_ref.resolve() // If the recipient's mind has gone, then anyone can open their mail // whether a mind can actually be qdel'd is an exercise for the reader if(recipient && recipient != user?.mind) to_chat(user, span_notice("You can't open somebody else's mail! That's illegal!")) - return + return FALSE - to_chat(user, span_notice("You start to unwrap the package...")) + balloon_alert(user, "unwrapping...") if(!do_after(user, 1.5 SECONDS, target = user)) - return - user.temporarilyRemoveItemFromInventory(src, TRUE) - if(contents.len) - user.put_in_hands(contents[1]) - playsound(loc, 'sound/items/poster_ripped.ogg', 50, TRUE) + return FALSE + return TRUE + +// proc that goes after unwrapping a mail. +/obj/item/mail/proc/after_unwrap(mob/user) + user.temporarilyRemoveItemFromInventory(src, force = TRUE) + for(var/obj/item/stuff as anything in contents) // Mail and envelope actually can have more than 1 item. + user.put_in_hands(stuff) + playsound(loc, 'sound/items/poster_ripped.ogg', vol = 50, vary = TRUE) qdel(src) + return TRUE + /obj/item/mail/examine_more(mob/user) . = ..() @@ -332,3 +352,153 @@ /obj/item/paper/fluff/junkmail_generic/Initialize(mapload) default_raw_text = pick(GLOB.junkmail_messages) return ..() + +/obj/item/mail/traitor + var/armed = FALSE + var/datum/weakref/made_by_ref + /// Cached information about who made it for logging purposes + var/made_by_cached_name + /// Cached information about who made it for logging purposes + var/made_by_cached_ckey + goodie_count = 0 + +/obj/item/mail/traitor/envelope + name = "envelope" + icon_state = "mail_large" + stamp_max = 2 + stamp_offset_y = 5 + +/obj/item/mail/traitor/after_unwrap(mob/user) + user.temporarilyRemoveItemFromInventory(src, force = TRUE) + playsound(loc, 'sound/items/poster_ripped.ogg', vol = 50, vary = TRUE) + for(var/obj/item/stuff as anything in contents) // Mail and envelope actually can have more than 1 item. + if(user.put_in_hands(stuff) && armed) + log_bomber(user, "opened armed mail made by [made_by_cached_name] ([made_by_cached_ckey]), activating", stuff) + INVOKE_ASYNC(stuff, TYPE_PROC_REF(/obj/item, attack_self), user) + qdel(src) + return TRUE + +/obj/item/mail/traitor/multitool_act(mob/living/user, obj/item/tool) + if(armed == FALSE || user.get_inactive_held_item() != src) + return ..() + if(IS_WEAKREF_OF(user.mind, made_by_ref)) + balloon_alert(user, "disarming trap...") + if(!do_after(user, 2 SECONDS, target = src)) + return FALSE + balloon_alert(user, "disarmed") + playsound(src, 'sound/machines/defib_ready.ogg', vol = 100, vary = TRUE) + armed = FALSE + return TRUE + else + balloon_alert(user, "tinkering with something...") + + if(!do_after(user, 2 SECONDS, target = src)) + after_unwrap(user) + return FALSE + if(prob(50)) + balloon_alert(user, "disarmed something...?") + playsound(src, 'sound/machines/defib_ready.ogg', vol = 100, vary = TRUE) + armed = FALSE + return TRUE + else + after_unwrap(user) + return TRUE + +/obj/item/storage/mail_counterfeit_device + name = "GLA-2 mail counterfeit device" + desc = "Device that actually able to counterfeit NT's mail. This device also able to place a trap inside of mail for malicious actions. Trap will \"activate\" any item inside of mail. Also it might be used for contraband purposes. Integrated micro-computer will give you great configuration optionality for your needs." + w_class = WEIGHT_CLASS_NORMAL + icon = 'icons/obj/device_syndie.dmi' + icon_state = "mail_counterfeit_device" + +/obj/item/storage/mail_counterfeit_device/Initialize(mapload) + . = ..() + atom_storage.max_slots = 1 + atom_storage.allow_big_nesting = TRUE + atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL + +/obj/item/storage/mail_counterfeit_device/examine_more(mob/user) + . = ..() + . += span_notice("You notice the manufacture marking on the side of the device...") + . += "\t[span_info("Guerilla Letter Assembler")]" + . += "\t[span_info("GLA Postal Service, right on schedule.")]" + return . + +/obj/item/storage/mail_counterfeit_device/attack_self(mob/user, modifiers) + var/mail_type = tgui_alert(user, "Make it look like an envelope or like normal mail?", "Mail Counterfeiting", list("Mail", "Envelope")) + if(isnull(mail_type)) + return FALSE + if(loc != user) + return FALSE + mail_type = lowertext(mail_type) + + var/mail_armed = tgui_alert(user, "Arm it?", "Mail Counterfeiting", list("Yes", "No")) == "Yes" + if(isnull(mail_armed)) + return FALSE + if(loc != user) + return FALSE + + var/list/mail_recipients = list("Anyone") + var/list/mail_recipients_for_input = list("Anyone") + var/list/used_names = list() + for(var/datum/record/locked/person in sort_record(GLOB.manifest.locked)) + if(isnull(person.mind_ref)) + continue + mail_recipients += person.mind_ref + mail_recipients_for_input += avoid_assoc_duplicate_keys(person.name, used_names) + + var/recipient = tgui_input_list(user, "Choose a recipient", "Mail Counterfeiting", mail_recipients_for_input) + if(isnull(recipient)) + return FALSE + if(!(src in user.contents)) + return FALSE + + var/index = mail_recipients_for_input.Find(recipient) + + var/obj/item/mail/traitor/shady_mail + if(mail_type == "mail") + shady_mail = new /obj/item/mail/traitor + else + shady_mail = new /obj/item/mail/traitor/envelope + + shady_mail.made_by_cached_ckey = user.ckey + shady_mail.made_by_cached_name = user.mind.name + + if(index == 1) + var/mail_name = tgui_input_text(user, "Enter mail title, or leave it blank", "Mail Counterfeiting") + if(!(src in user.contents)) + return FALSE + if(reject_bad_text(mail_name, ascii_only = FALSE)) + shady_mail.name = mail_name + else + shady_mail.name = mail_type + else + shady_mail.initialize_for_recipient(mail_recipients[index]) + + atom_storage.hide_contents(user) + user.temporarilyRemoveItemFromInventory(src, force = TRUE) + shady_mail.contents += contents + shady_mail.armed = mail_armed + shady_mail.made_by_ref = WEAKREF(user.mind) + user.put_in_hands(shady_mail) + qdel(src) + +/// Unobtainable item mostly for (b)admin purposes. +/obj/item/storage/mail_counterfeit_device/advanced + name = "GLA-MACRO mail counterfeit device" + +/obj/item/storage/mail_counterfeit_device/advanced/Initialize(mapload) + . = ..() + desc += " This model is highly advanced and capable of compressing items, making mail's storage space comparable to standard backpack." + create_storage(max_slots = 21, max_total_storage = 21) + atom_storage.allow_big_nesting = TRUE + +/// Unobtainable item mostly for (b)admin purposes. +/obj/item/storage/mail_counterfeit_device/bluespace + name = "GLA-ULTRA mail counterfeit device" + +/obj/item/storage/mail_counterfeit_device/bluespace/Initialize(mapload) + . = ..() + desc += " This model is the most advanced and capable of performing crazy bluespace compressions, making mail's storage space comparable to bluespace backpack." + create_storage(max_specific_storage = WEIGHT_CLASS_GIGANTIC, max_total_storage = 35, max_slots = 30) + atom_storage.allow_big_nesting = TRUE diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index c9ace922962..7fb901eebc5 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -426,6 +426,14 @@ new /obj/item/grenade/empgrenade(src) new /obj/item/implanter/emp(src) +/obj/item/storage/box/syndie_kit/mail_counterfeit + name = "mail counterfeit kit" + desc = "A box full of mail counterfeit devices. Nothing stops the mail." + +/obj/item/storage/box/syndie_kit/mail_counterfeit/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/storage/mail_counterfeit_device(src) + /obj/item/storage/box/syndie_kit/chemical name = "chemical kit" diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 22b1693f392..eaf25edf81f 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -230,6 +230,7 @@ #include "timer_sanity.dm" #include "trait_addition_and_removal.dm" #include "traitor.dm" +#include "traitor_mail_content_check.dm" #include "turf_icons.dm" #include "tutorial_sanity.dm" #include "unit_test.dm" diff --git a/code/modules/unit_tests/traitor_mail_content_check.dm b/code/modules/unit_tests/traitor_mail_content_check.dm new file mode 100644 index 00000000000..6d14d9d1428 --- /dev/null +++ b/code/modules/unit_tests/traitor_mail_content_check.dm @@ -0,0 +1,10 @@ +/// Makes sure that fake mail doesn't get random goods. +/datum/unit_test/traitor_mail_content_check + +/datum/unit_test/traitor_mail_content_check/Run() + var/mob/living/carbon/human/person = allocate(/mob/living/carbon/human/consistent) + person.mind_initialize() + var/obj/item/mail/traitor/test_mail = allocate(/obj/item/mail/traitor) + person.mind.set_assigned_role(SSjob.GetJobType(/datum/job/captain)) + test_mail.initialize_for_recipient(person.mind) + TEST_ASSERT_EQUAL(test_mail.contents.len, 0, "/obj/item/mail/traitor should not have items after initialize_for_recipient proc!") diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index be21458ee87..32788fad169 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -16,6 +16,15 @@ limited_stock = 1 //please don't spam deadchat surplus = 5 +/datum/uplink_item/role_restricted/mail_counterfeit_kit + name = "GLA Brand Mail Counterfeit Kit" + desc = "A box full of mail counterfeit devices. Devices that actually able to counterfeit NT's mail. Those devices also able to place a trap inside of mail for malicious actions. Trap will \"activate\" any item inside of mail. Also counterfieted mail might be used for contraband purposes. Integrated micro-computer will give you great configuration optionality for your needs. \nNothing stops the mail." + item = /obj/item/storage/box/syndie_kit/mail_counterfeit + cost = 2 + illegal_tech = FALSE + restricted_roles = list(JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER) + surplus = 5 + /datum/uplink_item/role_restricted/bureaucratic_error name = "Organic Capital Disturbance Virus" desc = "Randomizes job positions presented to new hires. May lead to too many/too few security officers and/or clowns. Single use." diff --git a/code/modules/uplink/uplink_items/stealthy_tools.dm b/code/modules/uplink/uplink_items/stealthy_tools.dm index 6cc5a12bd97..60f007ebae7 100644 --- a/code/modules/uplink/uplink_items/stealthy_tools.dm +++ b/code/modules/uplink/uplink_items/stealthy_tools.dm @@ -92,6 +92,13 @@ surplus = 30 illegal_tech = FALSE +/datum/uplink_item/stealthy_tools/mail_counterfeit + name = "GLA Brand Mail Counterfeit Device" + desc = "Device that actually able to counterfeit NT's mail. This device also able to place a trap inside of mail for malicious actions. Trap will \"activate\" any item inside of mail. Also it might be used for contraband purposes. Integrated micro-computer will give you great configuration optionality for your needs." + item = /obj/item/storage/mail_counterfeit_device + cost = 1 + surplus = 30 + /datum/uplink_item/stealthy_tools/telecomm_blackout name = "Disable Telecomms" desc = "When purchased, a virus will be uploaded to the telecommunication processing servers to temporarily disable themselves." diff --git a/icons/obj/device_syndie.dmi b/icons/obj/device_syndie.dmi index 5eaa05d0914b02ea9689d2425354df271d3247f4..25ac0ef9b394473f7494d827b8b3e512427271fe 100644 GIT binary patch delta 883 zcmV-(1C0Eg27w5W7Y<+u0{{R3)kcR30001@ktK+Kz`($92?<$QSu-;;krfpU4Gn8+ zYeYmuUJ?>HIXSVPh=l+E00DGTPE!Ct=GbNc006OiR9JLGWpiV4X>fFDZ*Bkpc$|%p z!485j42I9!Q!H>rqrlaRffx?*3S_e4n!rZ30`cvgk{AyfJ@x~KMOF7ekS52$&Bng6y{NzV$(T1X}frvAO&WFyPv(Cu@R{i2f zyMXJ^(@*j;UH@S=(%=xR`V40wgj|+a>*D#N zJBm41{rl?nMF0Q-P)S5VRA_AFc83hbG|TE$g*2nG91{WrP&%#c#QJ>zuL|w zgElXu;@cmUe-RGoB>!}NT&xfT?+18^h(Mi@5g>-);KLvc5rqUW9P;RJBPAGqycvx~ z<7g-*h{m6U1@Y(6I2IES3*s*^3rI?kMDcALC2|5tqUa_8K>;Mm9b6-r@YN|$yag zkQ?5T0fdS$9E3=!DPRMD8KGXmg*ga+Nh_WMrKv8cQh;B~@2A;p_SBI<|0+T($WSz& z2bp=uou_`*wM_f>0U|F@bG1BhvR8t)0fYq-+E%DkP?Z6R391aF1jQ+XLPnsADubf6 z7C8`{5fQKf?Wqfe`hRhF6zbpO@pwG0=sVXqiT9n%oW%RimeW%lG z?@fHUT=vFSt5r|@KV%?22hyuZejj)|9*@W4xlE~Ql#csfH*jlE>pai3`RMA)y8Z(A zYQaWtHXB`*_O=ldY`0F#*)rK)Vt|xABhj-tb&u zf8?$NklYyo&+GOC|8OQynx|k|$AZHv+zCh#?LxiB!=A^nPLxF9n*GapE02Pr^uJ4w@Ynk8a@ zYE(Rb5@6A*St*pEV`f`$ZiBnB7~NCCQ^1f2}PbVGt}v=&_fu#*UY3D|dC zC^Y|G^C&cbP*6}%(6!|2Yp&w^I