From ad813f76d97ceb38d397057cd3635072bd5d46d8 Mon Sep 17 00:00:00 2001 From: Luc <89928798+lewcc@users.noreply.github.com> Date: Wed, 24 Aug 2022 13:00:25 -0400 Subject: [PATCH] Allow cursed heart to be defibrillated up to three times (#18677) * cursed heart but funny * Flesh out this version a bit more * okay fine you get three shots miner gaming * Bitwise * Change wakeup method * Address Steel's review --- code/__DEFINES/dcs/signals.dm | 8 +++ code/game/gamemodes/wizard/artefact.dm | 1 + code/game/objects/items/weapons/defib.dm | 16 ++++-- code/modules/surgery/organs/heart.dm | 68 ++++++++++++++++++++++-- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 518005d9b31..d73198d466d 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -392,6 +392,14 @@ #define COMSIG_LIVING_SHOCK_PREVENTED "living_shock_prevented" ///sent by stuff like stunbatons and tasers: () #define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" +///Sent from defibrillators when everything seems good and the user will be shocked: (defibber, defib_item, ghost) +#define COMSIG_LIVING_PRE_DEFIB "living_pre_defib" + /// If returned from LIVING_BEFORE_DEFIB or LIVING_DEFIBBED, the defibrillation will fail + #define COMPONENT_BLOCK_DEFIB (1<<0) + /// If returned, don't even show the "failed" message, defer to the signal handler to do that. + #define COMPONENT_DEFIB_OVERRIDE (1<<1) +///send from defibs on ressurection: (defibber, defib_item, ghost) +#define COMSIG_LIVING_DEFIBBED "living_defibbed" ///from base of mob/living/revive() (full_heal, admin_revive) #define COMSIG_LIVING_REVIVE "living_revive" ///from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs) diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index c8e3fd4de38..c829d044fa7 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -814,6 +814,7 @@ GLOBAL_LIST_EMPTY(multiverse) unlimited = 1 /obj/item/organ/internal/heart/cursed/wizard + max_shocks_allowed = 3 pump_delay = 60 heal_brute = 25 heal_burn = 25 diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index f048e5ead22..a649ef540d3 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -404,7 +404,10 @@ var/total_burn = 0 var/total_brute = 0 + var/signal_result = SEND_SIGNAL(M, COMSIG_LIVING_PRE_DEFIB, user, defib, ghost) + if(do_after(user, 20 * toolspeed, target = M)) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total + signal_result |= SEND_SIGNAL(M, COMSIG_LIVING_DEFIBBED, user, defib, ghost) for(var/obj/item/carried_item in H.contents) if(istype(carried_item, /obj/item/clothing/suit/space)) if(!defib.combat) @@ -413,6 +416,9 @@ busy = FALSE update_icon(UPDATE_ICON_STATE) return + if(signal_result & COMPONENT_DEFIB_OVERRIDE) + // let our signal handle it + return if(H.undergoing_cardiac_arrest()) if(!H.get_int_organ(/obj/item/organ/internal/heart) && !H.get_int_organ(/obj/item/organ/internal/brain/slime)) //prevents defibing someone still alive suffering from a heart attack attack if they lack a heart user.visible_message("[defib] buzzes: Resuscitation failed - Failed to pick up any heart electrical activity.") @@ -450,7 +456,7 @@ total_brute += O.brute_dam total_burn += O.burn_dam ghost = H.get_ghost(TRUE) // We have to double check whether the dead guy has entered their body during the above - if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !HAS_TRAIT(H, TRAIT_HUSK) && !HAS_TRAIT(H, TRAIT_BADDNA) && H.blood_volume > BLOOD_VOLUME_SURVIVE && (H.get_int_organ(/obj/item/organ/internal/heart) || H.get_int_organ(/obj/item/organ/internal/brain/slime))) + if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !HAS_TRAIT(H, TRAIT_HUSK) && !HAS_TRAIT(H, TRAIT_BADDNA) && H.blood_volume > BLOOD_VOLUME_SURVIVE && (H.get_int_organ(/obj/item/organ/internal/heart) || H.get_int_organ(/obj/item/organ/internal/brain/slime)) && !(signal_result & COMPONENT_BLOCK_DEFIB)) tobehealed = min(health + threshold, 0) // It's HILARIOUS without this min statement, let me tell you tobehealed -= 5 //They get 5 of each type of damage healed so excessive combined damage will not immediately kill them after they get revived H.adjustOxyLoss(tobehealed) @@ -493,7 +499,7 @@ user.visible_message("[defib] buzzes: Resuscitation failed: Patient blood volume critically low.") else if(ghost) if(!ghost.can_reenter_corpse) // DNR or AntagHUD - user.visible_message("[defib] buzzes: Resucitation failed: No electrical brain activity detected.") + user.visible_message("[defib] buzzes: Resuscitation failed: No electrical brain activity detected.") else user.visible_message("[defib] buzzes: Resuscitation failed: Patient's brain is unresponsive. Further attempts may succeed.") else @@ -593,7 +599,10 @@ var/tloss = 600 //brain damage starts setting in on the patient after some time left rotting var/total_burn = 0 var/total_brute = 0 + + var/signal_result = SEND_SIGNAL(M, COMSIG_LIVING_PRE_DEFIB, user, src, ghost) if(do_after(user, 20 * toolspeed, target = M)) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total + signal_result |= SEND_SIGNAL(M, COMSIG_LIVING_DEFIBBED, user, src, ghost) if(H.stat == DEAD) var/health = H.health M.visible_message("[M]'s body convulses a bit.") @@ -602,7 +611,7 @@ for(var/obj/item/organ/external/O in H.bodyparts) total_brute += O.brute_dam total_burn += O.burn_dam - if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !HAS_TRAIT(H, TRAIT_HUSK)) + if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !HAS_TRAIT(H, TRAIT_HUSK) && !(signal_result & COMPONENT_BLOCK_DEFIB)) tobehealed = min(health + threshold, 0) // It's HILARIOUS without this min statement, let me tell you tobehealed -= 5 //They get 5 of each type of damage healed so excessive combined damage will not immediately kill them after they get revived H.adjustOxyLoss(tobehealed) @@ -618,6 +627,7 @@ if(tplus > tloss) H.setBrainLoss( max(0, min(99, ((tlimit - tplus) / tlimit * 100)))) SEND_SIGNAL(H, COMSIG_LIVING_MINOR_SHOCK, 100) + SEND_SIGNAL(H, COMSIG_LIVING_DEFIBBED, user, src) if(isrobot(user)) var/mob/living/silicon/robot/R = user R.cell.use(revivecost) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 157d1d2afd8..d8cb9ec38ec 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -79,6 +79,16 @@ var/pump_delay = 30 //you can pump 1 second early, for lag, but no more (otherwise you could spam heal) var/blood_loss = 100 //600 blood is human default, so 5 failures (below 122 blood is where humans die because reasons?) + // Give the user a chance to be shocked to life with the heart in, since defibs put them to sleep. + /// How long the shock pumps their heart for them. + var/revival_grace_period = 10 SECONDS + /// If true, the user doesn't need to pump their heart. + var/in_grace_period = FALSE + /// Times that it's been shocked. + var/times_shocked = 0 + /// Max times that the shock will work before it'll just refuse. + var/max_shocks_allowed = 5 + //How much to heal per pump, negative numbers would HURT the player var/heal_brute = 0 var/heal_burn = 0 @@ -96,7 +106,7 @@ return ..() /obj/item/organ/internal/heart/cursed/on_life() - if(world.time > (last_pump + pump_delay)) + if(world.time > (last_pump + pump_delay) && !in_grace_period) if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects. var/mob/living/carbon/human/H = owner if(!(NO_BLOOD in H.dna.species.species_traits)) @@ -111,9 +121,61 @@ ..() if(owner) to_chat(owner, "Your heart has been replaced with a cursed one, you have to pump this one manually otherwise you'll die!") + RegisterSignal(owner, COMSIG_LIVING_PRE_DEFIB, .proc/just_before_revive) + RegisterSignal(owner, COMSIG_LIVING_DEFIBBED, .proc/on_defib_revive) + +/obj/item/organ/internal/heart/cursed/proc/on_defib_revive(mob/living/carbon/shocked, mob/living/carbon/shocker, obj/item/defib, mob/dead/observer/ghost = null) + SIGNAL_HANDLER // COMSIG_LIVING_DEFIBBED + + if(!owner || !istype(owner) || owner.stat != DEAD) + return + + if(times_shocked >= max_shocks_allowed) + shocker.visible_message( + "Tendrils of ghastly electricity surge from [shocked] as [shocked.p_their()] heart seems to outright refuse defibrillation!", + blind_message = "You hear a loud shock." + ) + tesla_zap(owner, 4, 8000, ZAP_MOB_STUN | ZAP_MOB_DAMAGE) + // NO, YOU! + playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, 1) + + defib.audible_message("[defib] buzzes: Resuscitation failed - Anomalous heart activity detected while administering shock.") + playsound(defib, "defib_saftyon.ogg", 50, FALSE) + + return COMPONENT_DEFIB_OVERRIDE + + in_grace_period = TRUE + times_shocked++ + // wake up + addtimer(CALLBACK(src, .proc/after_revive), 2 SECONDS) // grab a brush and put a little make-up + addtimer(CALLBACK(src, .proc/on_end_grace_period), revival_grace_period) // hide the scars to fade away the shake-up + +/obj/item/organ/internal/heart/cursed/proc/after_revive() + owner.SetSleeping(0) + owner.SetParalysis(0) + +/// Run this just before the shock is applied so we end up with enough blood to revive. +/obj/item/organ/internal/heart/cursed/proc/just_before_revive(mob/living/carbon/shocked, mob/living/carbon/shocker, mob/dead/observer/ghost = null) + SIGNAL_HANDLER // COMSIG_LIVING_PRE_DEFIB + + if(owner.stat == DEAD) + owner.blood_volume = BLOOD_VOLUME_OKAY + +/obj/item/organ/internal/heart/cursed/proc/on_end_grace_period() + in_grace_period = FALSE + if(!owner) + return + to_chat(owner, "The effects of the shock seem to wear off, and you feel a familiar tightness in your chest! Get pumping!") + + if(times_shocked < max_shocks_allowed - 1) + to_chat(owner, "It doesn't feel like your [name] enjoyed that.") + else if(times_shocked == max_shocks_allowed - 1) + to_chat(owner, "Your [name] starts to feel heavy in your chest. It doesn't seem like it'll be able to take many more shocks!") + else + to_chat(owner, "Your [name] feels like lead. Something tells you that if you die with it again, you won't get another chance!") /datum/action/item_action/organ_action/cursed_heart - name = "pump your blood" + name = "Pump your heart" //You are now brea- pumping blood manually /datum/action/item_action/organ_action/cursed_heart/Trigger() @@ -127,7 +189,7 @@ cursed_heart.last_pump = world.time playsound(owner,'sound/effects/singlebeat.ogg',40,1) - to_chat(owner, "Your heart beats.") + to_chat(owner, "Your heart beats.") var/mob/living/carbon/human/H = owner if(istype(H))