From 9558252b93b7af3c3dbe5fecf88a7ff70dd63800 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Mon, 26 Aug 2019 14:22:17 -0500 Subject: [PATCH] Revert/replaces a lot of #8024 with bleed_rate Wearing armor reduces the blood loss you incur, no longer are you instantly deleted on blood. Dripping blood WILL kill you if you don't solve that issue, medical gauze has been tripled as a QoL for medical staff as a result. --- code/__HELPERS/unsorted.dm | 31 ++++++++ code/_onclick/item_attack.dm | 12 ++- .../effects/decals/cleanable/humans.dm | 5 +- code/game/objects/items/stacks/medical.dm | 8 +- code/game/objects/structures/kitchen_spike.dm | 9 ++- code/modules/mob/living/blood.dm | 74 +++++++++++++++++-- .../mob/living/carbon/human/species.dm | 2 +- code/modules/projectiles/projectile.dm | 39 +++++++++- .../surgery/bodyparts/dismemberment.dm | 4 + 9 files changed, 163 insertions(+), 21 deletions(-) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 7e078184b7..b4f1851bc3 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -492,6 +492,14 @@ Turf and target are separate in case you want to teleport some distance from a t assembled += A return assembled +//Return a list of atoms in a location of a given type. Can be refined to look for pixel-shift. +/proc/get_atoms_of_type(var/atom/here, var/type, var/check_shift, var/shift_x = 0, var/shift_y = 0) + . = list() + if(here) + for(var/atom/thing in here) + if(istype(thing, type) && (check_shift && thing.pixel_x == shift_x && thing.pixel_y == shift_y)) + . += thing + //Step-towards method of determining whether one atom can see another. Similar to viewers() /proc/can_see(atom/source, atom/target, length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate. var/turf/current = get_turf(source) @@ -756,6 +764,29 @@ Turf and target are separate in case you want to teleport some distance from a t loc = loc.loc return null +/proc/pixel_shift_dir(var/dir, var/amount_x = 32, var/amount_y = 32) //Returns a list with pixel_shift values that will shift an object's icon one tile in the direction passed. + amount_x = min(max(0, amount_x), 32) //No less than 0, no greater than 32. + amount_y = min(max(0, amount_x), 32) + var/list/shift = list("x" = 0, "y" = 0) + switch(dir) + if(NORTH) + shift["y"] = amount_y + if(SOUTH) + shift["y"] = -amount_y + if(EAST) + shift["x"] = amount_x + if(WEST) + shift["x"] = -amount_x + if(NORTHEAST) + shift = list("x" = amount_x, "y" = amount_y) + if(NORTHWEST) + shift = list("x" = -amount_x, "y" = amount_y) + if(SOUTHEAST) + shift = list("x" = amount_x, "y" = -amount_y) + if(SOUTHWEST) + shift = list("x" = -amount_x, "y" = -amount_y) + + return shift //For objects that should embed, but make no sense being is_sharp or is_pointed() //e.g: rods diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 6455b4ccb6..7d40df8aa4 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -126,8 +126,16 @@ I.add_mob_blood(src) var/turf/location = get_turf(src) if(iscarbon(src)) - var/mob/living/carbon/C = src - C.bleed(totitemdamage) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + var/armorsave = H.getarmor(H, "melee") + if(armorsave >= 30) // armor is useful again! + H.bleed_rate += round((totitemdamage * 0.15)) // internal bleeding, took it on the joint, what have you. + else + H.bleed_rate += round((totitemdamage * 0.50)) //it's not a 1:1 deletion of blood, but it's worrysome enough that you should get treated asap + else + var/mob/living/carbon/C = src + C.bleed(totitemdamage) else add_splatter_floor(location) if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 1af15b0383..842b230b53 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -35,9 +35,12 @@ icon_state += "-old" add_blood_DNA(list("Non-human DNA" = "A+")) -/obj/effect/decal/cleanable/blood/splatter +/obj/effect/decal/cleanable/blood/splats random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5") +/obj/effect/decal/cleanable/blood/splatter + random_icon_states = list("splatter1", "splatter2", "splatter3", "splatter4", "splatter5") + /obj/effect/decal/cleanable/blood/tracks icon_state = "tracks" desc = "They look like tracks left by wheels." diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 5610cbad9a..2826ef97a4 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -17,15 +17,15 @@ var/self_delay = 50 /obj/item/stack/medical/attack(mob/living/M, mob/user) - - if(M.stat == DEAD && !stop_bleeding) +//Let's see if this isn't a horrid mistake. Removes death check from applying medical stack stuff. should help. +/* if(M.stat == DEAD && !stop_bleeding) var/t_him = "it" if(M.gender == MALE) t_him = "him" else if(M.gender == FEMALE) t_him = "her" to_chat(user, "\The [M] is dead, you cannot help [t_him]!") - return + return */ if(!iscarbon(M) && !isanimal(M)) to_chat(user, "You don't know how to apply \the [src] to [M]!") @@ -125,7 +125,7 @@ icon_state = "gauze" stop_bleeding = 1800 self_delay = 20 - max_amount = 12 + max_amount = 36 //bleeding is a major issue now, let's be nice to our medical team /obj/item/stack/medical/gauze/attackby(obj/item/I, mob/user, params) diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index b9a75f88af..0041801872 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -76,8 +76,13 @@ L.forceMove(drop_location()) L.emote("scream") if(iscarbon(L)) - var/mob/living/carbon/C = L - C.bleed(30) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + H.bleed_rate += 10 + H.bleed(10) //less instant blood damage because you're bleeding, and bleeding is bad news. + else + var/mob/living/carbon/C = L + C.bleed(30) else L.add_splatter_floor() L.adjustBruteLoss(30) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 770e344636..80036a60e0 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -2,6 +2,9 @@ BLOOD SYSTEM ****************************************************/ +#define EXOTIC_BLEED_MULTIPLIER 4 //Multiplies the actually bled amount by this number for the purposes of turf reaction calculations. + + /mob/living/carbon/human/proc/suppress_bloodloss(amount) if(bleedsuppress) return @@ -80,6 +83,9 @@ var/obj/item/bodypart/BP = X var/brutedamage = BP.brute_dam + if(BP.status == BODYPART_ROBOTIC) //for the moment, synth limbs won't bleed, but soon, my pretty. + continue + //We want an accurate reading of .len listclearnulls(BP.embedded_objects) temp_bleed += 0.5*BP.embedded_objects.len @@ -105,9 +111,11 @@ /mob/living/carbon/human/bleed(amt) amt *= physiology.bleed_mod if(!(NOBLOOD in dna.species.species_traits)) - ..() - - + .=..() + if(dna.species.exotic_blood && .) // Do we have exotic blood, and have we left any on the ground? + var/datum/reagent/R = GLOB.chemical_reagents_list[get_blood_id()] + if(istype(R) && isturf(loc)) + R.reaction_turf(get_turf(src), amt * EXOTIC_BLEED_MULTIPLIER) /mob/living/proc/restore_blood() blood_volume = initial(blood_volume) @@ -259,7 +267,7 @@ . = safe //to add a splatter of blood or other mob liquid. -/mob/living/proc/add_splatter_floor(turf/T, small_drip) +/mob/living/proc/add_splatter_floor(turf/T, small_drip, shift_x, shift_y) if(get_blood_id() == null) return if(!T) @@ -274,6 +282,8 @@ drop.drips++ drop.add_overlay(pick(drop.random_icon_states)) drop.transfer_mob_blood_dna(src) + src.transfer_blood_to(drop, 2) + drop.update_icon() return else temp_blood_DNA = list() @@ -282,17 +292,30 @@ else drop = new(T, get_static_viruses()) drop.transfer_mob_blood_dna(src) + src.transfer_blood_to(drop, 2) + drop.update_icon() return // Find a blood decal or create a new one. - var/obj/effect/decal/cleanable/blood/B = locate() in T + var/obj/effect/decal/cleanable/blood/splats/B = locate() in T + var/list/bloods = get_atoms_of_type(T, B, TRUE, 0, 0) //Get all the non-projectile-splattered blood on this turf (not pixel-shifted). + if(shift_x || shift_y) + bloods = get_atoms_of_type(T, B, TRUE, shift_x, shift_y) //Get all the projectile-splattered blood at these pixels on this turf (pixel-shifted). + B = locate() in bloods if(!B) - B = new /obj/effect/decal/cleanable/blood/splatter(T, get_static_viruses()) - if (B.bloodiness < MAX_SHOE_BLOODINESS) //add more blood, up to a limit + B = new /obj/effect/decal/cleanable/blood/splats(T, get_static_viruses()) + if(B.bloodiness < MAX_SHOE_BLOODINESS) //add more blood, up to a limit B.bloodiness += BLOOD_AMOUNT_PER_DECAL B.transfer_mob_blood_dna(src) //give blood info to the blood decal. + src.transfer_blood_to(B, 10) //very heavy bleeding, should logically leave larger pools if(temp_blood_DNA) B.blood_DNA |= temp_blood_DNA + B.pixel_x = (shift_x) + B.pixel_y = (shift_y) + B.update_icon() + if(shift_x || shift_y) + B.layer = BELOW_MOB_LAYER //So the blood lands ontop of things like posters, windows, etc. + /mob/living/carbon/human/add_splatter_floor(turf/T, small_drip) if(!(NOBLOOD in dna.species.species_traits)) @@ -313,6 +336,43 @@ if(!B) B = new(T) +/mob/living/proc/add_splash_floor(turf/T) + if(get_blood_id() == null) + return + if(!T) + T = get_turf(src) + + var/list/temp_blood_DNA + + // Find a blood decal or create a new one. + var/obj/effect/decal/cleanable/blood/B = locate() in T + if(!B) + B = new /obj/effect/decal/cleanable/blood/splatter(T, get_static_viruses()) + if(B.bloodiness < MAX_SHOE_BLOODINESS) //add more blood, up to a limit + B.bloodiness += BLOOD_AMOUNT_PER_DECAL + B.transfer_mob_blood_dna(src) //give blood info to the blood decal. + if(temp_blood_DNA) + B.blood_DNA |= temp_blood_DNA + +/mob/living/carbon/human/add_splash_floor(turf/T) + if(!(NOBLOOD in dna.species.species_traits)) + ..() + +/mob/living/carbon/alien/add_splash_floor(turf/T) + if(!T) + T = get_turf(src) + var/obj/effect/decal/cleanable/blood/splatter/B = locate() in T.contents + if(!B) + B = new(T) + B.blood_DNA["UNKNOWN DNA"] = "X*" + +/mob/living/silicon/robot/add_splash_floor(turf/T) + if(!T) + T = get_turf(src) + var/obj/effect/decal/cleanable/oil/B = locate() in T.contents + if(!B) + B = new(T) + //This is a terrible way of handling it. /mob/living/proc/ResetBloodVol() if(ishuman(src)) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 28cc41c9ca..bbfd1db6b9 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1687,7 +1687,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) bloody = 1 var/turf/location = H.loc if(istype(location)) - H.bleed(totitemdamage) + H.bleed_rate += 2 //This usually stacks pretty quickly, death by a thousand cuts, etc etc. if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood user.add_mob_blood(H) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 44185b601f..b5c859432c 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -174,11 +174,38 @@ new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color(H.dna.blood_type)) else new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color()) + if(iscarbon(L)) - var/mob/living/carbon/C = L - C.bleed(damage) - else - L.add_splatter_floor(target_loca) + if(ishuman(L) + var/mob/living/carbon/human/H = L + var/armorsave + if(flag == "bullet") + armorsave = H.getarmor(B, "bullet") + else if(flag == "energy") + armorsave = H.getarmor(B, "energy") + else if(flag == "magic") + armorsave = H.getarmor(B, "magic") + if(armorsave >= 30) // armor is useful again, yay. + H.bleed_rate += (damage * 0.15) // a tiny bit of shrapnel and internal bleeding, I guess. + else + H.bleed_rate += (damage * 0.50) //it's not a 1:1 deletion of blood, but it's worrysome enough that you should get treated asap + else + var/mob/living/carbon/C = L + C.bleed(damage) + + if(prob(33)) + var/list/shift = list("x" = 0, "y" = 0) + var/turf/step_over = get_step(target_loca, splatter_dir) + + if(get_splatter_blockage(step_over, target, splatter_dir, target_loca)) //If you can't cross the tile or any of its relevant obstacles... + shift = pixel_shift_dir(splatter_dir) //Pixel shift the blood there instead (so you can't see wallsplatter through walls). + else + target_loca = step_over + L.add_splatter_floor(target_loca, shift_x = shift["x"], shift_y = shift["y"]) + if(ishuman(L)) + for(var/mob/living/carbon/human/M in step_over) //Bloody the mobs who're infront of the spray. + M.bloody_hands = rand(2, 4) + else if(impact_effect_type && !hitscan) new impact_effect_type(target_loca, hitx, hity) @@ -213,6 +240,10 @@ return L.apply_effects(stun, knockdown, unconscious, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter) +/obj/item/projectile/proc/get_splatter_blockage(var/turf/step_over, var/atom/target, var/splatter_dir, var/target_loca) //Check whether the place we want to splatter blood is blocked (i.e. by windows). + if(step_over.density && !step_over.CanPass(target, step_over, 1)) //Preliminary simple check. + return TRUE + /obj/item/projectile/proc/vol_by_damage() if(src.damage) return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100 diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 9341fb6c25..8ef623df73 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -27,6 +27,8 @@ return 1 add_mob_blood(C) C.bleed(40) + var/mob/living/carbon/human/H = C + H.bleed_rate += 40 var/direction = pick(GLOB.cardinals) var/t_range = rand(2,max(throw_range/2, 2)) var/turf/target_turf = get_turf(src) @@ -53,6 +55,8 @@ var/organ_spilled = 0 var/turf/T = get_turf(C) C.bleed(50) + var/mob/living/carbon/human/H = C + H.bleed_rate += 60 playsound(get_turf(C), 'sound/misc/splort.ogg', 80, 1) for(var/X in C.internal_organs) var/obj/item/organ/O = X