From 4a779bb4b6a5ba94ae35faccf27a8d96f9eac02e Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 12 Jul 2023 05:59:06 +0200 Subject: [PATCH] [MIRROR] Bibles, Lighters, and Cowboy Hats can block bullets [MDB IGNORE] (#22282) * Bibles, Lighters, and Cowboy Hats can block bullets (#76521) ## About The Pull Request If you are wearing a bible or lighter in your suit slot, or a cowboy hat on your head, there is a small (2%) chance that bullets (only bullets, not lasers) will hit them instead of you. This destroys lighters, removes the storage capacity of the bible, or sends the hat flying off your head. The Bounty Hunter's cowboy hat has a significantly higher chance to intercept bullets. ## Why It's Good For The Game Adds some fun flavour to these items. ## Changelog :cl: add: A bible or lighter in your suit slot, or cowboy hat on your head will occasionally intercept a bullet. /:cl: * Bibles, Lighters, and Cowboy Hats can block bullets --------- Co-authored-by: Jacquerel Co-authored-by: Bloop --- code/__DEFINES/dcs/signals/signals_object.dm | 1 + code/datums/components/bullet_intercepting.dm | 67 ++++++++++++++++++ code/game/objects/items/cigs_lighters.dm | 15 ++++ .../fugitive/hunters/hunter_outfits.dm | 2 +- code/modules/clothing/head/hat.dm | 22 ++++++ code/modules/library/bibles.dm | 27 +++++++ code/modules/projectiles/projectile.dm | 4 +- icons/obj/storage/book.dmi | Bin 5727 -> 5865 bytes tgstation.dme | 1 + 9 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 code/datums/components/bullet_intercepting.dm diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index ab0fbc9d781..bb899492072 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -352,6 +352,7 @@ #define COMSIG_PROJECTILE_FIRE "projectile_fire" ///sent to targets during the process_hit proc of projectiles #define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" + #define PROJECTILE_INTERRUPT_HIT (1<<0) ///from the base of /obj/projectile/Range(): () #define COMSIG_PROJECTILE_RANGE "projectile_range" ///from the base of /obj/projectile/on_range(): () diff --git a/code/datums/components/bullet_intercepting.dm b/code/datums/components/bullet_intercepting.dm new file mode 100644 index 00000000000..151f748e8aa --- /dev/null +++ b/code/datums/components/bullet_intercepting.dm @@ -0,0 +1,67 @@ +/** + * Component which allows an equipped item to occasionally absorb a projectile. + */ +/datum/component/bullet_intercepting + /// Chance to intercept a projectile + var/block_chance + /// Type of bullet to intercept + var/block_type + /// Slots in which effect can be active + var/active_slots + /// Person currently wearing us + var/mob/wearer + /// Callback called when we catch a projectile + var/datum/callback/on_intercepted + +/datum/component/bullet_intercepting/Initialize(block_chance = 2, block_type = BULLET, active_slots, datum/callback/on_intercepted) + . = ..() + if (!isitem(parent)) + return COMPONENT_INCOMPATIBLE + src.block_chance = block_chance + src.block_type = block_type + src.active_slots = active_slots + src.on_intercepted = on_intercepted + + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_parent_equipped)) + RegisterSignal(parent, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_unequipped)) + +/datum/component/bullet_intercepting/Destroy(force, silent) + QDEL_NULL(on_intercepted) + return ..() + +/// Called when item changes slots, check if we're in a valid location to take bullets +/datum/component/bullet_intercepting/proc/on_parent_equipped(obj/item/clothing/source, mob/equipper, slot) + SIGNAL_HANDLER + if (wearer) + if (!(active_slots & slot)) + on_unequipped() + return + + if (!(active_slots & slot)) + return + RegisterSignal(equipper, COMSIG_PROJECTILE_PREHIT, PROC_REF(on_wearer_shot)) + RegisterSignal(equipper, COMSIG_QDELETING, PROC_REF(on_wearer_deleted)) + wearer = equipper + +/// Called when item is unequipped, stop tracking bullets +/datum/component/bullet_intercepting/proc/on_unequipped() + SIGNAL_HANDLER + if (!wearer) + return + UnregisterSignal(wearer, list(COMSIG_PROJECTILE_PREHIT, COMSIG_QDELETING)) + wearer = null + +/// Called when wearer is shot, check if we're going to block the hit +/datum/component/bullet_intercepting/proc/on_wearer_shot(mob/living/victim, list/signal_args, obj/projectile/bullet) + SIGNAL_HANDLER + if (victim != wearer || victim.stat == DEAD || bullet.armor_flag != block_type ) + return + if (!prob(block_chance)) + return + on_intercepted?.Invoke(victim, bullet) + return PROJECTILE_INTERRUPT_HIT + +/// Called when wearer is deleted, stop tracking them +/datum/component/bullet_intercepting/proc/on_wearer_deleted() + SIGNAL_HANDLER + wearer = null diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 264847e3cb6..e19824d09d4 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -740,8 +740,23 @@ CIGARETTE PACKETS ARE IN FANCY.DM . = ..() if(!overlay_state) overlay_state = pick(overlay_list) + AddComponent(\ + /datum/component/bullet_intercepting,\ + block_chance = 0.5,\ + active_slots = ITEM_SLOT_SUITSTORE,\ + on_intercepted = CALLBACK(src, PROC_REF(on_intercepted_bullet)),\ + ) update_appearance() +/// Destroy the lighter when it's shot by a bullet +/obj/item/lighter/proc/on_intercepted_bullet(mob/living/victim, obj/projectile/bullet) + victim.visible_message(span_warning("\The [bullet] shatters on [victim]'s lighter!")) + playsound(victim, get_sfx(SFX_RICOCHET), 100, TRUE) + new /obj/effect/decal/cleanable/oil(get_turf(src)) + do_sparks(1, TRUE, src) + victim.dropItemToGround(src, force = TRUE, silent = TRUE) + qdel(src) + /obj/item/lighter/cyborg_unequip(mob/user) if(!lit) return diff --git a/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm b/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm index 52de7ee46c0..395be958e5e 100644 --- a/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm +++ b/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm @@ -100,7 +100,7 @@ name = "Bounty Hunter - Armored" uniform = /obj/item/clothing/under/rank/prisoner back = /obj/item/storage/backpack - head = /obj/item/clothing/head/cowboy + head = /obj/item/clothing/head/cowboy/bounty suit = /obj/item/clothing/suit/space/hunter belt = /obj/item/gun/ballistic/automatic/pistol/fire_mag gloves = /obj/item/clothing/gloves/tackler/combat diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm index 373787abe03..a17d3fb3c83 100644 --- a/code/modules/clothing/head/hat.dm +++ b/code/modules/clothing/head/hat.dm @@ -99,6 +99,24 @@ inhand_icon_state = null armor_type = /datum/armor/head_cowboy resistance_flags = FIRE_PROOF | ACID_PROOF + /// Chance that the hat will catch a bullet for you + var/deflect_chance = 2 + +/obj/item/clothing/head/cowboy/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/bullet_intercepting,\ + block_chance = deflect_chance,\ + active_slots = ITEM_SLOT_HEAD,\ + on_intercepted = CALLBACK(src, PROC_REF(on_intercepted_bullet)),\ + ) + +/// When we catch a bullet, fling away +/obj/item/clothing/head/cowboy/proc/on_intercepted_bullet(mob/living/victim, obj/projectile/bullet) + victim.visible_message(span_warning("\The [bullet] sends [victim]'s hat flying!")) + victim.dropItemToGround(src, force = TRUE, silent = TRUE) + throw_at(get_edge_target_turf(loc, pick(GLOB.alldirs)), range = 3, speed = 3) + playsound(victim, get_sfx(SFX_RICOCHET), 100, TRUE) /datum/armor/head_cowboy melee = 5 @@ -106,6 +124,10 @@ laser = 5 energy = 15 +/// Bounty hunter's hat, very likely to intercept bullets +/obj/item/clothing/head/cowboy/bounty + deflect_chance = 50 + /obj/item/clothing/head/cowboy/black name = "desperado hat" desc = "People with ropes around their necks don't always hang." diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 5a22b95db17..ecf85954fef 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -77,12 +77,39 @@ GLOBAL_LIST_INIT(bibleitemstates, list( unique = TRUE /// Deity this bible is related to var/deity_name = "Space Jesus" + /// Component which catches bullets for us + var/datum/component/bullet_catcher /obj/item/book/bible/Initialize(mapload) . = ..() AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE_HOLY) + bullet_catcher = AddComponent(\ + /datum/component/bullet_intercepting,\ + active_slots = ITEM_SLOT_SUITSTORE,\ + on_intercepted = CALLBACK(src, PROC_REF(on_intercepted_bullet)),\ + ) carve_out() +/obj/item/book/bible/Destroy(force) + QDEL_NULL(bullet_catcher) + return ..() + +/// Destroy the bible when it's shot by a bullet +/obj/item/book/bible/proc/on_intercepted_bullet(mob/living/victim, obj/projectile/bullet) + victim.add_mood_event("blessing", /datum/mood_event/blessing) + playsound(victim, 'sound/magic/magic_block_holy.ogg', 50, TRUE) + victim.visible_message(span_warning("\The [src] takes \the [bullet] in [victim]'s place!")) + var/obj/structure/fluff/paper/stack/pages = new(get_turf(src)) + pages.dir = pick(GLOB.alldirs) + name = "punctured bible" + desc = "A memento of good luck, or perhaps divine intervention?" + icon_state = "shot" + if (!GLOB.bible_icon_state) + GLOB.bible_icon_state = "shot" // New symbol of your religion if you hadn't picked one + atom_storage?.remove_all(get_turf(src)) + QDEL_NULL(atom_storage) + QDEL_NULL(bullet_catcher) + /obj/item/book/bible/examine(mob/user) . = ..() if(deity_name) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index cb38fb684c2..7f53613a672 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -503,7 +503,9 @@ return process_hit(T, select_target(T, target, bumped), bumped, hit_something) // try to hit something else // at this point we are going to hit the thing // in which case send signal to it - SEND_SIGNAL(target, COMSIG_PROJECTILE_PREHIT, args) + if (SEND_SIGNAL(target, COMSIG_PROJECTILE_PREHIT, args, src) & PROJECTILE_INTERRUPT_HIT) + qdel(src) + return BULLET_ACT_BLOCK if(mode == PROJECTILE_PIERCE_HIT) ++pierces hit_something = TRUE diff --git a/icons/obj/storage/book.dmi b/icons/obj/storage/book.dmi index aff3dc7ddd387fa664fbb035e826707e424b3fe4..72cf214bd5b023c491c982655f32cc25fc00cfe6 100644 GIT binary patch delta 5624 zcmai22T)U6w?3f+kY1EtM5J5<1f(h?AP9H~f*`#L3IZaCfGFfpR1l>IUI8fqR7#X4 zRa!z5=~4sI4MjSd5J(8&kN^AUy}9?jnKyH0&$rghUVD{&*8cXMJF}{kA_L*CJk10F zmv9S>jpe7kR1gC5EnV&L+Abm)Xn=^8|QjFA4xO@SfeedOBW_6lT%!*qb2J*J!R#%b>{V~{+kAr7?9I_zmrckD1f2B@RYcO zH@XCFV0Ci*_T}RbeAB<8{Ont)_zy-#SAsscx!Oe^DJ#ICue#Bw*ROjzIy+Cw$S?sr zr09T6i8*eY5%wI*3Sgh|%khYcKFf&7 zqEcuABz)6^#ReZ#+#;Fbw)u7{URP%Igm@`@Xy}-6d4A=Bg8N;D1KN5%c9AKRtzui$ z3k;x=43yKJO-$HlYX>pFlZBw;xIOlYj{p{ zq|rU&8mFh3(6X$Fv|oDG-S2aPA5|(3vfrw`s43GnW*AUpE;R`_G)|w@$`t3bp(;;ve@;F7 zUBthuuA*pi1cAq0bWrEnV4Z5OInv<|Y;t>VZt|BOsd$LUmPk=Q3K#vejYnh`^fp@w z>b9t;l=(1qSX&d7D$DV@J&8JhV2EV;GAnTRV;@GMKOT?!M1l<#<~qXJC~J)J4vb$O zk3<5ew;D)Zn|JYuyn6(8U~X|?i$qPGXHC(NMfT5JIsk7;-g^v|#;E^3MYO zo!wpITelPdsl|3~D^ZbzG|$gcZwsNoSv?u1ZQOW4X=!4V?)(a<1$m76i%+MHhk=11 zkV3pQIjD%{r_w~Pc)AW_+arz$I+^gX2HLVrtCeY=>GlNo3swne+AzsTg((*6HF|ET0ed@7($f&-_s?3)^eEKrZbuR=JiHfASxh4rYjE$)r zHH8y0zI^!tA*S?em=gK z;$r!@u1s@T{l`r_&H>1%5l&97z4UXbhuyi~mb9|^fharM!%;<*^#U*FUJq<;Ogedy1g>`Ub<+woeO7S>9IBFUl=P&NgFJ!+jyW=rtzB3UM)WZT2-fRpjPkagqfZeLcswh^u z2tJcx+~_U+J^4-d1{dI?)`)+@xL2uCcWKzzG`ev;xL@*}A4GW{Qhbv^dB4<;aoFq1 z1@=*aD#iS&+v&$NAIDt18mO%8AarkptS3?1Ney_m2hAn-d&V@~cK(MlfcHEmg)Zy>wfLHU% z2uC&Johnr7puuUU=q^F&Mwk4UPFoQM=H@7aaj6IkX8XE>Xmfc%YQ#tv#TDnm=oRG> z0Aeo{;CNo9#z;k#Lwc@9bxyq-15(eoB5sCdv8lb}pwVJn+0^Z|!Zr?o%VWU!CT%k- zGH`kSIMOWp_4O$`aEf xEU_`TNZ?(pq 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