mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-21 20:13:45 +01:00
225a38b7de
* Migrate organs to the new attack chain. * Migrate additional organs and rod of asclepius. * Update regenerative core. * Call parent activate_self of regenerative core.
346 lines
14 KiB
Plaintext
346 lines
14 KiB
Plaintext
/obj/item/organ/internal/heart
|
|
name = "heart"
|
|
icon_state = "heart-on"
|
|
organ_tag = "heart"
|
|
slot = "heart"
|
|
origin_tech = "biotech=5"
|
|
dead_icon = "heart-off"
|
|
base_icon_state = "heart"
|
|
organ_datums = list(/datum/organ/heart)
|
|
|
|
/obj/item/organ/internal/heart/update_icon_state()
|
|
var/datum/organ/heart/heart = organ_datums[ORGAN_DATUM_HEART]
|
|
if(heart.beating)
|
|
icon_state = "[base_icon_state]-on"
|
|
else
|
|
icon_state = "[base_icon_state]-off"
|
|
|
|
/obj/item/organ/internal/heart/activate_self(mob/user)
|
|
if(..())
|
|
return ITEM_INTERACT_COMPLETE
|
|
if(status & ORGAN_DEAD)
|
|
to_chat(user, SPAN_WARNING("You can't restart a dead heart."))
|
|
return ITEM_INTERACT_COMPLETE
|
|
var/datum/organ/heart/heart = organ_datums[ORGAN_DATUM_HEART]
|
|
heart.try_restart(8 SECONDS)
|
|
return ITEM_INTERACT_COMPLETE
|
|
|
|
/obj/item/organ/internal/heart/safe_replace(mob/living/carbon/human/target)
|
|
var/datum/organ/heart/heart = organ_datums[ORGAN_DATUM_HEART]
|
|
heart.change_beating(TRUE)
|
|
..()
|
|
|
|
/obj/item/organ/internal/heart/cursed
|
|
name = "cursed heart"
|
|
desc = "it needs to be pumped..."
|
|
icon_state = "cursedheart-off"
|
|
base_icon_state = "cursedheart"
|
|
origin_tech = "biotech=6"
|
|
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
|
|
organ_datums = list(/datum/organ/heart, /datum/organ/battery) // This doesn't actually work for IPCs but it also doesn't kill you, and it's funny
|
|
var/last_pump = 0
|
|
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
|
|
var/heal_oxy = 0
|
|
|
|
/obj/item/organ/internal/heart/cursed/interact_with_atom(atom/target, mob/living/carbon/human/user, list/modifiers)
|
|
if(!(target == user && istype(user)))
|
|
return ..()
|
|
if(NO_BLOOD in user.dna.species.species_traits)
|
|
to_chat(user, SPAN_USERDANGER("[src] is not compatible with your form!"))
|
|
return ITEM_INTERACT_COMPLETE
|
|
playsound(user,'sound/effects/singlebeat.ogg', 40, 1)
|
|
user.drop_item()
|
|
insert(user)
|
|
|
|
/obj/item/organ/internal/heart/cursed/on_life()
|
|
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))
|
|
H.blood_volume = max(H.blood_volume - blood_loss, 0)
|
|
to_chat(H, SPAN_USERDANGER("You have to keep pumping your blood!"))
|
|
if(H?.client?.prefs.colourblind_mode == COLOURBLIND_MODE_NONE)
|
|
H.client.color = "red" //bloody screen so real
|
|
else
|
|
last_pump = world.time //lets be extra fair *sigh*
|
|
|
|
/obj/item/organ/internal/heart/cursed/insert(mob/living/carbon/M, special = 0)
|
|
..()
|
|
if(owner)
|
|
to_chat(owner, SPAN_USERDANGER("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_REF(just_before_revive))
|
|
RegisterSignal(owner, COMSIG_LIVING_DEFIBBED, PROC_REF(on_defib_revive))
|
|
in_grace_period = TRUE
|
|
addtimer(VARSET_CALLBACK(src, in_grace_period, FALSE), revival_grace_period)
|
|
|
|
/obj/item/organ/internal/heart/cursed/remove(mob/living/carbon/M, special)
|
|
if(owner?.client?.prefs.colourblind_mode == COLOURBLIND_MODE_NONE)
|
|
owner.client.color = ""
|
|
|
|
UnregisterSignal(owner, COMSIG_LIVING_PRE_DEFIB, PROC_REF(just_before_revive))
|
|
UnregisterSignal(owner, COMSIG_LIVING_DEFIBBED, PROC_REF(on_defib_revive))
|
|
return ..()
|
|
|
|
|
|
/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(
|
|
"<span class='userdanger'>Tendrils of ghastly electricity surge from [shocked] as [shocked.p_their()] heart seems to outright refuse defibrillation!<span>",
|
|
blind_message = SPAN_DANGER("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(SPAN_BOLDNOTICE("[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_REF(after_revive)), 2 SECONDS) // grab a brush and put a little make-up
|
|
addtimer(CALLBACK(src, PROC_REF(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, SPAN_USERDANGER("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, SPAN_WARNING("It doesn't feel like your [name] enjoyed that."))
|
|
else if(times_shocked == max_shocks_allowed - 1)
|
|
to_chat(owner, SPAN_DANGER("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, SPAN_USERDANGER("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 heart"
|
|
|
|
//You are now brea- pumping blood manually
|
|
/datum/action/item_action/organ_action/cursed_heart/Trigger(left_click)
|
|
. = ..()
|
|
if(. && istype(target, /obj/item/organ/internal/heart/cursed))
|
|
var/obj/item/organ/internal/heart/cursed/cursed_heart = target
|
|
|
|
if(world.time < (cursed_heart.last_pump + (cursed_heart.pump_delay - 10))) //no spam
|
|
to_chat(owner, SPAN_USERDANGER("Too soon!"))
|
|
return
|
|
|
|
cursed_heart.last_pump = world.time
|
|
playsound(owner,'sound/effects/singlebeat.ogg',40,1)
|
|
to_chat(owner, SPAN_NOTICE("Your heart beats."))
|
|
|
|
var/mob/living/carbon/human/H = owner
|
|
if(istype(H))
|
|
if(!(NO_BLOOD in H.dna.species.species_traits))
|
|
H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss * 0.5, BLOOD_VOLUME_NORMAL)
|
|
if(owner?.client?.prefs.colourblind_mode == COLOURBLIND_MODE_NONE)
|
|
owner.client.color = ""
|
|
|
|
H.adjustBruteLoss(-cursed_heart.heal_brute)
|
|
H.adjustFireLoss(-cursed_heart.heal_burn)
|
|
H.adjustOxyLoss(-cursed_heart.heal_oxy)
|
|
|
|
/datum/action/item_action/organ_action/cursed_heart/Grant(mob/M)
|
|
..()
|
|
INVOKE_ASYNC(src, PROC_REF(poll_keybinds))
|
|
|
|
/datum/action/item_action/organ_action/cursed_heart/proc/poll_keybinds()
|
|
if(alert(owner, "You've been given a cursed heart! Do you want to bind its action to a keybind?", "Cursed Heart", "Yes", "No") == "Yes")
|
|
return
|
|
// button.set_to_keybind(owner)
|
|
// TODO GAHHH SORRY GDN
|
|
|
|
/obj/item/organ/internal/heart/cybernetic
|
|
name = "cybernetic heart"
|
|
desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make."
|
|
icon_state = "heart-c-on"
|
|
base_icon_state = "heart-c"
|
|
dead_icon = "heart-c-off"
|
|
status = ORGAN_ROBOT
|
|
organ_datums = list(/datum/organ/heart, /datum/organ/battery)
|
|
materials = list(MAT_METAL = 500, MAT_GLASS = 500)
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded
|
|
name = "upgraded cybernetic heart"
|
|
desc = "A more advanced version of a cybernetic heart. Grants the user additional stamina and heart stability, but the electronics are vulnerable to shock."
|
|
icon_state = "heart-c-u-on"
|
|
base_icon_state = "heart-c-u"
|
|
dead_icon = "heart-c-u-off"
|
|
materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 500)
|
|
var/attempted_restart = FALSE
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/insert(mob/living/carbon/M, special = FALSE)
|
|
..()
|
|
RegisterSignal(M, COMSIG_LIVING_MINOR_SHOCK, PROC_REF(shock_heart))
|
|
RegisterSignal(M, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(shock_heart))
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/remove(mob/living/carbon/M, special = FALSE)
|
|
UnregisterSignal(M, COMSIG_LIVING_MINOR_SHOCK)
|
|
UnregisterSignal(M, COMSIG_LIVING_ELECTROCUTE_ACT)
|
|
return ..()
|
|
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/on_life()
|
|
if(!ishuman(owner))
|
|
return
|
|
|
|
if(status & ORGAN_DEAD)
|
|
return
|
|
|
|
var/boost = emagged ? 2 : 1
|
|
owner.AdjustParalysis(-2 SECONDS * boost)
|
|
owner.AdjustStunned(-2 SECONDS * boost)
|
|
owner.AdjustWeakened(-2 SECONDS * boost)
|
|
owner.AdjustKnockDown(-2 SECONDS * boost)
|
|
owner.adjustStaminaLoss(-10 * boost)
|
|
|
|
if(attempted_restart)
|
|
return
|
|
|
|
var/datum/organ/heart/heart_datum = organ_datums[ORGAN_DATUM_HEART]
|
|
|
|
if(!heart_datum.beating)
|
|
to_chat(owner, SPAN_WARNING("Your [name] detects a cardiac event and attempts to return to its normal rhythm!"))
|
|
if(prob(20) && emagged)
|
|
attempted_restart = TRUE
|
|
heart_datum.change_beating(TRUE) // Mötley Crüe - Kickstart My Heart
|
|
owner.adjustOxyLoss(-100)
|
|
owner.SetLoseBreath(0)
|
|
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, SPAN_WARNING("Your [name] returns to its normal rhythm!")), 3 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 20 SECONDS)
|
|
else if(prob(10))
|
|
attempted_restart = TRUE
|
|
heart_datum.change_beating(TRUE)
|
|
owner.adjustOxyLoss(-100)
|
|
owner.SetLoseBreath(0)
|
|
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, SPAN_WARNING("Your [name] returns to its normal rhythm!")), 3 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 30 SECONDS)
|
|
else
|
|
attempted_restart = TRUE
|
|
if(emagged)
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 10 SECONDS)
|
|
else
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 15 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, SPAN_WARNING("Your [name] fails to return to its normal rhythm!")), 3 SECONDS)
|
|
|
|
if(owner.HasDisease(/datum/disease/critical/heart_failure))
|
|
to_chat(owner, SPAN_WARNING("Your [name] detects a cardiac event and attempts to return to its normal rhythm!"))
|
|
if(prob(40) && emagged)
|
|
attempted_restart = TRUE
|
|
for(var/datum/disease/critical/heart_failure/HF in owner.viruses)
|
|
HF.cure()
|
|
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, SPAN_WARNING("Your [name] returns to its normal rhythm!")), 30)
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 20 SECONDS)
|
|
else if(prob(25))
|
|
attempted_restart = TRUE
|
|
for(var/datum/disease/critical/heart_failure/HF in owner.viruses)
|
|
HF.cure()
|
|
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, SPAN_WARNING("Your [name] returns to its normal rhythm!")), 30)
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 20 SECONDS)
|
|
else
|
|
attempted_restart = TRUE
|
|
if(emagged)
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 10 SECONDS)
|
|
else
|
|
addtimer(CALLBACK(src, PROC_REF(recharge)), 15 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(message_to_owner), owner, SPAN_WARNING("Your [name] fails to return to its normal rhythm!")), 30)
|
|
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/proc/message_to_owner(mob/M, message)
|
|
to_chat(M, message)
|
|
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/proc/recharge()
|
|
attempted_restart = FALSE
|
|
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/emag_act(mob/user)
|
|
if(!emagged)
|
|
to_chat(user, SPAN_WARNING("You disable the safeties on [src]"))
|
|
emagged = TRUE
|
|
return TRUE
|
|
else
|
|
to_chat(user, SPAN_WARNING("You re-enable the safeties on [src]"))
|
|
emagged = FALSE
|
|
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/proc/shock_heart(mob/living/carbon/human/source, intensity)
|
|
SIGNAL_HANDLER // COMSIG_LIVING_MINOR_SHOCK + COMSIG_LIVING_ELECTROCUTE_ACT
|
|
|
|
if(!ishuman(owner))
|
|
return
|
|
if(emp_proof)
|
|
return
|
|
intensity = min(intensity, 100)
|
|
var/numHigh = round(intensity / 5)
|
|
var/numMid = round(intensity / 10)
|
|
var/numLow = round(intensity / 20)
|
|
if(emagged && !(status & ORGAN_DEAD))
|
|
if(prob(numHigh))
|
|
to_chat(owner, SPAN_WARNING("Your [name] spasms violently!"))
|
|
// invoke asyncs here because this sleeps
|
|
INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living/carbon/human, adjustBruteLoss), numHigh)
|
|
if(prob(numHigh))
|
|
to_chat(owner, SPAN_WARNING("Your [name] shocks you painfully!"))
|
|
INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living/carbon/human, adjustFireLoss), numHigh)
|
|
if(prob(numMid))
|
|
to_chat(owner, SPAN_WARNING("Your [name] lurches awkwardly!"))
|
|
owner.ForceContractDisease(new /datum/disease/critical/heart_failure(0))
|
|
if(prob(numMid))
|
|
to_chat(owner, SPAN_DANGER("Your [name] stops beating!"))
|
|
var/datum/organ/heart/heart_datum = organ_datums[ORGAN_DATUM_HEART]
|
|
heart_datum.change_beating(FALSE) // Rambunctious Crew - Stop My Fucking Heart
|
|
if(prob(numLow))
|
|
to_chat(owner, SPAN_DANGER("Your [name] shuts down!"))
|
|
INVOKE_ASYNC(src, PROC_REF(necrotize))
|
|
else if(!emagged && !(status & ORGAN_DEAD))
|
|
if(prob(numMid))
|
|
to_chat(owner, SPAN_WARNING("Your [name] spasms violently!"))
|
|
INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living/carbon/human, adjustBruteLoss), numMid)
|
|
if(prob(numMid))
|
|
to_chat(owner, SPAN_WARNING("Your [name] shocks you painfully!"))
|
|
INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living/carbon/human, adjustFireLoss), numMid)
|
|
if(prob(numLow))
|
|
to_chat(owner, SPAN_WARNING("Your [name] lurches awkwardly!"))
|
|
owner.ForceContractDisease(new /datum/disease/critical/heart_failure(0))
|
|
|
|
/obj/item/organ/internal/heart/cybernetic/upgraded/hardened
|
|
name = "hardened overclocked cybernetic heart"
|
|
emp_proof = TRUE
|
|
emagged = TRUE
|