diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 18033f79479b..1e8a554c95bd 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -36,8 +36,7 @@ HM.on_life(seconds_per_tick, times_fired) if(stat != DEAD) - //heart attack stuff - handle_heart(seconds_per_tick, times_fired) + // handle_heart(seconds_per_tick, times_fired) // NON-MODULE CHANGE handle_liver(seconds_per_tick, times_fired) dna.species.spec_life(src, seconds_per_tick, times_fired) // for mutantraces diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 12d6fa56d181..3d39e161c3bf 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1121,7 +1121,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(attacker_style?.help_act(user, target) == MARTIAL_ATTACK_SUCCESS) return TRUE - if(target.body_position == STANDING_UP || target.appears_alive()) + if(!target.undergoing_cardiac_arrest() && (target.body_position == STANDING_UP || target.appears_alive())) // NON-MODULE CHANGE target.help_shake_act(user) if(target != user) log_combat(user, target, "shaken") diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 9bf815d529f6..6cb626643de6 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -778,4 +778,9 @@ if(!istype(heart)) return - heart.beating = !status + // NON-MODULE CHANGE START + if(status) + heart.Stop() + else + heart.Restart() + // NON-MODULE CHANGE END diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index c7831346cd63..98eb7b23971f 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -758,6 +758,6 @@ /// Helper to check if we seem to be alive or not /mob/living/proc/appears_alive() - return health >= 0 && !HAS_TRAIT(src, TRAIT_FAKEDEATH) + return stat != DEAD && !HAS_TRAIT(src, TRAIT_FAKEDEATH) #undef IS_STUN_IMMUNE diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 5faa98b24d08..d23957add378 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -56,8 +56,7 @@ /obj/item/organ/internal/heart/OnEatFrom(eater, feeder) . = ..() - beating = FALSE - update_appearance() + Stop() // NON-MODULE CHANGE /obj/item/organ/internal/heart/on_life(seconds_per_tick, times_fired) ..() diff --git a/maplestation.dme b/maplestation.dme index a349d1ad3ffc..9c0d7d64198d 100644 --- a/maplestation.dme +++ b/maplestation.dme @@ -5572,6 +5572,7 @@ #include "maplestation_modules\code\modules\language\japanese.dm" #include "maplestation_modules\code\modules\language\language_holder.dm" #include "maplestation_modules\code\modules\language\skrellian.dm" +#include "maplestation_modules\code\modules\library\skill_learning\job_skillchips\medbay.dm" #include "maplestation_modules\code\modules\library\skill_learning\job_skillchips\mining.dm" #include "maplestation_modules\code\modules\loadouts\loadout_items\_limb_datums.dm" #include "maplestation_modules\code\modules\loadouts\loadout_items\_loadout_categories.dm" @@ -5632,6 +5633,9 @@ #include "maplestation_modules\code\modules\mob\living\carbon\human\human.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\modular_sechud_icons.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\skrell_hair.dm" +#include "maplestation_modules\code\modules\mob\living\carbon\human\heart_rework\cpr.dm" +#include "maplestation_modules\code\modules\mob\living\carbon\human\heart_rework\heart_attack.dm" +#include "maplestation_modules\code\modules\mob\living\carbon\human\heart_rework\heart_overrides.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\ornithid_features\armwings.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\ornithid_features\avian_tails.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\ornithid_features\plumage.dm" diff --git a/maplestation_modules/code/__DEFINES/_module_defines.dm b/maplestation_modules/code/__DEFINES/_module_defines.dm index d21d3f91e6f9..c8dd1faf9724 100644 --- a/maplestation_modules/code/__DEFINES/_module_defines.dm +++ b/maplestation_modules/code/__DEFINES/_module_defines.dm @@ -27,8 +27,11 @@ #define TOOLTIP_NO_DAMAGE "This item has very low force and is largely cosmetic." #define TOOLTIP_RANDOM_COLOR "This item has a random color and will change every round." -/// Modular traits +// Modular traits +/// Provides additional resistance to contracting diseases. Should be removed next upstream #define TRAIT_DISEASE_RESISTANT "disease_resistant" +/// Does not harm patients when undergoing CPR +#define TRAIT_CPR_CERTIFIED "cpr_certified" /// Bitflags for speech sounds #define SOUND_NORMAL (1<<0) diff --git a/maplestation_modules/code/datums/quirks/neutral.dm b/maplestation_modules/code/datums/quirks/neutral.dm index 24d8ef53833b..7c14930b0e6b 100644 --- a/maplestation_modules/code/datums/quirks/neutral.dm +++ b/maplestation_modules/code/datums/quirks/neutral.dm @@ -27,3 +27,10 @@ //Will add named cardbinder, starting base 2 cards, packbox of 28 Red cards, 4 counters, and a paper with rules. Now in a handy box! give_item_to_holder(card_binder, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) give_item_to_holder(/obj/item/storage/box/tdatet_starter, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +/datum/quirk/cpr_certified + name = "CPR Certified" + desc = "You are certified to perform CPR on others independent of your job." + icon = FA_ICON_HEARTBEAT + value = 0 + mob_trait = TRAIT_CPR_CERTIFIED diff --git a/maplestation_modules/code/game/objects/structures/crate_lockers/closets/secure/quartermaster.dm b/maplestation_modules/code/game/objects/structures/crate_lockers/closets/secure/quartermaster.dm index 704fc952c60a..a42c59887207 100644 --- a/maplestation_modules/code/game/objects/structures/crate_lockers/closets/secure/quartermaster.dm +++ b/maplestation_modules/code/game/objects/structures/crate_lockers/closets/secure/quartermaster.dm @@ -1,5 +1,4 @@ // -- Quartermaster locker stuff. -- /obj/structure/closet/secure_closet/quartermaster/PopulateContents() . = ..() - new /obj/item/storage/box/skillchips/cargo(src) new /obj/item/storage/bag/garment/magic/quartermaster(src) // done at the veeeery end for a reason. diff --git a/maplestation_modules/code/modules/library/skill_learning/job_skillchips/medbay.dm b/maplestation_modules/code/modules/library/skill_learning/job_skillchips/medbay.dm new file mode 100644 index 000000000000..561d5d3f83df --- /dev/null +++ b/maplestation_modules/code/modules/library/skill_learning/job_skillchips/medbay.dm @@ -0,0 +1,76 @@ +/obj/item/skillchip/entrails_reader + complexity = 0 // who cares? + +/// Teaches you how to perform CPR without harming the patient +/obj/item/skillchip/job/cpr + name = "CPR-Aid" + skill_name = "CPR Training" + skill_description = "Provides the user with the knowledge of how to safely perform CPR on a patient." + skill_icon = FA_ICON_HEARTBEAT + activate_message = span_notice("You feel more confident in your ability to perform CPR.") + deactivate_message = span_notice("You suddenly feel less confident in your ability to perform CPR.") + auto_traits = list(TRAIT_CPR_CERTIFIED) + complexity = 0 // it's pretty minor, all things considered + +/datum/outfit/job/doctor/New() + . = ..() + LAZYADD(skillchips, /obj/item/skillchip/job/cpr) + +/datum/outfit/job/paramedic/New() + . = ..() + LAZYADD(skillchips, /obj/item/skillchip/job/cpr) + +/datum/outfit/job/cmo/New() + . = ..() + LAZYADD(skillchips, /obj/item/skillchip/job/cpr) + +/obj/item/storage/box/skillchips/medbay + name = "box of medbay skillchips" + desc = "Contains spares of every medical job skillchip." + +/obj/item/storage/box/skillchips/medbay/PopulateContents() + new /obj/item/skillchip/job/cpr(src) + new /obj/item/skillchip/job/cpr(src) + new /obj/item/skillchip/job/cpr(src) + new /obj/item/skillchip/job/cpr(src) + new /obj/item/skillchip/entrails_reader(src) + +/obj/structure/closet/secure_closet/chief_medical/PopulateContents() + . = ..() + new /obj/item/storage/box/skillchips/medbay(src) + +/// Book that grants the same trait as a skillchip, since reasonably there's no need for it to be chip locked +/obj/item/book/granter/cpr + name = "CPR Training Manual" + desc = "A book that teaches you how to perform CPR properly and safely." + icon_state = "book7" + remarks = list( + "Assess the situation for danger... But it's always dangerous on the station!", + "Make sure to check for a pulse and call for help before starting...", + "Thirty compressions followed by two breaths...", + "Match compressions to the beat of 'Staying Alive'... What?", + "Proper hand placement is crucial. Wait, are lizardperson hearts in the same location as humans?", + "Tilt the head back and pinch the nose before delivering breaths.", + "Let the chest return to its normal position after each compression.", + "Follow up with an AED if available.", + ) + pages_to_mastery = 6 + reading_time = 2 SECONDS + uses = INFINITY + +/obj/item/book/granter/cpr/can_learn(mob/living/user) + return !HAS_TRAIT_FROM(user, TRAIT_CPR_CERTIFIED, name) + +/obj/item/book/granter/cpr/on_reading_start(mob/living/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_CPR_CERTIFIED)) + to_chat(user, span_notice("You already know how to perform CPR, but it can't hurt to brush up.")) + +/obj/item/book/granter/cpr/on_reading_finished(mob/living/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_CPR_CERTIFIED)) + to_chat(user, span_green("You remind yourself of the proper way to perform CPR safely.")) + else + to_chat(user, span_green("You feel confident in your ability to perform CPR safely.")) + + ADD_TRAIT(user, TRAIT_CPR_CERTIFIED, name) diff --git a/maplestation_modules/code/modules/library/skill_learning/job_skillchips/mining.dm b/maplestation_modules/code/modules/library/skill_learning/job_skillchips/mining.dm index 872d34fba159..9366382d5da4 100644 --- a/maplestation_modules/code/modules/library/skill_learning/job_skillchips/mining.dm +++ b/maplestation_modules/code/modules/library/skill_learning/job_skillchips/mining.dm @@ -5,8 +5,8 @@ skill_name = "Off Station Pain Resistance" skill_description = "For the adventurous in life, this skillchip provides a reduction in pain received when off the station." skill_icon = "fist-raised" - activate_message = "You feel like you can safely take on the unknown." - deactivate_message = "You feel more vulnerable to the unknown." + activate_message = span_notice("You feel like you can safely take on the unknown.") + deactivate_message = span_notice("You feel more vulnerable to the unknown.") /obj/item/skillchip/job/off_z_pain_resistance/on_activate(mob/living/carbon/user, silent = FALSE) . = ..() @@ -47,3 +47,7 @@ /obj/item/storage/box/skillchips/cargo/PopulateContents() new /obj/item/skillchip/job/off_z_pain_resistance(src) new /obj/item/skillchip/job/off_z_pain_resistance(src) + +/obj/structure/closet/secure_closet/quartermaster/PopulateContents() + . = ..() + new /obj/item/storage/box/skillchips/cargo(src) diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/cpr.dm b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/cpr.dm new file mode 100644 index 000000000000..fd0b7e32f415 --- /dev/null +++ b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/cpr.dm @@ -0,0 +1,161 @@ + +/mob/living/carbon/human/do_cpr(mob/living/carbon/human/target) + if(target == src) + return FALSE + + if (DOING_INTERACTION_WITH_TARGET(src, target)) + return FALSE + + cpr_process(target, beat = 1) // begin at beat 1, skip the first breath + return TRUE + +/// Number of "beats" per CPR cycle +/// This corresponds to N - 1 compressions and 1 breath +#define BEATS_PER_CPR_CYCLE 16 +// Also I'm kinda cheating here because we do 15 compressions to 1 breath rather than 30 compressions to 2 breaths +// But it's close enough to the real thing (ratio wise) that I'm OK with it + +/mob/living/carbon/human/proc/cpr_process(mob/living/carbon/human/target, beat = 0, panicking = FALSE) + set waitfor = FALSE + + if (!target.appears_alive()) + to_chat(src, span_warning("[target.name] is dead!")) + return + + if(!panicking && target.stat != CONSCIOUS && beat >= BEATS_PER_CPR_CYCLE + 1) + to_chat(src, span_warning("[target] still isn't up[HAS_TRAIT(src, TRAIT_CPR_CERTIFIED) ? " - you pick up the pace." : "! You try harder!"]")) + panicking = TRUE + + var/doafter_mod = panicking ? 0.5 : 1 + + var/doing_a_breath = FALSE + if(beat % BEATS_PER_CPR_CYCLE == 0) + if (is_mouth_covered()) + to_chat(src, span_warning("Your mouth is covered, so you can only perform compressions!")) + + else if (target.is_mouth_covered()) + to_chat(src, span_warning("[p_their(TRUE)] mouth is covered, so you can only perform compressions!")) + + else if (!get_organ_slot(ORGAN_SLOT_LUNGS)) + to_chat(src, span_warning("You have no lungs to breathe with, so you can only perform compressions!")) + + else if (HAS_TRAIT(src, TRAIT_NOBREATH)) + to_chat(src, span_warning("You do not breathe, so you can only perform compressions!")) + + else + doing_a_breath = TRUE + + if(doing_a_breath) + visible_message( + span_notice("[src] attempts to give [target.name] a rescue breath!"), + span_notice("You attempt to give [target.name] a rescue breath as a part of CPR... Hold still!"), + ) + + if(!do_after(user = src, delay = doafter_mod * 6 SECONDS, target = target)) + return + + add_mood_event("saved_life", /datum/mood_event/saved_life) + visible_message( + span_notice("[src] delivers a rescue breath on [target.name]!"), + span_notice("You deliver a rescue breath on [target.name]."), + ) + + else + var/is_first_compression = beat % BEATS_PER_CPR_CYCLE == 1 + if(is_first_compression) + visible_message( + span_notice("[src] attempts to give [target.name] chest compressions!"), + span_notice("You try to perform chest compressions as a part of CPR on [target.name]... Hold still!"), + ) + + if(!do_after(user = src, delay = doafter_mod * 1 SECONDS, target = target)) + return + + if(is_first_compression) + visible_message( + span_notice("[src] delivers chest compressions on [target.name]!"), + span_notice("You deliver chest compressions on [target.name]."), + ) + + target.apply_status_effect(/datum/status_effect/cpr_applied) + + if(doing_a_breath) + if(HAS_TRAIT(target, TRAIT_NOBREATH)) + to_chat(target, span_unconscious("You feel a breath of fresh air... which is a sensation you don't recognise...")) + else if (!target.get_organ_slot(ORGAN_SLOT_LUNGS)) + to_chat(target, span_unconscious("You feel a breath of fresh air... but you don't feel any better...")) + else if(HAS_TRAIT(src, TRAIT_CPR_CERTIFIED)) + target.adjustOxyLoss(-20) + to_chat(target, span_unconscious("You feel a breath of fresh air enter your lungs... It feels good...")) + else + target.adjustOxyLoss(-12) + to_chat(target, span_unconscious("You feel a breath of fresh air enter your lungs...")) + + // Breath relieves some of the pressure on the chest + var/obj/item/bodypart/chest/chest = target.get_bodypart(BODY_ZONE_CHEST) + if(IS_ORGANIC_LIMB(chest)) + to_chat(target, span_notice("You feel the pressure on your chest ease!")) + chest.heal_damage(brute = 3) + target.cause_pain(BODY_ZONE_CHEST, -2) + + log_combat(src, target, "CPRed", addition = "(breath)") + + else if(beat % (BEATS_PER_CPR_CYCLE / 4) == 0 && panicking) + var/obj/item/bodypart/chest/chest = target.get_bodypart(BODY_ZONE_CHEST) + if(IS_ORGANIC_LIMB(chest)) + var/critical_success = prob(1) && target.undergoing_cardiac_arrest() + if(!HAS_TRAIT(src, TRAIT_CPR_CERTIFIED)) + // Apply damage directly to chest. I would use apply damage but I can't, kinda + if(critical_success) + target.set_heartattack(FALSE) + to_chat(target, span_warning("You feel immense pressure on your chest, and a sudden wave of pain... and then relief.")) + chest.receive_damage(brute = 6, wound_bonus = CANT_WOUND, damage_source = "chest compressions") + target.cause_pain(BODY_ZONE_CHEST, 12) + + else + to_chat(target, span_warning("You feel pressure on your chest!")) + chest.receive_damage(brute = 3, wound_bonus = CANT_WOUND, damage_source = "chest compressions") + target.cause_pain(BODY_ZONE_CHEST, 2) + + to_chat(src, span_warning("You bruise [target.name]'s chest with the pressure!")) + + else if(critical_success) + target.set_heartattack(FALSE) + to_chat(target, span_warning("You pressure fade away from your chest... and then relief.")) + target.cause_pain(BODY_ZONE_CHEST, 8) + + log_combat(src, target, "CPRed", addition = "(compression)") + + if(target.body_position != LYING_DOWN) + return + if(target.stat == CONSCIOUS) + return + + cpr_process(target, beat + 1, panicking) + +#undef BEATS_PER_CPR_CYCLE + +/datum/status_effect/cpr_applied + id = "cpr" + alert_type = null + duration = 1 SECONDS + tick_interval = -1 + status_type = STATUS_EFFECT_REFRESH + +/datum/status_effect/cpr_applied/on_apply() + if(!is_effective(owner)) + return FALSE + return TRUE + +/datum/status_effect/cpr_applied/refresh(effect, ...) + if(!is_effective(owner)) + return + return ..() + +/// Checks if CPR is effective against this mob +/datum/status_effect/cpr_applied/proc/is_effective(mob/checking) + if(isnull(checking)) + return FALSE + if(!checking.get_organ_slot(ORGAN_SLOT_HEART)) // A heart is required for CPR to pump your heart + return FALSE + return TRUE diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/heart_attack.dm b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/heart_attack.dm new file mode 100644 index 000000000000..d4eb1a9d04e1 --- /dev/null +++ b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/heart_attack.dm @@ -0,0 +1,81 @@ +/datum/status_effect/heart_attack + id = "heart_attack" + alert_type = null + tick_interval = 2 SECONDS + /// TimerID for the initial knock out + VAR_FINAL/ko_timer + +/datum/status_effect/heart_attack/on_apply() + if(!iscarbon(owner)) + return FALSE + var/mob/living/carbon/carbon_owner = owner + if(isnull(carbon_owner.dna?.species?.mutantheart)) + return FALSE + + RegisterSignal(owner, COMSIG_SPECIES_GAIN, PROC_REF(species_changed)) + RegisterSignal(owner, COMSIG_CARBON_ATTEMPT_BREATHE, PROC_REF(block_breath)) + + // You get 1 tick of grace before you fall over due to your heart stopping + ko_timer = addtimer(CALLBACK(src, PROC_REF(delayed_ko)), initial(tick_interval), TIMER_STOPPABLE) + return TRUE + +/datum/status_effect/heart_attack/on_remove() + REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) + deltimer(ko_timer) + + UnregisterSignal(owner, COMSIG_SPECIES_GAIN) + UnregisterSignal(owner, COMSIG_CARBON_ATTEMPT_BREATHE) + UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOBREATH)) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOBREATH)) + + if(!QDELING(owner)) + owner.cause_pain(BODY_ZONE_CHEST, -20) + +/datum/status_effect/heart_attack/proc/delayed_ko() + if(!HAS_TRAIT(owner, TRAIT_NOBREATH)) + ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) + ko_timer = null + + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOBREATH), PROC_REF(gained_nobreath)) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOBREATH), PROC_REF(lost_nobreath)) + +/datum/status_effect/heart_attack/proc/species_changed(datum/source, datum/species/new_species, datum/species/old_species) + SIGNAL_HANDLER + if(isnull(new_species.mutantheart)) + qdel(src) + +/datum/status_effect/heart_attack/proc/gained_nobreath(datum/source) + SIGNAL_HANDLER + REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) + +/datum/status_effect/heart_attack/proc/lost_nobreath(datum/source) + SIGNAL_HANDLER + if(!HAS_TRAIT(owner, TRAIT_NOBREATH)) + ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) + +/datum/status_effect/heart_attack/proc/block_breath(datum/source) + SIGNAL_HANDLER + + if(HAS_TRAIT(owner, TRAIT_NOBREATH)) + return NONE + + if(prob(10)) + INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob, emote), "gasp") + + return COMSIG_CARBON_BLOCK_BREATH + +/datum/status_effect/heart_attack/tick(seconds_per_tick, times_fired) + seconds_per_tick = (initial(tick_interval) / 10) // to remove when upstream merge + + if(ko_timer) // Not yet + return + if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_STABLEHEART) || HAS_TRAIT(owner, TRAIT_NOBLOOD) || IS_IN_STASIS(owner)) + return + if(owner.has_status_effect(/datum/status_effect/cpr_applied)) + return + + if(!HAS_TRAIT(owner, TRAIT_NOBREATH)) + owner.adjustOxyLoss(4 * seconds_per_tick) + + // Tissues die without blood circulation + owner.adjustBruteLoss(1 * seconds_per_tick) diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/heart_overrides.dm b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/heart_overrides.dm new file mode 100644 index 000000000000..05624ad034c0 --- /dev/null +++ b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/heart_overrides.dm @@ -0,0 +1,41 @@ +/obj/item/organ/internal/heart/Stop() + if(!beating) + return + + . = ..() + if(!. || !owner) + return + + owner.apply_status_effect(/datum/status_effect/heart_attack) + +/obj/item/organ/internal/heart/Restart() + if(beating) + return + + . = ..() + if(!. || !owner) + return + + owner.remove_status_effect(/datum/status_effect/heart_attack) + +/obj/item/organ/internal/heart/on_insert(mob/living/carbon/organ_owner, special) + . = ..() + if(beating) + organ_owner.remove_status_effect(/datum/status_effect/heart_attack) + +/obj/item/organ/internal/heart/on_remove(mob/living/carbon/organ_owner, special) + . = ..() + if(!special) + organ_owner.apply_status_effect(/datum/status_effect/heart_attack) + +// Glands can't stop beating but they are cringe +/obj/item/organ/internal/heart/gland/Stop() + return FALSE + +/* +// I think this is un-necessary, so I'm commenting it out even if it's SUPPOSED to be a thing +/mob/living/carbon/human/setup_organless_effects() + . = ..() + // You don't spawn with a heart, so, technically... You spawn with a heart attack + apply_status_effect(/datum/status_effect/heart_attack) +*/