mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-15 03:52:43 +00:00
* spanish? * aaaagain * keep maptext * Update robot_items.dm * Update span_defines.dm * compiles * Update silicon_mob.dm * compile
415 lines
18 KiB
Plaintext
415 lines
18 KiB
Plaintext
/**
|
|
* A component for an item that attempts to defibrillate a mob when activated.
|
|
*/
|
|
|
|
#define DEFIB_TIME 5 SECONDS
|
|
|
|
/datum/component/defib
|
|
/// If this is being used by a borg or not, with necessary safeties applied if so.
|
|
var/robotic
|
|
/// If it should penetrate space suits
|
|
var/combat
|
|
/// If combat is true, this determines whether or not it should always cause a heart attack.
|
|
var/heart_attack_chance
|
|
/// Whether the safeties are enabled or not
|
|
var/safety
|
|
/// If the defib is actively performing a defib cycle
|
|
var/busy = FALSE
|
|
/// Cooldown length for this defib in deciseconds
|
|
var/cooldown
|
|
/// Whether or not we're currently on cooldown
|
|
var/on_cooldown = FALSE
|
|
/// How fast the defib should work.
|
|
var/speed_multiplier
|
|
/// If true, EMPs will have no effect.
|
|
var/emp_proof
|
|
/// If true, this cannot be emagged.
|
|
var/emag_proof
|
|
/// uid to an item that should be making noise and handling things that our direct parent shouldn't be concerned with.
|
|
var/actual_unit_uid
|
|
/// Sound for defib windup.
|
|
var/charge_sound = 'sound/machines/defib_charge.ogg'
|
|
/// Sound when the defib is successful.
|
|
var/success_sound = 'sound/machines/defib_success.ogg'
|
|
/// Sound when the defib fails.
|
|
var/fail_sound = 'sound/machines/defib_failed.ogg'
|
|
/// Sound when the defib shocks the patient.
|
|
var/zap_sound = 'sound/machines/defib_zap.ogg'
|
|
/// Sound when the defib's safety is enabled.
|
|
var/safety_on_sound = 'sound/machines/defib_saftyon.ogg'
|
|
/// Sound when the defib's safety is disabled.
|
|
var/safety_off_sound = 'sound/machines/defib_saftyoff.ogg'
|
|
|
|
/**
|
|
* Create a new defibrillation component.
|
|
*
|
|
* Arguments:
|
|
* * robotic - whether this should be treated like a borg module.
|
|
* * cooldown - Minimum time possible between shocks.
|
|
* * speed_multiplier - Speed multiplier for defib do-afters.
|
|
* * combat - If true, the defib can zap through hardsuits.
|
|
* * heart_attack_chance - If combat and safeties are off, the % chance for this to cause a heart attack on harm intent.
|
|
* * safe_by_default - If true, safety will be enabled by default.
|
|
* * emp_proof - If true, safety won't be switched by emp. Note that the device itself can still have behavior from it, it's just that the component will not.
|
|
* * emag_proof - If true, safety won't be switched by emag. Note that the device itself can still have behavior from it, it's just that the component will not.
|
|
* * actual_unit - Unit which the component's parent is based from, such as a large defib unit or a borg. The actual_unit will make the sounds and be the "origin" of visible messages, among other things.
|
|
*/
|
|
/datum/component/defib/Initialize(robotic, cooldown = 5 SECONDS, speed_multiplier = 1, combat = FALSE, heart_attack_chance = 100, safe_by_default = TRUE, emp_proof = FALSE, emag_proof = FALSE, obj/item/actual_unit = null)
|
|
if(!isitem(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
src.robotic = robotic
|
|
src.speed_multiplier = speed_multiplier
|
|
src.cooldown = cooldown
|
|
src.combat = combat
|
|
src.heart_attack_chance = heart_attack_chance
|
|
safety = safe_by_default
|
|
src.emp_proof = emp_proof
|
|
src.emag_proof = emag_proof
|
|
|
|
if(actual_unit)
|
|
actual_unit_uid = actual_unit.UID()
|
|
|
|
var/effect_target = isnull(actual_unit) ? parent : actual_unit
|
|
|
|
RegisterSignal(parent, COMSIG_ATTACK, PROC_REF(trigger_defib))
|
|
RegisterSignal(effect_target, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag))
|
|
RegisterSignal(effect_target, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp))
|
|
|
|
/**
|
|
* Get the "parent" that effects (emags, EMPs) should be applied onto.
|
|
*/
|
|
/datum/component/defib/proc/get_effect_target()
|
|
var/actual_unit = locateUID(actual_unit_uid)
|
|
if(!actual_unit)
|
|
return parent
|
|
return actual_unit
|
|
|
|
/datum/component/defib/proc/on_emp(obj/item/unit)
|
|
SIGNAL_HANDLER // COMSIG_ATOM_EMP_ACT
|
|
if(emp_proof)
|
|
return
|
|
|
|
if(safety)
|
|
safety = FALSE
|
|
unit.visible_message(SPAN_NOTICE("[unit] beeps: Safety protocols disabled!"))
|
|
playsound(get_turf(unit), safety_off_sound, 50, FALSE)
|
|
else
|
|
safety = TRUE
|
|
unit.visible_message(SPAN_NOTICE("[unit] beeps: Safety protocols enabled!"))
|
|
playsound(get_turf(unit), safety_on_sound, 50, FALSE)
|
|
|
|
/datum/component/defib/proc/on_emag(obj/item/unit, mob/user)
|
|
SIGNAL_HANDLER // COMSIG_ATOM_EMAG_ACT
|
|
if(emag_proof)
|
|
return
|
|
safety = !safety
|
|
if(user && !robotic)
|
|
to_chat(user, "<span class='warning'>You silently [safety ? "disable" : "enable"] [unit]'s safety protocols with the card.")
|
|
|
|
/datum/component/defib/proc/set_cooldown(how_short)
|
|
on_cooldown = TRUE
|
|
addtimer(CALLBACK(src, PROC_REF(end_cooldown)), how_short)
|
|
|
|
/datum/component/defib/proc/end_cooldown()
|
|
on_cooldown = FALSE
|
|
SEND_SIGNAL(parent, COMSIG_DEFIB_READY)
|
|
|
|
/**
|
|
* Start the defibrillation process when triggered by a signal.
|
|
*/
|
|
/datum/component/defib/proc/trigger_defib(obj/item/paddles, mob/living/carbon/human/target, mob/living/user)
|
|
SIGNAL_HANDLER // COMSIG_ATTACK
|
|
// This includes some do-afters, so we have to pass it off asynchronously
|
|
INVOKE_ASYNC(src, PROC_REF(defibrillate), user, target)
|
|
return TRUE
|
|
|
|
/**
|
|
* Perform a defibrillation.
|
|
*/
|
|
/datum/component/defib/proc/defibrillate(mob/living/user, mob/living/carbon/human/target)
|
|
// Before we do all the hard work, make sure we aren't already defibbing someone
|
|
if(busy)
|
|
return
|
|
|
|
var/parent_unit = locateUID(actual_unit_uid)
|
|
var/should_cause_harm = user.a_intent == INTENT_HARM && !safety
|
|
|
|
// Find what the defib should be referring to itself as
|
|
var/atom/defib_ref
|
|
if(parent_unit)
|
|
defib_ref = parent_unit
|
|
else if(robotic)
|
|
defib_ref = user
|
|
if(!defib_ref) // Contingency
|
|
defib_ref = parent
|
|
|
|
// Check what the unit itself has to say about how the defib went
|
|
var/application_result = SEND_SIGNAL(parent, COMSIG_DEFIB_PADDLES_APPLIED, user, target, should_cause_harm)
|
|
|
|
if(application_result & COMPONENT_BLOCK_DEFIB_DEAD)
|
|
user.visible_message(SPAN_NOTICE("[defib_ref] beeps: Unit is unpowered."))
|
|
playsound(get_turf(defib_ref), fail_sound, 50, FALSE)
|
|
return
|
|
|
|
if(on_cooldown)
|
|
to_chat(user, SPAN_NOTICE("[defib_ref] is recharging."))
|
|
return
|
|
|
|
if(application_result & COMPONENT_BLOCK_DEFIB_MISC)
|
|
return // The unit should handle this
|
|
|
|
if(!istype(target))
|
|
if(robotic)
|
|
to_chat(user, SPAN_NOTICE("This unit is only designed to work on humanoid lifeforms."))
|
|
else
|
|
to_chat(user, SPAN_NOTICE("The instructions on [defib_ref] don't mention how to defibrillate that..."))
|
|
return
|
|
|
|
if(should_cause_harm && combat && heart_attack_chance == 100)
|
|
combat_fibrillate(user, target)
|
|
SEND_SIGNAL(parent, COMSIG_DEFIB_SHOCK_APPLIED, user, target, should_cause_harm, TRUE)
|
|
busy = FALSE
|
|
return
|
|
|
|
if(should_cause_harm)
|
|
fibrillate(user, target)
|
|
SEND_SIGNAL(parent, COMSIG_DEFIB_SHOCK_APPLIED, user, target, should_cause_harm, TRUE)
|
|
return
|
|
|
|
user.visible_message(
|
|
SPAN_WARNING("[user] begins to place [parent] on [target]'s chest."),
|
|
SPAN_WARNING("You begin to place [parent] on [target.name]'s chest.")
|
|
)
|
|
|
|
busy = TRUE
|
|
var/mob/dead/observer/ghost = target.get_ghost()
|
|
if(ghost)
|
|
to_chat(ghost, "[SPAN_GHOSTALERT("Your heart is being defibrillated. Return to your body if you want to be revived!")] (Verbs -> Ghost -> Re-enter corpse)")
|
|
window_flash(ghost.client)
|
|
SEND_SOUND(ghost, sound('sound/effects/genetics.ogg'))
|
|
else if(HAS_TRAIT_FROM(target, TRAIT_FAKEDEATH, CHANGELING_TRAIT))
|
|
to_chat(target, SPAN_GHOSTALERT("Your heart is being defibrillated. Click the defibrillator status to be revived!"))
|
|
window_flash(target.client)
|
|
SEND_SOUND(target, sound('sound/effects/genetics.ogg'))
|
|
target.throw_alert("cling_defib", /atom/movable/screen/alert/changeling_defib_revive, alert_args = list(parent, target))
|
|
|
|
user.visible_message(SPAN_NOTICE("[user] places [parent] on [target]'s chest."), SPAN_WARNING("You place [parent] on [target]'s chest."))
|
|
playsound(get_turf(defib_ref), charge_sound, 50, FALSE)
|
|
|
|
if(ghost && !ghost.client && !QDELETED(ghost))
|
|
log_debug("Ghost of name [ghost.name] is bound to [target.real_name], but lacks a client. Deleting ghost.")
|
|
QDEL_NULL(ghost)
|
|
|
|
var/signal_result = SEND_SIGNAL(target, COMSIG_LIVING_PRE_DEFIB, user, parent, ghost)
|
|
|
|
if(!do_after(user, DEFIB_TIME * speed_multiplier, target = target)) // Placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
|
|
busy = FALSE
|
|
return
|
|
|
|
if(istype(target.wear_suit, /obj/item/clothing/suit/space) && !combat)
|
|
user.visible_message(SPAN_NOTICE("[defib_ref] buzzes: Patient's chest is obscured. Operation aborted."))
|
|
playsound(get_turf(defib_ref), fail_sound, 50, FALSE)
|
|
busy = FALSE
|
|
return
|
|
|
|
signal_result |= SEND_SIGNAL(target, COMSIG_LIVING_DEFIBBED, user, parent, ghost)
|
|
|
|
if(signal_result & COMPONENT_DEFIB_OVERRIDE)
|
|
// Let our signal handle it
|
|
busy = FALSE
|
|
return
|
|
|
|
if(target.undergoing_cardiac_arrest() && target.stat != DEAD) // Can have a heart attack and heart is either missing, necrotic, or not beating
|
|
var/datum/organ/heart/heart = target.get_int_organ_datum(ORGAN_DATUM_HEART)
|
|
if(!heart)
|
|
user.visible_message(SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Failed to pick up any heart electrical activity."))
|
|
else if(heart.linked_organ.status & ORGAN_DEAD)
|
|
user.visible_message(SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Heart necrosis detected."))
|
|
if(!heart || (heart.linked_organ.status & ORGAN_DEAD))
|
|
playsound(get_turf(defib_ref), fail_sound, 50, FALSE)
|
|
busy = FALSE
|
|
return
|
|
|
|
target.set_heartattack(FALSE)
|
|
SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK, 100)
|
|
SEND_SIGNAL(parent, COMSIG_DEFIB_SHOCK_APPLIED, user, target, should_cause_harm, TRUE)
|
|
set_cooldown(cooldown)
|
|
user.visible_message(SPAN_BOLDNOTICE("[defib_ref] pings: Cardiac arrhythmia corrected."))
|
|
target.visible_message(SPAN_WARNING("[target]'s body convulses a bit."), SPAN_USERDANGER("You feel a jolt, and your heartbeat seems to steady."))
|
|
playsound(get_turf(defib_ref), zap_sound, 50, TRUE, -1)
|
|
playsound(get_turf(defib_ref), "bodyfall", 50, TRUE)
|
|
playsound(get_turf(defib_ref), success_sound, 50, FALSE)
|
|
busy = FALSE
|
|
return
|
|
|
|
if(target.stat != DEAD && !HAS_TRAIT(target, TRAIT_FAKEDEATH))
|
|
user.visible_message(SPAN_NOTICE("[defib_ref] buzzes: Patient is not in a valid state. Operation aborted."))
|
|
playsound(get_turf(defib_ref), fail_sound, 50, FALSE)
|
|
busy = FALSE
|
|
return
|
|
|
|
target.visible_message(SPAN_WARNING("[target]'s body convulses a bit."))
|
|
playsound(get_turf(defib_ref), "bodyfall", 50, TRUE)
|
|
playsound(get_turf(defib_ref), zap_sound, 50, TRUE, -1)
|
|
ghost = target.get_ghost(TRUE) // We have to double check whether the dead guy has entered their body during the above
|
|
|
|
// Run through some quick failure states after shocking.
|
|
var/time_dead = world.time - target.timeofdeath
|
|
|
|
var/failure_message
|
|
if(!target.is_revivable())
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Heart tissue damage beyond point of no return for defibrillation.")
|
|
else if(target.getBruteLoss() >= 180 || target.getFireLoss() >= 180)
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Severe tissue damage detected.")
|
|
else if(HAS_TRAIT(target, TRAIT_HUSK))
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Subject is husked.")
|
|
else if(target.blood_volume < BLOOD_VOLUME_SURVIVE)
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Patient blood volume critically low.")
|
|
else if(!target.get_organ_slot("brain")) // So things like headless clings don't get outed
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - No brain detected within patient.")
|
|
else if(ghost)
|
|
if(!(ghost.ghost_flags & GHOST_CAN_REENTER) || target.suiciding) // DNR or AntagHUD
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - No electrical brain activity detected.")
|
|
else
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Patient's brain is unresponsive. Further attempts may succeed.")
|
|
else if(HAS_TRAIT(target, TRAIT_FAKEDEATH))
|
|
if(signal_result & COMPONENT_DEFIB_FAKEDEATH_DENIED)
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed - Patient's brain is unresponsive. Further attempts may succeed.")
|
|
else if(signal_result & COMPONENT_DEFIB_FAKEDEATH_ACCEPTED)
|
|
// as much as I hate that this is here, it has to come after the `Patient is not in a valid state. Operation aborted.` check.
|
|
REMOVE_TRAIT(target, TRAIT_FAKEDEATH, CHANGELING_TRAIT)
|
|
else
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed.") // has a fakedeath like capulettium
|
|
|
|
else if((signal_result & COMPONENT_BLOCK_DEFIB) || HAS_TRAIT(target, TRAIT_BADDNA) || target.suiciding) // these are a bit more arbitrary
|
|
failure_message = SPAN_BOLDNOTICE("[defib_ref] buzzes: Resuscitation failed.")
|
|
|
|
if(failure_message)
|
|
user.visible_message(failure_message)
|
|
playsound(get_turf(defib_ref), fail_sound, 50, FALSE)
|
|
else
|
|
// Heal each basic damage type by as much as we're under -100 health
|
|
var/damage_above_threshold = -(min(target.health, HEALTH_THRESHOLD_DEAD) - HEALTH_THRESHOLD_DEAD)
|
|
var/heal_amount = damage_above_threshold + 5
|
|
target.adjustOxyLoss(-heal_amount)
|
|
target.adjustToxLoss(-heal_amount)
|
|
target.adjustFireLoss(-heal_amount)
|
|
target.adjustBruteLoss(-heal_amount)
|
|
|
|
// Inflict some brain damage scaling with time spent dead
|
|
var/obj/item/organ/internal/brain/sponge = target.get_int_organ(/obj/item/organ/internal/brain)
|
|
var/defib_time_brain_damage = min(100 * time_dead / BASE_DEFIB_TIME_LIMIT, 99) // 20 from 1 minute onward, +20 per minute up to 99
|
|
if(time_dead > DEFIB_TIME_LOSS && defib_time_brain_damage > sponge.damage)
|
|
target.setBrainLoss(defib_time_brain_damage)
|
|
|
|
target.set_heartattack(FALSE)
|
|
target.update_revive()
|
|
target.KnockOut()
|
|
target.Paralyse(10 SECONDS)
|
|
target.emote("gasp")
|
|
|
|
// Check if the brain has more than a critical amount of brain damage
|
|
if(target.check_brain_threshold(BRAIN_DAMAGE_RATIO_CRITICAL))
|
|
// If you want to treat this with mannitol, it'll have to metabolize while the patient is alive, so it's alright to bring them back up for a minute
|
|
playsound(get_turf(defib_ref), safety_off_sound, 50, FALSE)
|
|
user.visible_message(SPAN_BOLDNOTICE("[defib_ref] chimes: Minimal brain activity detected, brain treatment recommended for full resuscitation."))
|
|
else
|
|
playsound(get_turf(defib_ref), success_sound, 50, FALSE)
|
|
|
|
user.visible_message(SPAN_BOLDNOTICE("[defib_ref] pings: Resuscitation successful."))
|
|
|
|
SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK, 100)
|
|
if(ishuman(target.pulledby)) // For some reason, pulledby isnt a list despite it being possible to be pulled by multiple people
|
|
excess_shock(user, target, target.pulledby, defib_ref)
|
|
for(var/obj/item/grab/G in target.grabbed_by)
|
|
if(ishuman(G.assailant))
|
|
excess_shock(user, target, G.assailant, defib_ref)
|
|
if(target.receiving_cpr_from)
|
|
var/mob/living/carbon/human/H = locateUID(target.receiving_cpr_from)
|
|
if(istype(H))
|
|
excess_shock(user, target, H, defib_ref)
|
|
|
|
target.med_hud_set_health()
|
|
target.med_hud_set_status()
|
|
add_attack_logs(user, target, "Revived with [defib_ref]")
|
|
SSblackbox.record_feedback("tally", "players_revived", 1, "defibrillator")
|
|
SEND_SIGNAL(parent, COMSIG_DEFIB_SHOCK_APPLIED, user, target, should_cause_harm, isnull(failure_message))
|
|
set_cooldown(cooldown)
|
|
busy = FALSE
|
|
|
|
/**
|
|
* Inflict stamina loss (and possibly inflict cardiac arrest) on someone.
|
|
*
|
|
* Arguments:
|
|
* * user - wielder of the defib
|
|
* * target - person getting shocked
|
|
*/
|
|
/datum/component/defib/proc/fibrillate(mob/user, mob/living/carbon/human/target)
|
|
if(!istype(target))
|
|
return
|
|
busy = TRUE
|
|
target.visible_message(SPAN_DANGER("[user] has touched [target] with [parent]!"), \
|
|
SPAN_USERDANGER("[user] touches you with [parent], and you feel a strong jolt!"))
|
|
target.apply_damage(60, STAMINA)
|
|
target.KnockDown(10 SECONDS)
|
|
playsound(get_turf(parent), zap_sound, 50, TRUE, -1)
|
|
target.emote("gasp")
|
|
if(combat && prob(heart_attack_chance))
|
|
target.set_heartattack(TRUE)
|
|
SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK, 100)
|
|
add_attack_logs(user, target, "Stunned with [parent]")
|
|
set_cooldown(cooldown)
|
|
busy = FALSE
|
|
|
|
/datum/component/defib/proc/combat_fibrillate(mob/user, mob/living/carbon/human/target)
|
|
if(!istype(target))
|
|
return
|
|
busy = TRUE
|
|
target.apply_damage(60, STAMINA)
|
|
target.emote("gasp")
|
|
add_attack_logs(user, target, "Stunned with [parent]")
|
|
target.KnockDown(4 SECONDS)
|
|
if(IS_HORIZONTAL(target) && HAS_TRAIT(target, TRAIT_HANDS_BLOCKED)) // Weakening exists which doesn't floor you while stunned
|
|
add_attack_logs(user, target, "Gave a heart attack with [parent]")
|
|
target.set_heartattack(TRUE)
|
|
target.visible_message(SPAN_DANGER("[user] has touched [target] with [parent]!"), \
|
|
SPAN_USERDANGER("[user] touches you with [parent], and you feel a strong jolt!"))
|
|
playsound(get_turf(parent), zap_sound, 50, TRUE, -1)
|
|
SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK, 100)
|
|
set_cooldown(cooldown)
|
|
return
|
|
target.visible_message(SPAN_DANGER("[user] touches [target] lightly with [parent]!"))
|
|
set_cooldown(2.5 SECONDS)
|
|
|
|
/*
|
|
* Pass excess shock from a defibrillation into someone else.
|
|
*
|
|
* Arguments:
|
|
* * user - The person using the defib
|
|
* * origin - The person the shock was originally applied to, the person being defibrillated
|
|
* * affecting - The person the shock is spreading to and negatively affecting.
|
|
* * cell_location - item holding the power source.
|
|
*/
|
|
/datum/component/defib/proc/excess_shock(mob/user, mob/living/origin, mob/living/carbon/human/affecting, obj/item/cell_location)
|
|
if(user == affecting)
|
|
return
|
|
var/power_source
|
|
if(robotic)
|
|
power_source = user
|
|
else
|
|
if(cell_location)
|
|
power_source = locate(/obj/item/stock_parts/cell) in cell_location
|
|
|
|
if(!power_source)
|
|
return
|
|
|
|
if(electrocute_mob(affecting, power_source, origin)) // shock anyone touching them >:)
|
|
var/datum/organ/heart/heart = affecting.get_int_organ_datum(ORGAN_DATUM_HEART)
|
|
if(heart.linked_organ.parent_organ == "chest" && affecting.has_both_hands()) // making sure the shock will go through their heart (drask hearts are in their head), and that they have both arms so the shock can cross their heart inside their chest
|
|
affecting.visible_message(SPAN_DANGER("[affecting]'s entire body shakes as a shock travels up [affecting.p_their()] arm!"), \
|
|
SPAN_USERDANGER("You feel a powerful shock travel up your [affecting.hand ? affecting.get_organ("l_arm") : affecting.get_organ("r_arm")] and back down your [affecting.hand ? affecting.get_organ("r_arm") : affecting.get_organ("l_arm")]!"))
|
|
affecting.set_heartattack(TRUE)
|
|
|
|
#undef DEFIB_TIME
|