diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 0570de6bcf..2a197cf844 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -423,7 +423,7 @@ if((!req_defib && grab_ghost) || (req_defib && defib.grab_ghost)) H.notify_ghost_cloning("Your heart is being defibrillated!") H.grab_ghost() // Shove them back in their body. - else if(H.can_defib()) + else if(H.can_revive()) H.notify_ghost_cloning("Your heart is being defibrillated. Re-enter your corpse if you want to be revived!", source = src) do_help(H, user) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f6ef8e8177..8b8caa1513 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -898,16 +898,16 @@ update_inv_handcuffed() update_hud_handcuffed() -/mob/living/carbon/proc/can_defib() +/mob/living/carbon/proc/can_revive(ignore_timelimit = FALSE, maximum_brute_dam = MAX_REVIVE_BRUTE_DAMAGE, maximum_fire_dam = MAX_REVIVE_FIRE_DAMAGE, ignore_heart = FALSE) var/tlimit = DEFIB_TIME_LIMIT * 10 var/obj/item/organ/heart = getorgan(/obj/item/organ/heart) if(suiciding || hellbound || HAS_TRAIT(src, TRAIT_HUSK) || AmBloodsucker(src)) return - if((world.time - timeofdeath) > tlimit) + if(!ignore_timelimit && (world.time - timeofdeath) > tlimit) return if((getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE)) return - if(!heart || (heart.organ_flags & ORGAN_FAILING)) + if(!ignore_heart && (!heart || (heart.organ_flags & ORGAN_FAILING))) return var/obj/item/organ/brain/BR = getorgan(/obj/item/organ/brain) if(QDELETED(BR) || BR.brain_death || (BR.organ_flags & ORGAN_FAILING) || suiciding) diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 922e14e580..9e939078e3 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -199,6 +199,7 @@ var/transfer_amount = T.volume * part if(preserve_data) trans_data = copy_data(T) + post_copy_data(T) transferred += "[T] - [transfer_amount]" R.add_reagent(T.type, transfer_amount * multiplier, trans_data, chem_temp, T.purity, pH, no_react = TRUE, ignore_pH = TRUE) //we only handle reaction after every reagent has been transfered. @@ -239,7 +240,8 @@ var/datum/reagent/T = reagent var/copy_amount = T.volume * part if(preserve_data) - trans_data = T.data + trans_data = copy_data(T) + post_copy_data(T) R.add_reagent(T.type, copy_amount * multiplier, trans_data) src.update_total() @@ -266,7 +268,8 @@ var/datum/reagent/current_reagent = CR if(current_reagent.type == reagent) if(preserve_data) - trans_data = current_reagent.data + trans_data = copy_data(current_reagent) + post_copy_data(current_reagent) R.add_reagent(current_reagent.type, amount, trans_data, chem_temp, current_reagent.purity, pH, no_react = TRUE) remove_reagent(current_reagent.type, amount, 1) if(log && amount > 0) @@ -1116,6 +1119,11 @@ return trans_data +/// +// Should be ran after using copy_data. Calls the reagent's post_copy_data, which usually does nothing. +/datum/reagents/proc/post_copy_data(datum/reagent/current_reagent) + return current_reagent.post_copy_data() + /datum/reagents/proc/get_reagent(type) var/list/cached_reagents = reagent_list . = locate(type) in cached_reagents diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index d6b7201ef9..334d91363a 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -178,6 +178,10 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) M.reagents.add_reagent(impure_chem, impureVol, FALSE, other_purity = 1-cached_purity) log_reagent("MOB ADD: on_merge() (mixed purity): merged [volume - impureVol] of [type] and [volume] of [impure_chem]") +//Ran by a reagent holder on a specific reagent after copying its data. +/datum/reagent/proc/post_copy_data() + return + /datum/reagent/proc/on_update(atom/A) return diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 72a9779726..e052d2475e 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -980,11 +980,11 @@ if(M.stat == DEAD) if(M.suiciding || M.hellbound) //they are never coming back M.visible_message("[M]'s body does not react...") - return + return ..() if(M.getBruteLoss() >= 100 || M.getFireLoss() >= 100 || HAS_TRAIT(M, TRAIT_HUSK)) //body is too damaged to be revived M.visible_message("[M]'s body convulses a bit, and then falls still once more.") M.do_jitter_animation(10) - return + return ..() else M.visible_message("[M]'s body starts convulsing!") M.notify_ghost_cloning(source = M) @@ -996,27 +996,27 @@ if(iscarbon(M)) var/mob/living/carbon/C = M if(!(C.dna && C.dna.species && (NOBLOOD in C.dna.species.species_traits))) - C.blood_volume = max(C.blood_volume, BLOOD_VOLUME_NORMAL*C.blood_ratio) //so you don't instantly re-die from a lack of blood - for(var/organ in C.internal_organs) - var/obj/item/organ/O = organ - if(O.damage > O.maxHealth/2) - O.setOrganDamage(O.maxHealth/2) //so you don't instantly die from organ damage when being revived - + C.blood_volume = max(C.blood_volume, BLOOD_VOLUME_BAD*C.blood_ratio) //so you don't instantly re-die from a lack of blood. You'll still need help if you had none though. + var/obj/item/organ/heart/H = C.getorganslot(ORGAN_SLOT_HEART) + if(H && H.organ_flags & ORGAN_FAILING) + H.applyOrganDamage(-15) M.adjustOxyLoss(-20, 0) M.adjustToxLoss(-20, 0) M.updatehealth() + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(!C.can_revive(ignore_timelimit = TRUE, maximum_brute_dam = 100, maximum_fire_dam = 100, ignore_heart = TRUE)) + return var/tplus = world.time - M.timeofdeath if(M.revive()) M.grab_ghost() M.emote("gasp") log_combat(M, M, "revived", src) var/list/policies = CONFIG_GET(keyed_list/policy) - var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds - var/late = timelimit && (tplus > timelimit) - var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT] + var/policy = policies[POLICYCONFIG_ON_DEFIB_LATE] //Always causes memory loss due to the nature of strange reagent. if(policy) to_chat(M, policy) - M.log_message("revived using strange reagent, [tplus] deciseconds from time of death, considered [late? "late" : "memory-intact"] revival under configured policy limits.", LOG_GAME) + M.log_message("revived using strange reagent, [tplus] deciseconds from time of death, considered late revival due to usage of strange reagent.", LOG_GAME) ..() diff --git a/code/modules/research/nanites/nanite_programs/healing.dm b/code/modules/research/nanites/nanite_programs/healing.dm index 81a837504a..c5f36182c7 100644 --- a/code/modules/research/nanites/nanite_programs/healing.dm +++ b/code/modules/research/nanites/nanite_programs/healing.dm @@ -234,7 +234,7 @@ var/mob/living/carbon/C = host_mob if(C.get_ghost()) return FALSE - return C.can_defib() + return C.can_revive() /datum/nanite_program/defib/proc/zap() var/mob/living/carbon/C = host_mob diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm index 2cdaef9c91..013539fd66 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm @@ -98,8 +98,8 @@ description = "Synthetic tissue used for grafting onto damaged organs during surgery, or for treating limb damage. Has a very tight growth window between 305-320, any higher and the temperature will cause the cells to die. Additionally, growth time is considerably long, so chemists are encouraged to leave beakers with said reaction ongoing, while they tend to their other duties." pH = 7.6 metabolization_rate = 0.05 //Give them time to graft - data = list("grown_volume" = 0, "injected_vol" = 0) - var/borrowed_health + data = list("grown_volume" = 0, "injected_vol" = 0, "borrowed_health" = 0) + var/borrowed_health = 0 color = "#FFDADA" value = REAGENT_VALUE_COMMON @@ -107,31 +107,44 @@ if(iscarbon(M)) var/mob/living/carbon/C = M var/healing_factor = (((data["grown_volume"] / 100) + 1)*reac_volume) - if(method in list(PATCH, TOUCH)) - if (M.stat == DEAD) - M.visible_message("The synthetic tissue rapidly grafts into [M]'s wounds, attemping to repair the damage as quickly as possible.") + if(method == PATCH) //Needs to actually be applied via patch / hypo / medspray and not just beakersplashed. + if (C.stat == DEAD) + C.visible_message("The synthetic tissue rapidly grafts into [M]'s wounds, attemping to repair the damage as quickly as possible.") borrowed_health += healing_factor - M.adjustBruteLoss(-healing_factor*2) - M.adjustFireLoss(-healing_factor*2) - M.adjustToxLoss(-healing_factor) - M.adjustCloneLoss(-healing_factor) - M.updatehealth() + C.adjustBruteLoss(-healing_factor*2) + C.adjustFireLoss(-healing_factor*2) + C.adjustToxLoss(-healing_factor) + C.adjustCloneLoss(-healing_factor) + C.updatehealth() if(data["grown_volume"] > 135 && ((C.health + C.oxyloss)>=80)) - if(M.revive()) - M.emote("gasp") + var/tplus = world.time - M.timeofdeath + if(C.can_revive(ignore_timelimit = TRUE, maximum_brute_dam = MAX_REVIVE_BRUTE_DAMAGE / 2, maximum_fire_dam = MAX_REVIVE_FIRE_DAMAGE / 2, ignore_heart = TRUE) && C.revive()) + C.emote("gasp") borrowed_health *= 2 if(borrowed_health < 100) borrowed_health = 100 - log_combat(M, M, "revived", src) + log_combat(C, C, "revived", src) + var/list/policies = CONFIG_GET(keyed_list/policy) + var/policy = policies[POLICYCONFIG_ON_DEFIB_LATE] //Always causes memory loss due to the nature of synthtissue + if(policy) + to_chat(C, policy) + C.log_message("revived using synthtissue, [tplus] deciseconds from time of death, considered late revival due to usage of synthtissue.", LOG_GAME) else M.adjustBruteLoss(-healing_factor) M.adjustFireLoss(-healing_factor) - to_chat(M, "You feel your flesh merge with the synthetic tissue! It stings like hell!") + var/datum/reagent/synthtissue/active_tissue = M.reagents.has_reagent(/datum/reagent/synthtissue) + var/imperfect = FALSE //Merging with synthtissue that has borrowed health + if(active_tissue && active_tissue.borrowed_health) + borrowed_health += healing_factor + imperfect = TRUE + to_chat(M, "You feel your flesh [imperfect ? "partially and painfully" : ""] merge with the synthetic tissue! It stings like hell[imperfect ? " and is making you feel terribly sick." : ""]!") SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine) + data["borrowed_health"] += borrowed_health //Preserve health offset + borrowed_health = 0 //We are applying this to someone else, so this info will be transferred via data. if(method==INJECT) data["injected_vol"] = reac_volume var/obj/item/organ/heart/H = C.getorganslot(ORGAN_SLOT_HEART) - if(data["grown_volume"] > 50 && H.organ_flags & ORGAN_FAILING) + if(H && data["grown_volume"] > 50 && H.organ_flags & ORGAN_FAILING) H.applyOrganDamage(-20) ..() @@ -145,7 +158,7 @@ C.reagents.remove_reagent(type, 15) to_chat(C, "You feel something reform inside of you!") - data["injected_vol"] -= metabolization_rate + data["injected_vol"] = max(0, data["injected_vol"] - metabolization_rate * C.metabolism_efficiency) //No negatives. if(borrowed_health) C.adjustToxLoss(1) C.adjustCloneLoss(1) @@ -155,6 +168,7 @@ /datum/reagent/synthtissue/on_merge(passed_data) if(!passed_data) return ..() + borrowed_health += passed_data["borrowed_health"] if(passed_data["grown_volume"] > data["grown_volume"]) data["grown_volume"] = passed_data["grown_volume"] if(iscarbon(holder.my_atom)) @@ -166,11 +180,16 @@ /datum/reagent/synthtissue/on_new(passed_data) if(!passed_data) return ..() + borrowed_health += passed_data["borrowed_health"] if(passed_data["grown_volume"] > data["grown_volume"]) data["grown_volume"] = passed_data["grown_volume"] update_name() ..() +/datum/reagent/synthtissue/post_copy_data() + data["borrowed_health"] = 0 //We passed this along to something that needed it, set it back to 0 so we don't do it twice. + return ..() + /datum/reagent/synthtissue/proc/update_name() //They are but babes on creation and have to grow unto godhood switch(data["grown_volume"]) if(-INFINITY to 50)