Files
Bubberstation/code/game/objects/items/defib.dm
SkyratBot 6947f89d04 [MIRROR] mobile defibrillator mount (#27737)
* mobile defibrillator mount (#83000)

## About The Pull Request

![image](https://github.com/tgstation/tgstation/assets/70376633/e8650bc6-e915-499c-8a63-eba0a70b4a96)

![image](https://github.com/tgstation/tgstation/assets/70376633/14a95345-e436-43c7-b4a7-de2502fc59cc)

5 iron and 1 sheet of silver and 15 cable to craft

its a defib mount but mobile, thats basically it

## Why It's Good For The Game

good for maps where there are no good spots to place wall defib mounts
or if you cant or dont want to take off your backpack (maybe using a
modsuit?) and theres no defib mount nearby

## Changelog
🆑
add: mobile defibrillator mount
/🆑

* mobile defibrillator mount

---------

Co-authored-by: jimmyl <70376633+mc-oofert@users.noreply.github.com>
2024-05-18 02:10:44 +02:00

753 lines
28 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/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(STANDARD_CELL_CHARGE / 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(QDELETED(cell))
return
if(cell.charge < (paddles.revivecost + chrgdeductamt))
powered = FALSE
if(!cell.use(chrgdeductamt))
powered = FALSE
update_power()
/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 as a weapon via applying the paddles while in a combat stance."
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 as a weapon via applying the paddles while in a combat stance."
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 = STANDARD_CELL_CHARGE * 0.1
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))
RegisterSignal(defib.loc, 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)
UnregisterSignal(defib.loc, 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_revival("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)
var/target_synthetic = (H.mob_biotypes & MOB_ROBOTIC) // SKYRAT EDIT ADDITION BEGIN - SYNTH REVIVAL
if (target_synthetic)
to_chat(user, span_boldwarning("[H] is a synthetic lifeform! This defibrillator probably isn't calibrated to revive [H.p_them()] properly and could have some serious consequences! \
[span_warning("You might want to [span_blue("surgically revive [H.p_them()]")]...")]"))
balloon_alert(user, "target is synthetic!") // immediately grabs their attention even if they dont see chat
// SKYRAT EDIT ADDITION END - SYNTH REVIVAL
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."
//SKYRAT EDIT ADDITION - DNR TRAIT
if (DEFIB_FAIL_DNR)
fail_reason = "Patient has been flagged as Do Not Resuscitate. Further attempts futile."
//SKYRAT EDIT ADDITION END - DNR TRAIT
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()
var/need_mob_update = FALSE
//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)
need_mob_update += H.adjustOxyLoss(H.health - HALFWAYCRITDEATH, updating_health = FALSE)
else
var/overall_damage = total_brute + total_burn + H.getToxLoss() + H.getOxyLoss()
var/mobhealth = H.health
need_mob_update += H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), updating_health = FALSE)
need_mob_update += H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), updating_health = FALSE, forced = TRUE) // force tox heal for toxin lovers too
need_mob_update += H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), updating_health = FALSE)
need_mob_update += H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), updating_health = FALSE)
if(need_mob_update)
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)
to_chat(H, "<span class='userdanger'>[CONFIG_GET(string/blackoutpolicy)]</span>") //SKYRAT EDIT ADDITION
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)
// SKYRAT EDIT ADDITION BEGIN - SYNTH REVIVAL
if (target_synthetic)
user.visible_message(span_boldwarning("[src] fire a powerful jolt of electricity into [H]'s vulnerable circuitry!"))
to_chat(H, span_userdanger("[user]'s defibrillator fires a powerful jolt of electricity into your vulnerable circuitry, overloading it!"))
// You may ask, why not just call H.emp_act()?
// well my dear reader, that EMPs contents. I only want to EMP bodyparts and organs specifically
for (var/obj/item/bodypart/iterated_part as anything in H.bodyparts)
iterated_part.emp_act(EMP_LIGHT)
for (var/obj/item/organ/iterated_organ as anything in H.organs)
iterated_organ.emp_act(EMP_LIGHT)
var/obj/item/organ/internal/brain/brain_organ = H.get_organ_slot(ORGAN_SLOT_BRAIN)
if (istype(brain_organ))
var/datum/brain_trauma/trauma = brain_organ.gain_trauma_type(SYNTH_DEFIBBED_TRAUMA_SEVERITY, TRAUMA_LIMIT_BASIC)
if (!QDELETED(trauma))
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_synth_defib_trauma), brain_organ, trauma), SYNTH_DEFIBBED_TRAUMA_DURATION)
// SKYRAT EDIT ADDITION END - SYNTH REVIVAL
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