Files
2026-05-25 20:54:20 -04:00

415 lines
19 KiB
Plaintext

/*
Piercing wounds
*/
/datum/wound/pierce
undiagnosed_name = "Puncture"
threshold_penalty = 5
/datum/wound/pierce/get_self_check_description(self_aware)
if(!limb.can_bleed())
return ..()
switch(severity)
if(WOUND_SEVERITY_TRIVIAL)
return span_danger("It's leaking blood from a small [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_MODERATE)
return span_warning("It's leaking blood from a [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_SEVERE)
return span_boldwarning("It's leaking blood from a serious [LOWER_TEXT(undiagnosed_name || name)]!")
if(WOUND_SEVERITY_CRITICAL)
return span_boldwarning("It's leaking blood from a major [LOWER_TEXT(undiagnosed_name || name)]!!")
/datum/wound/pierce/bleed
name = "Piercing Wound"
sound_effect = 'sound/items/weapons/slice.ogg'
processes = TRUE
treatable_tools = list(TOOL_CAUTERY)
base_treat_time = 3 SECONDS
wound_flags = (ACCEPTS_GAUZE | CAN_BE_GRASPED)
default_scar_file = FLESH_SCAR_FILE
/// How much blood we start losing when this wound is first applied
var/initial_flow
/// How much our blood_flow will naturally decrease per second, even without gauze
var/clot_rate
/// If gauzed, what percent of the internal bleeding actually clots of the total absorption rate
var/gauzed_clot_rate
/// When hit on this bodypart, we have this chance of losing some blood + the incoming damage
var/internal_bleeding_chance
/// A multiplier applied to how much blood is lost from damage to the wounded limb
var/internal_bleeding_coefficient = 1
/// If TRUE we are ready to be mended in surgery
VAR_FINAL/mend_state = FALSE
/datum/wound/pierce/bleed/wound_injury(datum/wound/old_wound = null, attack_direction = null)
set_blood_flow(initial_flow)
if(limb.can_bleed() && attack_direction && victim.get_blood_volume() > BLOOD_VOLUME_OKAY)
victim.spray_blood(attack_direction, severity)
return ..()
/datum/wound/pierce/bleed/receive_damage(wounding_type, wounding_dmg, wound_bonus, attack_direction, damage_source)
if(victim.stat == DEAD || wounding_dmg < 5 || !limb.can_bleed() || !victim.get_blood_volume() || !prob(internal_bleeding_chance + wounding_dmg))
return
// 20 force attack ~= 5-16 blood loss ~= 1%-3% of blood volume
// 30 force attack ~= 6-20 blood loss ~= 1%-4% of blood volume
var/blood_bled = sqrt(wounding_dmg) * internal_bleeding_coefficient * limb.get_splint_factor() * pick(0.75, 1, 1.25, 1.5)
switch(blood_bled)
if(8 to 12)
victim.visible_message(
span_smalldanger("Blood droplets fly from the hole in [victim]'s [limb.plaintext_zone]."),
span_danger("You cough up a bit of blood from the blow to your [limb.plaintext_zone]."),
vision_distance = COMBAT_MESSAGE_RANGE,
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
)
if(12 to 18)
victim.visible_message(
span_smalldanger("A small stream of blood spurts from the hole in [victim]'s [limb.plaintext_zone]!"),
span_danger("You spit out a string of blood from the blow to your [limb.plaintext_zone]!"),
vision_distance = COMBAT_MESSAGE_RANGE,
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
)
if(18 to INFINITY)
victim.visible_message(
span_danger("A spray of blood streams from the gash in [victim]'s [limb.plaintext_zone]!"),
span_bolddanger("You choke up on a spray of blood from the blow to your [limb.plaintext_zone]!"),
vision_distance = COMBAT_MESSAGE_RANGE,
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
)
victim.bleed(blood_bled)
if(blood_bled >= 18)
victim.spray_blood(attack_direction)
/datum/wound/pierce/bleed/get_bleed_rate_of_change()
//basically if a species doesn't bleed, the wound is stagnant and will not heal on its own (nor get worse)
if(!limb.can_bleed())
return BLOOD_FLOW_STEADY
if(HAS_TRAIT(victim, TRAIT_BLOOD_FOUNTAIN))
return BLOOD_FLOW_INCREASING
if(LAZYACCESS(limb.applied_items, LIMB_ITEM_GAUZE) || clot_rate > 0)
return BLOOD_FLOW_DECREASING
if(clot_rate < 0)
return BLOOD_FLOW_INCREASING
return BLOOD_FLOW_STEADY
/datum/wound/pierce/bleed/handle_process(seconds_per_tick)
if (!victim || HAS_TRAIT(victim, TRAIT_STASIS))
return
if(limb.can_bleed())
if(victim.bodytemperature < (BODYTEMP_NORMAL - 10))
adjust_blood_flow(-0.1 * seconds_per_tick)
if(QDELETED(src))
return
if(SPT_PROB(2.5, seconds_per_tick))
to_chat(victim, span_notice("You feel the [LOWER_TEXT(undiagnosed_name || name)] in your [limb.plaintext_zone] firming up from the cold!"))
if(HAS_TRAIT(victim, TRAIT_BLOOD_FOUNTAIN))
adjust_blood_flow(0.25 * seconds_per_tick) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first
//gauze always reduces blood flow, even for non bleeders
var/obj/item/stack/medical/wrap/current_gauze = LAZYACCESS(limb.applied_items, LIMB_ITEM_GAUZE)
if(current_gauze?.absorption_rate)
var/gauze_power = current_gauze.absorption_rate
limb.seep_gauze(gauze_power * seconds_per_tick)
adjust_blood_flow((-clot_rate * seconds_per_tick) + (-gauze_power * gauzed_clot_rate * seconds_per_tick))
//otherwise, only clot if it's a bleeder
else if(limb.can_bleed())
adjust_blood_flow(-clot_rate * seconds_per_tick)
/datum/wound/pierce/bleed/adjust_blood_flow(adjust_by, minimum)
. = ..()
if(blood_flow > WOUND_MAX_BLOODFLOW)
blood_flow = WOUND_MAX_BLOODFLOW
if(blood_flow <= 0 && !QDELETED(src))
to_chat(victim, span_green("The holes on your [limb.plaintext_zone] have [!limb.can_bleed() ? "healed up" : "stopped bleeding"]!"))
qdel(src)
/datum/wound/pierce/bleed/check_grab_treatments(obj/item/tool, mob/user)
// if we're using something hot but not a cautery, we need to be aggro grabbing them first,
// so we don't try treating someone we're eswording
return tool.get_temperature() >= FIRE_MINIMUM_TEMPERATURE_TO_EXIST
/datum/wound/pierce/bleed/treat(obj/item/tool, mob/user)
if(tool.tool_behaviour == TOOL_CAUTERY || tool.get_temperature() >= FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
tool_cauterize(tool, user)
/datum/wound/pierce/bleed/on_xadone(power)
. = ..()
if (limb) // parent can cause us to be removed, so its reasonable to check if we're still applied
adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
/datum/wound/pierce/bleed/on_synthflesh(reac_volume)
. = ..()
adjust_blood_flow(-0.025 * reac_volume) // 20u * 0.05 = -1 blood flow, less than with slashes but still good considering smaller bleed rates
/// If someone is using either a cautery tool or something with heat to cauterize this pierce
/datum/wound/pierce/bleed/proc/tool_cauterize(obj/item/I, mob/user)
var/improv_penalty_mult = (I.tool_behaviour == TOOL_CAUTERY ? 1 : 1.25) // 25% longer and less effective if you don't use a real cautery
var/self_penalty_mult = (user == victim ? 1.5 : 1) // 50% longer and less effective if you do it to yourself
var/treatment_delay = base_treat_time * self_penalty_mult * improv_penalty_mult
if(HAS_TRAIT(src, TRAIT_WOUND_SCANNED))
treatment_delay *= 0.5
user.visible_message(span_danger("[user] begins expertly cauterizing [victim]'s [limb.plaintext_zone] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I], keeping the holo-image indications in mind..."))
else
user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.plaintext_zone] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]..."))
playsound(user, 'sound/items/handling/surgery/cautery1.ogg', 75, TRUE)
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
return TRUE
playsound(user, 'sound/items/handling/surgery/cautery2.ogg', 75, TRUE)
var/bleeding_wording = (limb.can_bleed() ? "bleeding" : "holes")
user.visible_message(span_green("[user] cauterizes some of the [bleeding_wording] on [victim]."), span_green("You cauterize some of the [bleeding_wording] on [victim]."))
victim.apply_damage(2 + severity, BURN, limb, wound_bonus = CANT_WOUND)
if(prob(30))
victim.emote("scream")
var/blood_cauterized = (0.6 / (self_penalty_mult * improv_penalty_mult))
adjust_blood_flow(-blood_cauterized)
if(blood_flow > 0)
try_treating(I, user)
/datum/wound_pregen_data/flesh_pierce
abstract = TRUE
required_limb_biostate = BIO_FLESH
required_wounding_type = WOUND_PIERCE
wound_series = WOUND_SERIES_FLESH_PUNCTURE_BLEED
/datum/wound/pierce/get_limb_examine_description()
return span_warning("The flesh on this limb appears badly perforated.")
/datum/wound/pierce/bleed/moderate
name = "Minor Skin Breakage"
desc = "Patient's skin has been broken open, causing severe bruising and minor internal bleeding in affected area."
treat_text = "Apply bandaging or suturing to the wound, make use of blood clotting agents, \
cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \
Follow with food and a rest period."
treat_text_short = "Apply bandaging or suturing."
examine_desc = "has a small, torn hole, gently bleeding"
occur_text = "spurts out a thin stream of blood"
sound_effect = 'sound/effects/wounds/pierce1.ogg'
severity = WOUND_SEVERITY_MODERATE
initial_flow = 1.25
gauzed_clot_rate = 0.75
clot_rate = 0.03
internal_bleeding_chance = 30
internal_bleeding_coefficient = 1.5
series_threshold_penalty = 20
status_effect_type = /datum/status_effect/wound/pierce/moderate
scar_keyword = "piercemoderate"
simple_treat_text = "<b>Bandaging</b> the wound will reduce blood loss, help the wound close by itself quicker, and speed up the blood recovery period. The wound itself can be slowly <b>sutured</b> shut."
homemade_treat_text = "<b>Tea</b> stimulates the body's natural healing systems, slightly fastening clotting. The wound itself can be rinsed off on a sink or shower as well. Other remedies are unnecessary."
/datum/wound/pierce/bleed/moderate/update_descriptions()
if(!limb.can_bleed())
examine_desc = "has a small, torn hole"
occur_text = "splits a small hole open"
/datum/wound_pregen_data/flesh_pierce/breakage
abstract = FALSE
wound_path_to_generate = /datum/wound/pierce/bleed/moderate
threshold_minimum = 30
/datum/wound_pregen_data/flesh_pierce/breakage/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source)
if (isprojectile(damage_source))
return 0
return weight
/datum/wound/pierce/bleed/moderate/needle_fail //for blood testamajig
name = "Pinprick Pierce"
desc = "Patient's skin has been deeply pierced, causing mild bleeding."
treat_text_short = "Apply bandaging or suturing."
examine_desc = "has a small red pinprick, gently bleeding"
initial_flow = 0.5 //very minor, mostly there as fluff and "dont do that idiot" reminder
gauzed_clot_rate = 0.1
clot_rate = 0.03 // will close quickly on its own
internal_bleeding_chance = 0
threshold_penalty = 5
/datum/wound_pregen_data/flesh_pierce/open_puncture/pinprick
wound_path_to_generate = /datum/wound/pierce/bleed/moderate/needle_fail
can_be_randomly_generated = FALSE
abstract = FALSE
/datum/wound/pierce/bleed/moderate/projectile
name = "Minor Skin Penetration"
desc = "Patient's skin has been pierced through, causing severe bruising and minor internal bleeding in affected area."
treat_text = "Apply bandaging or suturing to the wound, make use of blood clotting agents, \
cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \
Follow with food and a rest period."
examine_desc = "has a small, circular hole, gently bleeding"
clot_rate = 0
/datum/wound/pierce/bleed/moderate/projectile/update_descriptions()
if(!limb.can_bleed())
examine_desc = "has a small, circular hole"
occur_text = "splits a small hole open"
/datum/wound_pregen_data/flesh_pierce/breakage/projectile
wound_path_to_generate = /datum/wound/pierce/bleed/moderate/projectile
/datum/wound_pregen_data/flesh_pierce/breakage/projectile/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source)
if (!isprojectile(damage_source))
return 0
return weight
/datum/wound/pierce/bleed/severe
name = "Open Stab Puncture"
desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability."
treat_text = "Swiftly apply bandaging or suturing to the wound, make use of blood clotting agents or saline-glucose, \
cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \
Follow with iron supplements and a rest period."
treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization."
examine_desc = "is pierced clear through, with bits of tissue obscuring the open hole"
occur_text = "looses a violent spray of blood, revealing a pierced wound"
sound_effect = 'sound/effects/wounds/pierce2.ogg'
severity = WOUND_SEVERITY_SEVERE
initial_flow = 2
gauzed_clot_rate = 0.5
clot_rate = 0.02
internal_bleeding_chance = 60
internal_bleeding_coefficient = 2
series_threshold_penalty = 35
status_effect_type = /datum/status_effect/wound/pierce/severe
scar_keyword = "piercesevere"
simple_treat_text = "<b>Bandaging</b> the wound is essential, and will reduce blood loss. Afterwards, the wound can be <b>sutured</b> shut, preferably while the patient is resting and/or grasping their wound."
homemade_treat_text = "Bed sheets can be ripped up to make <b>makeshift gauze</b>. <b>Flour, table salt, or salt mixed with water</b> can be applied directly to stem the flow, though unmixed salt will irritate the skin and worsen natural healing. Resting and grabbing your wound will also reduce bleeding."
/datum/wound/pierce/bleed/severe/update_descriptions()
if(!limb.can_bleed())
occur_text = "tears a hole open"
/datum/wound_pregen_data/flesh_pierce/open_puncture
abstract = FALSE
wound_path_to_generate = /datum/wound/pierce/bleed/severe
threshold_minimum = 50
/datum/wound_pregen_data/flesh_pierce/open_puncture/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source)
if (isprojectile(damage_source))
return 0
return weight
/datum/wound/pierce/bleed/severe/projectile
name = "Open Bullet Puncture"
examine_desc = "is pierced clear through, with bits of tissue obscuring the cleanly torn hole"
clot_rate = 0
/datum/wound_pregen_data/flesh_pierce/open_puncture/projectile
wound_path_to_generate = /datum/wound/pierce/bleed/severe/projectile
/datum/wound_pregen_data/flesh_pierce/open_puncture/projectile/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source)
if (!isprojectile(damage_source))
return 0
return weight
/datum/wound/pierce/bleed/severe/eye
name = "Eyeball Puncture"
desc = "Patient's eye has sustained extreme damage, causing severe bleeding from the ocular cavity."
occur_text = "looses a violent spray of blood, revealing a crushed eyeball"
var/right_side = FALSE
/datum/wound/pierce/bleed/severe/eye/apply_wound(obj/item/bodypart/limb, silent, datum/wound/old_wound, smited, attack_direction, wound_source, replacing, right_side)
var/obj/item/organ/eyes/eyes = locate() in limb
if (!istype(eyes))
return FALSE
. = ..()
src.right_side = right_side
examine_desc = "has its [right_side ? "right" : "left"] eye pierced clean through, blood spewing from the cavity"
RegisterSignal(limb, COMSIG_BODYPART_UPDATE_WOUND_OVERLAY, PROC_REF(wound_overlay))
limb.update_part_wound_overlay()
/datum/wound/pierce/bleed/severe/eye/remove_wound(ignore_limb, replaced, destroying)
if (!isnull(limb))
UnregisterSignal(limb, COMSIG_BODYPART_UPDATE_WOUND_OVERLAY)
return ..()
/datum/wound/pierce/bleed/severe/eye/proc/wound_overlay(obj/item/bodypart/source, limb_bleed_rate)
SIGNAL_HANDLER
if (limb_bleed_rate <= BLEED_OVERLAY_LOW || limb_bleed_rate > BLEED_OVERLAY_GUSH)
return
if (blood_flow <= BLEED_OVERLAY_LOW)
return
source.bleed_overlay_icon = right_side ? "r_eye" : "l_eye"
return COMPONENT_PREVENT_WOUND_OVERLAY_UPDATE
/datum/wound_pregen_data/flesh_pierce/open_puncture/eye
wound_path_to_generate = /datum/wound/pierce/bleed/severe/eye
viable_zones = list(BODY_ZONE_HEAD)
can_be_randomly_generated = FALSE
/datum/wound_pregen_data/flesh_pierce/open_puncture/eye/can_be_applied_to(obj/item/bodypart/limb, list/suggested_wounding_types, datum/wound/old_wound, random_roll, duplicates_allowed, care_about_existing_wounds)
if (isnull(locate(/obj/item/organ/eyes) in limb))
return FALSE
return ..()
/datum/wound/pierce/bleed/severe/magicalearpain //what happens if you try to listen to the heartbeat of a corrupt heart while not a heretic
name = "Bleeding Ears"
desc = "Patient's ears are bleeding heavily as blood seeps through the inner flesh of the ear through some unknown means."
examine_desc = "is covered in blood, black-purple fluid flowing from its ears"
occur_text = "is soaked as two spurts of black liquid spray from its ears"
internal_bleeding_chance = 0 // just your ears
/datum/wound_pregen_data/flesh_pierce/open_puncture/magicalearpain
wound_path_to_generate = /datum/wound/pierce/bleed/severe/magicalearpain
viable_zones = list(BODY_ZONE_HEAD)
can_be_randomly_generated = FALSE
/datum/wound/pierce/bleed/severe/magicalearpain/apply_wound(obj/item/bodypart/limb, silent, datum/wound/old_wound, smited, attack_direction, wound_source, replacing)
var/obj/item/organ/ears/ears = locate() in limb
if (!istype(ears))
return FALSE
. = ..()
/datum/wound/pierce/bleed/critical
name = "Ruptured Cavity"
desc = "Patient's internal tissue and circulatory system is shredded, causing significant internal bleeding and damage to internal organs."
treat_text = "Immediately apply bandaging or suturing to the wound, make use of blood clotting agents or saline-glucose, \
cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \
Follow with supervised resanguination."
treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization."
examine_desc = "is ripped clear through, barely held together by exposed bone"
occur_text = "blasts apart, sending chunks of viscera flying in all directions"
sound_effect = 'sound/effects/wounds/pierce3.ogg'
severity = WOUND_SEVERITY_CRITICAL
initial_flow = 2.5
gauzed_clot_rate = 0.3
internal_bleeding_chance = 80
internal_bleeding_coefficient = 2.5
threshold_penalty = 15
status_effect_type = /datum/status_effect/wound/pierce/critical
scar_keyword = "piercecritical"
surgery_states = SURGERY_SKIN_CUT | SURGERY_VESSELS_UNCLAMPED // Bad enough to count
wound_flags = (ACCEPTS_GAUZE | MANGLES_EXTERIOR | CAN_BE_GRASPED)
simple_treat_text = "<b>Bandaging</b> the wound is of utmost importance, as is seeking direct medical attention - <b>Death</b> will ensue if treatment is delayed whatsoever, with lack of <b>oxygen</b> killing the patient, thus <b>Food, Iron, and saline solution</b> is always recommended after treatment. This wound will not naturally seal itself."
homemade_treat_text = "Bed sheets can be ripped up to make <b>makeshift gauze</b>. <b>Flour, salt, and saltwater</b> topically applied will help. Dropping to the ground and grabbing your wound will reduce blood flow."
/datum/wound_pregen_data/flesh_pierce/cavity
abstract = FALSE
wound_path_to_generate = /datum/wound/pierce/bleed/critical
threshold_minimum = 100