diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 5492f83cfa9..cf2d69b7059 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -511,65 +511,67 @@ // Mob Overlays Indexes /// Total number of layers for mob overlays -#define TOTAL_LAYERS 31 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; +#define TOTAL_LAYERS 32 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; /// Mutations layer - Tk headglows, cold resistance glow, etc -#define MUTATIONS_LAYER 31 +#define MUTATIONS_LAYER 32 /// Mutantrace features (tail when looking south) that must appear behind the body parts -#define BODY_BEHIND_LAYER 30 +#define BODY_BEHIND_LAYER 31 /// Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag -#define BODYPARTS_LAYER 29 +#define BODYPARTS_LAYER 30 /// Mutantrace features (snout, body markings) that must appear above the body parts -#define BODY_ADJ_LAYER 28 +#define BODY_ADJ_LAYER 29 /// Underwear, undershirts, socks, eyes, lips(makeup) -#define BODY_LAYER 27 +#define BODY_LAYER 28 /// Mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) -#define FRONT_MUTATIONS_LAYER 26 +#define FRONT_MUTATIONS_LAYER 27 /// Damage indicators (cuts and burns) -#define DAMAGE_LAYER 25 +#define DAMAGE_LAYER 26 /// Jumpsuit clothing layer -#define UNIFORM_LAYER 24 +#define UNIFORM_LAYER 25 /// ID card layer (might be deprecated) -#define ID_LAYER 23 +#define ID_LAYER 24 /// ID card layer -#define ID_CARD_LAYER 22 +#define ID_CARD_LAYER 23 /// Hands body part layer (or is this for the arm? not sure...) -#define HANDS_PART_LAYER 21 +#define HANDS_PART_LAYER 22 /// Gloves layer -#define GLOVES_LAYER 20 +#define GLOVES_LAYER 21 /// Shoes layer -#define SHOES_LAYER 19 +#define SHOES_LAYER 20 /// Ears layer (Spessmen have ears? Wow) -#define EARS_LAYER 18 +#define EARS_LAYER 19 /// Suit layer (armor, hardsuits, etc.) -#define SUIT_LAYER 17 +#define SUIT_LAYER 18 /// Glasses layer -#define GLASSES_LAYER 16 +#define GLASSES_LAYER 17 /// Belt layer -#define BELT_LAYER 15 //Possible make this an overlay of somethign required to wear a belt? +#define BELT_LAYER 16 //Possible make this an overlay of somethign required to wear a belt? /// Suit storage layer (tucking a gun or baton underneath your armor) -#define SUIT_STORE_LAYER 14 +#define SUIT_STORE_LAYER 15 /// Neck layer (for wearing ties and bedsheets) -#define NECK_LAYER 13 +#define NECK_LAYER 14 /// Back layer (for backpacks and equipment on your back) -#define BACK_LAYER 12 +#define BACK_LAYER 13 /// Hair layer (mess with the fro and you got to go!) -#define HAIR_LAYER 11 //TODO: make part of head layer? +#define HAIR_LAYER 12 //TODO: make part of head layer? /// Facemask layer (gas masks, breath masks, etc.) -#define FACEMASK_LAYER 10 +#define FACEMASK_LAYER 11 /// Head layer (hats, helmets, etc.) -#define HEAD_LAYER 9 +#define HEAD_LAYER 10 /// Handcuff layer (when your hands are cuffed) -#define HANDCUFF_LAYER 8 +#define HANDCUFF_LAYER 9 /// Legcuff layer (when your feet are cuffed) -#define LEGCUFF_LAYER 7 +#define LEGCUFF_LAYER 8 /// Hands layer (for the actual hand, not the arm... I think?) -#define HANDS_LAYER 6 +#define HANDS_LAYER 7 /// Body front layer. Usually used for mutant bodyparts that need to be in front of stuff (e.g. cat ears) -#define BODY_FRONT_LAYER 5 +#define BODY_FRONT_LAYER 6 /// Special body layer that actually require to be above the hair (e.g. lifted welding goggles) -#define ABOVE_BODY_FRONT_GLASSES_LAYER 4 +#define ABOVE_BODY_FRONT_GLASSES_LAYER 5 /// Special body layer for the rare cases where something on the head needs to be above everything else (e.g. flowers) -#define ABOVE_BODY_FRONT_HEAD_LAYER 3 +#define ABOVE_BODY_FRONT_HEAD_LAYER 4 +/// Bleeding wound icons +#define WOUND_LAYER 3 /// Blood cult ascended halo layer, because there's currently no better solution for adding/removing #define HALO_LAYER 2 /// Fire layer when you're on fire diff --git a/code/__DEFINES/wounds.dm b/code/__DEFINES/wounds.dm index 3575397d4d1..f30947c0362 100644 --- a/code/__DEFINES/wounds.dm +++ b/code/__DEFINES/wounds.dm @@ -77,10 +77,12 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datu // ~random wound balance defines /// how quickly sanitization removes infestation and decays per second #define WOUND_BURN_SANITIZATION_RATE 0.075 -/// how much blood you can lose per second per slash max. 4 is a LOT of blood for one cut so don't worry about hitting it easily -#define WOUND_SLASH_MAX_BLOODFLOW 4 +/// how much blood you can lose per tick per slash max. +#define WOUND_SLASH_MAX_BLOODFLOW 4.5 /// dead people don't bleed, but they can clot! this is the minimum amount of clotting per tick on dead people, so even critical cuts will slowly clot in dead people #define WOUND_SLASH_DEAD_CLOT_MIN 0.025 +/// further slash attacks on a bodypart with a slash wound have their blood_flow further increased by damage * this (10 damage slash adds .25 flow) +#define WOUND_SLASH_DAMAGE_FLOW_COEFF 0.025 /// if we suffer a bone wound to the head that creates brain traumas, the timer for the trauma cycle is +/- by this percent (0-100) #define WOUND_BONE_HEAD_TIME_VARIANCE 20 diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 245f5ac65b6..16c4d634ce6 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -243,7 +243,9 @@ owner.add_filter("stasis_status_ripple", 2, list("type" = "ripple", "flags" = WAVE_BOUNDED, "radius" = 0, "size" = 2)) var/filter = owner.get_filter("stasis_status_ripple") animate(filter, radius = 32, time = 15, size = 0, loop = -1) - + if(iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner + carbon_owner.update_bodypart_bleed_overlays() /datum/status_effect/grouped/stasis/tick() update_time_of_death() @@ -253,6 +255,9 @@ REMOVE_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id)) owner.remove_filter("stasis_status_ripple") update_time_of_death() + if(iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner + carbon_owner.update_bodypart_bleed_overlays() return ..() /atom/movable/screen/alert/status_effect/stasis diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 441fcbf5ee2..0b39d88cc98 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -146,7 +146,7 @@ if(severity == WOUND_SEVERITY_TRIVIAL) return - if(!(silent || demoted)) + if(!silent && !demoted) var/msg = span_danger("[victim]'s [limb.name] [occur_text]!") var/vis_dist = COMBAT_MESSAGE_RANGE @@ -158,8 +158,8 @@ if(sound_effect) playsound(L.owner, sound_effect, 70 + 20 * severity, TRUE) + wound_injury(old_wound, attack_direction = attack_direction) if(!demoted) - wound_injury(old_wound, attack_direction = attack_direction) second_wind() /datum/wound/proc/null_victim() diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index c6a750cca06..045f20b123c 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -18,7 +18,7 @@ var/initial_flow /// When we have less than this amount of flow, either from treatment or clotting, we demote to a lower cut or are healed of the wound var/minimum_flow - /// How much our blood_flow will naturally decrease per tick, not only do larger cuts bleed more blood faster, they clot slower (higher number = clot quicker, negative = opening up) + /// How much our blood_flow will naturally decrease per second, not only do larger cuts bleed more blood faster, they clot slower (higher number = clot quicker, negative = opening up) var/clot_rate /// Once the blood flow drops below minimum_flow, we demote it to this type of wound. If there's none, we're all better @@ -31,14 +31,15 @@ var/datum/scar/highest_scar /datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null, attack_direction = null) - blood_flow = initial_flow if(old_wound) blood_flow = max(old_wound.blood_flow, initial_flow) if(old_wound.severity > severity && old_wound.highest_scar) set_highest_scar(old_wound.highest_scar) old_wound.clear_highest_scar() - else if(attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) - victim.spray_blood(attack_direction, severity) + else + blood_flow = initial_flow + if(attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) + victim.spray_blood(attack_direction, severity) if(!highest_scar) var/datum/scar/new_scar = new @@ -83,7 +84,7 @@ /datum/wound/slash/receive_damage(wounding_type, wounding_dmg, wound_bonus) if(victim.stat != DEAD && wound_bonus != CANT_WOUND && wounding_type == WOUND_SLASH) // can't stab dead bodies to make it bleed faster this way - blood_flow += 0.05 * wounding_dmg + blood_flow += WOUND_SLASH_DAMAGE_FLOW_COEFF * wounding_dmg /datum/wound/slash/drag_bleed_amount() // say we have 3 severe cuts with 3 blood flow each, pretty reasonable @@ -252,6 +253,7 @@ if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists))) return + user.visible_message(span_green("[user] stitches up some of the bleeding on [victim]."), span_green("You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].")) var/blood_sutured = I.stop_bleeding / self_penalty_mult blood_flow -= blood_sutured @@ -274,7 +276,7 @@ severity = WOUND_SEVERITY_MODERATE initial_flow = 2 minimum_flow = 0.5 - clot_rate = 0.06 + clot_rate = 0.05 threshold_minimum = 20 threshold_penalty = 10 status_effect_type = /datum/status_effect/wound/slash/moderate @@ -305,9 +307,9 @@ occur_text = "is torn open, spraying blood wildly" sound_effect = 'sound/effects/wounds/blood3.ogg' severity = WOUND_SEVERITY_CRITICAL - initial_flow = 4.25 - minimum_flow = 4 - clot_rate = -0.025 // critical cuts actively get worse instead of better + initial_flow = 4 + minimum_flow = 3.85 + clot_rate = -0.015 // critical cuts actively get worse instead of better threshold_minimum = 80 threshold_penalty = 40 demotes_to = /datum/wound/slash/severe diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 406b8dd5269..06fe6189032 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -10,65 +10,83 @@ if(NOBLOOD in dna.species.species_traits || HAS_TRAIT(src, TRAIT_NOBLEED) || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) return - if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood. + if(bodytemperature < TCRYO || (HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood. + return - //Blood regeneration if there is some space - if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER)) - var/nutrition_ratio = 0 - switch(nutrition) - if(0 to NUTRITION_LEVEL_STARVING) - nutrition_ratio = 0.2 - if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) - nutrition_ratio = 0.4 - if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) - nutrition_ratio = 0.6 - if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) - nutrition_ratio = 0.8 - else - nutrition_ratio = 1 - if(satiety > 80) - nutrition_ratio *= 1.25 - adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR * delta_time) - blood_volume = min(blood_volume + (BLOOD_REGEN_FACTOR * nutrition_ratio * delta_time), BLOOD_VOLUME_NORMAL) + //Blood regeneration if there is some space + if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER)) + var/nutrition_ratio = 0 + switch(nutrition) + if(0 to NUTRITION_LEVEL_STARVING) + nutrition_ratio = 0.2 + if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) + nutrition_ratio = 0.4 + if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) + nutrition_ratio = 0.6 + if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) + nutrition_ratio = 0.8 + else + nutrition_ratio = 1 + if(satiety > 80) + nutrition_ratio *= 1.25 + adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR * delta_time) + blood_volume = min(blood_volume + (BLOOD_REGEN_FACTOR * nutrition_ratio * delta_time), BLOOD_VOLUME_NORMAL) - //Effects of bloodloss - var/word = pick("dizzy","woozy","faint") - switch(blood_volume) - if(BLOOD_VOLUME_EXCESS to BLOOD_VOLUME_MAX_LETHAL) - if(DT_PROB(7.5, delta_time)) - to_chat(src, span_userdanger("Blood starts to tear your skin apart. You're going to burst!")) - inflate_gib() - if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS) - if(DT_PROB(5, delta_time)) - to_chat(src, span_warning("You feel terribly bloated.")) - if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) - if(DT_PROB(2.5, delta_time)) - to_chat(src, span_warning("You feel [word].")) - adjustOxyLoss(round(0.005 * (BLOOD_VOLUME_NORMAL - blood_volume) * delta_time, 1)) - if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - adjustOxyLoss(round(0.01 * (BLOOD_VOLUME_NORMAL - blood_volume) * delta_time, 1)) - if(DT_PROB(2.5, delta_time)) - blur_eyes(6) - to_chat(src, span_warning("You feel very [word].")) - if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) - adjustOxyLoss(2.5 * delta_time) - if(DT_PROB(7.5, delta_time)) - Unconscious(rand(20,60)) - to_chat(src, span_warning("You feel extremely [word].")) - if(-INFINITY to BLOOD_VOLUME_SURVIVE) - if(!HAS_TRAIT(src, TRAIT_NODEATH)) - death() + //Effects of bloodloss + var/word = pick("dizzy","woozy","faint") + switch(blood_volume) + if(BLOOD_VOLUME_EXCESS to BLOOD_VOLUME_MAX_LETHAL) + if(DT_PROB(7.5, delta_time)) + to_chat(src, span_userdanger("Blood starts to tear your skin apart. You're going to burst!")) + inflate_gib() + if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS) + if(DT_PROB(5, delta_time)) + to_chat(src, span_warning("You feel terribly bloated.")) + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + if(DT_PROB(2.5, delta_time)) + to_chat(src, span_warning("You feel [word].")) + adjustOxyLoss(round(0.005 * (BLOOD_VOLUME_NORMAL - blood_volume) * delta_time, 1)) + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + adjustOxyLoss(round(0.01 * (BLOOD_VOLUME_NORMAL - blood_volume) * delta_time, 1)) + if(DT_PROB(2.5, delta_time)) + blur_eyes(6) + to_chat(src, span_warning("You feel very [word].")) + if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) + adjustOxyLoss(2.5 * delta_time) + if(DT_PROB(7.5, delta_time)) + Unconscious(rand(20,60)) + to_chat(src, span_warning("You feel extremely [word].")) + if(-INFINITY to BLOOD_VOLUME_SURVIVE) + if(!HAS_TRAIT(src, TRAIT_NODEATH)) + death() - var/temp_bleed = 0 - //Bleeding out - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - temp_bleed += BP.get_bleed_rate() * delta_time - BP.generic_bleedstacks = max(0, BP.generic_bleedstacks - 1) + var/temp_bleed = 0 + var/update_bleed_icons = FALSE + //Bleeding out + for(var/obj/item/bodypart/iter_part as anything in bodyparts) + var/iter_bleed_rate = iter_part.get_part_bleed_rate() + temp_bleed += iter_bleed_rate * delta_time + iter_part.generic_bleedstacks = max(0, iter_part.generic_bleedstacks - 1) + if(iter_part.update_part_wound_overlay()) + update_bleed_icons = TRUE - if(temp_bleed) - bleed(temp_bleed) - bleed_warn(temp_bleed) + if(update_bleed_icons) + update_wound_overlays() + + if(temp_bleed) + bleed(temp_bleed) + bleed_warn(temp_bleed) + +/// Has each bodypart update its bleed/wound overlay icon states. If any have changed, it has the owner update wound overlays and returns TRUE +/mob/living/carbon/proc/update_bodypart_bleed_overlays() + var/update_bleed_icons + for(var/obj/item/bodypart/iter_part as anything in bodyparts) + if(iter_part.update_part_wound_overlay()) + update_bleed_icons = TRUE + + if(update_bleed_icons) + update_wound_overlays() + return update_bleed_icons //Makes a blood drop, leaking amt units of blood from the mob /mob/living/carbon/proc/bleed(amt) @@ -92,7 +110,7 @@ var/bleed_amt = 0 for(var/X in bodyparts) var/obj/item/bodypart/iter_bodypart = X - bleed_amt += iter_bodypart.get_bleed_rate() + bleed_amt += iter_bodypart.get_part_bleed_rate() return bleed_amt /mob/living/carbon/human/get_bleed_rate() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f1fd5be4f94..c13b54af5e3 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1216,7 +1216,7 @@ /mob/living/carbon/proc/is_bleeding() for(var/i in bodyparts) var/obj/item/bodypart/BP = i - if(BP.get_bleed_rate()) + if(BP.get_part_bleed_rate()) return TRUE /// get our total bleedrate @@ -1224,7 +1224,7 @@ var/total_bleed_rate = 0 for(var/i in bodyparts) var/obj/item/bodypart/BP = i - total_bleed_rate += BP.get_bleed_rate() + total_bleed_rate += BP.get_part_bleed_rate() return total_bleed_rate diff --git a/code/modules/mob/living/carbon/carbon_context.dm b/code/modules/mob/living/carbon/carbon_context.dm index 826784c7789..eb30dbcaf62 100644 --- a/code/modules/mob/living/carbon/carbon_context.dm +++ b/code/modules/mob/living/carbon/carbon_context.dm @@ -15,7 +15,7 @@ else if (human_user == src) context[SCREENTIP_CONTEXT_LMB] = "Check injuries" - if (get_bodypart(human_user.zone_selected)?.get_bleed_rate()) + if (get_bodypart(human_user.zone_selected)?.get_part_bleed_rate()) context[SCREENTIP_CONTEXT_CTRL_LMB] = "Grab limb" if (human_user != src) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 551b0441a73..f4962699cc3 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -651,7 +651,7 @@ return ..() var/obj/item/bodypart/grasped_part = get_bodypart(zone_selected) - if(!grasped_part?.get_bleed_rate()) + if(!grasped_part?.get_part_bleed_rate()) return var/starting_hand_index = active_hand_index if(starting_hand_index == grasped_part.held_index) @@ -659,7 +659,7 @@ return to_chat(src, span_warning("You try grasping at your [grasped_part.name], trying to stop the bleeding...")) - if(!do_after(src, 1.5 SECONDS)) + if(!do_after(src, 0.75 SECONDS)) to_chat(src, span_danger("You fail to grasp your [grasped_part.name].")) return @@ -676,7 +676,7 @@ desc = "Sometimes all you can do is slow the bleeding." icon_state = "latexballon" inhand_icon_state = "nothing" - slowdown = 1 + slowdown = 0.5 item_flags = DROPDEL | ABSTRACT | NOBLUDGEON | SLOWS_WHILE_IN_HAND | HAND_ITEM /// The bodypart we're staunching bleeding on, which also has a reference to us in [/obj/item/bodypart/var/grasped_by] var/obj/item/bodypart/grasped_part diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index 6e8dd843080..4bd940c9e9f 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -92,16 +92,26 @@ var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/dam_mob.dmi', "blank", -DAMAGE_LAYER) overlays_standing[DAMAGE_LAYER] = damage_overlay - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if(BP.dmg_overlay_type) - if(BP.brutestate) - damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_[BP.brutestate]0") //we're adding icon_states of the base image as overlays - if(BP.burnstate) - damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_0[BP.burnstate]") + for(var/obj/item/bodypart/iter_part as anything in bodyparts) + if(iter_part.dmg_overlay_type) + if(iter_part.brutestate) + damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0") //we're adding icon_states of the base image as overlays + if(iter_part.burnstate) + damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_0[iter_part.burnstate]") apply_overlay(DAMAGE_LAYER) +/mob/living/carbon/update_wound_overlays() + remove_overlay(WOUND_LAYER) + + var/mutable_appearance/wound_overlay = mutable_appearance('icons/mob/bleed_overlays.dmi', "blank", -WOUND_LAYER) + overlays_standing[WOUND_LAYER] = wound_overlay + + for(var/obj/item/bodypart/iter_part as anything in bodyparts) + if(iter_part.bleed_overlay_icon) + wound_overlay.add_overlay(iter_part.bleed_overlay_icon) + + apply_overlay(WOUND_LAYER) /mob/living/carbon/update_inv_wear_mask() remove_overlay(FACEMASK_LAYER) @@ -254,6 +264,7 @@ apply_overlay(BODYPARTS_LAYER) update_damage_overlays() + update_wound_overlays() diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 2eac1502ec4..d2143b6f4e1 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -256,7 +256,7 @@ for(var/i in bodyparts) var/obj/item/bodypart/body_part = i - if(body_part.get_bleed_rate()) + if(body_part.get_part_bleed_rate()) bleeding_limbs += body_part if(body_part.grasped_by) grasped_limbs += body_part diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index b469a56b113..e6ab4dd5796 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -809,7 +809,7 @@ var/list/obj/item/bodypart/bleeding_limbs = list() for(var/i in bodyparts) var/obj/item/bodypart/BP = i - if(BP.get_bleed_rate()) + if(BP.get_part_bleed_rate()) bleeding_limbs += BP var/num_bleeds = LAZYLEN(bleeding_limbs) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index bd9dd088918..8e5578c80b2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -859,6 +859,10 @@ /mob/living/proc/update_damage_overlays() return +/// Proc that only really gets called for humans, to handle bleeding overlays. +/mob/living/proc/update_wound_overlays() + return + /mob/living/Move(atom/newloc, direct, glide_size_override) if(lying_angle != 0) lying_angle_on_movement(direct) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 951847922ed..71f39a0b81d 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -76,6 +76,8 @@ var/species_flags_list = list() ///the type of damage overlay (if any) to use when this bodypart is bruised/burned. var/dmg_overlay_type + /// If we're bleeding, which icon are we displaying on this part + var/bleed_overlay_icon //Damage messages used by help_shake_act() var/light_brute_msg = "bruised" @@ -969,8 +971,13 @@ wound_damage_multiplier = dam_mul - -/obj/item/bodypart/proc/get_bleed_rate() +/** + * Calculates how much blood this limb is losing per life tick + * + * Arguments: + * * ignore_modifiers - If TRUE, ignore the bleed reduction for laying down and grabbing your limb + */ +/obj/item/bodypart/proc/get_part_bleed_rate(ignore_modifiers = FALSE) if(HAS_TRAIT(owner, TRAIT_NOBLEED)) return if(status != BODYPART_ORGANIC) // maybe in the future we can bleed oil from aug parts, but not now @@ -986,20 +993,61 @@ if(!embeddies.isEmbedHarmless()) bleed_rate += 0.25 - for(var/datum/wound/wound as anything in wounds) - bleed_rate += wound.blood_flow + for(var/datum/wound/iter_wound as anything in wounds) + bleed_rate += iter_wound.blood_flow - if(owner.body_position == LYING_DOWN) - bleed_rate *= 0.75 - - if(grasped_by) - bleed_rate *= 0.7 + if(!ignore_modifiers) + if(owner.body_position == LYING_DOWN) + bleed_rate *= 0.75 + if(grasped_by) + bleed_rate *= 0.7 if(!bleed_rate) QDEL_NULL(grasped_by) return bleed_rate +// how much blood the limb needs to be losing per tick (not counting laying down/self grasping modifiers) to get the different bleed icons +#define BLEED_OVERLAY_LOW 0.5 +#define BLEED_OVERLAY_MED 1.5 +#define BLEED_OVERLAY_GUSH 3.25 + +/obj/item/bodypart/proc/update_part_wound_overlay() + if(!owner) + return FALSE + if(HAS_TRAIT(owner, TRAIT_NOBLEED) || status != BODYPART_ORGANIC) + if(bleed_overlay_icon) + bleed_overlay_icon = null + owner.update_wound_overlays() + return FALSE + + var/bleed_rate = get_part_bleed_rate(ignore_modifiers = TRUE) + var/new_bleed_icon + + switch(bleed_rate) + if(-INFINITY to BLEED_OVERLAY_LOW) + new_bleed_icon = null + if(BLEED_OVERLAY_LOW to BLEED_OVERLAY_MED) + new_bleed_icon = "[body_zone]_1" + if(BLEED_OVERLAY_MED to BLEED_OVERLAY_GUSH) + if(owner.body_position == LYING_DOWN || IS_IN_STASIS(owner) || owner.stat == DEAD) + new_bleed_icon = "[body_zone]_2s" + else + new_bleed_icon = "[body_zone]_2" + if(BLEED_OVERLAY_GUSH to INFINITY) + if(IS_IN_STASIS(owner) || owner.stat == DEAD) + new_bleed_icon = "[body_zone]_2s" + else + new_bleed_icon = "[body_zone]_3" + + if(new_bleed_icon != bleed_overlay_icon) + bleed_overlay_icon = new_bleed_icon + return TRUE + +#undef BLEED_OVERLAY_LOW +#undef BLEED_OVERLAY_MED +#undef BLEED_OVERLAY_GUSH + /** * apply_gauze() is used to- well, apply gauze to a bodypart * diff --git a/icons/mob/bleed_overlays.dmi b/icons/mob/bleed_overlays.dmi new file mode 100644 index 00000000000..aa82d5578f8 Binary files /dev/null and b/icons/mob/bleed_overlays.dmi differ