mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Ports Bay/Paradise Defibs
I like the ones I wrote, but these are proooobably better. They have normal units, which are worn on the back and you can grab the paddles out of to shock people. Then there's compact units, which are worn as a belt, and serve the same purpose. And finally there's the combat units, which allow revives through spacesuits, and have no safety so you can zap living people on harm intent (good for antags? CMO?). These appropriately check for blood, a heart, etc. So, in that way, they're a bit more realisic than my original ones which I was sorta lazy in writing. Emagging them turns off the safeties, allowing them to zap people who are still alive. I actually cleaned up their sprite choice code a little and added a sprite for the 'combat' one since previously it was just the emagged sprite (flashing exclamation point). Now it's just got a red heart monitor, and the emagged ones keeps the exclamation. Did make one balance change in that compact ones use twice the power (inefficient small capacitors? or something?).
This commit is contained in:
@@ -331,7 +331,7 @@
|
||||
|
||||
/datum/supply_packs/med/defib
|
||||
name = "Defibrilator crate"
|
||||
contains = list(/obj/item/device/defib_kit = 4)
|
||||
contains = list(/obj/item/device/defib_kit = 2)
|
||||
cost = 30
|
||||
containertype = /obj/structure/closet/crate/medical
|
||||
containername = "Defibrilator crate"
|
||||
@@ -159,7 +159,7 @@
|
||||
/obj/item/device/kit/paint/gygax/recitence
|
||||
)
|
||||
name = "Random Gygax exosuit modkit"
|
||||
|
||||
/*
|
||||
/datum/supply_packs/robotics/jumper_cables
|
||||
name = "Jumper kit crate"
|
||||
contains = list(
|
||||
@@ -168,4 +168,5 @@
|
||||
cost = 30
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Jumper kit crate"
|
||||
access = access_robotics
|
||||
access = access_robotics
|
||||
*/
|
||||
@@ -1,185 +1,631 @@
|
||||
//The case the paddles are kept in.
|
||||
#define DEFIB_TIME_LIMIT (8 MINUTES) //past this many seconds, defib is useless.
|
||||
#define DEFIB_TIME_LOSS (2 MINUTES) //past this many seconds, brain damage occurs.
|
||||
|
||||
//backpack item
|
||||
/obj/item/device/defib_kit
|
||||
name = "defibrillator kit"
|
||||
desc = "This KHI-branded defib kit is a semi-automated model. Remove pads, slap on chest, wait."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "defib_kit"
|
||||
name = "defibrillator"
|
||||
desc = "A device that delivers powerful shocks to detachable paddles that resuscitate incapacitated patients."
|
||||
icon = 'icons/obj/defibrillator.dmi'
|
||||
icon_state = "defibunit"
|
||||
item_state = "defibunit"
|
||||
slot_flags = SLOT_BACK
|
||||
force = 5
|
||||
throwforce = 6
|
||||
w_class = ITEMSIZE_LARGE
|
||||
origin_tech = list(TECH_BIO = 4, TECH_POWER = 2)
|
||||
action_button_name = "Remove/Replace Paddles"
|
||||
|
||||
var/obj/item/weapon/shockpaddles/linked/paddles
|
||||
var/obj/item/weapon/cell/bcell = null
|
||||
|
||||
/obj/item/device/defib_kit/New() //starts without a cell for rnd
|
||||
..()
|
||||
if(ispath(paddles))
|
||||
paddles = new paddles(src, src)
|
||||
else
|
||||
paddles = new(src, src)
|
||||
|
||||
if(ispath(bcell))
|
||||
bcell = new bcell(src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/defib_kit/Destroy()
|
||||
. = ..()
|
||||
qdel_null(paddles)
|
||||
qdel_null(bcell)
|
||||
|
||||
/obj/item/device/defib_kit/loaded //starts with highcap cell
|
||||
bcell = /obj/item/weapon/cell/high
|
||||
|
||||
|
||||
/obj/item/device/defib_kit/update_icon()
|
||||
var/list/new_overlays = list()
|
||||
|
||||
if(paddles && paddles.loc == src) //in case paddles got destroyed somehow.
|
||||
new_overlays += "[initial(icon_state)]-paddles"
|
||||
if(bcell)
|
||||
if(bcell.check_charge(paddles.chargecost))
|
||||
if(paddles.combat)
|
||||
new_overlays += "[initial(icon_state)]-combat"
|
||||
else if(!paddles.safety)
|
||||
new_overlays += "[initial(icon_state)]-emagged"
|
||||
else
|
||||
new_overlays += "[initial(icon_state)]-powered"
|
||||
|
||||
var/ratio = Ceiling(bcell.percent()/25) * 25
|
||||
new_overlays += "[initial(icon_state)]-charge[ratio]"
|
||||
else
|
||||
new_overlays += "[initial(icon_state)]-nocell"
|
||||
|
||||
overlays = new_overlays
|
||||
|
||||
/obj/item/device/defib_kit/ui_action_click()
|
||||
toggle_paddles()
|
||||
|
||||
/obj/item/device/defib_kit/attack_hand(mob/user)
|
||||
if(loc == user)
|
||||
toggle_paddles()
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/device/defib_kit/MouseDrop()
|
||||
if(ismob(src.loc))
|
||||
if(!CanMouseDrop(src))
|
||||
return
|
||||
var/mob/M = src.loc
|
||||
if(!M.unEquip(src))
|
||||
return
|
||||
src.add_fingerprint(usr)
|
||||
M.put_in_any_hand_if_possible(src)
|
||||
|
||||
|
||||
/obj/item/device/defib_kit/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(W == paddles)
|
||||
reattach_paddles(user)
|
||||
else if(istype(W, /obj/item/weapon/cell))
|
||||
if(bcell)
|
||||
to_chat(user, "<span class='notice'>\the [src] already has a cell.</span>")
|
||||
else
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.forceMove(src)
|
||||
bcell = W
|
||||
to_chat(user, "<span class='notice'>You install a cell in \the [src].</span>")
|
||||
update_icon()
|
||||
|
||||
else if(isscrewdriver(W))
|
||||
if(bcell)
|
||||
bcell.update_icon()
|
||||
bcell.forceMove(get_turf(src.loc))
|
||||
bcell = null
|
||||
to_chat(user, "<span class='notice'>You remove the cell from \the [src].</span>")
|
||||
update_icon()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/defib_kit/emag_act(mob/user)
|
||||
if(paddles)
|
||||
. = paddles.emag_act(user)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
//Paddle stuff
|
||||
|
||||
/obj/item/device/defib_kit/verb/toggle_paddles()
|
||||
set name = "Toggle Paddles"
|
||||
set category = "Object"
|
||||
|
||||
var/mob/living/carbon/human/user = usr
|
||||
if(!paddles)
|
||||
to_chat(user, "<span class='warning'>The paddles are missing!</span>")
|
||||
return
|
||||
|
||||
if(paddles.loc != src)
|
||||
reattach_paddles(user) //Remove from their hands and back onto the defib unit
|
||||
return
|
||||
|
||||
if(!slot_check())
|
||||
to_chat(user, "<span class='warning'>You need to equip [src] before taking out [paddles].</span>")
|
||||
else
|
||||
if(!usr.put_in_hands(paddles)) //Detach the paddles into the user's hands
|
||||
to_chat(user, "<span class='warning'>You need a free hand to hold the paddles!</span>")
|
||||
update_icon() //success
|
||||
|
||||
//checks that the base unit is in the correct slot to be used
|
||||
/obj/item/device/defib_kit/proc/slot_check()
|
||||
var/mob/M = loc
|
||||
if(!istype(M))
|
||||
return 0 //not equipped
|
||||
|
||||
if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src)
|
||||
return 1
|
||||
if((slot_flags & SLOT_BELT) && M.get_equipped_item(slot_belt) == src)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/obj/item/device/defib_kit/dropped(mob/user)
|
||||
..()
|
||||
reattach_paddles(user) //paddles attached to a base unit should never exist outside of their base unit or the mob equipping the base unit
|
||||
|
||||
/obj/item/device/defib_kit/proc/reattach_paddles(mob/user)
|
||||
if(!paddles) return
|
||||
|
||||
if(ismob(paddles.loc))
|
||||
var/mob/M = paddles.loc
|
||||
if(M.drop_from_inventory(paddles, src))
|
||||
to_chat(user, "<span class='notice'>\The [paddles] snap back into the main unit.</span>")
|
||||
else
|
||||
paddles.forceMove(src)
|
||||
|
||||
update_icon()
|
||||
|
||||
/*
|
||||
Base Unit Subtypes
|
||||
*/
|
||||
|
||||
/obj/item/device/defib_kit/compact
|
||||
name = "compact defibrillator"
|
||||
desc = "A belt-equipped defibrillator that can be rapidly deployed."
|
||||
icon_state = "defibcompact"
|
||||
item_state = "defibcompact"
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
slot_flags = SLOT_BELT
|
||||
origin_tech = list(TECH_BIO = 5, TECH_POWER = 3)
|
||||
|
||||
/obj/item/device/defib_kit/compact/loaded
|
||||
bcell = /obj/item/weapon/cell/high
|
||||
|
||||
|
||||
/obj/item/device/defib_kit/compact/combat
|
||||
name = "combat defibrillator"
|
||||
desc = "A belt-equipped blood-red defibrillator that can be rapidly deployed. Does not have the restrictions or safeties of conventional defibrillators and can revive through space suits."
|
||||
paddles = /obj/item/weapon/shockpaddles/linked/combat
|
||||
|
||||
/obj/item/device/defib_kit/compact/combat/loaded
|
||||
bcell = /obj/item/weapon/cell/high
|
||||
|
||||
/obj/item/weapon/shockpaddles/linked/combat
|
||||
combat = 1
|
||||
safety = 0
|
||||
chargetime = (1 SECONDS)
|
||||
|
||||
|
||||
//paddles
|
||||
|
||||
/obj/item/weapon/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/defibrillator.dmi'
|
||||
icon_state = "defibpaddles"
|
||||
item_state = "defibpaddles"
|
||||
gender = PLURAL
|
||||
force = 2
|
||||
throwforce = 6
|
||||
w_class = ITEMSIZE_LARGE
|
||||
|
||||
var/state //0 off, 1 open, 2 working, 3 dead
|
||||
var/uses = 2 //Calculates initial uses based on starting cell size
|
||||
var/use_on_synthetic = 0 //If 1, this is only useful on FBPs, if 0, this is only useful on fleshies
|
||||
var/pad_name = "defib pads" //Just the name given for some cosmetic things
|
||||
var/chance = 75 //Percent chance of working
|
||||
var/charge_cost //Set in New() based on uses
|
||||
var/obj/item/weapon/cell/cell //The size is mostly irrelevant, see 'uses'
|
||||
var/mob/living/carbon/human/patient //The person the paddles are on
|
||||
var/safety = 1 //if you can zap people with the paddles on harm mode
|
||||
var/combat = 0 //If it can be used to revive people wearing thick clothing (e.g. spacesuits)
|
||||
var/cooldowntime = (6 SECONDS) // How long in deciseconds until the defib is ready again after use.
|
||||
var/chargetime = (2 SECONDS)
|
||||
var/chargecost = 1000 //units of charge
|
||||
var/burn_damage_amt = 15
|
||||
|
||||
/obj/item/device/defib_kit/New()
|
||||
var/wielded = 0
|
||||
var/cooldown = 0
|
||||
var/busy = 0
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/set_cooldown(var/delay)
|
||||
cooldown = 1
|
||||
update_icon()
|
||||
|
||||
spawn(delay)
|
||||
if(cooldown)
|
||||
cooldown = 0
|
||||
update_icon()
|
||||
|
||||
make_announcement("beeps, \"Unit is re-energized.\"", "notice")
|
||||
playsound(src, 'sound/machines/defib_ready.ogg', 50, 0)
|
||||
|
||||
/obj/item/weapon/shockpaddles/update_held_icon()
|
||||
var/mob/living/M = loc
|
||||
if(istype(M) && !issmall(M) && M.item_is_in_hands(src) && !M.hands_are_full())
|
||||
wielded = 1
|
||||
name = "[initial(name)] (wielded)"
|
||||
else
|
||||
wielded = 0
|
||||
name = initial(name)
|
||||
update_icon()
|
||||
..()
|
||||
//Create cell and determine uses (futureproofing against cell size changes)
|
||||
cell = new(src)
|
||||
charge_cost = cell.maxcharge / uses
|
||||
statechange(0)
|
||||
|
||||
/obj/item/device/defib_kit/attack_self(mob/user as mob)
|
||||
..()
|
||||
if(patient)
|
||||
patient = null
|
||||
user.visible_message("<span class='notice'>[user] returns the pads to \the [src] and closes it.</span>",
|
||||
"<span class='notice'>You return the pads to \the [src] and close it.</span>")
|
||||
statechange(0)
|
||||
/obj/item/weapon/shockpaddles/update_icon()
|
||||
icon_state = "defibpaddles[wielded]"
|
||||
item_state = "defibpaddles[wielded]"
|
||||
if(cooldown)
|
||||
icon_state = "defibpaddles[wielded]_cooldown"
|
||||
|
||||
/obj/item/device/defib_kit/MouseDrop(var/mob/living/carbon/human/onto)
|
||||
if(istype(onto) && Adjacent(usr) && !usr.restrained() && !usr.stat)
|
||||
var/mob/living/carbon/human/user = usr
|
||||
//<--Feel free to code clothing checks right here
|
||||
if(can_defib(onto))
|
||||
user.visible_message("<span class='warning'>[user] begins applying [pad_name] to [onto].</span>",
|
||||
"<span class='warning'>You begin applying [pad_name] to [onto].</span>")
|
||||
if(do_after(user, 100, onto))
|
||||
patient = onto
|
||||
statechange(1,patient)
|
||||
user.visible_message("<span class='warning'>[user] applies [pad_name] to [onto].</span>",
|
||||
"<span class='warning'>You finish applying [pad_name] to [onto].</span>")
|
||||
|
||||
|
||||
//can_defib() check is where all of the qualifying conditions should go
|
||||
//Could probably toss in checks here for damage, organs, etc, but for now I'll leave it as just this
|
||||
/obj/item/device/defib_kit/proc/can_defib(var/mob/living/carbon/human/target)
|
||||
var/mob/living/carbon/human/user = usr
|
||||
if(use_on_synthetic && !target.isSynthetic())
|
||||
to_chat(user, "[src] isn't designed for organics!")
|
||||
/obj/item/weapon/shockpaddles/proc/can_use(mob/user, mob/M)
|
||||
if(busy)
|
||||
return 0
|
||||
else if(!use_on_synthetic && target.isSynthetic())
|
||||
to_chat(user, "[src] isn't designed for synthetics!")
|
||||
if(!check_charge(chargecost))
|
||||
to_chat(user, "<span class='warning'>\The [src] doesn't have enough charge left to do that.</span>")
|
||||
return 0
|
||||
else if(!target.isSynthetic() && ((world.time - target.timeofdeath) > (10 MINUTES)))//Can only revive organics within a few minutes
|
||||
to_chat(user, "There is no spark of life in [target.name], they've been dead too long to revive this way.")
|
||||
if(!wielded && !isrobot(user))
|
||||
to_chat(user, "<span class='warning'>You need to wield the paddles with both hands before you can use them on someone!</span>")
|
||||
return 0
|
||||
if(cooldown)
|
||||
to_chat(user, "<span class='warning'>\The [src] are re-energizing!</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//Checks for various conditions to see if the mob is revivable
|
||||
/obj/item/weapon/shockpaddles/proc/can_defib(mob/living/carbon/human/H) //This is checked before doing the defib operation
|
||||
if((H.species.flags & NO_SCAN) || H.isSynthetic())
|
||||
return "buzzes, \"Unrecogized physiology. Operation aborted.\""
|
||||
|
||||
/obj/item/device/defib_kit/attackby(var/obj/item/A as obj, mob/living/user as mob)
|
||||
if(H.stat != DEAD)
|
||||
return "buzzes, \"Patient is not in a valid state. Operation aborted.\""
|
||||
|
||||
if(!check_contact(H))
|
||||
return "buzzes, \"Patient's chest is obstructed. Operation aborted.\""
|
||||
|
||||
return null
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/can_revive(mob/living/carbon/human/H) //This is checked right before attempting to revive
|
||||
|
||||
var/deadtime = world.time - H.timeofdeath
|
||||
if (deadtime > DEFIB_TIME_LIMIT)
|
||||
return "buzzes, \"Resuscitation failed - Excessive neural degeneration. Further attempts futile.\""
|
||||
|
||||
H.updatehealth()
|
||||
if(H.health + H.getOxyLoss() <= config.health_threshold_dead || (HUSK in H.mutations))
|
||||
return "buzzes, \"Resuscitation failed - Severe tissue damage makes recovery of patient impossible via defibrillator. Further attempts futile.\""
|
||||
|
||||
var/bad_vital_organ = check_vital_organs(H)
|
||||
if(bad_vital_organ)
|
||||
return bad_vital_organ
|
||||
|
||||
//this needs to be last since if any of the 'other conditions are met their messages take precedence
|
||||
if(!H.client && !H.teleop)
|
||||
return "buzzes, \"Resuscitation failed - Mental interface error. Further attempts may be successful.\""
|
||||
|
||||
return null
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/check_contact(mob/living/carbon/human/H)
|
||||
if(!combat)
|
||||
for(var/obj/item/clothing/cloth in list(H.wear_suit, H.w_uniform))
|
||||
if((cloth.body_parts_covered & UPPER_TORSO) && (cloth.item_flags & THICKMATERIAL))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/check_vital_organs(mob/living/carbon/human/H)
|
||||
for(var/organ_tag in H.species.has_organ)
|
||||
var/obj/item/organ/O = H.species.has_organ[organ_tag]
|
||||
var/name = initial(O.name)
|
||||
var/vital = initial(O.vital) //check for vital organs
|
||||
if(vital)
|
||||
O = H.internal_organs_by_name[organ_tag]
|
||||
if(!O)
|
||||
return "buzzes, \"Resuscitation failed - Patient is missing vital organ ([name]). Further attempts futile.\""
|
||||
if(O.damage > O.max_damage)
|
||||
return "buzzes, \"Resuscitation failed - Excessive damage to vital organ ([name]). Further attempts futile.\""
|
||||
return null
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/check_blood_level(mob/living/carbon/human/H)
|
||||
if(!H.should_have_organ(O_HEART))
|
||||
return FALSE
|
||||
|
||||
var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[O_HEART]
|
||||
if(!heart)
|
||||
return TRUE
|
||||
|
||||
var/blood_volume = round((H.vessel.get_reagent_amount("blood")/H.species.blood_volume)*100)
|
||||
if(!heart || heart.is_broken())
|
||||
blood_volume *= 0.3
|
||||
else if(heart.is_bruised())
|
||||
blood_volume *= 0.7
|
||||
else if(heart.damage > 1)
|
||||
blood_volume *= 0.8
|
||||
return blood_volume < BLOOD_VOLUME_SURVIVE
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/check_charge(var/charge_amt)
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/checked_use(var/charge_amt)
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/shockpaddles/attack(mob/living/M, mob/living/user, var/target_zone)
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(!istype(H) || user.a_intent == I_HURT)
|
||||
return ..() //Do a regular attack. Harm intent shocking happens as a hit effect
|
||||
|
||||
if(can_use(user, H))
|
||||
busy = 1
|
||||
update_icon()
|
||||
|
||||
do_revive(H, user)
|
||||
|
||||
busy = 0
|
||||
update_icon()
|
||||
|
||||
return 1
|
||||
|
||||
//Since harm-intent now skips the delay for deliberate placement, you have to be able to hit them in combat in order to shock people.
|
||||
/obj/item/weapon/shockpaddles/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
|
||||
if(ishuman(target) && can_use(user, target))
|
||||
busy = 1
|
||||
update_icon()
|
||||
|
||||
do_electrocute(target, user, hit_zone)
|
||||
|
||||
busy = 0
|
||||
update_icon()
|
||||
|
||||
return 1
|
||||
|
||||
return ..()
|
||||
|
||||
// This proc is used so that we can return out of the revive process while ensuring that busy and update_icon() are handled
|
||||
/obj/item/weapon/shockpaddles/proc/do_revive(mob/living/carbon/human/H, mob/user)
|
||||
if(!H.client && !H.teleop)
|
||||
to_chat(find_dead_player(H.ckey, 1), "Someone is attempting to resuscitate you. Re-enter your body if you want to be revived!")
|
||||
|
||||
//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 class='warning'>\The [user] begins to place [src] on [H]'s chest.</span>", "<span class='warning'>You begin to place [src] on [H]'s chest...</span>")
|
||||
if(!do_after(user, 30, H))
|
||||
return
|
||||
user.visible_message("<span class='notice'>\The [user] places [src] on [H]'s chest.</span>", "<span class='warning'>You place [src] on [H]'s chest.</span>")
|
||||
playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0)
|
||||
|
||||
var/error = can_defib(H)
|
||||
if(error)
|
||||
make_announcement(error, "warning")
|
||||
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
return
|
||||
|
||||
if(check_blood_level(H))
|
||||
make_announcement("buzzes, \"Warning - Patient is in hypovolemic shock.\"", "warning") //also includes heart damage
|
||||
|
||||
//placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
|
||||
if(!do_after(user, chargetime, H))
|
||||
return
|
||||
|
||||
//deduct charge here, in case the base unit was EMPed or something during the delay time
|
||||
if(!checked_use(chargecost))
|
||||
make_announcement("buzzes, \"Insufficient charge.\"", "warning")
|
||||
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
return
|
||||
|
||||
H.visible_message("<span class='warning'>\The [H]'s body convulses a bit.</span>")
|
||||
playsound(get_turf(src), "bodyfall", 50, 1)
|
||||
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
set_cooldown(cooldowntime)
|
||||
|
||||
error = can_revive(H)
|
||||
if(error)
|
||||
make_announcement(error, "warning")
|
||||
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
return
|
||||
|
||||
H.apply_damage(burn_damage_amt, BURN, BP_TORSO)
|
||||
|
||||
//set oxyloss so that the patient is just barely in crit, if possible
|
||||
var/barely_in_crit = config.health_threshold_crit - 1
|
||||
var/adjust_health = barely_in_crit - H.health //need to increase health by this much
|
||||
H.adjustOxyLoss(-adjust_health)
|
||||
|
||||
make_announcement("pings, \"Resuscitation successful.\"", "notice")
|
||||
playsound(get_turf(src), 'sound/machines/defib_success.ogg', 50, 0)
|
||||
|
||||
make_alive(H)
|
||||
|
||||
log_and_message_admins("used \a [src] to revive [key_name(H)].")
|
||||
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/do_electrocute(mob/living/carbon/human/H, mob/user, var/target_zone)
|
||||
var/obj/item/organ/external/affecting = H.get_organ(target_zone)
|
||||
if(!affecting)
|
||||
to_chat(user, "<span class='warning'>They are missing that body part!</span>")
|
||||
return
|
||||
|
||||
//no need to spend time carefully placing the paddles, we're just trying to shock them
|
||||
user.visible_message("<span class='danger'>\The [user] slaps [src] onto [H]'s [affecting.name].</span>", "<span class='danger'>You overcharge [src] and slap them onto [H]'s [affecting.name].</span>")
|
||||
|
||||
//Just stop at awkwardly slapping electrodes on people if the safety is enabled
|
||||
if(safety)
|
||||
to_chat(user, "<span class='warning'>You can't do that while the safety is enabled.</span>")
|
||||
return
|
||||
|
||||
playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0)
|
||||
audible_message("<span class='warning'>\The [src] lets out a steadily rising hum...</span>")
|
||||
|
||||
if(!do_after(user, chargetime, H))
|
||||
return
|
||||
|
||||
//deduct charge here, in case the base unit was EMPed or something during the delay time
|
||||
if(!checked_use(chargecost))
|
||||
make_announcement("buzzes, \"Insufficient charge.\"", "warning")
|
||||
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
return
|
||||
|
||||
user.visible_message("<span class='danger'><i>\The [user] shocks [H] with \the [src]!</i></span>", "<span class='warning'>You shock [H] with \the [src]!</span>")
|
||||
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 100, 1, -1)
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 100, 1, -1)
|
||||
set_cooldown(cooldowntime)
|
||||
|
||||
H.stun_effect_act(2, 120, target_zone)
|
||||
var/burn_damage = H.electrocute_act(burn_damage_amt*2, src, def_zone = target_zone)
|
||||
if(burn_damage > 15 && H.can_feel_pain())
|
||||
H.emote("scream")
|
||||
|
||||
admin_attack_log(user, H, "Electrocuted using \a [src]", "Was electrocuted with \a [src]", "used \a [src] to electrocute")
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/make_alive(mob/living/carbon/human/M) //This revives the mob
|
||||
var/deadtime = world.time - M.timeofdeath
|
||||
|
||||
dead_mob_list.Remove(M)
|
||||
if((M in living_mob_list) || (M in dead_mob_list))
|
||||
WARNING("Mob [M] was defibbed but already in the living or dead list still!")
|
||||
living_mob_list += M
|
||||
|
||||
M.timeofdeath = 0
|
||||
M.stat = UNCONSCIOUS //Life() can bring them back to consciousness if it needs to.
|
||||
M.regenerate_icons()
|
||||
M.failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
|
||||
M.reload_fullscreen()
|
||||
|
||||
M.emote("gasp")
|
||||
M.Weaken(rand(10,25))
|
||||
M.updatehealth()
|
||||
apply_brain_damage(M, deadtime)
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/apply_brain_damage(mob/living/carbon/human/H, var/deadtime)
|
||||
if(deadtime < DEFIB_TIME_LOSS) return
|
||||
|
||||
if(!H.should_have_organ(O_BRAIN)) return //no brain
|
||||
|
||||
var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[O_BRAIN]
|
||||
if(!brain) return //no brain
|
||||
|
||||
var/brain_damage = Clamp((deadtime - DEFIB_TIME_LOSS)/(DEFIB_TIME_LIMIT - DEFIB_TIME_LOSS)*brain.max_damage, H.getBrainLoss(), brain.max_damage)
|
||||
H.setBrainLoss(brain_damage)
|
||||
|
||||
/obj/item/weapon/shockpaddles/proc/make_announcement(var/message, var/msg_class)
|
||||
audible_message("<b>\The [src]</b> [message]", "\The [src] vibrates slightly.")
|
||||
|
||||
/obj/item/weapon/shockpaddles/emag_act(mob/user)
|
||||
if(safety)
|
||||
safety = 0
|
||||
to_chat(user, "<span class='warning'>You silently disable \the [src]'s safety protocols with the cryptographic sequencer.</span>")
|
||||
update_icon()
|
||||
return 1
|
||||
else
|
||||
safety = 1
|
||||
to_chat(user, "<span class='notice'>You silently enable \the [src]'s safety protocols with the cryptographic sequencer.</span>")
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/shockpaddles/emp_act(severity)
|
||||
var/new_safety = rand(0, 1)
|
||||
if(safety != new_safety)
|
||||
safety = new_safety
|
||||
if(safety)
|
||||
make_announcement("beeps, \"Safety protocols enabled!\"", "notice")
|
||||
playsound(get_turf(src), 'sound/machines/defib_safetyon.ogg', 50, 0)
|
||||
else
|
||||
make_announcement("beeps, \"Safety protocols disabled!\"", "warning")
|
||||
playsound(get_turf(src), 'sound/machines/defib_safetyoff.ogg', 50, 0)
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
if(!cell && istype(A,/obj/item/weapon/cell))
|
||||
if(!user.unEquip(A)) return
|
||||
to_chat(user,"You jack \the [A] into \the [src]'s battery mount.")
|
||||
A.forceMove(src)
|
||||
src.cell = A
|
||||
/obj/item/weapon/shockpaddles/robot
|
||||
name = "defibrillator paddles"
|
||||
desc = "A pair of advanced shockpaddles powered by a robot's internal power cell, able to penetrate thick clothing."
|
||||
chargecost = 50
|
||||
combat = 1
|
||||
icon_state = "defibpaddles0"
|
||||
item_state = "defibpaddles0"
|
||||
cooldowntime = (3 SECONDS)
|
||||
|
||||
else if(istype(A,/obj/item/weapon/screwdriver))
|
||||
if(cell)
|
||||
to_chat(user,"<span class='notice'>You remove \the [cell] from \the [src].</span>")
|
||||
if(user.r_hand && user.l_hand)
|
||||
cell.forceMove(get_turf(user))
|
||||
else
|
||||
user.put_in_hands(cell)
|
||||
cell = null
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
else
|
||||
to_chat(user,"<span class='warning'>The power source has already been removed!</span>")
|
||||
/obj/item/weapon/shockpaddles/robot/check_charge(var/charge_amt)
|
||||
if(isrobot(src.loc))
|
||||
var/mob/living/silicon/robot/R = src.loc
|
||||
return (R.cell && R.cell.check_charge(charge_amt))
|
||||
|
||||
/obj/item/device/defib_kit/proc/statechange(var/new_state, var/pat)
|
||||
if(state == new_state) return //Let's just save ourselves some time
|
||||
state = new_state
|
||||
icon_state = "[initial(icon_state)][state]"
|
||||
var/turf/T = get_turf(src)
|
||||
var/state_words = ""
|
||||
switch(state)
|
||||
if(0)
|
||||
state_words = "It is currently closed."
|
||||
processing_objects -= src
|
||||
/obj/item/weapon/shockpaddles/robot/checked_use(var/charge_amt)
|
||||
if(isrobot(src.loc))
|
||||
var/mob/living/silicon/robot/R = src.loc
|
||||
return (R.cell && R.cell.checked_use(charge_amt))
|
||||
|
||||
/*
|
||||
Shockpaddles that are linked to a base unit
|
||||
*/
|
||||
/obj/item/weapon/shockpaddles/linked
|
||||
var/obj/item/device/defib_kit/base_unit
|
||||
|
||||
/obj/item/weapon/shockpaddles/linked/New(newloc, obj/item/device/defib_kit/defib)
|
||||
base_unit = defib
|
||||
..(newloc)
|
||||
|
||||
/obj/item/weapon/shockpaddles/linked/Destroy()
|
||||
if(base_unit)
|
||||
//ensure the base unit's icon updates
|
||||
if(base_unit.paddles == src)
|
||||
base_unit.paddles = null
|
||||
base_unit.update_icon()
|
||||
base_unit = null
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/shockpaddles/linked/dropped(mob/user)
|
||||
..() //update twohanding
|
||||
if(base_unit)
|
||||
base_unit.reattach_paddles(user) //paddles attached to a base unit should never exist outside of their base unit or the mob equipping the base unit
|
||||
|
||||
/obj/item/weapon/shockpaddles/linked/check_charge(var/charge_amt)
|
||||
return (base_unit.bcell && base_unit.bcell.check_charge(charge_amt))
|
||||
|
||||
/obj/item/weapon/shockpaddles/linked/checked_use(var/charge_amt)
|
||||
return (base_unit.bcell && base_unit.bcell.checked_use(charge_amt))
|
||||
|
||||
/obj/item/weapon/shockpaddles/linked/make_announcement(var/message, var/msg_class)
|
||||
base_unit.audible_message("<b>\The [base_unit]</b> [message]", "\The [base_unit] vibrates slightly.")
|
||||
|
||||
/*
|
||||
Standalone Shockpaddles
|
||||
*/
|
||||
|
||||
/obj/item/weapon/shockpaddles/standalone
|
||||
desc = "A pair of shockpaddles powered by an experimental miniaturized reactor" //Inspired by the advanced e-gun
|
||||
var/fail_counter = 0
|
||||
|
||||
/obj/item/weapon/shockpaddles/standalone/Destroy()
|
||||
. = ..()
|
||||
if(fail_counter)
|
||||
processing_objects.Remove(src)
|
||||
|
||||
/obj/item/weapon/shockpaddles/standalone/check_charge(var/charge_amt)
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/shockpaddles/standalone/checked_use(var/charge_amt)
|
||||
radiation_repository.radiate(src, charge_amt/12) //just a little bit of radiation. It's the price you pay for being powered by magic I guess
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/shockpaddles/standalone/process()
|
||||
if(fail_counter > 0)
|
||||
radiation_repository.radiate(src, fail_counter--)
|
||||
else
|
||||
processing_objects.Remove(src)
|
||||
|
||||
/obj/item/weapon/shockpaddles/standalone/emp_act(severity)
|
||||
..()
|
||||
var/new_fail = 0
|
||||
switch(severity)
|
||||
if(1)
|
||||
state_words = "A green light is lit; it has charge."
|
||||
processing_objects |= src
|
||||
new_fail = max(fail_counter, 20)
|
||||
visible_message("\The [src]'s reactor overloads!")
|
||||
if(2)
|
||||
state_words = "A yellow light is flashing: it's in the process of reviving a patient."
|
||||
T.visible_message("<span class='notice'>A yellow light starts flashing on \the [src].</span>")
|
||||
playsound(T, 'sound/machines/chime.ogg', 50, 0)
|
||||
if(3)
|
||||
state_words = "A red light is flashing: the battery needs to be recharged."
|
||||
T.visible_message("<span class='warning'>A red light starts flashing on \the [src].</span>")
|
||||
playsound(T, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
new_fail = max(fail_counter, 8)
|
||||
if(ismob(loc))
|
||||
to_chat(loc, "<span class='warning'>\The [src] feel pleasantly warm.</span>")
|
||||
|
||||
desc = "[initial(desc)] [state_words][pat ? " The pads are attached to [pat]." : ""]"
|
||||
update_icon()
|
||||
if(new_fail && !fail_counter)
|
||||
processing_objects.Add(src)
|
||||
fail_counter = new_fail
|
||||
|
||||
/obj/item/device/defib_kit/process()
|
||||
if(!state) //0 or null
|
||||
statechange(0)
|
||||
processing_objects -= src
|
||||
return
|
||||
|
||||
//Patient moved too far
|
||||
if(patient && !(get_dist(src,patient) <= 1)) //You separated the kit and pads too far
|
||||
audible_message("<span class='warning'>There is a clatter as the [pad_name] are yanked off of [patient].</span>")
|
||||
statechange(0)
|
||||
patient = null
|
||||
return
|
||||
|
||||
//Battery died
|
||||
if(!cell || cell.charge < charge_cost)
|
||||
statechange(3,patient)
|
||||
return
|
||||
|
||||
//A patient isn't being worked on, but we have one, so start
|
||||
if(patient && patient.stat == DEAD && state != 2)
|
||||
statechange(2)
|
||||
if(attempt_shock()) //Try to shock them, has timer and such
|
||||
patient.visible_message("<span class='warning'>[patient] convulses!</span>")
|
||||
playsound(src.loc, 'sound/effects/sparks2.ogg', 75, 1)
|
||||
//Actual rezzing code
|
||||
if(prob(chance))
|
||||
if(!patient.client && patient.mind) //Don't force the dead person to come back if they don't want to.
|
||||
for(var/mob/observer/dead/ghost in player_list)
|
||||
if(ghost.mind == patient.mind)
|
||||
to_chat(ghost, "<b><font color = #330033><font size = 3>Someone is trying to \
|
||||
revive you. Return to your body if you want to be revived!</b> \
|
||||
(Verbs -> Ghost -> Re-enter corpse). You have 15 seconds to do this!</font></font>")
|
||||
sleep(15 SECONDS)
|
||||
break
|
||||
|
||||
if(!(HUSK in patient.mutations)) // Husked people can't come back with a Defib.
|
||||
if(patient.client)
|
||||
patient.adjustOxyLoss(-20) //Look, blood stays oxygenated for quite some time, but I'm not recoding the entire oxy system
|
||||
patient.stat = CONSCIOUS //Note that if whatever killed them in the first place wasn't fixed, they're likely to die again.
|
||||
dead_mob_list -= patient
|
||||
living_mob_list += patient
|
||||
patient.timeofdeath = null
|
||||
patient.visible_message("<span class='notice'>[patient]'s eyes open!</span>")
|
||||
log_and_message_admins("[patient] was revived by a defib.")
|
||||
cell.charge -= charge_cost //Always charge the cost after any attempt, failed or not
|
||||
sleep(20) //Wait 2 seconds before next attempt
|
||||
statechange(1,patient) //Back to ready
|
||||
|
||||
/obj/item/device/defib_kit/proc/attempt_shock()
|
||||
if(!patient || cell.charge < charge_cost)
|
||||
return
|
||||
|
||||
var/zap_time = world.time + (7 SECONDS)
|
||||
var/o_patient_loc = patient.loc
|
||||
. = 1
|
||||
|
||||
while(world.time < zap_time) //This is basically a custom do_after() call
|
||||
sleep(1)
|
||||
|
||||
//Failed: We lost something important
|
||||
if(!patient || !cell || cell.charge < charge_cost)
|
||||
. = 0
|
||||
break
|
||||
|
||||
//Failed: The locations aren't right
|
||||
if((o_patient_loc != patient.loc) || !(get_dist(src,patient) <= 1))
|
||||
. = 0
|
||||
break
|
||||
|
||||
return
|
||||
/* From the Bay port, this doesn't seem to have a sprite.
|
||||
/obj/item/weapon/shockpaddles/standalone/traitor
|
||||
name = "defibrillator paddles"
|
||||
desc = "A pair of unusual looking paddles powered by an experimental miniaturized reactor. It possesses both the ability to penetrate armor and to deliver powerful shocks."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "defibpaddles0"
|
||||
item_state = "defibpaddles0"
|
||||
combat = 1
|
||||
safety = 0
|
||||
chargetime = (1 SECONDS)
|
||||
*/
|
||||
|
||||
//Stub
|
||||
/obj/item/device/defib_kit/jumper_kit
|
||||
name = "jumper cable kit"
|
||||
desc = "This Morpheus-branded FBP defib kit is a semi-automated model. Apply cables, step back, wait."
|
||||
icon_state = "jumper_kit"
|
||||
use_on_synthetic = 1
|
||||
pad_name = "jumper cables"
|
||||
|
||||
#undef DEFIB_TIME_LIMIT
|
||||
#undef DEFIB_TIME_LOSS
|
||||
|
||||
Reference in New Issue
Block a user