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
This commit is contained in:
Leland Kemble
2025-08-29 16:25:26 -04:00
committed by GitHub
parent 319bd8303a
commit 69f21ff997
2 changed files with 32 additions and 18 deletions

View File

@@ -4,8 +4,8 @@
/datum/component/bullet_intercepting /datum/component/bullet_intercepting
/// Chance to intercept a projectile /// Chance to intercept a projectile
var/block_chance var/block_chance
/// Type of bullet to intercept /// List of types of bullets to intercept
var/block_type var/list/block_type
/// Slots in which effect can be active /// Slots in which effect can be active
var/active_slots var/active_slots
/// Person currently wearing us /// Person currently wearing us
@@ -14,8 +14,10 @@
var/datum/callback/on_intercepted var/datum/callback/on_intercepted
/// Number of things we can block before we delete ourself (stop being able to block) /// Number of things we can block before we delete ourself (stop being able to block)
var/block_charges = INFINITY 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)) if (!isitem(parent))
return COMPONENT_INCOMPATIBLE return COMPONENT_INCOMPATIBLE
@@ -24,6 +26,7 @@
src.active_slots = active_slots src.active_slots = active_slots
src.on_intercepted = on_intercepted src.on_intercepted = on_intercepted
src.block_charges = block_charges 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_EQUIPPED, PROC_REF(on_parent_equipped))
RegisterSignal(parent, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_unequipped)) 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 /// 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) /datum/component/bullet_intercepting/proc/on_wearer_shot(mob/living/victim, obj/projectile/bullet)
SIGNAL_HANDLER SIGNAL_HANDLER
if (victim != wearer || victim.stat == DEAD || bullet.armor_flag != block_type) if(!isnull(is_blocking_check) && !is_blocking_check.Invoke())
return NONE return NONE
if (!prob(block_chance)) if (victim != wearer || victim.stat == DEAD || !prob(block_chance))
return NONE return NONE
on_intercepted?.Invoke(victim, bullet) for (var/blocktype in block_type)
block_charges-- if (bullet.armor_flag == blocktype)
if (block_charges <= 0) on_intercepted?.Invoke(victim, bullet)
qdel(src) block_charges--
return PROJECTILE_INTERRUPT_HIT if (block_charges <= 0)
qdel(src)
return PROJECTILE_INTERRUPT_HIT
return NONE
/// Called when wearer is deleted, stop tracking them /// Called when wearer is deleted, stop tracking them
/datum/component/bullet_intercepting/proc/on_wearer_deleted() /datum/component/bullet_intercepting/proc/on_wearer_deleted()

View File

@@ -237,6 +237,14 @@
/obj/item/flamethrower/Initialize(mapload) /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(create_full)
if(!weldtool) if(!weldtool)
weldtool = new /obj/item/weldingtool(src) weldtool = new /obj/item/weldingtool(src)
@@ -256,15 +264,15 @@
/obj/item/flamethrower/full/tank /obj/item/flamethrower/full/tank
create_with_tank = TRUE 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) /obj/item/flamethrower/proc/intercepted_bullet_reaction(mob/living/holder, obj/projectile/bullet)
if(damage && attack_type == PROJECTILE_ATTACK && damage_type != STAMINA && prob(15)) holder.visible_message(span_danger("\The [bullet] hits the fuel tank on [holder]'s [name], rupturing it! What a shot!"))
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(holder)
var/turf/target_turf = get_turf(owner) holder.log_message("held a flamethrower tank detonated by a projectile ([bullet])", LOG_GAME)
owner.log_message("held a flamethrower tank detonated by a projectile ([hitby])", LOG_GAME) igniter.ignite_turf(src,target_turf, release_amount = 100)
igniter.ignite_turf(src,target_turf, release_amount = 100) qdel(ptank)
qdel(ptank)
return 1 //It hit the flamethrower, not them
/obj/item/flamethrower/proc/check_tank()
return ptank
/obj/item/assembly/igniter/proc/flamethrower_process(turf/open/location) /obj/item/assembly/igniter/proc/flamethrower_process(turf/open/location)
location.hotspot_expose(heat,2) location.hotspot_expose(heat,2)