Ports arterial bleeding and tendon severing (#7432)

This commit is contained in:
Matt Atlas
2019-11-21 14:45:19 +01:00
committed by Werner
parent a8ffad24bc
commit ce6c12f8a6
27 changed files with 437 additions and 277 deletions
+89 -6
View File
@@ -131,18 +131,53 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
//Bleeding out
var/blood_max = 0
var/open_wound
var/list/do_spray = list()
for(var/obj/item/organ/external/temp in organs)
if(!(temp.status & ORGAN_BLEEDING) || temp.status & ORGAN_ROBOT)
continue
for(var/datum/wound/W in temp.wounds)
if(W.bleeding())
blood_max += ((W.damage / 40) * species.bleed_mod)
open_wound = TRUE
if(temp.applied_pressure)
if(ishuman(temp.applied_pressure))
var/mob/living/carbon/human/H = temp.applied_pressure
H.bloody_hands(src, 0)
var/min_eff_damage = max(0, W.damage - 10) / 6
blood_max += max(min_eff_damage, W.damage - 30) / 40
else
blood_max += ((W.damage / 40) * species.bleed_mod)
if(temp.status & ORGAN_ARTERY_CUT)
var/bleed_amount = Floor(vessel.total_volume / (temp.applied_pressure || !open_wound ? 450 : 300))
if(bleed_amount)
if(open_wound)
blood_max += bleed_amount
do_spray += temp.name
else
blood_max += W.damage / 40
if (temp.open)
blood_max += 2 * species.bleed_mod //Yer stomach is cut open
drip(blood_max)
if(world.time >= next_blood_squirt && istype(loc, /turf) && do_spray.len)
visible_message("<span class='danger'>Blood squirts from \the [src]'s [pick(do_spray)]!</span>", "<span class='danger'><font size='3'>Blood is squirting out of your [pick(do_spray)]!</font></span>")
eye_blurry = 2
Stun(1)
next_blood_squirt = world.time + 100
var/turf/sprayloc = get_turf(src)
blood_max -= drip(Ceiling(blood_max/3), sprayloc)
if(blood_max > 0)
blood_max -= blood_squirt(blood_max, sprayloc)
if(blood_max > 0)
drip(blood_max, get_turf(src))
else
drip(blood_max)
/mob/living/carbon/human
var/next_blood_squirt = 0
//Makes a blood drop, leaking amt units of blood from the mob
/mob/living/carbon/human/proc/drip(var/amt as num)
/mob/living/carbon/human/proc/drip(var/amt as num, var/tar = src, var/spraydir)
if(species && species.flags & NO_BLOOD) //TODO: Make drips come from the reagents instead.
return
@@ -151,7 +186,52 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
return
vessel.remove_reagent("blood",amt)
blood_splatter(src,src)
blood_splatter(tar, src, spray_dir = spraydir)
#define BLOOD_SPRAY_DISTANCE 2
/mob/living/carbon/human/proc/blood_squirt(var/amt, var/turf/sprayloc)
if(amt <= 0 || !istype(sprayloc))
return
var/spraydir = pick(alldirs)
amt = Ceiling(amt/BLOOD_SPRAY_DISTANCE)
var/bled = 0
spawn(0)
for(var/i = 1 to BLOOD_SPRAY_DISTANCE)
sprayloc = get_step(sprayloc, spraydir)
if(!istype(sprayloc) || sprayloc.density)
break
var/hit_mob
for(var/thing in sprayloc)
var/atom/A = thing
if(!A.simulated)
continue
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(!H.lying)
H.bloody_body(src)
H.bloody_hands(src)
var/blinding = FALSE
if(ran_zone("head", 75))
blinding = TRUE
for(var/obj/item/I in list(H.head, H.glasses, H.wear_mask))
if(I && (I.body_parts_covered & EYES))
blinding = FALSE
break
if(blinding)
H.eye_blurry = max(H.eye_blurry, 10)
H.eye_blind = max(H.eye_blind, 5)
to_chat(H, "<span class='danger'>You are blinded by a spray of blood!</span>")
else
to_chat(H, "<span class='danger'>You are hit by a spray of blood!</span>")
hit_mob = TRUE
if(hit_mob || !A.CanPass(src, sprayloc))
break
drip(amt, sprayloc, spraydir)
bled += amt
return bled
#undef BLOOD_SPRAY_DISTANCE
/****************************************************
BLOOD TRANSFERS
@@ -274,7 +354,7 @@ proc/blood_incompatible(donor,receiver,donor_species,receiver_species)
//AB is a universal receiver.
return 0
proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large)
proc/blood_splatter(var/target, var/datum/reagent/blood/source, var/large, var/spray_dir)
var/obj/effect/decal/cleanable/blood/B
var/decal_type = /obj/effect/decal/cleanable/blood/splatter
@@ -283,7 +363,6 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large)
var/mob/living/carbon/human/M = source
source = M.get_blood(M.vessel)
// Are we dripping or splattering?
var/list/drips = list()
// Only a certain number of drips (or one large splatter) can be on a given turf.
@@ -312,6 +391,10 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large)
B.basecolor = source.data["blood_colour"]
B.update_icon()
if(spray_dir)
B.icon_state = "squirt"
B.dir = spray_dir
// Update blood information.
if(source.data["blood_DNA"])
B.blood_DNA = list()
+35 -29
View File
@@ -51,7 +51,10 @@
var/encased // Needs to be opened with a saw to access the organs.
var/list/implants = list()
var/wound_update_accuracy = 1 // how often wounds should be updated, a higher number means less often
var/has_tendon = FALSE //Does this limb have a tendon?
var/joint = "joint" // Descriptive string used in dislocation.
var/artery_name = "artery" //Name of the artery. Cartoid, etc.
var/tendon_name = "tendon" //Name of the limb's tendon. Achilles heel, etc.
var/amputation_point // Descriptive string used in amputation.
var/dislocated = 0 // If you target a joint, you can dislocate the limb, causing temporary damage to the organ.
var/can_grasp //It would be more appropriate if these two were named "affects_grasp" and "affects_stand" at this point
@@ -64,6 +67,8 @@
var/maim_bonus = 0.75 //For special projectile gibbing calculation, dubbed "maiming"
var/can_be_maimed = TRUE //Can this limb be 'maimed'?
var/atom/movable/applied_pressure //Pressure applied to wounds. It'll make them bleed less, generally.
/obj/item/organ/external/proc/invalidate_marking_cache()
cached_markings = null
@@ -79,6 +84,8 @@
for(var/obj/item/organ/O in internal_organs)
qdel(O)
applied_pressure = null
return ..()
/obj/item/organ/external/attack_self(var/mob/user)
@@ -401,10 +408,14 @@ This function completely restores a damaged organ to perfect condition.
//moved this before the open_wound check so that having many small wounds for example doesn't somehow protect you from taking internal damage (because of the return)
//Possibly trigger an internal wound, too.
var/local_damage = brute_dam + burn_dam + damage
if(damage > 15 && type != BURN && local_damage > 30 && prob(damage) && !(status & ORGAN_ROBOT))
var/datum/wound/internal_bleeding/I = new (min(damage - 15, 15))
wounds += I
owner.custom_pain("You feel something rip in your [name]!", 1)
if(damage > 15 && type != BURN && local_damage > 30 && !(status & ORGAN_ROBOT))
var/internal_damage
if(prob(damage) && sever_artery())
internal_damage = TRUE
if(prob(Ceiling(damage / 4)) && type == CUT && sever_tendon())
internal_damage = TRUE
if(internal_damage)
owner.custom_pain("You feel something rip in your [name]!", 25)
// first check whether we can widen an existing wound
if(wounds.len > 0 && prob(max(50+(number_wounds-1)*10,90)))
@@ -631,18 +642,6 @@ Note that amputating the affected organ does in fact remove the infection from t
if (W.damage > 0)
updatehud = 1//If there are any wounds with damage to heal, then we'll update health huds
// Internal wounds get worse over time. Low temperatures (cryo) stop them.
if(W.damage && W.internal && owner.bodytemperature >= 170)
var/bicardose = owner.reagents.get_reagent_amount("bicaridine")
var/inaprovaline = owner.reagents.get_reagent_amount("inaprovaline")
if(!(W.can_autoheal() || (bicardose && inaprovaline))) //bicaridine and inaprovaline stop internal wounds from growing bigger with time, unless it is so small that it is already healing
W.open_wound(0.09 * wound_update_accuracy)
if(!owner.reagents.has_reagent("coagulant", 2))
owner.vessel.remove_reagent("blood", wound_update_accuracy * W.damage/40) //line should possibly be moved to handle_blood, so all the bleeding stuff is in one place.
if(prob(1 * wound_update_accuracy))
owner.custom_pain("You feel a stabbing pain in your [name]!",1)
// slow healing
var/heal_amt = 0
@@ -687,11 +686,10 @@ Note that amputating the affected organ does in fact remove the infection from t
//update damage counts
for(var/datum/wound/W in wounds)
if(!W.internal) //so IB doesn't count towards crit/paincrit
if(W.damage_type == BURN)
burn_dam += W.damage
else
brute_dam += W.damage
if(W.damage_type == BURN)
burn_dam += W.damage
else
brute_dam += W.damage
if(!(status & ORGAN_ROBOT) && W.bleeding() && (H && !(H.species.flags & NO_BLOOD)))
W.bleed_timer--
@@ -870,7 +868,6 @@ Note that amputating the affected organ does in fact remove the infection from t
// checks if all wounds on the organ are bandaged
/obj/item/organ/external/proc/is_bandaged()
for(var/datum/wound/W in wounds)
if(W.internal) continue
if(!W.bandaged)
return 0
return 1
@@ -878,7 +875,6 @@ Note that amputating the affected organ does in fact remove the infection from t
// checks if all wounds on the organ are salved
/obj/item/organ/external/proc/is_salved()
for(var/datum/wound/W in wounds)
if(W.internal) continue
if(!W.salved)
return 0
return 1
@@ -886,7 +882,6 @@ Note that amputating the affected organ does in fact remove the infection from t
// checks if all wounds on the organ are disinfected
/obj/item/organ/external/proc/is_disinfected()
for(var/datum/wound/W in wounds)
if(W.internal) continue
if(!W.disinfected)
return 0
return 1
@@ -895,7 +890,6 @@ Note that amputating the affected organ does in fact remove the infection from t
var/rval = 0
status &= ~ORGAN_BLEEDING
for(var/datum/wound/W in wounds)
if(W.internal) continue
rval |= !W.bandaged
W.bandaged = 1
return rval
@@ -910,7 +904,6 @@ Note that amputating the affected organ does in fact remove the infection from t
/obj/item/organ/external/proc/disinfect()
var/rval = 0
for(var/datum/wound/W in wounds)
if(W.internal) continue
rval |= !W.disinfected
W.disinfected = 1
W.germ_level = 0
@@ -920,7 +913,6 @@ Note that amputating the affected organ does in fact remove the infection from t
var/rval = 0
src.status &= ~ORGAN_BLEEDING
for(var/datum/wound/W in wounds)
if(W.internal) continue
rval |= !W.clamped
W.clamped = 1
return rval
@@ -1020,7 +1012,7 @@ Note that amputating the affected organ does in fact remove the infection from t
return 0
/obj/item/organ/external/proc/is_usable()
return !is_dislocated() && !(status & (ORGAN_MUTATED|ORGAN_DEAD))
return !is_dislocated() && !(status & (ORGAN_MUTATED|ORGAN_DEAD)) && !(status & ORGAN_TENDON_CUT)
/obj/item/organ/external/proc/is_malfunctioning()
return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam))
@@ -1139,7 +1131,6 @@ Note that amputating the affected organ does in fact remove the infection from t
else if (open)
wound_descriptors["an incision"] = 1
for(var/datum/wound/W in wounds)
if(W.internal && !open) continue // can't see internal wounds
var/this_wound_desc = W.desc
if(W.damage_type == BURN && W.salved) this_wound_desc = "salved [this_wound_desc]"
if(W.bleeding()) this_wound_desc = "bleeding [this_wound_desc]"
@@ -1182,3 +1173,18 @@ Note that amputating the affected organ does in fact remove the infection from t
if(6 to INFINITY)
flavor_text += "a ton of [wound]\s"
return english_list(flavor_text)
/obj/item/organ/external/proc/sever_artery()
if((status & ORGAN_ROBOT) || (status & ORGAN_ARTERY_CUT) || !species || species.flags & NO_BLOOD || species.flags & NO_ARTERIES)
return FALSE
else
status |= ORGAN_ARTERY_CUT
return TRUE
/obj/item/organ/external/proc/sever_tendon()
if(!has_tendon || (status & ORGAN_ROBOT) || (status & ORGAN_TENDON_CUT) || species.flags & NO_TENDONS)
return FALSE
else
status |= ORGAN_TENDON_CUT
return TRUE
+15 -1
View File
@@ -13,6 +13,7 @@
vital = 1
amputation_point = "spine"
joint = "neck"
artery_name = "internal thoracic artery"
dislocated = -1
gendered_icon = 1
cannot_amputate = 1
@@ -32,6 +33,7 @@
parent_organ = BP_CHEST
amputation_point = "lumbar"
joint = "hip"
artery_name = "iliac artery"
dislocated = -1
gendered_icon = 1
maim_bonus = 0.25
@@ -46,6 +48,9 @@
body_part = ARM_LEFT
parent_organ = BP_CHEST
joint = "left elbow"
has_tendon = TRUE
tendon_name = "palmaris longus tendon"
artery_name = "basilic vein"
amputation_point = "left shoulder"
can_grasp = 1
@@ -55,6 +60,9 @@
icon_name = "r_arm"
body_part = ARM_RIGHT
joint = "right elbow"
has_tendon = TRUE
tendon_name = "cruciate ligament"
artery_name = "brachial artery"
amputation_point = "right shoulder"
/obj/item/organ/external/leg
@@ -68,6 +76,9 @@
icon_position = LEFT
parent_organ = BP_GROIN
joint = "left knee"
has_tendon = TRUE
tendon_name = "quadriceps tendon"
artery_name = "femoral artery"
amputation_point = "left hip"
can_stand = 1
@@ -120,6 +131,8 @@
body_part = HAND_LEFT
parent_organ = BP_L_ARM
joint = "left wrist"
has_tendon = TRUE
tendon_name = "carpal ligament"
amputation_point = "left wrist"
can_grasp = 1
maim_bonus = 1
@@ -152,6 +165,7 @@
vital = 1
parent_organ = BP_CHEST
joint = "jaw"
artery_name = "cartoid artery"
amputation_point = "neck"
gendered_icon = 1
encased = "skull"
@@ -187,4 +201,4 @@
/obj/item/organ/external/head/undislocate()
. = ..()
if(owner)
owner.brokejaw = 0
owner.brokejaw = 0
-26
View File
@@ -36,8 +36,6 @@
// stages such as "cut", "deep cut", etc.
var/list/stages
// internal wounds can only be fixed through surgery
var/internal = 0
// maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented.
var/max_bleeding_stage = 0
// one of CUT, BRUISE, PIERCE , BURN
@@ -157,10 +155,6 @@
// than what needed to be healed, return how much heal was left
// set @heals_internal to also heal internal organ damage
/datum/wound/proc/heal_damage(amount, heals_internal = 0)
if(src.internal && !heals_internal)
// heal nothing
return amount
var/healed_damage = min(src.damage, amount)
amount -= healed_damage
src.damage -= healed_damage
@@ -170,16 +164,6 @@
desc = desc_list[current_stage]
src.min_damage = damage_list[current_stage]
//Internal wounds should vanish if damage reaches 0
if (internal && damage <= 0)
//Wounds can't clean themselves up. Instead we'll set vars that will make the organ delete us
internal = 0
bleed_timer = 0
damage = 0
created = -6000//Wounds only disappear after 10 mins
//These vars will cause this wound to be removed and GC'd next tick
// return amount of healing still leftover, can be used for other wounds
return amount
@@ -213,9 +197,6 @@
return 1
/datum/wound/proc/bleeding()
if (src.internal)
return 0 // internal wounds don't bleed in the sense of this function
if (current_stage > max_bleeding_stage)
return 0
@@ -373,13 +354,6 @@ datum/wound/puncture/massive
/datum/wound/burn/carbonised
stages = list("carbonised area" = 50, "healing carbonised area" = 20, "massive burn scar" = 0)
/** INTERNAL BLEEDING **/
/datum/wound/internal_bleeding
internal = 1
stages = list("severed artery" = 30, "cut artery" = 20, "damaged artery" = 10, "bruised artery" = 5)
autoheal_cutoff = 5
max_bleeding_stage = 4 //all stages bleed. It's called internal bleeding after all.
/** EXTERNAL ORGAN LOSS **/
/datum/wound/lost_limb