From 69f21ff99710c9f3bbcd3db4e809f5228e8436b5 Mon Sep 17 00:00:00 2001 From: Leland Kemble <70413276+lelandkemble@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:25:26 -0400 Subject: [PATCH] Replaces flamethrower unique hit_reaction handling with the bullet_intercepting component (#92731) ## About The Pull Request Flamethrower exploding when shot was handled by hit_reaction previously, and will now use the generic bullet_intercepting component. Also adds handling for multiple projectile types in the bullet_intercepting component, as well as a check for whether the object currently can block bullets. Should have no gameplay changes. ## Why It's Good For The Game closes #81863 , they said it'd be better consistency --- code/datums/components/bullet_intercepting.dm | 26 ++++++++++++------- code/game/objects/items/flamethrower.dm | 24 +++++++++++------ 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/code/datums/components/bullet_intercepting.dm b/code/datums/components/bullet_intercepting.dm index f327cae9543..53a2874f6d6 100644 --- a/code/datums/components/bullet_intercepting.dm +++ b/code/datums/components/bullet_intercepting.dm @@ -4,8 +4,8 @@ /datum/component/bullet_intercepting /// Chance to intercept a projectile var/block_chance - /// Type of bullet to intercept - var/block_type + /// List of types of bullets to intercept + var/list/block_type /// Slots in which effect can be active var/active_slots /// Person currently wearing us @@ -14,8 +14,10 @@ var/datum/callback/on_intercepted /// Number of things we can block before we delete ourself (stop being able to block) var/block_charges = INFINITY + /// Callback to check if the object is currently able to block + var/datum/callback/is_blocking_check -/datum/component/bullet_intercepting/Initialize(block_chance = 2, block_type = BULLET, active_slots, datum/callback/on_intercepted, block_charges = INFINITY) +/datum/component/bullet_intercepting/Initialize(block_chance = 2, list/block_type = list(BULLET), active_slots, datum/callback/on_intercepted, block_charges = INFINITY, datum/callback/is_blocking_check = null) . = ..() if (!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -24,6 +26,7 @@ src.active_slots = active_slots src.on_intercepted = on_intercepted src.block_charges = block_charges + src.is_blocking_check = is_blocking_check RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_parent_equipped)) RegisterSignal(parent, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_unequipped)) @@ -58,15 +61,18 @@ /// 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, obj/projectile/bullet) SIGNAL_HANDLER - if (victim != wearer || victim.stat == DEAD || bullet.armor_flag != block_type) + if(!isnull(is_blocking_check) && !is_blocking_check.Invoke()) return NONE - if (!prob(block_chance)) + if (victim != wearer || victim.stat == DEAD || !prob(block_chance)) return NONE - on_intercepted?.Invoke(victim, bullet) - block_charges-- - if (block_charges <= 0) - qdel(src) - return PROJECTILE_INTERRUPT_HIT + for (var/blocktype in block_type) + if (bullet.armor_flag == blocktype) + on_intercepted?.Invoke(victim, bullet) + block_charges-- + if (block_charges <= 0) + qdel(src) + return PROJECTILE_INTERRUPT_HIT + return NONE /// Called when wearer is deleted, stop tracking them /datum/component/bullet_intercepting/proc/on_wearer_deleted() diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm index d6cf9fd9336..b7da99fdfdb 100644 --- a/code/game/objects/items/flamethrower.dm +++ b/code/game/objects/items/flamethrower.dm @@ -237,6 +237,14 @@ /obj/item/flamethrower/Initialize(mapload) . = ..() + AddComponent(\ + /datum/component/bullet_intercepting,\ + block_chance = 15,\ + on_intercepted = CALLBACK(src, PROC_REF(intercepted_bullet_reaction)),\ + active_slots = ITEM_SLOT_HANDS,\ + block_type = list(BULLET,LASER),\ + is_blocking_check = CALLBACK(src, PROC_REF(check_tank)),\ + ) if(create_full) if(!weldtool) weldtool = new /obj/item/weldingtool(src) @@ -256,15 +264,15 @@ /obj/item/flamethrower/full/tank create_with_tank = TRUE -/obj/item/flamethrower/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) - if(damage && attack_type == PROJECTILE_ATTACK && damage_type != STAMINA && prob(15)) - owner.visible_message(span_danger("\The [attack_text] hits the fuel tank on [owner]'s [name], rupturing it! What a shot!")) - var/turf/target_turf = get_turf(owner) - owner.log_message("held a flamethrower tank detonated by a projectile ([hitby])", LOG_GAME) - igniter.ignite_turf(src,target_turf, release_amount = 100) - qdel(ptank) - return 1 //It hit the flamethrower, not them +/obj/item/flamethrower/proc/intercepted_bullet_reaction(mob/living/holder, obj/projectile/bullet) + holder.visible_message(span_danger("\The [bullet] hits the fuel tank on [holder]'s [name], rupturing it! What a shot!")) + var/turf/target_turf = get_turf(holder) + holder.log_message("held a flamethrower tank detonated by a projectile ([bullet])", LOG_GAME) + igniter.ignite_turf(src,target_turf, release_amount = 100) + qdel(ptank) +/obj/item/flamethrower/proc/check_tank() + return ptank /obj/item/assembly/igniter/proc/flamethrower_process(turf/open/location) location.hotspot_expose(heat,2)