diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 14ff38bf3d0..91c637a9492 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -647,3 +647,7 @@ /// Sent from /obj/effect/rune/convert/try_sacrifice_item(obj/effect/rune/convert/rune) #define COMSIG_ITEM_CULT_SACRIFICE "item_cult_sacrifice" #define COMPONENT_SACRIFICE_SUCCESSFUL (1<<0) + +/// Sent from /obj/item/mail/traitor/after_unwrap(mob/user, obj/item/mail/traitor/letter) +#define COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL "traitor_mail_opened" + #define COMPONENT_TRAITOR_MAIL_HANDLED (1<<0) diff --git a/code/game/objects/items/food/monkeycube.dm b/code/game/objects/items/food/monkeycube.dm index a6554230f25..fcce5eb9f0a 100644 --- a/code/game/objects/items/food/monkeycube.dm +++ b/code/game/objects/items/food/monkeycube.dm @@ -13,6 +13,10 @@ /// Whether we've been wetted and are expanding var/expanding = FALSE +/obj/item/food/monkeycube/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) + /obj/item/food/monkeycube/attempt_pickup(mob/user) if(expanding) return FALSE @@ -77,6 +81,12 @@ user.visible_message(span_danger("[user]'s torso bursts open as a primate emerges!")) user.gib(DROP_BRAIN|DROP_BODYPARTS|DROP_ITEMS) // just remove the organs +/obj/item/food/monkeycube/proc/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + to_chat(user, span_danger("As you open [letter], its contents rapidly expand!")) + Expand() + return COMPONENT_TRAITOR_MAIL_HANDLED + /obj/item/food/monkeycube/syndicate faction = list(FACTION_NEUTRAL, ROLE_SYNDICATE) diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm index 02368f80e75..bebc7b4ceab 100644 --- a/code/game/objects/items/mail.dm +++ b/code/game/objects/items/mail.dm @@ -400,10 +400,18 @@ user.temporarilyRemoveItemFromInventory(src, force = TRUE) playsound(loc, 'sound/items/poster/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) - var/whomst = made_by_cached_name ? "[made_by_cached_name] ([made_by_cached_ckey])" : "no one in particular" - log_bomber(user, "opened armed mail made by [whomst], activating", stuff) - INVOKE_ASYNC(stuff, TYPE_PROC_REF(/obj/item, attack_self), user) + if(!armed) + continue + var/whomst = made_by_cached_name ? "[made_by_cached_name] ([made_by_cached_ckey])" : "no one in particular" + log_bomber(user, "opened armed mail made by [whomst], activating", stuff) + + if(SEND_SIGNAL(stuff, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, user, src) & COMPONENT_TRAITOR_MAIL_HANDLED) + continue + + if(!user.put_in_hands(stuff)) + continue + + INVOKE_ASYNC(stuff, TYPE_PROC_REF(/obj/item, attack_self), user) qdel(src) return TRUE @@ -418,20 +426,18 @@ playsound(src, 'sound/machines/defib/defib_ready.ogg', vol = 100, vary = TRUE) armed = FALSE return TRUE - else - balloon_alert(user, "tinkering with something...") + 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/defib_ready.ogg', vol = 100, vary = TRUE) - armed = FALSE - return TRUE - else - after_unwrap(user) - return TRUE + 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/defib_ready.ogg', vol = 100, vary = TRUE) + armed = FALSE + return TRUE + after_unwrap(user) + return TRUE ///Generic mail used in the mail strike shuttle loan event /obj/item/mail/mail_strike diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index c1df928d8b6..dfb5c628a68 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -28,6 +28,10 @@ var/cooldown = 0 var/last_trigger = 0 //Last time it was successfully triggered. +/obj/item/assembly/flash/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) + /obj/item/assembly/flash/suicide_act(mob/living/user) if(burnt_out) user.visible_message(span_suicide("[user] raises \the [src] up to [user.p_their()] eyes and activates it ... but it's burnt out!")) @@ -265,6 +269,15 @@ // Attacker lateral to the victim. return DEVIATION_PARTIAL +/obj/item/assembly/flash/proc/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + if(!try_use_flash()) + return NONE + to_chat(user, span_danger("As you open [letter], a very bright light shoots out from inside!")) + flash_mob(user) + forceMove(user.loc) + return COMPONENT_TRAITOR_MAIL_HANDLED + /obj/item/assembly/flash/attack(mob/living/target, mob/user) if(!try_use_flash(user)) return FALSE diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 0c122e7c851..0e4712288ee 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -53,6 +53,7 @@ /obj/item/assembly/signaler/Initialize(mapload) . = ..() set_frequency(frequency) + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) /obj/item/assembly/signaler/Destroy() SSradio.remove_object(src,frequency) @@ -181,6 +182,12 @@ radio_connection = SSradio.add_object(src, frequency, RADIO_SIGNALER) return +/obj/item/assembly/signaler/proc/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + to_chat(user, span_danger("As you open [letter], you accidentally press a button on [src]!")) + INVOKE_ASYNC(src, PROC_REF(signal)) // No need to check for cooldown, the cooldown is shorter than the do_after for opening mail + return NONE //don't return handled, we want in hands and open ui + /obj/item/assembly/signaler/cyborg /obj/item/assembly/signaler/cyborg/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) diff --git a/code/modules/clothing/gloves/boxing.dm b/code/modules/clothing/gloves/boxing.dm index 9b3c54b901d..60f097eddaa 100644 --- a/code/modules/clothing/gloves/boxing.dm +++ b/code/modules/clothing/gloves/boxing.dm @@ -9,6 +9,8 @@ equip_sound = 'sound/items/equip/glove_equip.ogg' /// Determines the version of boxing (or any martial art for that matter) that the boxing gloves gives var/style_to_give = /datum/martial_art/boxing + /// Specifically for whether they get longer knockdown when they jump out of traitor mail + var/extrapower = FALSE /obj/item/clothing/gloves/boxing/Initialize(mapload) . = ..() @@ -21,12 +23,24 @@ AddComponent(/datum/component/martial_art_giver, style_to_give) AddElement(/datum/element/adjust_fishing_difficulty, 19) + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) + +/obj/item/clothing/gloves/boxing/proc/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + to_chat(user, span_danger("As you open [letter], boxing gloves spring out and deliver you a swift uppercut!")) + var/mob/living/userasliving = user + playsound(user, SFX_PUNCH, 25, TRUE) + userasliving.Knockdown((extrapower ? 2 : 4) SECONDS, (extrapower ? 4 : 6) SECONDS) + userasliving.adjust_stamina_loss(extrapower ? 40 : 80) + forceMove(user.loc) + return COMPONENT_TRAITOR_MAIL_HANDLED /obj/item/clothing/gloves/boxing/evil name = "evil boxing gloves" desc = "These strange gloves radiate an unusually evil aura." greyscale_colors = "#21211f" style_to_give = /datum/martial_art/boxing/evil + extrapower = TRUE /obj/item/clothing/gloves/boxing/green icon_state = "boxinggreen" @@ -48,6 +62,7 @@ material_flags = MATERIAL_EFFECTS | MATERIAL_AFFECT_STATISTICS equip_delay_other = 12 SECONDS resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE + extrapower = TRUE /obj/item/clothing/gloves/boxing/golden/Initialize(mapload) . = ..() diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 4e4a616a005..b06e9ab1fbc 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -43,6 +43,7 @@ AddElement(/datum/element/muffles_speech) RegisterSignal(src, COMSIG_LIVING_TRYING_TO_PULL, PROC_REF(react_to_mob)) + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) /obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) ..() @@ -294,6 +295,14 @@ return TRUE return FALSE +/obj/item/clothing/mask/facehugger/proc/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + if(stat != CONSCIOUS) + return NONE + to_chat(user, span_danger("There's something moving inside of \the [letter]!")) + Leap(user) + return COMPONENT_TRAITOR_MAIL_HANDLED + /obj/item/clothing/mask/facehugger/lamarr name = "Lamarr" desc = "The Research Director's pet, a domesticated and debeaked xenomorph facehugger. Friendly, but may still try to couple with your head." diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index d998760b601..0f93174325c 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -110,6 +110,9 @@ var/pb_knockback = 0 + /// What this gun says when it's gonna shoot inside mail. + var/about_to_shoot_inside_mail_text = "Its trigger is already pulled!" + /// Cooldown for the visible message sent from gun flipping. COOLDOWN_DECLARE(flip_cooldown) @@ -121,6 +124,7 @@ add_seclight_point() add_bayonet_point() + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) /obj/item/gun/Destroy() if(isobj(pin)) //Can still be the initial path, then we skip @@ -713,5 +717,21 @@ /obj/item/gun/proc/before_firing(atom/target,mob/user) return +/obj/item/gun/proc/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(fire_at_opener), user, letter) + return COMPONENT_TRAITOR_MAIL_HANDLED + +/obj/item/gun/proc/fire_at_opener(mob/user, obj/item/mail/traitor/letter) + if(!user.put_in_hands(src)) //this won't ever fail under normal circumstances, but will happen with the admin versions + forceMove(user.loc) + to_chat(user, span_danger("As you open [letter], you see [src] inside! [about_to_shoot_inside_mail_text]")) + if(!can_shoot()) + shoot_with_empty_chamber(user) + return + if(process_fire(user, user, FALSE, zone_override = BODY_ZONE_HEAD)) + forceMove(user.loc) + throw_at(pick(get_step(user, user.dir)), 1, 3) + #undef FIRING_PIN_REMOVAL_DELAY #undef DUALWIELD_PENALTY_EXTRA_MULTIPLIER diff --git a/code/modules/projectiles/guns/ballistic/bows/_bow.dm b/code/modules/projectiles/guns/ballistic/bows/_bow.dm index 69399c71138..fa14d0df3d6 100644 --- a/code/modules/projectiles/guns/ballistic/bows/_bow.dm +++ b/code/modules/projectiles/guns/ballistic/bows/_bow.dm @@ -23,6 +23,7 @@ click_on_low_ammo = FALSE must_hold_to_load = TRUE trigger_guard = TRIGGER_GUARD_ALLOW_ALL + about_to_shoot_inside_mail_text = "Its bowstring is pulled back!" /// whether the bow is drawn back var/drawn = FALSE diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index ac7abb4c024..444d726dac9 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -369,6 +369,11 @@ shoot_self(user, check_zone(user.zone_selected)) return . +/obj/item/gun/ballistic/revolver/russian/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + if((get_ammo(FALSE, FALSE) > 1) || (get_ammo(TRUE, TRUE) < 6)) + return NONE + return ..() + /// Called after successfully(if you can call it that) shooting ourselves /obj/item/gun/ballistic/revolver/russian/proc/shoot_self(mob/living/carbon/human/user, affecting = BODY_ZONE_HEAD) user.add_mood_event( diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index db6567e2767..770992e4dff 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -98,7 +98,7 @@ return FALSE return ..() -/obj/item/gun/ballistic/rifle/boltaction/process_fire(mob/user) +/obj/item/gun/ballistic/rifle/boltaction/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) if(can_jam) if(chambered.loaded_projectile) if(prob(jamming_chance)) diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index cceeb6b547b..2119b904e92 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -13,6 +13,7 @@ clumsy_check = FALSE trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses magic instead pin = /obj/item/firing_pin/magic + about_to_shoot_inside_mail_text = "It's humming with energy!" /// If true, our fire sound gets lower as our charges decrease var/pitch_with_charges = TRUE /// What kind of magic is this diff --git a/code/modules/projectiles/guns/special/meat_hook.dm b/code/modules/projectiles/guns/special/meat_hook.dm index 302ebb435cf..35183e65b0f 100644 --- a/code/modules/projectiles/guns/special/meat_hook.dm +++ b/code/modules/projectiles/guns/special/meat_hook.dm @@ -42,6 +42,9 @@ removable.dismember(silent = FALSE) return BRUTELOSS +/obj/item/gun/magic/hook/on_mail_unwrap(mob/user, obj/item/mail/traitor/letter) + return NONE + /obj/item/ammo_casing/magic/hook name = "hook" desc = "A hook." diff --git a/code/modules/projectiles/guns/special/medbeam.dm b/code/modules/projectiles/guns/special/medbeam.dm index 45c9de8e186..290da403b83 100644 --- a/code/modules/projectiles/guns/special/medbeam.dm +++ b/code/modules/projectiles/guns/special/medbeam.dm @@ -93,6 +93,9 @@ if(current_target) on_beam_tick(current_target) +/obj/item/gun/medbeam/on_mail_unwrap(mob/user, obj/item/mail/traitor/letter) + return NONE + /obj/item/gun/medbeam/proc/mid_los_check(atom/movable/user, mob/target, pass_args = PASSTABLE|PASSGLASS|PASSGRILLE, turf/next_step, obj/dummy) for(var/obj/effect/ebeam/medical/B in next_step)// Don't cross the str-beams! if(QDELETED(current_beam)) diff --git a/code/modules/projectiles/guns/special/syringe_gun.dm b/code/modules/projectiles/guns/special/syringe_gun.dm index e17e9bb43ea..ca79d6d9800 100644 --- a/code/modules/projectiles/guns/special/syringe_gun.dm +++ b/code/modules/projectiles/guns/special/syringe_gun.dm @@ -225,6 +225,7 @@ force = 4 trigger_guard = TRIGGER_GUARD_ALLOW_ALL custom_materials = list(/datum/material/bamboo = SHEET_MATERIAL_AMOUNT * 10) + about_to_shoot_inside_mail_text = "The air in the envelope is rushing out!" /obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0) . = ..() diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 2aba2fd1c11..e2a849e650e 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -30,6 +30,7 @@ /obj/item/reagent_containers/spray/Initialize(mapload, vol) . = ..() AddElement(/datum/element/reagents_item_heatable) + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) /obj/item/reagent_containers/spray/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) return try_spray(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING @@ -150,6 +151,16 @@ log_combat(usr, usr.loc, "emptied onto", src, addition="which had [reagents.get_reagent_log_string()]") src.reagents.clear_reagents() +/obj/item/reagent_containers/spray/proc/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + if(reagents.total_volume < amount_per_transfer_from_this) + return + to_chat(user, span_danger("As you open [letter], a mist spritzes out from inside!")) + spray(user, user) + playsound(user, spray_sound, 50, TRUE, -6) + forceMove(user.loc) + return COMPONENT_TRAITOR_MAIL_HANDLED + /// Handles updating the spray distance when the reagents change. /obj/item/reagent_containers/spray/on_reagent_change(datum/reagents/holder, ...) . = ..() diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index e32b60e9a2b..4136687774e 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -33,6 +33,7 @@ dart_insert_projectile_icon_state, \ CALLBACK(src, PROC_REF(get_dart_var_modifiers))\ ) + RegisterSignal(src, COMSIG_ITEM_IN_UNWRAPPED_TRAITOR_MAIL, PROC_REF(on_mail_unwrap)) /obj/item/reagent_containers/syringe/proc/try_syringe(atom/target, mob/user) if(!target.reagents) @@ -193,6 +194,15 @@ "demolition_mod" = demolition_mod, ) +/obj/item/reagent_containers/syringe/proc/on_mail_unwrap(atom/source, mob/living/user, obj/item/mail/traitor/letter) + SIGNAL_HANDLER + if(!reagents.total_volume || !user.reagents || !user.try_inject(user, user.get_active_hand())) + return + to_chat(user, span_danger("As you open [letter], you prick yourself on a syringe inside!")) + reagents.trans_to(user, min(reagents.total_volume, 5)) + forceMove(user.loc) + return COMPONENT_TRAITOR_MAIL_HANDLED + /datum/embedding/syringe embed_chance = 85 fall_chance = 2 diff --git a/code/modules/research/anomaly/anomaly_core.dm b/code/modules/research/anomaly/anomaly_core.dm index 78e37bb9cf0..970673019ac 100644 --- a/code/modules/research/anomaly/anomaly_core.dm +++ b/code/modules/research/anomaly/anomaly_core.dm @@ -36,6 +36,9 @@ to_chat(user, span_notice("Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(frequency)], code [code].")) return ..() +/obj/item/assembly/signaler/anomaly/on_mail_unwrap(atom/source, mob/user, obj/item/mail/traitor/letter) + return NONE + //Anomaly cores /obj/item/assembly/signaler/anomaly/pyro name = "\improper pyroclastic anomaly core"