Files
Bubberstation/code/game/objects/items/defib.dm
nikothedude ccf547c142 Adds an extra malf AI ability: Remote emagging. Also tidies up emag code and coverts a lot of things to balloon alerts (#76669)
## About The Pull Request

New malf AI upgrade

Remote safety overrides: Mid-cost, Mid-supply. Allows the AI to remotely
emag things it can see and can access.
1. Very useful for psychological warfare (Emagging APCs to throw the
crew off their trail)
2. Logically makes sense - why, of all things, can the AI not emag
anything when it's fundumentally integrated with the station's
electronics?
3. Generally speaking can only access things that make sense for it to
access - it cannot emag ethereals, sadly

In order for this to work, emag_act now returns a boolean, designating
if the emag had any effect.
While I was in there, I also added args to every single emag_act I could
find and added far more feedback/converted a lot of things to balloon
alerts to allow the AI to see if its emag had any effect.
## Why It's Good For The Game

It just makes sense that the AI, the most electronically-sensitive
entity in the game, would be able to emag things. Plus, more options
given to malf that aren't strictly MURDER KILL MURDER are always a plus,
especially if they allow for fancier plays.
## Changelog
🆑
add: New malf ability: Remote safety overrides. Allows the AI to
remotely emag things it has access to.
code: emag_act() now returns a boolean designating it's success in
emagging
code: All instances of emag_act() now have the proper arguments
qol: Most usecases of emagging now have some kind of feedback, and
existing feedback has been sanity checked and converted to balloon
alerts.
/🆑
2023-07-15 15:35:14 +01:00

721 lines
25 KiB
Plaintext

//backpack item
#define HALFWAYCRITDEATH ((HEALTH_THRESHOLD_CRIT + HEALTH_THRESHOLD_DEAD) * 0.5)
#define DEFIB_CAN_HURT(source) (source.combat || (source.req_defib && !source.defib.safety))
/obj/item/defibrillator
name = "defibrillator"
desc = "A device that delivers powerful shocks to detachable paddles that resuscitate incapacitated patients. \
Has a rear bracket for attachments to wall mounts and medical cyborgs."
icon = 'icons/obj/medical/defib.dmi'
icon_state = "defibunit"
inhand_icon_state = "defibunit"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
slot_flags = ITEM_SLOT_BACK
force = 5
throwforce = 6
w_class = WEIGHT_CLASS_BULKY
actions_types = list(/datum/action/item_action/toggle_paddles)
armor_type = /datum/armor/item_defibrillator
var/obj/item/shockpaddles/paddle_type = /obj/item/shockpaddles
/// If the paddles are equipped (1) or on the defib (0)
var/on = FALSE
/// If you can zap people with the defibs on harm mode
var/safety = TRUE
/// If there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise
var/powered = FALSE
/// If the cell can be removed via screwdriver
var/cell_removable = TRUE
var/obj/item/shockpaddles/paddles
var/obj/item/stock_parts/cell/high/cell
/// If true, revive through space suits, allow for combat shocking
var/combat = FALSE
/// How long does it take to recharge
var/cooldown_duration = 5 SECONDS
/// The icon state for the paddle overlay, not applied if null
var/paddle_state = "defibunit-paddles"
/// The icon state for the powered on overlay, not applied if null
var/powered_state = "defibunit-powered"
/// The icon state for the charge bar overlay, not applied if null
var/charge_state = "defibunit-charge"
/// The icon state for the missing cell overlay, not applied if null
var/nocell_state = "defibunit-nocell"
/// The icon state for the emagged overlay, not applied if null
var/emagged_state = "defibunit-emagged"
/datum/armor/item_defibrillator
fire = 50
acid = 50
/obj/item/defibrillator/get_cell()
return cell
/obj/item/defibrillator/Initialize(mapload) //starts without a cell for rnd
. = ..()
paddles = new paddle_type(src)
update_power()
RegisterSignal(paddles, COMSIG_DEFIBRILLATOR_SUCCESS, PROC_REF(on_defib_success))
/obj/item/defibrillator/loaded/Initialize(mapload) //starts with hicap
. = ..()
cell = new(src)
update_power()
/obj/item/defibrillator/examine(mob/user)
. = ..()
if(!cell_removable)
return
if(cell)
. += span_notice("Use a screwdriver to remove the cell.")
else
. += span_warning("It has no power cell!")
/obj/item/defibrillator/fire_act(exposed_temperature, exposed_volume)
. = ..()
if(paddles?.loc == src)
paddles.fire_act(exposed_temperature, exposed_volume)
/obj/item/defibrillator/extinguish()
. = ..()
if(paddles?.loc == src)
paddles.extinguish()
/obj/item/defibrillator/proc/update_power()
if(!QDELETED(cell))
if(QDELETED(paddles) || cell.charge < paddles.revivecost)
powered = FALSE
else
powered = TRUE
else
powered = FALSE
update_appearance()
if(istype(loc, /obj/machinery/defibrillator_mount))
loc.update_appearance()
/obj/item/defibrillator/update_overlays()
. = ..()
if(!on && paddle_state)
. += paddle_state
if(powered && powered_state)
. += powered_state
if(!QDELETED(cell) && charge_state)
var/ratio = cell.charge / cell.maxcharge
ratio = CEILING(ratio*4, 1) * 25
. += "[charge_state][ratio]"
if(!cell && nocell_state)
. += "[nocell_state]"
if(!safety && emagged_state)
. += emagged_state
/obj/item/defibrillator/CheckParts(list/parts_list)
..()
cell = locate(/obj/item/stock_parts/cell) in contents
update_power()
/obj/item/defibrillator/ui_action_click()
INVOKE_ASYNC(src, PROC_REF(toggle_paddles))
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/defibrillator/attack_hand(mob/user, list/modifiers)
if(loc == user)
if(slot_flags & ITEM_SLOT_BACK)
if(user.get_item_by_slot(ITEM_SLOT_BACK) == src)
ui_action_click()
else
to_chat(user, span_warning("Put the defibrillator on your back first!"))
else if(slot_flags & ITEM_SLOT_BELT)
if(user.get_item_by_slot(ITEM_SLOT_BELT) == src)
ui_action_click()
else
to_chat(user, span_warning("Strap the defibrillator's belt on first!"))
return
else if(istype(loc, /obj/machinery/defibrillator_mount))
ui_action_click() //checks for this are handled in defibrillator.mount.dm
return ..()
/obj/item/defibrillator/MouseDrop(obj/over_object)
. = ..()
if(ismob(loc))
var/mob/M = loc
if(!M.incapacitated() && istype(over_object, /atom/movable/screen/inventory/hand))
var/atom/movable/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
/obj/item/defibrillator/screwdriver_act(mob/living/user, obj/item/tool)
if(!cell || !cell_removable)
return FALSE
cell.update_appearance()
cell.forceMove(get_turf(src))
balloon_alert(user, "removed [cell]")
cell = null
tool.play_tool_sound(src, 50)
update_power()
return TRUE
/obj/item/defibrillator/attackby(obj/item/W, mob/user, params)
if(W == paddles)
toggle_paddles()
else if(istype(W, /obj/item/stock_parts/cell))
var/obj/item/stock_parts/cell/C = W
if(cell)
to_chat(user, span_warning("[src] already has a cell!"))
else
if(C.maxcharge < paddles.revivecost)
to_chat(user, span_notice("[src] requires a higher capacity cell."))
return
if(!user.transferItemToLoc(W, src))
return
cell = W
to_chat(user, span_notice("You install a cell in [src]."))
update_power()
else
return ..()
/obj/item/defibrillator/emag_act(mob/user, obj/item/card/emag/emag_card)
safety = !safety
var/enabled_or_disabled = (safety ? "enabled" : "disabled")
balloon_alert(user, "safety protocols [enabled_or_disabled]")
return TRUE
/obj/item/defibrillator/emp_act(severity)
. = ..()
if(cell && !(. & EMP_PROTECT_CONTENTS))
deductcharge(1000 / severity)
if (. & EMP_PROTECT_SELF)
return
update_power()
/obj/item/defibrillator/proc/toggle_paddles()
set name = "Toggle Paddles"
set category = "Object"
on = !on
var/mob/living/carbon/user = usr
if(on)
//Detach the paddles into the user's hands
if(!usr.put_in_hands(paddles))
on = FALSE
to_chat(user, span_warning("You need a free hand to hold the paddles!"))
update_power()
return
else
//Remove from their hands and back onto the defib unit
remove_paddles(user)
update_power()
update_item_action_buttons()
/obj/item/defibrillator/equipped(mob/user, slot)
..()
if(!(slot_flags & slot))
remove_paddles(user)
update_power()
/obj/item/defibrillator/item_action_slot_check(slot, mob/user)
if(slot_flags & slot)
return TRUE
/obj/item/defibrillator/proc/remove_paddles(mob/user) //this fox the bug with the paddles when other player stole you the defib when you have the paddles equiped
if(ismob(paddles.loc))
var/mob/M = paddles.loc
M.dropItemToGround(paddles, TRUE)
return
/obj/item/defibrillator/Destroy()
if(on)
var/M = get(paddles, /mob)
remove_paddles(M)
QDEL_NULL(paddles)
QDEL_NULL(cell)
return ..()
/obj/item/defibrillator/proc/deductcharge(chrgdeductamt)
if(cell)
if(cell.charge < (paddles.revivecost+chrgdeductamt))
powered = FALSE
update_power()
if(cell.use(chrgdeductamt))
update_power()
return TRUE
else
return FALSE
/obj/item/defibrillator/proc/cooldowncheck()
addtimer(CALLBACK(src, PROC_REF(finish_charging)), cooldown_duration)
/obj/item/defibrillator/proc/finish_charging()
if(cell)
if(cell.charge >= paddles.revivecost)
visible_message(span_notice("[src] beeps: Unit ready."))
playsound(src, 'sound/machines/defib_ready.ogg', 50, FALSE)
else
visible_message(span_notice("[src] beeps: Charge depleted."))
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
paddles.cooldown = FALSE
paddles.update_appearance()
update_power()
/obj/item/defibrillator/proc/on_defib_success(obj/item/shockpaddles/source)
deductcharge(source.revivecost)
source.cooldown = TRUE
cooldowncheck()
return COMPONENT_DEFIB_STOP
/obj/item/defibrillator/compact
name = "compact defibrillator"
desc = "A belt-equipped defibrillator that can be rapidly deployed."
icon_state = "defibcompact"
inhand_icon_state = null
worn_icon_state = "defibcompact"
w_class = WEIGHT_CLASS_NORMAL
slot_flags = ITEM_SLOT_BELT
paddle_state = "defibcompact-paddles"
powered_state = "defibcompact-powered"
charge_state = "defibcompact-charge"
nocell_state = "defibcompact-nocell"
emagged_state = "defibcompact-emagged"
/obj/item/defibrillator/compact/item_action_slot_check(slot, mob/user)
if(slot & user.getBeltSlot())
return TRUE
/obj/item/defibrillator/compact/loaded/Initialize(mapload)
. = ..()
cell = new(src)
update_power()
/obj/item/defibrillator/compact/combat
name = "combat defibrillator"
desc = "A belt-equipped blood-red defibrillator. Can revive through thick clothing, has an experimental self-recharging battery, and can be utilized in combat via applying the paddles in a disarming or aggressive manner."
icon_state = "defibcombat" //needs defib inhand sprites
inhand_icon_state = null
worn_icon_state = "defibcombat"
combat = TRUE
safety = FALSE
cooldown_duration = 2.5 SECONDS
paddle_type = /obj/item/shockpaddles/syndicate
paddle_state = "defibcombat-paddles"
powered_state = null
emagged_state = null
/obj/item/defibrillator/compact/combat/loaded
cell_removable = FALSE // Don't let people just have an infinite power cell
/obj/item/defibrillator/compact/combat/loaded/Initialize(mapload)
. = ..()
cell = new /obj/item/stock_parts/cell/infinite(src)
update_power()
/obj/item/defibrillator/compact/combat/loaded/attackby(obj/item/W, mob/user, params)
if(W == paddles)
toggle_paddles()
return
/obj/item/defibrillator/compact/combat/loaded/nanotrasen
name = "elite Nanotrasen defibrillator"
desc = "A belt-equipped state-of-the-art defibrillator. Can revive through thick clothing, has an experimental self-recharging battery, and can be utilized in combat via applying the paddles in a disarming or aggressive manner."
icon_state = "defibnt" //needs defib inhand sprites
inhand_icon_state = null
worn_icon_state = "defibnt"
paddle_type = /obj/item/shockpaddles/syndicate/nanotrasen
paddle_state = "defibnt-paddles"
//paddles
/obj/item/shockpaddles
name = "defibrillator paddles"
desc = "A pair of plastic-gripped paddles with flat metal surfaces that are used to deliver powerful electric shocks."
icon = 'icons/obj/medical/defib.dmi'
icon_state = "defibpaddles0"
inhand_icon_state = "defibpaddles0"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
force = 0
throwforce = 6
w_class = WEIGHT_CLASS_BULKY
resistance_flags = INDESTRUCTIBLE
base_icon_state = "defibpaddles"
var/revivecost = 1000
var/cooldown = FALSE
var/busy = FALSE
var/obj/item/defibrillator/defib
var/req_defib = TRUE // Whether or not the paddles require a defibrilator object
var/recharge_time = 6 SECONDS // Only applies to defibs that do not require a defibrilator. See: do_success()
var/combat = FALSE //If it penetrates armor and gives additional functionality
/obj/item/shockpaddles/Initialize(mapload)
. = ..()
AddElement(/datum/element/update_icon_updates_onmob, ITEM_SLOT_BACK)
AddComponent(/datum/component/two_handed, force_unwielded=8, force_wielded=12)
/obj/item/shockpaddles/Destroy()
defib = null
return ..()
/obj/item/shockpaddles/equipped(mob/user, slot)
. = ..()
if(!req_defib)
return
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(check_range))
/obj/item/shockpaddles/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
. = ..()
check_range()
/obj/item/shockpaddles/fire_act(exposed_temperature, exposed_volume)
. = ..()
if((req_defib && defib) && loc != defib)
defib.fire_act(exposed_temperature, exposed_volume)
/obj/item/shockpaddles/proc/check_range()
SIGNAL_HANDLER
if(!req_defib || !defib)
return
if(!in_range(src,defib))
if(isliving(loc))
var/mob/living/user = loc
to_chat(user, span_warning("[defib]'s paddles overextend and come out of your hands!"))
else
visible_message(span_notice("[src] snap back into [defib]."))
snap_back()
/obj/item/shockpaddles/proc/recharge(time = 0)
if(req_defib)
return
cooldown = TRUE
update_appearance()
addtimer(CALLBACK(src, PROC_REF(finish_recharge)), time)
/obj/item/shockpaddles/proc/finish_recharge()
var/turf/current_turf = get_turf(src)
current_turf.audible_message(span_notice("[src] beeps: Unit is recharged."))
playsound(src, 'sound/machines/defib_ready.ogg', 50, FALSE)
cooldown = FALSE
update_appearance()
/obj/item/shockpaddles/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NO_STORAGE_INSERT, TRAIT_GENERIC) //stops shockpaddles from being inserted in BoH
if(!req_defib)
return //If it doesn't need a defib, just say it exists
if (!loc || !istype(loc, /obj/item/defibrillator)) //To avoid weird issues from admin spawns
return INITIALIZE_HINT_QDEL
defib = loc
busy = FALSE
update_appearance()
/obj/item/shockpaddles/suicide_act(mob/living/user)
user.visible_message(span_danger("[user] is putting the live paddles on [user.p_their()] chest! It looks like [user.p_theyre()] trying to commit suicide!"))
if(req_defib)
defib.deductcharge(revivecost)
playsound(src, 'sound/machines/defib_zap.ogg', 50, TRUE, -1)
return OXYLOSS
/obj/item/shockpaddles/update_icon_state()
icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]"
inhand_icon_state = icon_state
if(cooldown)
icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]_cooldown"
return ..()
/obj/item/shockpaddles/dropped(mob/user)
. = ..()
if(user)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
if(req_defib)
if(user)
to_chat(user, span_notice("The paddles snap back into the main unit."))
snap_back()
/obj/item/shockpaddles/proc/snap_back()
if(!defib)
return
defib.on = FALSE
forceMove(defib)
defib.update_power()
/obj/item/shockpaddles/attack(mob/M, mob/living/user, params)
if(busy)
return
defib?.update_power()
if(req_defib && !defib.powered)
user.visible_message(span_warning("[defib] beeps: Not enough charge!"))
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
return
if(!HAS_TRAIT(src, TRAIT_WIELDED))
if(iscyborg(user))
to_chat(user, span_warning("You must activate the paddles in your active module before you can use them on someone!"))
else
to_chat(user, span_warning("You need to wield the paddles in both hands before you can use them on someone!"))
return
if(cooldown)
if(req_defib)
to_chat(user, span_warning("[defib] is recharging!"))
else
to_chat(user, span_warning("[src] are recharging!"))
return
var/list/modifiers = params2list(params)
if(LAZYACCESS(modifiers, RIGHT_CLICK))
do_disarm(M, user)
return
if(!iscarbon(M))
if(req_defib)
to_chat(user, span_warning("The instructions on [defib] don't mention how to revive that..."))
else
to_chat(user, span_warning("You aren't sure how to revive that..."))
return
var/mob/living/carbon/H = M
if(user.zone_selected != BODY_ZONE_CHEST)
to_chat(user, span_warning("You need to target your patient's chest with [src]!"))
return
if(user.combat_mode)
do_harm(H, user)
return
if(H.can_defib() == DEFIB_POSSIBLE)
H.notify_ghost_cloning("Your heart is being defibrillated!")
H.grab_ghost() // Shove them back in their body.
do_help(H, user)
/// Called whenever the paddles successfuly shock something
/obj/item/shockpaddles/proc/do_success()
if(busy)
busy = FALSE
update_appearance()
if(SEND_SIGNAL(src, COMSIG_DEFIBRILLATOR_SUCCESS) & COMPONENT_DEFIB_STOP)
return
recharge(recharge_time)
/// Called whenever the paddles fail to shock something after a do_x proc
/obj/item/shockpaddles/proc/do_cancel()
if(busy)
busy = FALSE
update_appearance()
/obj/item/shockpaddles/proc/shock_pulling(dmg, mob/H)
if(isliving(H.pulledby)) //CLEAR!
var/mob/living/M = H.pulledby
if(M.electrocute_act(dmg, H))
M.visible_message(span_danger("[M] is electrocuted by [M.p_their()] contact with [H]!"))
M.emote("scream")
/obj/item/shockpaddles/proc/do_disarm(mob/living/M, mob/living/user)
if(!DEFIB_CAN_HURT(src))
return
busy = TRUE
M.visible_message(span_danger("[user] touches [M] with [src]!"), \
span_userdanger("[user] touches [M] with [src]!"))
M.adjustStaminaLoss(60)
M.Knockdown(75)
M.set_jitter_if_lower(100 SECONDS)
M.apply_status_effect(/datum/status_effect/convulsing)
playsound(src, 'sound/machines/defib_zap.ogg', 50, TRUE, -1)
if(HAS_TRAIT(M,MOB_ORGANIC))
M.emote("gasp")
log_combat(user, M, "zapped", src)
do_success()
/obj/item/shockpaddles/proc/do_harm(mob/living/carbon/H, mob/living/user)
if(!DEFIB_CAN_HURT(src))
return
user.visible_message(span_warning("[user] begins to place [src] on [H]'s chest."),
span_warning("You overcharge the paddles and begin to place them onto [H]'s chest..."))
busy = TRUE
update_appearance()
if(do_after(user, 1.5 SECONDS, H, extra_checks = CALLBACK(src, PROC_REF(is_wielded))))
user.visible_message(span_notice("[user] places [src] on [H]'s chest."),
span_warning("You place [src] on [H]'s chest and begin to charge them."))
var/turf/T = get_turf(defib)
playsound(src, 'sound/machines/defib_charge.ogg', 50, FALSE)
if(req_defib)
T.audible_message(span_warning("\The [defib] lets out an urgent beep and lets out a steadily rising hum..."))
else
user.audible_message(span_warning("[src] let out an urgent beep."))
if(do_after(user, 1.5 SECONDS, H, extra_checks = CALLBACK(src, PROC_REF(is_wielded)))) //Takes longer due to overcharging
if(!H)
do_cancel()
return
if(H && H.stat == DEAD)
to_chat(user, span_warning("[H] is dead."))
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
do_cancel()
return
user.visible_message(span_boldannounce("<i>[user] shocks [H] with \the [src]!"), span_warning("You shock [H] with \the [src]!"))
playsound(src, 'sound/machines/defib_zap.ogg', 100, TRUE, -1)
playsound(src, 'sound/weapons/egloves.ogg', 100, TRUE, -1)
H.emote("scream")
shock_pulling(45, H)
if(H.can_heartattack() && !H.undergoing_cardiac_arrest())
if(!H.stat)
H.visible_message(span_warning("[H] thrashes wildly, clutching at [H.p_their()] chest!"),
span_userdanger("You feel a horrible agony in your chest!"))
H.set_heartattack(TRUE)
H.apply_damage(50, BURN, BODY_ZONE_CHEST)
log_combat(user, H, "overloaded the heart of", defib)
H.Paralyze(100)
H.set_jitter_if_lower(200 SECONDS)
do_success()
return
do_cancel()
/obj/item/shockpaddles/proc/do_help(mob/living/carbon/H, mob/living/user)
user.visible_message(span_warning("[user] begins to place [src] on [H]'s chest."), span_warning("You begin to place [src] on [H]'s chest..."))
busy = TRUE
update_appearance()
if(do_after(user, 3 SECONDS, H, extra_checks = CALLBACK(src, PROC_REF(is_wielded)))) //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process
user.visible_message(span_notice("[user] places [src] on [H]'s chest."), span_warning("You place [src] on [H]'s chest."))
playsound(src, 'sound/machines/defib_charge.ogg', 75, FALSE)
var/obj/item/organ/internal/heart = H.get_organ_by_type(/obj/item/organ/internal/heart)
if(do_after(user, 2 SECONDS, H, extra_checks = CALLBACK(src, PROC_REF(is_wielded)))) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
if((!combat && !req_defib) || (req_defib && !defib.combat))
for(var/obj/item/clothing/C in H.get_equipped_items())
if((C.body_parts_covered & CHEST) && (C.clothing_flags & THICKMATERIAL)) //check to see if something is obscuring their chest.
user.audible_message(span_warning("[req_defib ? "[defib]" : "[src]"] buzzes: Patient's chest is obscured. Operation aborted."))
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
do_cancel()
return
if(SEND_SIGNAL(H, COMSIG_DEFIBRILLATOR_PRE_HELP_ZAP, user, src) & COMPONENT_DEFIB_STOP)
do_cancel()
return
if(H.stat == DEAD)
H.visible_message(span_warning("[H]'s body convulses a bit."))
playsound(src, SFX_BODYFALL, 50, TRUE)
playsound(src, 'sound/machines/defib_zap.ogg', 75, TRUE, -1)
shock_pulling(30, H)
var/defib_result = H.can_defib()
var/fail_reason
switch (defib_result)
if (DEFIB_FAIL_SUICIDE)
fail_reason = "Recovery of patient impossible. Further attempts futile."
if (DEFIB_FAIL_NO_HEART)
fail_reason = "Patient's heart is missing."
if (DEFIB_FAIL_FAILING_HEART)
fail_reason = "Patient's heart too damaged, replace or repair and try again."
if (DEFIB_FAIL_TISSUE_DAMAGE)
fail_reason = "Tissue damage too severe, repair and try again."
if (DEFIB_FAIL_HUSK)
fail_reason = "Patient's body is a mere husk, repair and try again."
if (DEFIB_FAIL_FAILING_BRAIN)
fail_reason = "Patient's brain is too damaged, repair and try again."
if (DEFIB_FAIL_NO_INTELLIGENCE)
fail_reason = "No intelligence pattern can be detected in patient's brain. Further attempts futile."
if (DEFIB_FAIL_NO_BRAIN)
fail_reason = "Patient's brain is missing. Further attempts futile."
if (DEFIB_FAIL_BLACKLISTED)
fail_reason = "Patient has been blacklisted from revival. Further attempts futile."
if(fail_reason)
user.visible_message(span_warning("[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - [fail_reason]"))
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
else
var/total_brute = H.getBruteLoss()
var/total_burn = H.getFireLoss()
//If the body has been fixed so that they would not be in crit when defibbed, give them oxyloss to put them back into crit
if (H.health > HALFWAYCRITDEATH)
H.adjustOxyLoss(H.health - HALFWAYCRITDEATH, 0)
else
var/overall_damage = total_brute + total_burn + H.getToxLoss() + H.getOxyLoss()
var/mobhealth = H.health
H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0)
H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0, TRUE) // force tox heal for toxin lovers too
H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0)
H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually.
user.visible_message(span_notice("[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful."))
playsound(src, 'sound/machines/defib_success.ogg', 50, FALSE)
H.set_heartattack(FALSE)
if(defib_result == DEFIB_POSSIBLE)
H.grab_ghost()
H.revive()
H.emote("gasp")
H.set_jitter_if_lower(200 SECONDS)
SEND_SIGNAL(H, COMSIG_LIVING_MINOR_SHOCK)
if(HAS_MIND_TRAIT(user, TRAIT_MORBID))
user.add_mood_event("morbid_saved_life", /datum/mood_event/morbid_saved_life)
else
user.add_mood_event("saved_life", /datum/mood_event/saved_life)
log_combat(user, H, "revived", defib)
do_success()
return
else if (!H.get_organ_by_type(/obj/item/organ/internal/heart))
user.visible_message(span_warning("[req_defib ? "[defib]" : "[src]"] buzzes: Patient's heart is missing. Operation aborted."))
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
else if(H.undergoing_cardiac_arrest())
playsound(src, 'sound/machines/defib_zap.ogg', 50, TRUE, -1)
if(!(heart.organ_flags & ORGAN_FAILING))
H.set_heartattack(FALSE)
user.visible_message(span_notice("[req_defib ? "[defib]" : "[src]"] pings: Patient's heart is now beating again."))
else
user.visible_message(span_warning("[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed, heart damage detected."))
else
user.visible_message(span_warning("[req_defib ? "[defib]" : "[src]"] buzzes: Patient is not in a valid state. Operation aborted."))
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
do_cancel()
/obj/item/shockpaddles/proc/is_wielded()
return HAS_TRAIT(src, TRAIT_WIELDED)
/obj/item/shockpaddles/cyborg
name = "cyborg defibrillator paddles"
icon = 'icons/obj/medical/defib.dmi'
icon_state = "defibpaddles0"
inhand_icon_state = "defibpaddles0"
req_defib = FALSE
/obj/item/shockpaddles/cyborg/attack(mob/M, mob/user)
if(iscyborg(user))
var/mob/living/silicon/robot/R = user
if(R.emagged)
combat = TRUE
else
combat = FALSE
else
combat = FALSE
. = ..()
/obj/item/shockpaddles/syndicate
name = "syndicate defibrillator paddles"
desc = "A pair of paddles used to revive deceased operatives. They possess both the ability to penetrate armor and to deliver powerful or disabling shocks offensively."
combat = TRUE
icon = 'icons/obj/medical/defib.dmi'
icon_state = "syndiepaddles0"
inhand_icon_state = "syndiepaddles0"
base_icon_state = "syndiepaddles"
/obj/item/shockpaddles/syndicate/nanotrasen
name = "elite nanotrasen defibrillator paddles"
desc = "A pair of paddles used to revive deceased ERT members. They possess both the ability to penetrate armor and to deliver powerful or disabling shocks offensively."
icon_state = "ntpaddles0"
inhand_icon_state = "ntpaddles0"
base_icon_state = "ntpaddles"
/obj/item/shockpaddles/syndicate/cyborg
req_defib = FALSE
#undef HALFWAYCRITDEATH
#undef DEFIB_CAN_HURT