Files
Bubberstation/code/datums/components/explodable.dm

173 lines
5.9 KiB
Plaintext

///Component specifically for explosion sensetive things, currently only applies to heat based explosions but can later perhaps be used for things that are dangerous to handle carelessly like nitroglycerin.
/datum/component/explodable
/// The devastation range of the resulting explosion.
var/devastation_range = 0
/// The heavy impact range of the resulting explosion.
var/heavy_impact_range = 0
/// The light impact range of the resulting explosion.
var/light_impact_range = 2
/// The flame range of the resulting explosion.
var/flame_range = 0
/// The flash range of the resulting explosion.
var/flash_range = 3
/// Whether this explosion ignores the bombcap.
var/uncapped
/// Whether we always delete. Useful for nukes turned plasma and such, so they don't default delete and can survive
var/delete_after
/// For items, lets us determine where things should be hit.
var/equipped_slot
/// Whether this component is currently in the process of exploding.
var/tmp/exploding = FALSE
/datum/component/explodable/Initialize(devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, uncapped = FALSE, delete_after = EXPLODABLE_DELETE_PARENT)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(explodable_attack))
RegisterSignal(parent, COMSIG_ATOM_EX_ACT, PROC_REF(detonate))
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_WELDER), PROC_REF(welder_react))
RegisterSignal(parent, COMSIG_ATOM_BULLET_ACT, PROC_REF(projectile_react))
if(ismovable(parent))
RegisterSignal(parent, COMSIG_MOVABLE_IMPACT, PROC_REF(explodable_impact))
RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(explodable_bump))
if(isitem(parent))
RegisterSignals(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_ATOM, COMSIG_ITEM_HIT_REACT), PROC_REF(explodable_attack))
if(isclothing(parent))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
var/atom/atom_parent = parent
if(atom_parent.atom_storage)
RegisterSignal(parent, COMSIG_ATOM_ENTERED, PROC_REF(explodable_insert_item))
if (devastation_range)
src.devastation_range = devastation_range
if (heavy_impact_range)
src.heavy_impact_range = heavy_impact_range
if (light_impact_range)
src.light_impact_range = light_impact_range
if (flame_range)
src.flame_range = flame_range
if (flash_range)
src.flash_range = flash_range
src.uncapped = uncapped
src.delete_after = delete_after
/// Explode if our parent is a storage place and something with high heat is inserted in.
/datum/component/explodable/proc/explodable_insert_item(datum/source, obj/item/I)
SIGNAL_HANDLER
if(!(I.item_flags & IN_STORAGE))
return
check_if_detonate(I)
/datum/component/explodable/proc/explodable_impact(datum/source, atom/hit_atom, datum/thrownthing/throwing_datum, caught)
SIGNAL_HANDLER
if(!caught)
check_if_detonate(hit_atom)
/datum/component/explodable/proc/explodable_bump(datum/source, atom/A)
SIGNAL_HANDLER
check_if_detonate(A)
///Called when you use this object to attack sopmething
/datum/component/explodable/proc/explodable_attack(datum/source, atom/movable/target, mob/living/user)
SIGNAL_HANDLER
check_if_detonate(target)
/// Welder check. Here because tool_act is higher priority than attackby.
/datum/component/explodable/proc/welder_react(datum/source, mob/user, obj/item/tool)
SIGNAL_HANDLER
if(check_if_detonate(tool))
return ITEM_INTERACT_BLOCKING
/// Shot by something
/datum/component/explodable/proc/projectile_react(datum/source, obj/projectile/shot)
SIGNAL_HANDLER
if(shot.damage_type == BURN && shot.damage > 0)
detonate()
///Called when you attack a specific body part of the thing this is equipped on. Useful for exploding pants.
/datum/component/explodable/proc/explodable_attack_zone(datum/source, damage, damagetype, def_zone, ...)
SIGNAL_HANDLER
if(!def_zone)
return
if(damagetype != BURN) //Don't bother if it's not fire.
return
if(isbodypart(def_zone))
var/obj/item/bodypart/hitting = def_zone
def_zone = hitting.body_zone
if(!is_hitting_zone(def_zone)) //You didn't hit us! ha!
return
detonate()
/datum/component/explodable/proc/on_equip(datum/source, mob/equipper, slot)
SIGNAL_HANDLER
RegisterSignal(equipper, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(explodable_attack_zone), TRUE)
/datum/component/explodable/proc/on_drop(datum/source, mob/user)
SIGNAL_HANDLER
UnregisterSignal(user, COMSIG_MOB_APPLY_DAMAGE)
/// Checks if we're hitting the zone this component is covering
/datum/component/explodable/proc/is_hitting_zone(def_zone)
var/obj/item/item = parent
var/mob/living/carbon/wearer = item.loc //Get whoever is equipping the item currently
if(!istype(wearer))
return FALSE
var/list/worn_items = wearer.get_equipped_items()
if(!(item in worn_items))
return FALSE
if(item.body_parts_covered & def_zone)
return TRUE
return FALSE
/datum/component/explodable/proc/check_if_detonate(target)
if(!isitem(target))
return
var/obj/item/I = target
if(I.get_temperature() > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
detonate() //If we're touching a hot item we go boom
return TRUE
/// Explode and remove the object
/datum/component/explodable/proc/detonate()
SIGNAL_HANDLER
if (exploding)
return // If we don't do this and this doesn't delete it can lock the MC into only processing Input, Timers, and Explosions.
var/atom/bomb = parent
var/do_log = light_impact_range >= 1
exploding = TRUE
explosion(bomb, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, do_log, uncapped) //epic explosion time
switch(delete_after)
if(EXPLODABLE_DELETE_SELF)
qdel(src)
if(EXPLODABLE_DELETE_PARENT)
if(isobj(bomb))
var/obj/obj_bomb = bomb
obj_bomb.deconstruct(disassembled = FALSE)
else
qdel(bomb)
else
addtimer(CALLBACK(src, PROC_REF(reset_exploding)), 0.1 SECONDS)
/**
* Resets the expoding flag
*/
/datum/component/explodable/proc/reset_exploding()
SIGNAL_HANDLER
src.exploding = FALSE