mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 13:38:41 +01:00
Medical update - Muscle wound, Splints, Bandages, Closer Examine (#2336)
* everything but wound topics * Update bodypart_aid.dm * aaa * aaa * aaa * aaaa * Update _bodyparts.dm * Update carbon_examine.dm * Update bodypart_aid.dm * Update slash.dm * Wound topics, self grasping on a topic, bandages on top uniform * Merge branch 'master' into med
This commit is contained in:
+10
-9
@@ -13,14 +13,15 @@
|
||||
#define REVERSE_DIR(dir) ( ((dir & 85) << 1) | ((dir & 170) >> 1) )
|
||||
|
||||
//Human Overlays Indexes/////////
|
||||
#define MUTATIONS_LAYER 28 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define BODY_BEHIND_LAYER 27 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define BODYPARTS_LAYER 26 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
|
||||
#define BODY_ADJ_LAYER 25 //certain mutantrace features (snout, body markings) that must appear above the body parts
|
||||
#define BODY_LAYER 24 //underwear, undershirts, socks, eyes, lips(makeup)
|
||||
#define FRONT_MUTATIONS_LAYER 23 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
|
||||
#define DAMAGE_LAYER 22 //damage indicators (cuts and burns)
|
||||
#define UNIFORM_LAYER 21
|
||||
#define MUTATIONS_LAYER 29 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define BODY_BEHIND_LAYER 28 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
|
||||
#define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts
|
||||
#define BODY_LAYER 25 //underwear, undershirts, socks, eyes, lips(makeup)
|
||||
#define FRONT_MUTATIONS_LAYER 24 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
|
||||
#define DAMAGE_LAYER 23 //damage indicators (cuts and burns)
|
||||
#define UNIFORM_LAYER 22
|
||||
#define BANDAGE_LAYER 21 //Overlays related to wounds, bandages and splints too //SKYRAT EDIT ADDITION - MEDICAL
|
||||
#define ID_LAYER 20 //lmao at the idiot who put both ids and hands on the same layer
|
||||
#define HANDS_PART_LAYER 19
|
||||
#define GLOVES_LAYER 18
|
||||
@@ -41,7 +42,7 @@
|
||||
#define BODY_FRONT_LAYER 3
|
||||
#define HALO_LAYER 2 //blood cult ascended halo, because there's currently no better solution for adding/removing
|
||||
#define FIRE_LAYER 1 //If you're on fire
|
||||
#define TOTAL_LAYERS 28 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
|
||||
#define TOTAL_LAYERS 29 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; //SKYRAT EDIT CHANGE - 29 from 28. Added BANDAGE_LAYER
|
||||
|
||||
//Human Overlay Index Shortcuts for alternate_worn_layer, layers
|
||||
//Because I *KNOW* somebody will think layer+1 means "above"
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
#define WOUND_PIERCE 3
|
||||
/// any concentrated burn attack (lasers really). rolls for burning wounds
|
||||
#define WOUND_BURN 4
|
||||
//SKYRAT EDIT ADDITION BEGIN - MEDICAL
|
||||
/// any brute attacks, rolled on a chance
|
||||
#define WOUND_MUSCLE 5
|
||||
//SKYRAT EDIT ADDITION END
|
||||
|
||||
|
||||
// ~determination second wind defines
|
||||
@@ -49,14 +53,15 @@
|
||||
GLOBAL_LIST_INIT(global_wound_types, list(WOUND_BLUNT = list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate),
|
||||
WOUND_SLASH = list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate),
|
||||
WOUND_PIERCE = list(/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate),
|
||||
WOUND_BURN = list(/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate)
|
||||
WOUND_BURN = list(/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate),
|
||||
WOUND_MUSCLE = list(/datum/wound/muscle/severe, /datum/wound/muscle/moderate)
|
||||
))
|
||||
|
||||
// every single type of wound that can be rolled naturally, in case you need to pull a random one
|
||||
GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate,
|
||||
/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate,
|
||||
/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate,
|
||||
/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate))
|
||||
/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate, /datum/wound/muscle/severe, /datum/wound/muscle/moderate))
|
||||
|
||||
|
||||
// ~burn wound infection defines
|
||||
@@ -118,6 +123,10 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datu
|
||||
#define MANGLES_BONE (1<<3)
|
||||
/// If this wound marks the limb as being allowed to have gauze applied
|
||||
#define ACCEPTS_GAUZE (1<<4)
|
||||
//SKYRAT EDIT ADDITION BEGIN - MEDICAL
|
||||
/// If this wound marks the limb as being allowed to have splints applied
|
||||
#define ACCEPTS_SPLINT (1<<5)
|
||||
//SKYRAT EDIT ADDITION END
|
||||
|
||||
|
||||
// ~scar persistence defines
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#define GAUZE_STAIN_BLOOD 1
|
||||
#define GAUZE_STAIN_PUS 2
|
||||
|
||||
#define COMSIG_BODYPART_SPLINTED "bodypart_splinted" // from /obj/item/bodypart/proc/apply_gauze(/obj/item/stack/gauze)
|
||||
#define COMSIG_BODYPART_SPLINT_DESTROYED "bodypart_desplinted" // from [/obj/item/bodypart/proc/seep_gauze] when it runs out of absorption
|
||||
@@ -1,3 +1,5 @@
|
||||
//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
|
||||
/*
|
||||
|
||||
/*
|
||||
Blunt/Bone wounds
|
||||
@@ -446,3 +448,4 @@
|
||||
else if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume)
|
||||
. += "Ribcage Trauma Detected: Further trauma to chest is likely to worsen internal bleeding until bone is repaired."
|
||||
. += "</div>"
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
|
||||
/*
|
||||
|
||||
/*
|
||||
Burn wounds
|
||||
@@ -301,3 +303,4 @@
|
||||
infestation_rate = 0.15 // appx 4.33 minutes to reach sepsis without any treatment
|
||||
flesh_damage = 20
|
||||
scar_keyword = "burncritical"
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
|
||||
/*
|
||||
|
||||
/*
|
||||
Piercing wounds
|
||||
@@ -177,3 +179,4 @@
|
||||
status_effect_type = /datum/status_effect/wound/pierce/critical
|
||||
scar_keyword = "piercecritical"
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
|
||||
/*
|
||||
|
||||
/*
|
||||
Slashing wounds
|
||||
@@ -297,3 +299,4 @@
|
||||
status_effect_type = /datum/status_effect/wound/slash/critical
|
||||
scar_keyword = "slashcritical"
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
|
||||
*/
|
||||
|
||||
@@ -119,7 +119,8 @@
|
||||
|
||||
/obj/item/stack/medical/gauze
|
||||
name = "medical gauze"
|
||||
desc = "A roll of elastic cloth, perfect for stabilizing all kinds of wounds, from cuts and burns, to broken bones. "
|
||||
//desc = "A roll of elastic cloth, perfect for stabilizing all kinds of wounds, from cuts and burns, to broken bones. " //ORIGINAL
|
||||
desc = "A roll of elastic cloth, perfect for stabilizing all kinds of slashes, punctures and burns. " //SKYRAT EDIT CHANGE - MEDICAL
|
||||
gender = PLURAL
|
||||
singular_name = "medical gauze"
|
||||
icon_state = "gauze"
|
||||
@@ -133,6 +134,7 @@
|
||||
absorption_capacity = 5
|
||||
splint_factor = 0.35
|
||||
merge_type = /obj/item/stack/medical/gauze
|
||||
var/gauze_type = /datum/bodypart_aid/gauze //SKYRAT EDIT ADDITION - MEDICAL
|
||||
|
||||
// gauze is only relevant for wounds, which are handled in the wounds themselves
|
||||
/obj/item/stack/medical/gauze/try_heal(mob/living/M, mob/user, silent)
|
||||
@@ -154,9 +156,16 @@
|
||||
to_chat(user, "<span class='notice'>There's no wounds that require bandaging on [user==M ? "your" : "[M]'s"] [limb.name]!</span>") // good problem to have imo
|
||||
return
|
||||
|
||||
//SKYRAT EDIT CHANGE BEGIN - MEDICAL
|
||||
/*
|
||||
if(limb.current_gauze && (limb.current_gauze.absorption_capacity * 0.8 > absorption_capacity)) // ignore if our new wrap is < 20% better than the current one, so someone doesn't bandage it 5 times in a row
|
||||
to_chat(user, "<span class='warning'>The bandage currently on [user==M ? "your" : "[M]'s"] [limb.name] is still in good condition!</span>")
|
||||
return
|
||||
*/
|
||||
if(limb.current_gauze)
|
||||
to_chat(user, "<span class='warning'>[user==M ? "Your" : "[M]'s"] [limb.name] is already bandaged!</span>")
|
||||
return
|
||||
//SKYRAT EDIT CHANGE END
|
||||
|
||||
user.visible_message("<span class='warning'>[user] begins wrapping the wounds on [M]'s [limb.name] with [src]...</span>", "<span class='warning'>You begin wrapping the wounds on [user == M ? "your" : "[M]'s"] [limb.name] with [src]...</span>")
|
||||
if(!do_after(user, (user == M ? self_delay : other_delay), target=M))
|
||||
@@ -194,6 +203,7 @@
|
||||
absorption_rate = 0.15
|
||||
absorption_capacity = 4
|
||||
merge_type = /obj/item/stack/medical/gauze/improvised
|
||||
gauze_type = /datum/bodypart_aid/gauze/improvised //SKYRAT EDIT ADDITION - MEDICAL
|
||||
|
||||
/*
|
||||
The idea is for the following medical devices to work like a hybrid of the old brute packs and tend wounds,
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
return
|
||||
var/static/items_inside = list(
|
||||
/obj/item/stack/medical/gauze = 1,
|
||||
/obj/item/stack/medical/splint = 1, //SKYRAT EDIT ADDITION - MEDICAL
|
||||
/obj/item/stack/medical/suture = 2,
|
||||
/obj/item/stack/medical/mesh = 2,
|
||||
/obj/item/reagent_containers/hypospray/medipen = 1)
|
||||
@@ -48,6 +49,7 @@
|
||||
var/static/items_inside = list(
|
||||
/obj/item/healthanalyzer/wound = 1,
|
||||
/obj/item/stack/medical/gauze = 1,
|
||||
/obj/item/stack/medical/splint = 1, //SKYRAT EDIT ADDITION - MEDICAL
|
||||
/obj/item/stack/medical/suture/emergency = 1,
|
||||
/obj/item/stack/medical/ointment = 1,
|
||||
/obj/item/reagent_containers/hypospray/medipen/ekit = 2,
|
||||
@@ -124,6 +126,7 @@
|
||||
var/static/items_inside = list(
|
||||
/obj/item/healthanalyzer = 1,
|
||||
/obj/item/stack/medical/gauze/twelve = 1,
|
||||
/obj/item/stack/medical/splint/twelve = 1, //SKYRAT EDIT ADDITION - MEDICAL
|
||||
/obj/item/stack/medical/suture = 2,
|
||||
/obj/item/stack/medical/mesh = 2,
|
||||
/obj/item/reagent_containers/hypospray/medipen = 1,
|
||||
@@ -142,6 +145,7 @@
|
||||
return
|
||||
var/static/items_inside = list(
|
||||
/obj/item/stack/medical/gauze = 1,
|
||||
/obj/item/stack/medical/splint = 1, //SKYRAT EDIT ADDITION - MEDICAL
|
||||
/obj/item/stack/medical/bruise_pack = 3,
|
||||
/obj/item/stack/medical/ointment= 3)
|
||||
generate_items_inside(items_inside,src)
|
||||
@@ -246,6 +250,7 @@
|
||||
var/static/items_inside = list(
|
||||
/obj/item/reagent_containers/pill/patch/libital = 3,
|
||||
/obj/item/stack/medical/gauze = 1,
|
||||
/obj/item/stack/medical/splint = 1, //SKYRAT EDIT ADDITION - MEDICAL
|
||||
/obj/item/storage/pill_bottle/probital = 1,
|
||||
/obj/item/reagent_containers/hypospray/medipen/salacid = 1)
|
||||
generate_items_inside(items_inside,src)
|
||||
@@ -265,6 +270,7 @@
|
||||
/obj/item/reagent_containers/pill/patch/synthflesh = 3,
|
||||
/obj/item/reagent_containers/hypospray/medipen/atropine = 2,
|
||||
/obj/item/stack/medical/gauze = 1,
|
||||
/obj/item/stack/medical/splint = 1, //SKYRAT EDIT ADDITION - MEDICAL
|
||||
/obj/item/storage/pill_bottle/penacid = 1)
|
||||
generate_items_inside(items_inside,src)
|
||||
|
||||
@@ -283,6 +289,7 @@
|
||||
if(empty)
|
||||
return
|
||||
new /obj/item/stack/medical/gauze(src)
|
||||
new /obj/item/stack/medical/splint //SKYRAT EDIT ADDITION - MEDICAL
|
||||
new /obj/item/defibrillator/compact/combat/loaded(src)
|
||||
new /obj/item/reagent_containers/hypospray/combat(src)
|
||||
new /obj/item/reagent_containers/pill/patch/libital(src)
|
||||
|
||||
@@ -700,6 +700,8 @@
|
||||
return ..()
|
||||
|
||||
var/obj/item/bodypart/grasped_part = get_bodypart(zone_selected)
|
||||
//SKYRAT EDIT CHANGE BEGIN - MEDICAL
|
||||
/*
|
||||
if(!grasped_part?.get_bleed_rate())
|
||||
return
|
||||
var/starting_hand_index = active_hand_index
|
||||
@@ -718,6 +720,9 @@
|
||||
QDEL_NULL(grasp)
|
||||
return
|
||||
grasp.grasp_limb(grasped_part)
|
||||
*/
|
||||
self_grasp_bleeding_limb(grasped_part, supress_message)
|
||||
//SKYRAT EDIT CHANGE END
|
||||
|
||||
/// an abstract item representing you holding your own limb to staunch the bleeding, see [/mob/living/carbon/proc/grabbedby] will probably need to find somewhere else to put this.
|
||||
/obj/item/self_grasp
|
||||
|
||||
@@ -154,6 +154,8 @@
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
|
||||
|
||||
//SKYRAT EDIT REMOVAL - MOVED - MEDICAL
|
||||
/*
|
||||
/mob/living/carbon/examine_more(mob/user)
|
||||
if(!all_scars)
|
||||
return ..()
|
||||
@@ -175,3 +177,4 @@
|
||||
msg += "[scar_text]"
|
||||
|
||||
return msg
|
||||
*/
|
||||
|
||||
@@ -741,13 +741,17 @@
|
||||
var/msg
|
||||
switch(W.severity)
|
||||
if(WOUND_SEVERITY_TRIVIAL)
|
||||
msg = "\t <span class='danger'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)].</span>"
|
||||
//msg = "\t <span class='danger'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)].</span>" //ORIGINAL
|
||||
msg = "\t <span class='danger'>Your [LB.name] is suffering [W.a_or_from] [W.get_topic_name(src)].</span>" //SKYRAT EDIT CHANGE - MEDICAL
|
||||
if(WOUND_SEVERITY_MODERATE)
|
||||
msg = "\t <span class='warning'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</span>"
|
||||
//msg = "\t <span class='warning'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</span>" //ORIGINAL
|
||||
msg = "\t <span class='warning'>Your [LB.name] is suffering [W.a_or_from] [W.get_topic_name(src)]!</span>" //SKYRAT EDIT CHANGE - MEDICAL
|
||||
if(WOUND_SEVERITY_SEVERE)
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</b></span>"
|
||||
//msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</b></span>" //ORIGINAL
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [W.get_topic_name(src)]!</b></span>" //SKYRAT EDIT CHANGE - MEDICAL
|
||||
if(WOUND_SEVERITY_CRITICAL)
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!</b></span>"
|
||||
//msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!</b></span>" //ORIGINAL
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [W.get_topic_name(src)]!!</b></span>" //SKYRAT EDIT CHANGE - MEDICAL
|
||||
combined_msg += msg
|
||||
|
||||
for(var/obj/item/I in LB.embedded_objects)
|
||||
@@ -756,6 +760,15 @@
|
||||
else
|
||||
combined_msg += "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>"
|
||||
|
||||
//SKYRAT EDIT ADDITION BEGIN - MEDICAL
|
||||
if(LB.current_gauze)
|
||||
var/datum/bodypart_aid/current_gauze = LB.current_gauze
|
||||
combined_msg += "\t <span class='notice'>Your [LB.name] is [current_gauze.desc_prefix] with <a href='?src=[REF(current_gauze)];remove=1'>[current_gauze.get_description()]</a>.</span>"
|
||||
if(LB.current_splint)
|
||||
var/datum/bodypart_aid/current_splint = LB.current_splint
|
||||
combined_msg += "\t <span class='notice'>Your [LB.name] is [current_splint.desc_prefix] with <a href='?src=[REF(current_splint)];remove=1'>[current_splint.get_description()]</a>.</span>"
|
||||
//SKYRAT EDIT END
|
||||
|
||||
for(var/t in missing)
|
||||
combined_msg += "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>"
|
||||
|
||||
|
||||
@@ -90,8 +90,16 @@
|
||||
var/last_maxed
|
||||
/// How much generic bleedstacks we have on this bodypart
|
||||
var/generic_bleedstacks
|
||||
//SKYRAT EDIT CHANGE BEGIN - MEDICAL
|
||||
/*
|
||||
/// If we have a gauze wrapping currently applied (not including splints)
|
||||
var/obj/item/stack/current_gauze
|
||||
*/
|
||||
/// If we have a gauze wrapping currently applied
|
||||
var/datum/bodypart_aid/gauze/current_gauze
|
||||
/// If we have a splint currently applied
|
||||
var/datum/bodypart_aid/splint/current_splint
|
||||
//SKYRAT EDIT CHANGE END
|
||||
/// If something is currently grasping this bodypart and trying to staunch bleeding (see [/obj/item/self_grasp])
|
||||
var/obj/item/self_grasp/grasped_by
|
||||
var/rendered_bp_icon //SKYRAT EDIT ADDITION - CUSTOMIZATION
|
||||
@@ -114,6 +122,12 @@
|
||||
if(length(wounds))
|
||||
stack_trace("[type] qdeleted with [length(wounds)] uncleared wounds")
|
||||
wounds.Cut()
|
||||
//SKYRAT EDIT ADDITION BEGIN - MEDICAL
|
||||
if(current_gauze)
|
||||
qdel(current_gauze)
|
||||
if(current_splint)
|
||||
qdel(current_splint)
|
||||
//SKYRAT EDIT ADDITION END
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -181,7 +195,11 @@
|
||||
var/turf/T = get_turf(src)
|
||||
if(status != BODYPART_ROBOTIC)
|
||||
playsound(T, 'sound/misc/splort.ogg', 50, TRUE, -1)
|
||||
seep_gauze(9999) // destroy any existing gauze if any exists
|
||||
//seep_gauze(9999) // destroy any existing gauze if any exists
|
||||
if(current_gauze)
|
||||
qdel(current_gauze)
|
||||
if(current_splint)
|
||||
qdel(current_splint)
|
||||
for(var/obj/item/organ/drop_organ in get_organs())
|
||||
drop_organ.transfer_to_limb(src, owner)
|
||||
for(var/obj/item/I in src)
|
||||
@@ -268,6 +286,11 @@
|
||||
// note that there's no handling for BIO_JUST_FLESH since we don't have any that are that right now (slimepeople maybe someday)
|
||||
// standard humanoids
|
||||
if(BIO_FLESH_BONE)
|
||||
//SKYRAT EDIT ADDITION BEGIN - MEDICAL
|
||||
//We do a body zone check here because muscles dont have any variants for head or chest, and rolling a muscle wound on them wound end up on a wasted wound roll
|
||||
if(body_zone != BODY_ZONE_CHEST && body_zone != BODY_ZONE_HEAD && prob(35))
|
||||
wounding_type = WOUND_MUSCLE
|
||||
//SKYRAT EDIT ADDITION END
|
||||
// if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate
|
||||
// So a big sharp weapon is still all you need to destroy a limb
|
||||
if(mangled_state == BODYPART_MANGLED_FLESH && sharpness)
|
||||
@@ -282,6 +305,12 @@
|
||||
|
||||
// now we have our wounding_type and are ready to carry on with wounds and dealing the actual damage
|
||||
if(owner && wounding_dmg >= WOUND_MINIMUM_DAMAGE && wound_bonus != CANT_WOUND)
|
||||
//SKYRAT EDIT ADDITION - MEDICAL
|
||||
if(current_gauze)
|
||||
current_gauze.take_damage()
|
||||
if(current_splint)
|
||||
current_splint.take_damage()
|
||||
//SKYRAT EDIT ADDITION - MEDICAL
|
||||
check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)
|
||||
|
||||
for(var/i in wounds)
|
||||
@@ -907,9 +936,11 @@
|
||||
var/datum/wound/iter_wound = i
|
||||
dam_mul *= iter_wound.damage_mulitplier_penalty
|
||||
|
||||
/*
|
||||
if(!LAZYLEN(wounds) && current_gauze && !replaced) // no more wounds = no need for the gauze anymore
|
||||
owner.visible_message("<span class='notice'>\The [current_gauze] on [owner]'s [name] fall away.</span>", "<span class='notice'>The [current_gauze] on your [name] fall away.</span>")
|
||||
QDEL_NULL(current_gauze)
|
||||
*/
|
||||
|
||||
wound_damage_multiplier = dam_mul
|
||||
|
||||
@@ -954,6 +985,7 @@
|
||||
* Arguments:
|
||||
* * gauze- Just the gauze stack we're taking a sheet from to apply here
|
||||
*/
|
||||
/*
|
||||
/obj/item/bodypart/proc/apply_gauze(obj/item/stack/gauze)
|
||||
if(!istype(gauze) || !gauze.absorption_capacity)
|
||||
return
|
||||
@@ -965,6 +997,7 @@
|
||||
gauze.use(1)
|
||||
if(newly_gauzed)
|
||||
SEND_SIGNAL(src, COMSIG_BODYPART_GAUZED, gauze)
|
||||
*/
|
||||
|
||||
/**
|
||||
* seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity.
|
||||
@@ -974,6 +1007,7 @@
|
||||
* Arguments:
|
||||
* * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?)
|
||||
*/
|
||||
/*
|
||||
/obj/item/bodypart/proc/seep_gauze(seep_amt = 0)
|
||||
if(!current_gauze)
|
||||
return
|
||||
@@ -982,3 +1016,4 @@
|
||||
owner.visible_message("<span class='danger'>\The [current_gauze] on [owner]'s [name] fall away in rags.</span>", "<span class='warning'>\The [current_gauze] on your [name] fall away in rags.</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
QDEL_NULL(current_gauze)
|
||||
SEND_SIGNAL(src, COMSIG_BODYPART_GAUZE_DESTROYED)
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/obj/item/bodypart/proc/apply_gauze(obj/item/stack/medical/gauze/new_gauze)
|
||||
if(!istype(new_gauze) || current_gauze)
|
||||
return
|
||||
current_gauze = new new_gauze.gauze_type(src)
|
||||
new_gauze.use(1)
|
||||
|
||||
/obj/item/bodypart/proc/apply_splint(obj/item/stack/medical/splint/new_splint)
|
||||
if(!istype(new_splint) || current_splint)
|
||||
return
|
||||
current_splint = new new_splint.splint_type(src)
|
||||
new_splint.use(1)
|
||||
@@ -0,0 +1,231 @@
|
||||
#define SELF_AID_REMOVE_DELAY 5 SECONDS
|
||||
#define OTHER_AID_REMOVE_DELAY 2 SECONDS
|
||||
|
||||
/datum/bodypart_aid
|
||||
var/name
|
||||
/// Keeping track of how damaged our aid is from external things, such as hits, it will break when it reaches 0
|
||||
var/integrity = 2
|
||||
/// To which bodypart we're attached to
|
||||
var/obj/item/bodypart/bodypart
|
||||
/// Which item do we get when we rip this off, while its in pristine condition
|
||||
var/stack_to_drop
|
||||
/// Suffix for our used overlay. The suffix is the bodypart zone, and "_digitigrade" for some legs. If this is null then it wont make an overlay. Gauzes are rendered before splints
|
||||
var/overlay_prefix
|
||||
/// Bodypart is [this_prefix] with get_description()
|
||||
var/desc_prefix
|
||||
|
||||
/datum/bodypart_aid/Topic(href, href_list)
|
||||
. = ..()
|
||||
if(href_list["remove"])
|
||||
if(!bodypart.owner)
|
||||
return
|
||||
if(!iscarbon(usr))
|
||||
return
|
||||
if(!in_range(usr, bodypart.owner))
|
||||
return
|
||||
var/mob/living/carbon/C = usr
|
||||
var/self = (C == bodypart.owner)
|
||||
C.visible_message("<span class='notice'>[C] begins removing [name] from [self ? "[bodypart.owner.p_their(TRUE)]" : "[bodypart.owner]'s" ] [bodypart.name]...</span>", "<span class='notice'>You begin to remove [name] from [self ? "your" : "[bodypart.owner]'s"] [bodypart.name]...</span>")
|
||||
if(!do_after(C, (self ? SELF_AID_REMOVE_DELAY : OTHER_AID_REMOVE_DELAY), target=bodypart.owner))
|
||||
return
|
||||
if(QDELETED(src))
|
||||
return
|
||||
C.visible_message("<span class='notice'>[C] removes [name] from [self ? "[bodypart.owner.p_their(TRUE)]" : "[bodypart.owner]'s" ] [bodypart.name].</span>", "<span class='notice'>You remove [name] from [self ? "your" : "[bodypart.owner]'s" ] [bodypart.name].</span>")
|
||||
var/obj/item/gotten = rip_off()
|
||||
if(gotten && !C.put_in_hands(gotten))
|
||||
gotten.forceMove(get_turf(C))
|
||||
|
||||
/datum/bodypart_aid/New(obj/item/bodypart/BP)
|
||||
//'bodypart == BP' is set in subtypes to ensure some proper signals and behaviours
|
||||
if(overlay_prefix && bodypart.owner)
|
||||
bodypart.owner.update_bandage_overlays()
|
||||
|
||||
/datum/bodypart_aid/Destroy()
|
||||
if(overlay_prefix && bodypart.owner)
|
||||
bodypart.owner.update_bandage_overlays()
|
||||
bodypart = null
|
||||
..()
|
||||
|
||||
/**
|
||||
* take_damage() called when the bandage gets damaged
|
||||
*
|
||||
* This proc will subtract integrity and delete the bandage with a to_chat message to whoever was bandaged
|
||||
*
|
||||
*/
|
||||
|
||||
/datum/bodypart_aid/proc/take_damage()
|
||||
integrity--
|
||||
if(integrity <= 0)
|
||||
if(bodypart.owner)
|
||||
to_chat(bodypart.owner, "<span class='warning'>The [name] on your [bodypart.name] tears and falls off!</span>")
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* rip_off() called when someone rips it off
|
||||
*
|
||||
* It will return the bandage if it's considered pristine
|
||||
*
|
||||
*/
|
||||
|
||||
/datum/bodypart_aid/proc/rip_off()
|
||||
if(is_pristine())
|
||||
. = new stack_to_drop(null, 1)
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* get_description() called by examine procs
|
||||
*
|
||||
* It will returns a description of the bandage
|
||||
*
|
||||
*/
|
||||
|
||||
/datum/bodypart_aid/proc/get_description()
|
||||
return "[name]"
|
||||
|
||||
/**
|
||||
* is_pristine() called by rip_off()
|
||||
*
|
||||
* Used to determine whether the bandage can be re-used and won't qdel itself
|
||||
*
|
||||
*/
|
||||
|
||||
/datum/bodypart_aid/proc/is_pristine()
|
||||
return (integrity == initial(integrity))
|
||||
|
||||
/datum/bodypart_aid/splint
|
||||
name = "splint"
|
||||
overlay_prefix = "splint"
|
||||
desc_prefix = "fastened"
|
||||
stack_to_drop = /obj/item/stack/medical/splint
|
||||
/// How effective are we in keeping the bodypart rigid
|
||||
var/splint_factor = 0.3
|
||||
/// Whether the splint prevents the limb from being disabled, with a ruptured tendon or a shattered bone
|
||||
var/helps_disabled = TRUE
|
||||
/// Total condition of our splint, the more we use it the more it gets looser
|
||||
var/sling_condition = 5
|
||||
|
||||
/datum/bodypart_aid/splint/get_description()
|
||||
var/desc
|
||||
switch(sling_condition)
|
||||
if(0 to 1.25)
|
||||
desc = "barely holding"
|
||||
if(1.25 to 2.75)
|
||||
desc = "loose"
|
||||
if(2.75 to 4)
|
||||
desc = "rigid"
|
||||
if(4 to INFINITY)
|
||||
desc = "tight"
|
||||
desc += " [name]"
|
||||
return desc
|
||||
|
||||
/datum/bodypart_aid/splint/Destroy()
|
||||
SEND_SIGNAL(bodypart, COMSIG_BODYPART_SPLINT_DESTROYED)
|
||||
bodypart.current_splint = null
|
||||
return ..()
|
||||
|
||||
/datum/bodypart_aid/splint/New(obj/item/bodypart/BP)
|
||||
bodypart = BP
|
||||
BP.current_splint = src
|
||||
SEND_SIGNAL(BP, COMSIG_BODYPART_SPLINTED, src)
|
||||
..()
|
||||
|
||||
/datum/bodypart_aid/splint/improvised
|
||||
name = "improvised splint"
|
||||
splint_factor = 0.6
|
||||
helps_disabled= FALSE
|
||||
stack_to_drop = /obj/item/stack/medical/splint/improvised
|
||||
overlay_prefix = "splint_improv"
|
||||
|
||||
/datum/bodypart_aid/splint/tribal
|
||||
name = "tribal splint"
|
||||
splint_factor = 0.5
|
||||
stack_to_drop = /obj/item/stack/medical/splint/tribal
|
||||
overlay_prefix = "splint_tribal"
|
||||
|
||||
/datum/bodypart_aid/gauze
|
||||
name = "gauze"
|
||||
stack_to_drop = /obj/item/stack/medical/gauze
|
||||
overlay_prefix = "gauze"
|
||||
desc_prefix = "bandaged"
|
||||
/// How much more can we absorb
|
||||
var/absorption_capacity = 5
|
||||
/// How fast do we absorb
|
||||
var/absorption_rate = 0.12
|
||||
/// How much does the gauze help with keeping infections clean
|
||||
var/sanitisation_factor = 0.4
|
||||
/// How much sanitisation we've got after we become fairly stained and worn
|
||||
var/sanitisation_factor_stained = 0.8
|
||||
/// Is it blood stained? For description
|
||||
var/blood_stained = FALSE
|
||||
/// Is it pus stained? For description
|
||||
var/pus_stained = FALSE
|
||||
|
||||
/datum/bodypart_aid/gauze/get_description()
|
||||
var/desc
|
||||
switch(absorption_capacity)
|
||||
if(0 to 1.25)
|
||||
desc = "nearly ruined"
|
||||
if(1.25 to 2.75)
|
||||
desc = "badly worn"
|
||||
if(2.75 to 4)
|
||||
desc = "slightly used"
|
||||
if(4 to INFINITY)
|
||||
desc = "clean"
|
||||
if(blood_stained)
|
||||
desc += ", bloodied"
|
||||
if(pus_stained)
|
||||
desc += ", pus stained"
|
||||
desc += " [name]"
|
||||
return desc
|
||||
|
||||
/datum/bodypart_aid/gauze/New(obj/item/bodypart/BP)
|
||||
bodypart = BP
|
||||
BP.current_gauze = src
|
||||
SEND_SIGNAL(BP, COMSIG_BODYPART_GAUZED, src)
|
||||
..()
|
||||
|
||||
/datum/bodypart_aid/gauze/Destroy()
|
||||
SEND_SIGNAL(bodypart, COMSIG_BODYPART_GAUZE_DESTROYED)
|
||||
bodypart.current_gauze = null
|
||||
return ..()
|
||||
|
||||
/datum/bodypart_aid/gauze/is_pristine()
|
||||
. = ..()
|
||||
if(.)
|
||||
return (absorption_capacity == initial(absorption_capacity))
|
||||
|
||||
/**
|
||||
* seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity.
|
||||
*
|
||||
* The passed amount of seepage is deducted from the bandage's absorption capacity, and if we reach a negative absorption capacity, the bandage won't help our wounds.
|
||||
* When the bandage is left with a low amount of absorption, it'll notify user and act worse as a sanitiser for infections
|
||||
* Returns TRUE if the bandage absorbed anything, FALSE if it's fully stained.
|
||||
*
|
||||
* Arguments:
|
||||
* * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?)
|
||||
* * type - Is it blood or pus we're being stained with? GAUZE_STAIN_BLOOD, GAUZE_STAIN_PUS defines from wounds.dm
|
||||
*/
|
||||
|
||||
/datum/bodypart_aid/gauze/proc/seep_gauze(amount, type)
|
||||
if(absorption_capacity > 0)
|
||||
. = TRUE
|
||||
absorption_capacity -= amount
|
||||
else
|
||||
return FALSE
|
||||
//If our remaining absorption capacity is low, make so blood and pus stains show
|
||||
if(absorption_capacity < 2)
|
||||
sanitisation_factor = sanitisation_factor_stained
|
||||
if(type == GAUZE_STAIN_BLOOD && !blood_stained)
|
||||
blood_stained = TRUE
|
||||
if(bodypart.owner)
|
||||
to_chat(bodypart.owner, "<span class='warning'>The [name] on your [bodypart.name] [pick(list("pools", "trickles", "seeps"))] with blood.</span>")
|
||||
else if(type == GAUZE_STAIN_PUS && !pus_stained)
|
||||
pus_stained = TRUE
|
||||
if(bodypart.owner)
|
||||
to_chat(bodypart.owner, "<span class='warning'>The [name] on your [bodypart.name] [pick(list("pools", "trickles", "seeps"))] with pus.</span>")
|
||||
|
||||
/datum/bodypart_aid/gauze/improvised
|
||||
name = "improvised gauze"
|
||||
stack_to_drop = /obj/item/stack/medical/gauze/improvised
|
||||
absorption_rate = 0.09
|
||||
absorption_capacity = 3
|
||||
@@ -0,0 +1,19 @@
|
||||
/mob/living/carbon/proc/self_grasp_bleeding_limb(obj/item/bodypart/grasped_part, supress_message = FALSE)
|
||||
if(!grasped_part?.get_bleed_rate())
|
||||
return
|
||||
var/starting_hand_index = active_hand_index
|
||||
if(starting_hand_index == grasped_part.held_index)
|
||||
to_chat(src, "<span class='danger'>You can't grasp your [grasped_part.name] with itself!</span>")
|
||||
return
|
||||
|
||||
to_chat(src, "<span class='warning'>You try grasping at your [grasped_part.name], trying to stop the bleeding...</span>")
|
||||
if(!do_after(src, 1.5 SECONDS))
|
||||
to_chat(src, "<span class='danger'>You fail to grasp your [grasped_part.name].</span>")
|
||||
return
|
||||
|
||||
var/obj/item/self_grasp/grasp = new
|
||||
if(starting_hand_index != active_hand_index || !put_in_active_hand(grasp))
|
||||
to_chat(src, "<span class='danger'>You fail to grasp your [grasped_part.name].</span>")
|
||||
QDEL_NULL(grasp)
|
||||
return
|
||||
grasp.grasp_limb(grasped_part)
|
||||
@@ -0,0 +1,76 @@
|
||||
/mob/living/carbon/examine_more(mob/user)
|
||||
var/msg = list("<span class='notice'><i>You examine [src] closer, and note the following...</i></span>")
|
||||
var/t_His = p_their(TRUE)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_Has = p_have()
|
||||
|
||||
var/any_bodypart_damage = FALSE
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/LB = X
|
||||
if(LB.is_pseudopart)
|
||||
continue
|
||||
var/limb_max_damage = LB.max_damage
|
||||
var/status = ""
|
||||
var/brutedamage = round(LB.brute_dam/limb_max_damage*100)
|
||||
var/burndamage = round(LB.burn_dam/limb_max_damage*100)
|
||||
switch(brutedamage)
|
||||
if(20 to 50)
|
||||
status = LB.light_brute_msg
|
||||
if(51 to 75)
|
||||
status = LB.medium_brute_msg
|
||||
if(76 to 100)
|
||||
status += LB.heavy_brute_msg
|
||||
|
||||
if(burndamage >= 20 && status)
|
||||
status += "and "
|
||||
switch(burndamage)
|
||||
if(20 to 50)
|
||||
status += LB.light_burn_msg
|
||||
if(51 to 75)
|
||||
status += LB.medium_burn_msg
|
||||
if(76 to 100)
|
||||
status += LB.heavy_burn_msg
|
||||
|
||||
if(status)
|
||||
any_bodypart_damage = TRUE
|
||||
msg += "\t<span class='warning'>[t_His] [LB.name] is [status].</span>"
|
||||
|
||||
for(var/thing in LB.wounds)
|
||||
any_bodypart_damage = TRUE
|
||||
var/datum/wound/W = thing
|
||||
switch(W.severity)
|
||||
if(WOUND_SEVERITY_TRIVIAL)
|
||||
msg += "\t<span class='warning'>[t_His] [LB.name] is suffering [W.a_or_from] [W.get_topic_name(user)].</span>"
|
||||
if(WOUND_SEVERITY_MODERATE)
|
||||
msg += "\t<span class='warning'>[t_His] [LB.name] is suffering [W.a_or_from] [W.get_topic_name(user)]!</span>"
|
||||
if(WOUND_SEVERITY_SEVERE)
|
||||
msg += "\t<span class='warning'><b>[t_His] [LB.name] is suffering [W.a_or_from] [W.get_topic_name(user)]!</b></span>"
|
||||
if(WOUND_SEVERITY_CRITICAL)
|
||||
msg += "\t<span class='warning'><b>[t_His] [LB.name] is suffering [W.a_or_from] [W.get_topic_name(user)]!!</b></span>"
|
||||
if(LB.current_gauze)
|
||||
var/datum/bodypart_aid/current_gauze = LB.current_gauze
|
||||
msg += "\t<span class='notice'><i>[t_His] [LB.name] is [current_gauze.desc_prefix] with <a href='?src=[REF(current_gauze)];remove=1'>[current_gauze.get_description()]</a>.</i></span>"
|
||||
if(LB.current_splint)
|
||||
var/datum/bodypart_aid/current_splint = LB.current_splint
|
||||
msg += "\t<span class='notice'><i>[t_His] [LB.name] is [current_splint.desc_prefix] with <a href='?src=[REF(current_splint)];remove=1'>[current_splint.get_description()]</a>.</i></span>"
|
||||
|
||||
if(!any_bodypart_damage)
|
||||
msg += "\t<span class='smallnotice'><i>[t_He] [t_Has] no significantly damaged bodyparts.</i></span>"
|
||||
|
||||
var/list/visible_scars
|
||||
if(all_scars)
|
||||
for(var/i in all_scars)
|
||||
var/datum/scar/S = i
|
||||
if(S.is_visible(user))
|
||||
LAZYADD(visible_scars, S)
|
||||
|
||||
if(!visible_scars)
|
||||
msg |= "\t<span class='smallnotice'><i>[t_He] [t_Has] no visible scars.</i></span>"
|
||||
else
|
||||
for(var/i in visible_scars)
|
||||
var/datum/scar/S = i
|
||||
var/scar_text = S.get_examine_description(user)
|
||||
if(scar_text)
|
||||
msg += "[scar_text]"
|
||||
|
||||
return msg
|
||||
@@ -0,0 +1,20 @@
|
||||
/mob/living/carbon/proc/update_bandage_overlays()
|
||||
remove_overlay(BANDAGE_LAYER)
|
||||
|
||||
var/mutable_appearance/overlays = mutable_appearance('modular_skyrat/modules/medical/icons/on_limb_overlays.dmi', "", -BANDAGE_LAYER)
|
||||
overlays_standing[BANDAGE_LAYER] = overlays
|
||||
|
||||
for(var/b in bodyparts)
|
||||
var/obj/item/bodypart/BP = b
|
||||
if(BP.current_gauze && BP.current_gauze.overlay_prefix)
|
||||
var/bp_suffix = BP.body_zone
|
||||
if(BP.use_digitigrade)
|
||||
bp_suffix += "_digitigrade"
|
||||
overlays.add_overlay("[BP.current_gauze.overlay_prefix]_[bp_suffix]")
|
||||
if(BP.current_splint && BP.current_splint.overlay_prefix)
|
||||
var/bp_suffix = BP.body_zone
|
||||
if(BP.use_digitigrade)
|
||||
bp_suffix += "_digitigrade"
|
||||
overlays.add_overlay("[BP.current_splint.overlay_prefix]_[bp_suffix]")
|
||||
|
||||
apply_overlay(BANDAGE_LAYER)
|
||||
@@ -0,0 +1,14 @@
|
||||
/datum/crafting_recipe/tribalsplint
|
||||
name = "Tribal Splint"
|
||||
result = /obj/item/stack/medical/splint/tribal
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/bone = 2,
|
||||
/obj/item/stack/sheet/sinew = 1)
|
||||
category = CAT_PRIMAL
|
||||
|
||||
/datum/crafting_recipe/improvsplint
|
||||
name = "Improvised Splint"
|
||||
result = /obj/item/stack/medical/splint/improvised
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 2, /obj/item/stack/sheet/cloth = 2)
|
||||
category = CAT_MISC
|
||||
@@ -0,0 +1,66 @@
|
||||
/obj/item/stack/medical/splint
|
||||
name = "medical splint"
|
||||
desc = "Medical splints, designed to fastened a limb with ease, perfect for stabilizing broken bones and torn muscles. "
|
||||
gender = PLURAL
|
||||
singular_name = "medical splint"
|
||||
icon_state = "splint"
|
||||
icon = 'modular_skyrat/modules/medical/icons/stack_medical.dmi'
|
||||
self_delay = 5 SECONDS
|
||||
other_delay = 2 SECONDS
|
||||
max_amount = 12
|
||||
amount = 6
|
||||
grind_results = list(/datum/reagent/carbon = 2)
|
||||
custom_price = PAYCHECK_ASSISTANT * 2
|
||||
merge_type = /obj/item/stack/medical/splint
|
||||
var/splint_type = /datum/bodypart_aid/splint
|
||||
|
||||
/obj/item/stack/medical/splint/try_heal(mob/living/M, mob/user, silent)
|
||||
var/obj/item/bodypart/limb = M.get_bodypart(check_zone(user.zone_selected))
|
||||
if(!limb)
|
||||
to_chat(user, "<span class='notice'>There's nothing there to bandage!</span>")
|
||||
return
|
||||
if(!LAZYLEN(limb.wounds))
|
||||
to_chat(user, "<span class='notice'>There's no wounds that require bandaging on [user==M ? "your" : "[M]'s"] [limb.name]!</span>") // good problem to have imo
|
||||
return
|
||||
|
||||
var/splintable_wound = FALSE
|
||||
for(var/i in limb.wounds)
|
||||
var/datum/wound/woundies = i
|
||||
if(woundies.wound_flags & ACCEPTS_SPLINT)
|
||||
splintable_wound = TRUE
|
||||
break
|
||||
if(!splintable_wound)
|
||||
to_chat(user, "<span class='notice'>There's no wounds that require splinting on [user==M ? "your" : "[M]'s"] [limb.name]!</span>") // good problem to have imo
|
||||
return
|
||||
|
||||
if(limb.current_splint)
|
||||
to_chat(user, "<span class='warning'>[user==M ? "Your" : "[M]'s"] [limb.name] is already fastened in a splint!</span>")
|
||||
return
|
||||
|
||||
user.visible_message("<span class='warning'>[user] begins fastening [M]'s [limb.name] with [src]...</span>", "<span class='warning'>You begin to fasten [user == M ? "your" : "[M]'s"] [limb.name] with [src]...</span>")
|
||||
if(!do_after(user, (user == M ? self_delay : other_delay), target=M))
|
||||
return
|
||||
|
||||
user.visible_message("<span class='green'>[user] applies [src] to [M]'s [limb.name].</span>", "<span class='green'>You splint [user == M ? "your" : "[M]'s"] [limb.name].</span>")
|
||||
limb.apply_splint(src)
|
||||
|
||||
/obj/item/stack/medical/splint/twelve
|
||||
amount = 12
|
||||
|
||||
/obj/item/stack/medical/splint/tribal
|
||||
name = "tribal splint"
|
||||
desc = "Bone fastened with sinew, used to keep injured limbs rigid, surprisingly effective."
|
||||
singular_name = "tribal splint"
|
||||
icon_state = "splint_tribal"
|
||||
amount = 1
|
||||
splint_type = /datum/bodypart_aid/splint/tribal
|
||||
merge_type = /obj/item/stack/medical/splint/tribal
|
||||
|
||||
/obj/item/stack/medical/splint/improvised
|
||||
name = "improvised splint"
|
||||
desc = "Crudely made out splints with wood and some cotton sling, you doubt this will be any good."
|
||||
singular_name = "improvised splint"
|
||||
icon_state = "splint_improv"
|
||||
amount = 1
|
||||
splint_type = /datum/bodypart_aid/splint/improvised
|
||||
merge_type = /obj/item/stack/medical/splint/improvised
|
||||
@@ -0,0 +1,7 @@
|
||||
/// Whether we should show an interactable topic in examines of the wound. href_list["wound_topic"]
|
||||
/datum/wound/proc/show_wound_topic(mob/user)
|
||||
return FALSE
|
||||
|
||||
/// Gets the name of the wound with any interactable topic if possible
|
||||
/datum/wound/proc/get_topic_name(mob/user)
|
||||
return show_wound_topic(user) ? "<a href='?src=[REF(src)];wound_topic=1'>[lowertext(name)]</a>" : lowertext(name)
|
||||
@@ -0,0 +1,448 @@
|
||||
|
||||
/*
|
||||
Blunt/Bone wounds
|
||||
*/
|
||||
// TODO: well, a lot really, but i'd kill to get overlays and a bonebreaking effect like Blitz: The League, similar to electric shock skeletons
|
||||
|
||||
/datum/wound/blunt
|
||||
name = "Blunt (Bone) Wound"
|
||||
sound_effect = 'sound/effects/wounds/crack1.ogg'
|
||||
wound_type = WOUND_BLUNT
|
||||
wound_flags = (BONE_WOUND | ACCEPTS_SPLINT)
|
||||
|
||||
/// Have we been taped?
|
||||
var/taped
|
||||
/// Have we been bone gel'd?
|
||||
var/gelled
|
||||
/// If we did the gel + surgical tape healing method for fractures, how many ticks does it take to heal by default
|
||||
var/regen_ticks_needed
|
||||
/// Our current counter for gel + surgical tape regeneration
|
||||
var/regen_ticks_current
|
||||
/// If we suffer severe head booboos, we can get brain traumas tied to them
|
||||
var/datum/brain_trauma/active_trauma
|
||||
/// What brain trauma group, if any, we can draw from for head wounds
|
||||
var/brain_trauma_group
|
||||
/// If we deal brain traumas, when is the next one due?
|
||||
var/next_trauma_cycle
|
||||
/// How long do we wait +/- 20% for the next trauma?
|
||||
var/trauma_cycle_cooldown
|
||||
/// If this is a chest wound and this is set, we have this chance to cough up blood when hit in the chest
|
||||
var/internal_bleeding_chance = 0
|
||||
|
||||
/*
|
||||
Overwriting of base procs
|
||||
*/
|
||||
/datum/wound/blunt/wound_injury(datum/wound/old_wound = null)
|
||||
// hook into gaining/losing gauze so crit bone wounds can re-enable/disable depending if they're slung or not
|
||||
RegisterSignal(limb, list(COMSIG_BODYPART_SPLINTED, COMSIG_BODYPART_SPLINT_DESTROYED), .proc/update_inefficiencies)
|
||||
|
||||
if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group)
|
||||
processes = TRUE
|
||||
active_trauma = victim.gain_trauma_type(brain_trauma_group, TRAUMA_RESILIENCE_WOUND)
|
||||
next_trauma_cycle = world.time + (rand(100-WOUND_BONE_HEAD_TIME_VARIANCE, 100+WOUND_BONE_HEAD_TIME_VARIANCE) * 0.01 * trauma_cycle_cooldown)
|
||||
|
||||
RegisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, .proc/attack_with_hurt_hand)
|
||||
if(limb.held_index && victim.get_item_for_held_index(limb.held_index) && (disabling || prob(30 * severity)))
|
||||
var/obj/item/I = victim.get_item_for_held_index(limb.held_index)
|
||||
if(istype(I, /obj/item/offhand))
|
||||
I = victim.get_inactive_held_item()
|
||||
|
||||
if(I && victim.dropItemToGround(I))
|
||||
victim.visible_message("<span class='danger'>[victim] drops [I] in shock!</span>", "<span class='warning'><b>The force on your [limb.name] causes you to drop [I]!</b></span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
|
||||
update_inefficiencies()
|
||||
|
||||
/datum/wound/blunt/remove_wound(ignore_limb, replaced)
|
||||
limp_slowdown = 0
|
||||
QDEL_NULL(active_trauma)
|
||||
if(limb)
|
||||
UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED))
|
||||
if(victim)
|
||||
UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
|
||||
return ..()
|
||||
|
||||
/datum/wound/blunt/handle_process()
|
||||
. = ..()
|
||||
if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle)
|
||||
if(active_trauma)
|
||||
QDEL_NULL(active_trauma)
|
||||
else
|
||||
active_trauma = victim.gain_trauma_type(brain_trauma_group, TRAUMA_RESILIENCE_WOUND)
|
||||
next_trauma_cycle = world.time + (rand(100-WOUND_BONE_HEAD_TIME_VARIANCE, 100+WOUND_BONE_HEAD_TIME_VARIANCE) * 0.01 * trauma_cycle_cooldown)
|
||||
|
||||
if(!gelled || !taped)
|
||||
return
|
||||
|
||||
regen_ticks_current++
|
||||
if(victim.body_position == LYING_DOWN)
|
||||
if(prob(50))
|
||||
regen_ticks_current += 0.5
|
||||
if(victim.IsSleeping() && prob(50))
|
||||
regen_ticks_current += 0.5
|
||||
|
||||
if(prob(severity * 3))
|
||||
victim.take_bodypart_damage(rand(1, severity * 2), stamina=rand(2, severity * 2.5), wound_bonus=CANT_WOUND)
|
||||
if(prob(33))
|
||||
to_chat(victim, "<span class='danger'>You feel a sharp pain in your body as your bones are reforming!</span>")
|
||||
|
||||
if(regen_ticks_current > regen_ticks_needed)
|
||||
if(!victim || !limb)
|
||||
qdel(src)
|
||||
return
|
||||
to_chat(victim, "<span class='green'>Your [limb.name] has recovered from your fracture!</span>")
|
||||
remove_wound()
|
||||
|
||||
/// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so
|
||||
/datum/wound/blunt/proc/attack_with_hurt_hand(mob/M, atom/target, proximity)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(victim.get_active_hand() != limb || victim.a_intent == INTENT_HELP || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE)
|
||||
return
|
||||
|
||||
// With a severe or critical wound, you have a 15% or 30% chance to proc pain on hit
|
||||
if(prob((severity - 1) * 15))
|
||||
// And you have a 70% or 50% chance to actually land the blow, respectively
|
||||
if(prob(70 - 20 * (severity - 1)))
|
||||
to_chat(victim, "<span class='userdanger'>The fracture in your [limb.name] shoots with pain as you strike [target]!</span>")
|
||||
limb.receive_damage(brute=rand(1,5))
|
||||
else
|
||||
victim.visible_message("<span class='danger'>[victim] weakly strikes [target] with [victim.p_their()] broken [limb.name], recoiling from pain!</span>", \
|
||||
"<span class='userdanger'>You fail to strike [target] as the fracture in your [limb.name] lights up in unbearable pain!</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
INVOKE_ASYNC(victim, /mob.proc/emote, "scream")
|
||||
victim.Stun(0.5 SECONDS)
|
||||
limb.receive_damage(brute=rand(3,7))
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
|
||||
/datum/wound/blunt/receive_damage(wounding_type, wounding_dmg, wound_bonus)
|
||||
if(!victim || wounding_dmg < WOUND_MINIMUM_DAMAGE)
|
||||
return
|
||||
if(ishuman(victim))
|
||||
var/mob/living/carbon/human/human_victim = victim
|
||||
if(NOBLOOD in human_victim.dna?.species.species_traits)
|
||||
return
|
||||
|
||||
if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume && prob(internal_bleeding_chance + wounding_dmg))
|
||||
var/blood_bled = rand(1, wounding_dmg * (severity == WOUND_SEVERITY_CRITICAL ? 2 : 1.5)) // 12 brute toolbox can cause up to 18/24 bleeding with a severe/critical chest wound
|
||||
switch(blood_bled)
|
||||
if(1 to 6)
|
||||
victim.bleed(blood_bled, TRUE)
|
||||
if(7 to 13)
|
||||
victim.visible_message("<span class='smalldanger'>[victim] coughs up a bit of blood from the blow to [victim.p_their()] chest.</span>", "<span class='danger'>You cough up a bit of blood from the blow to your chest.</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
victim.bleed(blood_bled, TRUE)
|
||||
if(14 to 19)
|
||||
victim.visible_message("<span class='smalldanger'>[victim] spits out a string of blood from the blow to [victim.p_their()] chest!</span>", "<span class='danger'>You spit out a string of blood from the blow to your chest!</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
|
||||
victim.bleed(blood_bled)
|
||||
if(20 to INFINITY)
|
||||
victim.visible_message("<span class='danger'>[victim] chokes up a spray of blood from the blow to [victim.p_their()] chest!</span>", "<span class='danger'><b>You choke up on a spray of blood from the blow to your chest!</b></span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
victim.bleed(blood_bled)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
|
||||
victim.add_splatter_floor(get_step(victim.loc, victim.dir))
|
||||
|
||||
|
||||
/datum/wound/blunt/get_examine_description(mob/user)
|
||||
if(!limb.current_splint && !gelled && !taped)
|
||||
return ..()
|
||||
|
||||
var/list/msg = list()
|
||||
if(!limb.current_splint)
|
||||
msg += "[victim.p_their(TRUE)] [limb.name] [examine_desc]"
|
||||
else
|
||||
var/sling_condition = ""
|
||||
// how much life we have left in these bandages
|
||||
switch(limb.current_splint.sling_condition)
|
||||
if(0 to 1.25)
|
||||
sling_condition = "just barely"
|
||||
if(1.25 to 2.75)
|
||||
sling_condition = "loosely"
|
||||
if(2.75 to 4)
|
||||
sling_condition = "mostly"
|
||||
if(4 to INFINITY)
|
||||
sling_condition = "tightly"
|
||||
|
||||
msg += "[victim.p_their(TRUE)] [limb.name] is [sling_condition] fastened with a [limb.current_splint.name]"
|
||||
|
||||
if(taped)
|
||||
msg += ", <span class='notice'>and appears to be reforming itself under some surgical tape!</span>"
|
||||
else if(gelled)
|
||||
msg += ", <span class='notice'>with fizzing flecks of blue bone gel sparking off the bone!</span>"
|
||||
else
|
||||
msg += "!"
|
||||
return "<B>[msg.Join()]</B>"
|
||||
|
||||
/*
|
||||
New common procs for /datum/wound/blunt/
|
||||
*/
|
||||
|
||||
/datum/wound/blunt/proc/update_inefficiencies()
|
||||
if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(limb.current_splint)
|
||||
limp_slowdown = initial(limp_slowdown) * limb.current_splint.splint_factor
|
||||
else
|
||||
limp_slowdown = initial(limp_slowdown)
|
||||
victim.apply_status_effect(STATUS_EFFECT_LIMP)
|
||||
else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
if(limb.current_splint)
|
||||
interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_splint.splint_factor)
|
||||
else
|
||||
interaction_efficiency_penalty = interaction_efficiency_penalty
|
||||
|
||||
if(initial(disabling))
|
||||
set_disabling(!(limb.current_splint && limb.current_splint.helps_disabled))
|
||||
|
||||
limb.update_wounds()
|
||||
|
||||
/// Joint Dislocation (Moderate Blunt)
|
||||
/datum/wound/blunt/moderate
|
||||
name = "Joint Dislocation"
|
||||
desc = "Patient's bone has been unset from socket, causing pain and reduced motor function."
|
||||
treat_text = "Recommended application of bonesetter to affected limb, though manual relocation by applying an aggressive grab to the patient and helpfully interacting with afflicted limb may suffice."
|
||||
examine_desc = "is awkwardly jammed out of place"
|
||||
occur_text = "jerks violently and becomes unseated"
|
||||
severity = WOUND_SEVERITY_MODERATE
|
||||
viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
interaction_efficiency_penalty = 1.5
|
||||
limp_slowdown = 3
|
||||
threshold_minimum = 35
|
||||
threshold_penalty = 15
|
||||
treatable_tool = TOOL_BONESET
|
||||
wound_flags = (BONE_WOUND)
|
||||
status_effect_type = /datum/status_effect/wound/blunt/moderate
|
||||
scar_keyword = "bluntmoderate"
|
||||
|
||||
/datum/wound/blunt/moderate/Destroy()
|
||||
if(victim)
|
||||
UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED)
|
||||
return ..()
|
||||
|
||||
/datum/wound/blunt/moderate/wound_injury(datum/wound/old_wound)
|
||||
. = ..()
|
||||
RegisterSignal(victim, COMSIG_LIVING_DOORCRUSHED, .proc/door_crush)
|
||||
|
||||
/// Getting smushed in an airlock/firelock is a last-ditch attempt to try relocating your limb
|
||||
/datum/wound/blunt/moderate/proc/door_crush()
|
||||
if(prob(33))
|
||||
victim.visible_message("<span class='danger'>[victim]'s dislocated [limb.name] pops back into place!</span>", "<span class='userdanger'>Your dislocated [limb.name] pops back into place! Ow!</span>")
|
||||
remove_wound()
|
||||
|
||||
/datum/wound/blunt/moderate/try_handling(mob/living/carbon/human/user)
|
||||
if(user.pulling != victim || user.zone_selected != limb.body_zone || user.a_intent == INTENT_GRAB)
|
||||
return FALSE
|
||||
|
||||
if(user.grab_state == GRAB_PASSIVE)
|
||||
to_chat(user, "<span class='warning'>You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [lowertext(name)]!</span>")
|
||||
return TRUE
|
||||
|
||||
if(user.grab_state >= GRAB_AGGRESSIVE)
|
||||
user.visible_message("<span class='danger'>[user] begins twisting and straining [victim]'s dislocated [limb.name]!</span>", "<span class='notice'>You begin twisting and straining [victim]'s dislocated [limb.name]...</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[user] begins twisting and straining your dislocated [limb.name]!</span>")
|
||||
if(user.a_intent == INTENT_HELP)
|
||||
chiropractice(user)
|
||||
else
|
||||
malpractice(user)
|
||||
return TRUE
|
||||
|
||||
/// If someone is snapping our dislocated joint back into place by hand with an aggro grab and help intent
|
||||
/datum/wound/blunt/moderate/proc/chiropractice(mob/living/carbon/human/user)
|
||||
var/time = base_treat_time
|
||||
|
||||
if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
if(prob(65))
|
||||
user.visible_message("<span class='danger'>[user] snaps [victim]'s dislocated [limb.name] back into place!</span>", "<span class='notice'>You snap [victim]'s dislocated [limb.name] back into place!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[user] snaps your dislocated [limb.name] back into place!</span>")
|
||||
victim.emote("scream")
|
||||
limb.receive_damage(brute=20, wound_bonus=CANT_WOUND)
|
||||
qdel(src)
|
||||
else
|
||||
user.visible_message("<span class='danger'>[user] wrenches [victim]'s dislocated [limb.name] around painfully!</span>", "<span class='danger'>You wrench [victim]'s dislocated [limb.name] around painfully!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[user] wrenches your dislocated [limb.name] around painfully!</span>")
|
||||
limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
|
||||
chiropractice(user)
|
||||
|
||||
/// If someone is snapping our dislocated joint into a fracture by hand with an aggro grab and harm or disarm intent
|
||||
/datum/wound/blunt/moderate/proc/malpractice(mob/living/carbon/human/user)
|
||||
var/time = base_treat_time
|
||||
|
||||
if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
if(prob(65))
|
||||
user.visible_message("<span class='danger'>[user] snaps [victim]'s dislocated [limb.name] with a sickening crack!</span>", "<span class='danger'>You snap [victim]'s dislocated [limb.name] with a sickening crack!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[user] snaps your dislocated [limb.name] with a sickening crack!</span>")
|
||||
victim.emote("scream")
|
||||
limb.receive_damage(brute=25, wound_bonus=30)
|
||||
else
|
||||
user.visible_message("<span class='danger'>[user] wrenches [victim]'s dislocated [limb.name] around painfully!</span>", "<span class='danger'>You wrench [victim]'s dislocated [limb.name] around painfully!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[user] wrenches your dislocated [limb.name] around painfully!</span>")
|
||||
limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
|
||||
malpractice(user)
|
||||
|
||||
|
||||
/datum/wound/blunt/moderate/treat(obj/item/I, mob/user)
|
||||
if(victim == user)
|
||||
victim.visible_message("<span class='danger'>[user] begins resetting [victim.p_their()] [limb.name] with [I].</span>", "<span class='warning'>You begin resetting your [limb.name] with [I]...</span>")
|
||||
else
|
||||
user.visible_message("<span class='danger'>[user] begins resetting [victim]'s [limb.name] with [I].</span>", "<span class='notice'>You begin resetting [victim]'s [limb.name] with [I]...</span>")
|
||||
|
||||
if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
if(victim == user)
|
||||
limb.receive_damage(brute=15, wound_bonus=CANT_WOUND)
|
||||
victim.visible_message("<span class='danger'>[user] finishes resetting [victim.p_their()] [limb.name]!</span>", "<span class='userdanger'>You reset your [limb.name]!</span>")
|
||||
else
|
||||
limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
|
||||
user.visible_message("<span class='danger'>[user] finishes resetting [victim]'s [limb.name]!</span>", "<span class='nicegreen'>You finish resetting [victim]'s [limb.name]!</span>", victim)
|
||||
to_chat(victim, "<span class='userdanger'>[user] resets your [limb.name]!</span>")
|
||||
|
||||
victim.emote("scream")
|
||||
qdel(src)
|
||||
|
||||
/*
|
||||
Severe (Hairline Fracture)
|
||||
*/
|
||||
|
||||
/datum/wound/blunt/severe
|
||||
name = "Hairline Fracture"
|
||||
desc = "Patient's bone has suffered a crack in the foundation, causing serious pain and reduced limb functionality."
|
||||
treat_text = "Recommended light surgical application of bone gel, though a sling of medical gauze will prevent worsening situation."
|
||||
examine_desc = "appears grotesquely swollen, its attachment weakened"
|
||||
occur_text = "sprays chips of bone and develops a nasty looking bruise"
|
||||
|
||||
severity = WOUND_SEVERITY_SEVERE
|
||||
interaction_efficiency_penalty = 2
|
||||
limp_slowdown = 6
|
||||
threshold_minimum = 60
|
||||
threshold_penalty = 30
|
||||
treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
|
||||
status_effect_type = /datum/status_effect/wound/blunt/severe
|
||||
scar_keyword = "bluntsevere"
|
||||
brain_trauma_group = BRAIN_TRAUMA_MILD
|
||||
trauma_cycle_cooldown = 1.5 MINUTES
|
||||
internal_bleeding_chance = 40
|
||||
wound_flags = (BONE_WOUND | ACCEPTS_SPLINT | MANGLES_BONE)
|
||||
regen_ticks_needed = 120 // ticks every 2 seconds, 240 seconds, so roughly 4 minutes default
|
||||
|
||||
/// Compound Fracture (Critical Blunt)
|
||||
/datum/wound/blunt/critical
|
||||
name = "Compound Fracture"
|
||||
desc = "Patient's bones have suffered multiple gruesome fractures, causing significant pain and near uselessness of limb."
|
||||
treat_text = "Immediate binding of affected limb, followed by surgical intervention ASAP."
|
||||
examine_desc = "is mangled and pulped, seemingly held together by tissue alone"
|
||||
occur_text = "cracks apart, exposing broken bones to open air"
|
||||
|
||||
severity = WOUND_SEVERITY_CRITICAL
|
||||
interaction_efficiency_penalty = 4
|
||||
limp_slowdown = 9
|
||||
sound_effect = 'sound/effects/wounds/crack2.ogg'
|
||||
threshold_minimum = 115
|
||||
threshold_penalty = 50
|
||||
disabling = TRUE
|
||||
treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
|
||||
status_effect_type = /datum/status_effect/wound/blunt/critical
|
||||
scar_keyword = "bluntcritical"
|
||||
brain_trauma_group = BRAIN_TRAUMA_SEVERE
|
||||
trauma_cycle_cooldown = 2.5 MINUTES
|
||||
internal_bleeding_chance = 60
|
||||
wound_flags = (BONE_WOUND | ACCEPTS_SPLINT | MANGLES_BONE)
|
||||
regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default
|
||||
|
||||
// doesn't make much sense for "a" bone to stick out of your head
|
||||
/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent, datum/wound/old_wound, smited)
|
||||
if(L.body_zone == BODY_ZONE_HEAD)
|
||||
occur_text = "splits open, exposing a bare, cracked skull through the flesh and blood"
|
||||
examine_desc = "has an unsettling indent, with bits of skull poking out"
|
||||
. = ..()
|
||||
|
||||
/// if someone is using bone gel on our wound
|
||||
/datum/wound/blunt/proc/gel(obj/item/stack/medical/bone_gel/I, mob/user)
|
||||
if(gelled)
|
||||
to_chat(user, "<span class='warning'>[user == victim ? "Your" : "[victim]'s"] [limb.name] is already coated with bone gel!</span>")
|
||||
return
|
||||
|
||||
user.visible_message("<span class='danger'>[user] begins hastily applying [I] to [victim]'s' [limb.name]...</span>", "<span class='warning'>You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name], disregarding the warning label...</span>")
|
||||
|
||||
if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
I.use(1)
|
||||
victim.emote("scream")
|
||||
if(user != victim)
|
||||
user.visible_message("<span class='notice'>[user] finishes applying [I] to [victim]'s [limb.name], emitting a fizzing noise!</span>", "<span class='notice'>You finish applying [I] to [victim]'s [limb.name]!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[user] finishes applying [I] to your [limb.name], and you can feel the bones exploding with pain as they begin melting and reforming!</span>")
|
||||
else
|
||||
var/painkiller_bonus = 0
|
||||
if(victim.drunkenness > 10)
|
||||
painkiller_bonus += 10
|
||||
if(victim.reagents.has_reagent(/datum/reagent/medicine/morphine))
|
||||
painkiller_bonus += 20
|
||||
if(victim.reagents.has_reagent(/datum/reagent/determination))
|
||||
painkiller_bonus += 10
|
||||
if(victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/painkiller))
|
||||
painkiller_bonus += 5
|
||||
if(victim.reagents.has_reagent(/datum/reagent/medicine/mine_salve))
|
||||
painkiller_bonus += 20
|
||||
|
||||
if(prob(25 + (20 * (severity - 2)) - painkiller_bonus)) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by painkillers
|
||||
victim.visible_message("<span class='danger'>[victim] fails to finish applying [I] to [victim.p_their()] [limb.name], passing out from the pain!</span>", "<span class='notice'>You pass out from the pain of applying [I] to your [limb.name] before you can finish!</span>")
|
||||
victim.AdjustUnconscious(5 SECONDS)
|
||||
return
|
||||
victim.visible_message("<span class='notice'>[victim] finishes applying [I] to [victim.p_their()] [limb.name], grimacing from the pain!</span>", "<span class='notice'>You finish applying [I] to your [limb.name], and your bones explode in pain!</span>")
|
||||
|
||||
limb.receive_damage(25, stamina=100, wound_bonus=CANT_WOUND)
|
||||
if(!gelled)
|
||||
gelled = TRUE
|
||||
|
||||
/// if someone is using surgical tape on our wound
|
||||
/datum/wound/blunt/proc/tape(obj/item/stack/sticky_tape/surgical/I, mob/user)
|
||||
if(!gelled)
|
||||
to_chat(user, "<span class='warning'>[user == victim ? "Your" : "[victim]'s"] [limb.name] must be coated with bone gel to perform this emergency operation!</span>")
|
||||
return
|
||||
if(taped)
|
||||
to_chat(user, "<span class='warning'>[user == victim ? "Your" : "[victim]'s"] [limb.name] is already wrapped in [I.name] and reforming!</span>")
|
||||
return
|
||||
|
||||
user.visible_message("<span class='danger'>[user] begins applying [I] to [victim]'s' [limb.name]...</span>", "<span class='warning'>You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...</span>")
|
||||
|
||||
if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
if(victim == user)
|
||||
regen_ticks_needed *= 1.5
|
||||
|
||||
I.use(1)
|
||||
if(user != victim)
|
||||
user.visible_message("<span class='notice'>[user] finishes applying [I] to [victim]'s [limb.name], emitting a fizzing noise!</span>", "<span class='notice'>You finish applying [I] to [victim]'s [limb.name]!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='green'>[user] finishes applying [I] to your [limb.name], you immediately begin to feel your bones start to reform!</span>")
|
||||
else
|
||||
victim.visible_message("<span class='notice'>[victim] finishes applying [I] to [victim.p_their()] [limb.name], !</span>", "<span class='green'>You finish applying [I] to your [limb.name], and you immediately begin to feel your bones start to reform!</span>")
|
||||
|
||||
taped = TRUE
|
||||
processes = TRUE
|
||||
|
||||
/datum/wound/blunt/treat(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/stack/medical/bone_gel))
|
||||
gel(I, user)
|
||||
else if(istype(I, /obj/item/stack/sticky_tape/surgical))
|
||||
tape(I, user)
|
||||
|
||||
/datum/wound/blunt/get_scanner_description(mob/user)
|
||||
. = ..()
|
||||
|
||||
. += "<div class='ml-3'>"
|
||||
|
||||
if(!gelled)
|
||||
. += "Alternative Treatment: Apply bone gel directly to injured limb, then apply surgical tape to begin bone regeneration. This is both excruciatingly painful and slow, and only recommended in dire circumstances.\n"
|
||||
else if(!taped)
|
||||
. += "<span class='notice'>Continue Alternative Treatment: Apply surgical tape directly to injured limb to begin bone regeneration. Note, this is both excruciatingly painful and slow, though sleep or laying down will speed recovery.</span>\n"
|
||||
else
|
||||
. += "<span class='notice'>Note: Bone regeneration in effect. Bone is [round(regen_ticks_current*100/regen_ticks_needed)]% regenerated.</span>\n"
|
||||
|
||||
if(limb.body_zone == BODY_ZONE_HEAD)
|
||||
. += "Cranial Trauma Detected: Patient will suffer random bouts of [severity == WOUND_SEVERITY_SEVERE ? "mild" : "severe"] brain traumas until bone is repaired."
|
||||
else if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume)
|
||||
. += "Ribcage Trauma Detected: Further trauma to chest is likely to worsen internal bleeding until bone is repaired."
|
||||
. += "</div>"
|
||||
@@ -0,0 +1,302 @@
|
||||
|
||||
/*
|
||||
Burn wounds
|
||||
*/
|
||||
|
||||
// TODO: well, a lot really, but specifically I want to add potential fusing of clothing/equipment on the affected area, and limb infections, though those may go in body part code
|
||||
/datum/wound/burn
|
||||
name = "Burn Wound"
|
||||
a_or_from = "from"
|
||||
wound_type = WOUND_BURN
|
||||
processes = TRUE
|
||||
sound_effect = 'sound/effects/wounds/sizzle1.ogg'
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
|
||||
|
||||
treatable_by = list(/obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh) // sterilizer and alcohol will require reagent treatments, coming soon
|
||||
|
||||
// Flesh damage vars
|
||||
/// How much damage to our flesh we currently have. Once both this and infestation reach 0, the wound is considered healed
|
||||
var/flesh_damage = 5
|
||||
/// Our current counter for how much flesh regeneration we have stacked from regenerative mesh/synthflesh/whatever, decrements each tick and lowers flesh_damage
|
||||
var/flesh_healing = 0
|
||||
|
||||
// Infestation vars (only for severe and critical)
|
||||
/// How quickly infection breeds on this burn if we don't have disinfectant
|
||||
var/infestation_rate = 0
|
||||
/// Our current level of infection
|
||||
var/infestation = 0
|
||||
/// Our current level of sanitization/anti-infection, from disinfectants/alcohol/UV lights. While positive, totally pauses and slowly reverses infestation effects each tick
|
||||
var/sanitization = 0
|
||||
|
||||
/// Once we reach infestation beyond WOUND_INFESTATION_SEPSIS, we get this many warnings before the limb is completely paralyzed (you'd have to ignore a really bad burn for a really long time for this to happen)
|
||||
var/strikes_to_lose_limb = 3
|
||||
|
||||
|
||||
/datum/wound/burn/handle_process()
|
||||
. = ..()
|
||||
if(strikes_to_lose_limb == 0)
|
||||
victim.adjustToxLoss(0.5)
|
||||
if(prob(1))
|
||||
victim.visible_message("<span class='danger'>The infection on the remnants of [victim]'s [limb.name] shift and bubble nauseatingly!</span>", "<span class='warning'>You can feel the infection on the remnants of your [limb.name] coursing through your veins!</span>")
|
||||
return
|
||||
|
||||
if(victim.reagents)
|
||||
if(victim.reagents.has_reagent(/datum/reagent/medicine/spaceacillin))
|
||||
sanitization += 0.9
|
||||
if(victim.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine/))
|
||||
sanitization += 0.9
|
||||
if(victim.reagents.has_reagent(/datum/reagent/medicine/mine_salve))
|
||||
sanitization += 0.3
|
||||
flesh_healing += 0.5
|
||||
|
||||
var/bandage_factor = 1
|
||||
if(limb.current_gauze && limb.current_gauze.seep_gauze(WOUND_BURN_SANITIZATION_RATE, GAUZE_STAIN_PUS))
|
||||
bandage_factor = limb.current_gauze.sanitisation_factor
|
||||
|
||||
if(flesh_healing > 0)
|
||||
flesh_damage = max(0, flesh_damage - 0.5)
|
||||
flesh_healing = max(0, flesh_healing - (0.5 * bandage_factor)) // good bandages multiply the length of flesh healing
|
||||
|
||||
// here's the check to see if we're cleared up
|
||||
if((flesh_damage <= 0) && (infestation <= 1))
|
||||
to_chat(victim, "<span class='green'>The burns on your [limb.name] have cleared up!</span>")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
// sanitization is checked after the clearing check but before the rest, because we freeze the effects of infection while we have sanitization
|
||||
if(sanitization > 0)
|
||||
infestation = max(0, infestation - WOUND_BURN_SANITIZATION_RATE)
|
||||
sanitization = max(0, sanitization - (WOUND_BURN_SANITIZATION_RATE * bandage_factor))
|
||||
return
|
||||
|
||||
infestation += infestation_rate
|
||||
|
||||
switch(infestation)
|
||||
if(0 to WOUND_INFECTION_MODERATE)
|
||||
if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
|
||||
if(prob(30))
|
||||
victim.adjustToxLoss(0.2)
|
||||
if(prob(6))
|
||||
to_chat(victim, "<span class='warning'>The blisters on your [limb.name] ooze a strange pus...</span>")
|
||||
if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
|
||||
if(!disabling && prob(2))
|
||||
to_chat(victim, "<span class='warning'><b>Your [limb.name] completely locks up, as you struggle for control against the infection!</b></span>")
|
||||
set_disabling(TRUE)
|
||||
else if(disabling && prob(8))
|
||||
to_chat(victim, "<span class='notice'>You regain sensation in your [limb.name], but it's still in terrible shape!</span>")
|
||||
set_disabling(FALSE)
|
||||
else if(prob(20))
|
||||
victim.adjustToxLoss(0.5)
|
||||
if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
|
||||
if(!disabling && prob(3))
|
||||
to_chat(victim, "<span class='warning'><b>You suddenly lose all sensation of the festering infection in your [limb.name]!</b></span>")
|
||||
set_disabling(TRUE)
|
||||
else if(disabling && prob(3))
|
||||
to_chat(victim, "<span class='notice'>You can barely feel your [limb.name] again, and you have to strain to retain motor control!</span>")
|
||||
set_disabling(FALSE)
|
||||
else if(prob(1))
|
||||
to_chat(victim, "<span class='warning'>You contemplate life without your [limb.name]...</span>")
|
||||
victim.adjustToxLoss(0.75)
|
||||
else if(prob(4))
|
||||
victim.adjustToxLoss(1)
|
||||
if(WOUND_INFECTION_SEPTIC to INFINITY)
|
||||
if(prob(infestation))
|
||||
switch(strikes_to_lose_limb)
|
||||
if(3 to INFINITY)
|
||||
to_chat(victim, "<span class='deadsay'>The skin on your [limb.name] is literally dripping off, you feel awful!</span>")
|
||||
if(2)
|
||||
to_chat(victim, "<span class='deadsay'><b>The infection in your [limb.name] is literally dripping off, you feel horrible!</b></span>")
|
||||
if(1)
|
||||
to_chat(victim, "<span class='deadsay'><b>Infection has just about completely claimed your [limb.name]!</b></span>")
|
||||
if(0)
|
||||
to_chat(victim, "<span class='deadsay'><b>The last of the nerve endings in your [limb.name] wither away, as the infection completely paralyzes your joint connector.</b></span>")
|
||||
threshold_penalty = 120 // piss easy to destroy
|
||||
var/datum/brain_trauma/severe/paralysis/sepsis = new (limb.body_zone)
|
||||
victim.gain_trauma(sepsis)
|
||||
strikes_to_lose_limb--
|
||||
|
||||
/datum/wound/burn/get_examine_description(mob/user)
|
||||
if(strikes_to_lose_limb <= 0)
|
||||
return "<span class='deadsay'><B>[victim.p_their(TRUE)] [limb.name] is completely dead and unrecognizable as organic.</B></span>"
|
||||
|
||||
var/list/condition = list("[victim.p_their(TRUE)] [limb.name] [examine_desc]")
|
||||
if(limb.current_gauze)
|
||||
var/bandage_condition
|
||||
switch(limb.current_gauze.absorption_capacity)
|
||||
if(0 to 1.25)
|
||||
bandage_condition = "nearly ruined"
|
||||
if(1.25 to 2.75)
|
||||
bandage_condition = "badly worn"
|
||||
if(2.75 to 4)
|
||||
bandage_condition = "slightly pus-stained"
|
||||
if(4 to INFINITY)
|
||||
bandage_condition = "clean"
|
||||
|
||||
condition += " underneath a dressing of [bandage_condition] [limb.current_gauze.name]"
|
||||
else
|
||||
switch(infestation)
|
||||
if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
|
||||
condition += ", <span class='deadsay'>with small spots of discoloration along the nearby veins!</span>"
|
||||
if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
|
||||
condition += ", <span class='deadsay'>with dark clouds spreading outwards under the skin!</span>"
|
||||
if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
|
||||
condition += ", <span class='deadsay'>with streaks of rotten infection pulsating outward!</span>"
|
||||
if(WOUND_INFECTION_SEPTIC to INFINITY)
|
||||
return "<span class='deadsay'><B>[victim.p_their(TRUE)] [limb.name] is a mess of char and rot, skin literally dripping off the bone with infection!</B></span>"
|
||||
else
|
||||
condition += "!"
|
||||
|
||||
return "<B>[condition.Join()]</B>"
|
||||
|
||||
/datum/wound/burn/get_scanner_description(mob/user)
|
||||
if(strikes_to_lose_limb == 0)
|
||||
var/oopsie = "Type: [name]\nSeverity: [severity_text()]"
|
||||
oopsie += "<div class='ml-3'>Infection Level: <span class='deadsay'>The infection is total. The bodypart is lost. Amputate or augment limb immediately.</span></div>"
|
||||
return oopsie
|
||||
|
||||
. = ..()
|
||||
. += "<div class='ml-3'>"
|
||||
|
||||
if(infestation <= sanitization && flesh_damage <= flesh_healing)
|
||||
. += "No further treatment required: Burns will heal shortly."
|
||||
else
|
||||
switch(infestation)
|
||||
if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
|
||||
. += "Infection Level: Moderate\n"
|
||||
if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
|
||||
. += "Infection Level: Severe\n"
|
||||
if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
|
||||
. += "Infection Level: <span class='deadsay'>CRITICAL</span>\n"
|
||||
if(WOUND_INFECTION_SEPTIC to INFINITY)
|
||||
. += "Infection Level: <span class='deadsay'>LOSS IMMINENT</span>\n"
|
||||
if(infestation > sanitization)
|
||||
. += "\tSurgical debridement, antiobiotics/sterilizers, or regenerative mesh will rid infection. Paramedic UV penlights are also effective.\n"
|
||||
|
||||
if(flesh_damage > 0)
|
||||
. += "Flesh damage detected: Please apply ointment or regenerative mesh to allow recovery.\n"
|
||||
. += "</div>"
|
||||
|
||||
/*
|
||||
new burn common procs
|
||||
*/
|
||||
|
||||
/// if someone is using ointment on our burns
|
||||
/datum/wound/burn/proc/ointment(obj/item/stack/medical/ointment/I, mob/user)
|
||||
user.visible_message("<span class='notice'>[user] begins applying [I] to [victim]'s [limb.name]...</span>", "<span class='notice'>You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...</span>")
|
||||
if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
limb.heal_damage(I.heal_brute, I.heal_burn)
|
||||
user.visible_message("<span class='green'>[user] applies [I] to [victim].</span>", "<span class='green'>You apply [I] to [user == victim ? "your" : "[victim]'s"] [limb.name].</span>")
|
||||
I.use(1)
|
||||
sanitization += I.sanitization
|
||||
flesh_healing += I.flesh_regeneration
|
||||
|
||||
if((infestation <= 0 || sanitization >= infestation) && (flesh_damage <= 0 || flesh_healing > flesh_damage))
|
||||
to_chat(user, "<span class='notice'>You've done all you can with [I], now you must wait for the flesh on [victim]'s [limb.name] to recover.</span>")
|
||||
else
|
||||
try_treating(I, user)
|
||||
|
||||
/// if someone is using mesh on our burns
|
||||
/datum/wound/burn/proc/mesh(obj/item/stack/medical/mesh/I, mob/user)
|
||||
if(!I.is_open)
|
||||
to_chat(user, "<span class='warning'>You need to open [I] first.</span>")
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] begins wrapping [victim]'s [limb.name] with [I]...</span>", "<span class='notice'>You begin wrapping [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...</span>")
|
||||
if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
limb.heal_damage(I.heal_brute, I.heal_burn)
|
||||
user.visible_message("<span class='green'>[user] applies [I] to [victim].</span>", "<span class='green'>You apply [I] to [user == victim ? "your" : "[victim]'s"] [limb.name].</span>")
|
||||
I.use(1)
|
||||
sanitization += I.sanitization
|
||||
flesh_healing += I.flesh_regeneration
|
||||
|
||||
if(sanitization >= infestation && flesh_healing > flesh_damage)
|
||||
to_chat(user, "<span class='notice'>You've done all you can with [I], now you must wait for the flesh on [victim]'s [limb.name] to recover.</span>")
|
||||
else
|
||||
try_treating(I, user)
|
||||
|
||||
/// Paramedic UV penlights
|
||||
/datum/wound/burn/proc/uv(obj/item/flashlight/pen/paramedic/I, mob/user)
|
||||
if(!COOLDOWN_FINISHED(I, uv_cooldown))
|
||||
to_chat(user, "<span class='notice'>[I] is still recharging!</span>")
|
||||
return
|
||||
if(infestation <= 0 || infestation < sanitization)
|
||||
to_chat(user, "<span class='notice'>There's no infection to treat on [victim]'s [limb.name]!</span>")
|
||||
return
|
||||
|
||||
user.visible_message("<span class='notice'>[user] flashes the burns on [victim]'s [limb] with [I].</span>", "<span class='notice'>You flash the burns on [user == victim ? "your" : "[victim]'s"] [limb.name] with [I].</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
sanitization += I.uv_power
|
||||
COOLDOWN_START(I, uv_cooldown, I.uv_cooldown_length)
|
||||
|
||||
/datum/wound/burn/treat(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/stack/medical/ointment))
|
||||
ointment(I, user)
|
||||
else if(istype(I, /obj/item/stack/medical/mesh))
|
||||
mesh(I, user)
|
||||
else if(istype(I, /obj/item/flashlight/pen/paramedic))
|
||||
uv(I, user)
|
||||
|
||||
// people complained about burns not healing on stasis beds, so in addition to checking if it's cured, they also get the special ability to very slowly heal on stasis beds if they have the healing effects stored
|
||||
/datum/wound/burn/on_stasis()
|
||||
. = ..()
|
||||
if(flesh_healing > 0)
|
||||
flesh_damage = max(0, flesh_damage - 0.2)
|
||||
if((flesh_damage <= 0) && (infestation <= 1))
|
||||
to_chat(victim, "<span class='green'>The burns on your [limb.name] have cleared up!</span>")
|
||||
qdel(src)
|
||||
return
|
||||
if(sanitization > 0)
|
||||
infestation = max(0, infestation - WOUND_BURN_SANITIZATION_RATE * 0.2)
|
||||
|
||||
/datum/wound/burn/on_synthflesh(amount)
|
||||
flesh_healing += amount * 0.5 // 20u patch will heal 10 flesh standard
|
||||
|
||||
// we don't even care about first degree burns, straight to second
|
||||
/datum/wound/burn/moderate
|
||||
name = "Second Degree Burns"
|
||||
desc = "Patient is suffering considerable burns with mild skin penetration, weakening limb integrity and increased burning sensations."
|
||||
treat_text = "Recommended application of topical ointment or regenerative mesh to affected region."
|
||||
examine_desc = "is badly burned and breaking out in blisters"
|
||||
occur_text = "breaks out with violent red burns"
|
||||
severity = WOUND_SEVERITY_MODERATE
|
||||
damage_mulitplier_penalty = 1.1
|
||||
threshold_minimum = 40
|
||||
threshold_penalty = 30 // burns cause significant decrease in limb integrity compared to other wounds
|
||||
status_effect_type = /datum/status_effect/wound/burn/moderate
|
||||
flesh_damage = 5
|
||||
scar_keyword = "burnmoderate"
|
||||
|
||||
/datum/wound/burn/severe
|
||||
name = "Third Degree Burns"
|
||||
desc = "Patient is suffering extreme burns with full skin penetration, creating serious risk of infection and greatly reduced limb integrity."
|
||||
treat_text = "Recommended immediate disinfection and excision of any infected skin, followed by bandaging and ointment."
|
||||
examine_desc = "appears seriously charred, with aggressive red splotches"
|
||||
occur_text = "chars rapidly, exposing ruined tissue and spreading angry red burns"
|
||||
severity = WOUND_SEVERITY_SEVERE
|
||||
damage_mulitplier_penalty = 1.2
|
||||
threshold_minimum = 80
|
||||
threshold_penalty = 40
|
||||
status_effect_type = /datum/status_effect/wound/burn/severe
|
||||
treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
|
||||
infestation_rate = 0.05 // appx 13 minutes to reach sepsis without any treatment
|
||||
flesh_damage = 12.5
|
||||
scar_keyword = "burnsevere"
|
||||
|
||||
/datum/wound/burn/critical
|
||||
name = "Catastrophic Burns"
|
||||
desc = "Patient is suffering near complete loss of tissue and significantly charred muscle and bone, creating life-threatening risk of infection and negligible limb integrity."
|
||||
treat_text = "Immediate surgical debriding of any infected skin, followed by potent tissue regeneration formula and bandaging."
|
||||
examine_desc = "is a ruined mess of blanched bone, melted fat, and charred tissue"
|
||||
occur_text = "vaporizes as flesh, bone, and fat melt together in a horrifying mess"
|
||||
severity = WOUND_SEVERITY_CRITICAL
|
||||
damage_mulitplier_penalty = 1.3
|
||||
sound_effect = 'sound/effects/wounds/sizzle2.ogg'
|
||||
threshold_minimum = 140
|
||||
threshold_penalty = 80
|
||||
status_effect_type = /datum/status_effect/wound/burn/critical
|
||||
treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
|
||||
infestation_rate = 0.15 // appx 4.33 minutes to reach sepsis without any treatment
|
||||
flesh_damage = 20
|
||||
scar_keyword = "burncritical"
|
||||
@@ -0,0 +1,206 @@
|
||||
|
||||
/*
|
||||
Muscle wounds. There is a chance to roll a muscle wound instead of others while doing brute damage
|
||||
*/
|
||||
|
||||
/datum/wound/muscle
|
||||
name = "Muscle Wound"
|
||||
sound_effect = 'sound/effects/wounds/blood1.ogg'
|
||||
wound_type = WOUND_MUSCLE
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_SPLINT)
|
||||
viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
processes = TRUE
|
||||
/// How much do we need to regen. Will regen faster if we're splinted and or laying down
|
||||
var/regen_ticks_needed
|
||||
/// Our current counter for healing
|
||||
var/regen_ticks_current = 0
|
||||
|
||||
/*
|
||||
Overwriting of base procs
|
||||
*/
|
||||
/datum/wound/muscle/wound_injury(datum/wound/old_wound = null)
|
||||
// hook into gaining/losing gauze so crit muscle wounds can re-enable/disable depending if they're slung or not
|
||||
RegisterSignal(limb, list(COMSIG_BODYPART_SPLINTED, COMSIG_BODYPART_SPLINT_DESTROYED), .proc/update_inefficiencies)
|
||||
|
||||
RegisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, .proc/attack_with_hurt_hand)
|
||||
if(limb.held_index && victim.get_item_for_held_index(limb.held_index) && (disabling || prob(30 * severity)))
|
||||
var/obj/item/I = victim.get_item_for_held_index(limb.held_index)
|
||||
if(istype(I, /obj/item/offhand))
|
||||
I = victim.get_inactive_held_item()
|
||||
|
||||
if(I && victim.dropItemToGround(I))
|
||||
victim.visible_message("<span class='danger'>[victim] drops [I] in shock!</span>", "<span class='warning'><b>The force on your [limb.name] causes you to drop [I]!</b></span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
|
||||
update_inefficiencies()
|
||||
|
||||
/datum/wound/muscle/remove_wound(ignore_limb, replaced)
|
||||
limp_slowdown = 0
|
||||
if(limb)
|
||||
UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED))
|
||||
if(victim)
|
||||
UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
|
||||
return ..()
|
||||
|
||||
/datum/wound/muscle/handle_process()
|
||||
. = ..()
|
||||
|
||||
regen_ticks_current++
|
||||
if(victim.body_position == LYING_DOWN)
|
||||
if(prob(50))
|
||||
regen_ticks_current += 0.5
|
||||
if(victim.IsSleeping())
|
||||
regen_ticks_current += 0.5
|
||||
|
||||
if(limb.current_splint)
|
||||
regen_ticks_current += (1-limb.current_splint.splint_factor)
|
||||
|
||||
if(regen_ticks_current > regen_ticks_needed)
|
||||
if(!victim || !limb)
|
||||
qdel(src)
|
||||
return
|
||||
to_chat(victim, "<span class='green'>Your [limb.name] has regenerated its muscle!</span>")
|
||||
remove_wound()
|
||||
|
||||
/// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so
|
||||
/datum/wound/muscle/proc/attack_with_hurt_hand(mob/M, atom/target, proximity)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(victim.get_active_hand() != limb || victim.a_intent == INTENT_HELP || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE)
|
||||
return
|
||||
|
||||
// 15% of 30% chance to proc pain on hit
|
||||
if(prob(severity * 15))
|
||||
// And you have a 70% or 50% chance to actually land the blow, respectively
|
||||
if(prob(70 - 20 * severity))
|
||||
to_chat(victim, "<span class='userdanger'>The damaged muscle in your [limb.name] shoots with pain as you strike [target]!</span>")
|
||||
limb.receive_damage(brute=rand(1,5))
|
||||
else
|
||||
victim.visible_message("<span class='danger'>[victim] weakly strikes [target] with [victim.p_their()] swollen [limb.name], recoiling from pain!</span>", \
|
||||
"<span class='userdanger'>You fail to strike [target] as the fracture in your [limb.name] lights up in unbearable pain!</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
INVOKE_ASYNC(victim, /mob.proc/emote, "scream")
|
||||
victim.Stun(0.5 SECONDS)
|
||||
limb.receive_damage(brute=rand(3,7))
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/datum/wound/muscle/get_examine_description(mob/user)
|
||||
if(!limb.current_splint)
|
||||
return ..()
|
||||
|
||||
var/list/msg = list()
|
||||
if(!limb.current_splint)
|
||||
msg += "[victim.p_their(TRUE)] [limb.name] [examine_desc]"
|
||||
else
|
||||
var/sling_condition = ""
|
||||
// how much life we have left in these bandages
|
||||
switch(limb.current_splint.sling_condition)
|
||||
if(0 to 1.25)
|
||||
sling_condition = "just barely"
|
||||
if(1.25 to 2.75)
|
||||
sling_condition = "loosely"
|
||||
if(2.75 to 4)
|
||||
sling_condition = "mostly"
|
||||
if(4 to INFINITY)
|
||||
sling_condition = "tightly"
|
||||
|
||||
msg += "[victim.p_their(TRUE)] [limb.name] is [sling_condition] fastened with a [limb.current_splint.name]!"
|
||||
|
||||
return "<B>[msg.Join()]</B>"
|
||||
|
||||
/*
|
||||
Common procs mostly copied from bone wounds, as their behaviour is very similar
|
||||
*/
|
||||
|
||||
/datum/wound/muscle/proc/update_inefficiencies()
|
||||
if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(limb.current_splint)
|
||||
limp_slowdown = initial(limp_slowdown) * limb.current_splint.splint_factor
|
||||
else
|
||||
limp_slowdown = initial(limp_slowdown)
|
||||
victim.apply_status_effect(STATUS_EFFECT_LIMP)
|
||||
else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
if(limb.current_splint)
|
||||
interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_splint.splint_factor)
|
||||
else
|
||||
interaction_efficiency_penalty = interaction_efficiency_penalty
|
||||
|
||||
if(initial(disabling))
|
||||
if(limb.current_splint && limb.current_splint.helps_disabled)
|
||||
set_disabling(FALSE)
|
||||
else
|
||||
set_disabling(TRUE)
|
||||
|
||||
limb.update_wounds()
|
||||
|
||||
/// Moderate (Muscle Tear)
|
||||
/datum/wound/muscle/moderate
|
||||
name = "Muscle Tear"
|
||||
desc = "Patient's muscle has torn, causing serious pain and reduced limb functionality."
|
||||
treat_text = "Recommended rest and sleep, or splinting the limb."
|
||||
examine_desc = "appears unnaturallly red and swollen"
|
||||
occur_text = "swells up, it's skin turning red"
|
||||
severity = WOUND_SEVERITY_MODERATE
|
||||
interaction_efficiency_penalty = 1.5
|
||||
limp_slowdown = 2
|
||||
threshold_minimum = 35
|
||||
threshold_penalty = 15
|
||||
status_effect_type = /datum/status_effect/wound/muscle/moderate
|
||||
regen_ticks_needed = 90
|
||||
|
||||
/*
|
||||
Severe (Ruptured Tendon)
|
||||
*/
|
||||
|
||||
/datum/wound/muscle/severe
|
||||
name = "Ruptured Tendon"
|
||||
sound_effect = 'sound/effects/wounds/blood2.ogg'
|
||||
desc = "Patient's tendon has been severed, causing significant pain and near uselessness of limb."
|
||||
treat_text = "Recommended rest and sleep aswell as splinting the limb."
|
||||
examine_desc = "is limp and awkwardly twitching, skin swollen and red"
|
||||
occur_text = "twists in pain and goes limp, it's tendon ruptured"
|
||||
severity = WOUND_SEVERITY_SEVERE
|
||||
interaction_efficiency_penalty = 2
|
||||
limp_slowdown = 5
|
||||
threshold_minimum = 80
|
||||
threshold_penalty = 35
|
||||
disabling = TRUE
|
||||
status_effect_type = /datum/status_effect/wound/muscle/severe
|
||||
regen_ticks_needed = 150
|
||||
|
||||
/datum/status_effect/wound/muscle
|
||||
|
||||
/datum/status_effect/wound/muscle/on_apply()
|
||||
. = ..()
|
||||
RegisterSignal(owner, COMSIG_MOB_SWAP_HANDS, .proc/on_swap_hands)
|
||||
on_swap_hands()
|
||||
|
||||
/datum/status_effect/wound/muscle/on_remove()
|
||||
. = ..()
|
||||
UnregisterSignal(owner, COMSIG_MOB_SWAP_HANDS)
|
||||
var/mob/living/carbon/wound_owner = owner
|
||||
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/muscle_wound)
|
||||
|
||||
/datum/status_effect/wound/muscle/proc/on_swap_hands()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/living/carbon/wound_owner = owner
|
||||
if(wound_owner.get_active_hand() == linked_limb)
|
||||
wound_owner.add_actionspeed_modifier(/datum/actionspeed_modifier/muscle_wound, (linked_wound.interaction_efficiency_penalty - 1))
|
||||
else
|
||||
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/muscle_wound)
|
||||
|
||||
/datum/status_effect/wound/muscle/nextmove_modifier()
|
||||
var/mob/living/carbon/C = owner
|
||||
|
||||
if(C.get_active_hand() == linked_limb)
|
||||
return linked_wound.interaction_efficiency_penalty
|
||||
|
||||
return 1
|
||||
|
||||
// muscle
|
||||
/datum/status_effect/wound/muscle/moderate
|
||||
id = "torn muscle"
|
||||
/datum/status_effect/wound/muscle/severe
|
||||
id = "ruptured tendon"
|
||||
|
||||
/datum/actionspeed_modifier/muscle_wound
|
||||
variable = TRUE
|
||||
@@ -0,0 +1,188 @@
|
||||
|
||||
/*
|
||||
Piercing wounds
|
||||
*/
|
||||
|
||||
/datum/wound/pierce
|
||||
name = "Piercing Wound"
|
||||
sound_effect = 'sound/weapons/slice.ogg'
|
||||
processes = TRUE
|
||||
wound_type = WOUND_PIERCE
|
||||
treatable_by = list(/obj/item/stack/medical/suture)
|
||||
treatable_tool = TOOL_CAUTERY
|
||||
base_treat_time = 3 SECONDS
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
|
||||
|
||||
/// How much blood we start losing when this wound is first applied
|
||||
var/initial_flow
|
||||
/// 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
|
||||
/// If we let off blood when hit, the max blood lost is this * the incoming damage
|
||||
var/internal_bleeding_coefficient
|
||||
|
||||
/datum/wound/slash/show_wound_topic(mob/user)
|
||||
return (user == victim && blood_flow)
|
||||
|
||||
/datum/wound/slash/Topic(href, href_list)
|
||||
. = ..()
|
||||
if(href_list["wound_topic"])
|
||||
if(!usr == victim)
|
||||
return
|
||||
victim.self_grasp_bleeding_limb(limb)
|
||||
|
||||
/datum/wound/pierce/wound_injury(datum/wound/old_wound)
|
||||
blood_flow = initial_flow
|
||||
|
||||
/datum/wound/pierce/receive_damage(wounding_type, wounding_dmg, wound_bonus)
|
||||
if(victim.stat == DEAD || wounding_dmg < 5)
|
||||
return
|
||||
if(victim.blood_volume && prob(internal_bleeding_chance + wounding_dmg))
|
||||
if(limb.current_splint && limb.current_splint.splint_factor)
|
||||
wounding_dmg *= (1 - limb.current_splint.splint_factor)
|
||||
var/blood_bled = rand(1, wounding_dmg * internal_bleeding_coefficient) // 12 brute toolbox can cause up to 15/18/21 bloodloss on mod/sev/crit
|
||||
switch(blood_bled)
|
||||
if(1 to 6)
|
||||
victim.bleed(blood_bled, TRUE)
|
||||
if(7 to 13)
|
||||
victim.visible_message("<span class='smalldanger'>Blood droplets fly from the hole in [victim]'s [limb.name].</span>", "<span class='danger'>You cough up a bit of blood from the blow to your [limb.name].</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
victim.bleed(blood_bled, TRUE)
|
||||
if(14 to 19)
|
||||
victim.visible_message("<span class='smalldanger'>A small stream of blood spurts from the hole in [victim]'s [limb.name]!</span>", "<span class='danger'>You spit out a string of blood from the blow to your [limb.name]!</span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
|
||||
victim.bleed(blood_bled)
|
||||
if(20 to INFINITY)
|
||||
victim.visible_message("<span class='danger'>A spray of blood streams from the gash in [victim]'s [limb.name]!</span>", "<span class='danger'><b>You choke up on a spray of blood from the blow to your [limb.name]!</b></span>", vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
victim.bleed(blood_bled)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
|
||||
victim.add_splatter_floor(get_step(victim.loc, victim.dir))
|
||||
|
||||
/datum/wound/pierce/handle_process()
|
||||
blood_flow = min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)
|
||||
|
||||
if(victim.bodytemperature < (BODYTEMP_NORMAL - 10))
|
||||
blood_flow -= 0.2
|
||||
if(prob(5))
|
||||
to_chat(victim, "<span class='notice'>You feel the [lowertext(name)] in your [limb.name] firming up from the cold!</span>")
|
||||
|
||||
if(victim.reagents.has_reagent(/datum/reagent/toxin/heparin))
|
||||
blood_flow += 0.5 // old herapin 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
|
||||
|
||||
if(limb.current_gauze && limb.current_gauze.seep_gauze(limb.current_gauze.absorption_rate, GAUZE_STAIN_BLOOD))
|
||||
blood_flow -= limb.current_gauze.absorption_rate * gauzed_clot_rate
|
||||
|
||||
if(blood_flow <= 0)
|
||||
qdel(src)
|
||||
|
||||
/datum/wound/pierce/on_stasis()
|
||||
. = ..()
|
||||
if(blood_flow <= 0)
|
||||
qdel(src)
|
||||
|
||||
/datum/wound/pierce/check_grab_treatments(obj/item/I, mob/user)
|
||||
if(I.get_temperature()) // 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 TRUE
|
||||
|
||||
/datum/wound/pierce/treat(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/stack/medical/suture))
|
||||
suture(I, user)
|
||||
else if(I.tool_behaviour == TOOL_CAUTERY || I.get_temperature())
|
||||
tool_cauterize(I, user)
|
||||
|
||||
/datum/wound/pierce/on_xadone(power)
|
||||
. = ..()
|
||||
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/on_synthflesh(power)
|
||||
. = ..()
|
||||
blood_flow -= 0.05 * power // 20u * 0.05 = -1 blood flow, less than with slashes but still good considering smaller bleed rates
|
||||
|
||||
/// If someone is using a suture to close this puncture
|
||||
/datum/wound/pierce/proc/suture(obj/item/stack/medical/suture/I, mob/user)
|
||||
var/self_penalty_mult = (user == victim ? 1.4 : 1)
|
||||
user.visible_message("<span class='notice'>[user] begins stitching [victim]'s [limb.name] with [I]...</span>", "<span class='notice'>You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...</span>")
|
||||
if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
user.visible_message("<span class='green'>[user] stitches up some of the bleeding on [victim].</span>", "<span class='green'>You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].</span>")
|
||||
var/blood_sutured = I.stop_bleeding / self_penalty_mult
|
||||
blood_flow -= blood_sutured
|
||||
limb.heal_damage(I.heal_brute, I.heal_burn)
|
||||
I.use(1)
|
||||
|
||||
if(blood_flow > 0)
|
||||
try_treating(I, user)
|
||||
else
|
||||
to_chat(user, "<span class='green'>You successfully close the hole in [user == victim ? "your" : "[victim]'s"] [limb.name].</span>")
|
||||
|
||||
/// If someone is using either a cautery tool or something with heat to cauterize this pierce
|
||||
/datum/wound/pierce/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
|
||||
|
||||
user.visible_message("<span class='danger'>[user] begins cauterizing [victim]'s [limb.name] with [I]...</span>", "<span class='warning'>You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...</span>")
|
||||
if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
user.visible_message("<span class='green'>[user] cauterizes some of the bleeding on [victim].</span>", "<span class='green'>You cauterize some of the bleeding on [victim].</span>")
|
||||
limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
|
||||
if(prob(30))
|
||||
victim.emote("scream")
|
||||
var/blood_cauterized = (0.6 / (self_penalty_mult * improv_penalty_mult))
|
||||
blood_flow -= blood_cauterized
|
||||
|
||||
if(blood_flow > 0)
|
||||
try_treating(I, user)
|
||||
|
||||
/datum/wound/pierce/moderate
|
||||
name = "Minor Breakage"
|
||||
desc = "Patient's skin has been broken open, causing severe bruising and minor internal bleeding in affected area."
|
||||
treat_text = "Treat affected site with bandaging or exposure to extreme cold. In dire cases, brief exposure to vacuum may suffice." // space is cold in ss13, so it's like an ice pack!
|
||||
examine_desc = "has a small, circular 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.5
|
||||
gauzed_clot_rate = 0.8
|
||||
internal_bleeding_chance = 30
|
||||
internal_bleeding_coefficient = 1.25
|
||||
threshold_minimum = 30
|
||||
threshold_penalty = 20
|
||||
status_effect_type = /datum/status_effect/wound/pierce/moderate
|
||||
scar_keyword = "piercemoderate"
|
||||
|
||||
/datum/wound/pierce/severe
|
||||
name = "Open Puncture"
|
||||
desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability."
|
||||
treat_text = "Repair punctures in skin by suture or cautery, extreme cold may also work."
|
||||
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.25
|
||||
gauzed_clot_rate = 0.6
|
||||
internal_bleeding_chance = 60
|
||||
internal_bleeding_coefficient = 1.5
|
||||
threshold_minimum = 50
|
||||
threshold_penalty = 35
|
||||
status_effect_type = /datum/status_effect/wound/pierce/severe
|
||||
scar_keyword = "piercesevere"
|
||||
|
||||
/datum/wound/pierce/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 = "Surgical repair of puncture wound, followed by supervised resanguination."
|
||||
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 = 3
|
||||
gauzed_clot_rate = 0.4
|
||||
internal_bleeding_chance = 80
|
||||
internal_bleeding_coefficient = 1.75
|
||||
threshold_minimum = 100
|
||||
threshold_penalty = 50
|
||||
status_effect_type = /datum/status_effect/wound/pierce/critical
|
||||
scar_keyword = "piercecritical"
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
|
||||
@@ -0,0 +1,314 @@
|
||||
|
||||
/*
|
||||
Slashing wounds
|
||||
*/
|
||||
|
||||
/datum/wound/slash
|
||||
name = "Slashing (Cut) Wound"
|
||||
sound_effect = 'sound/weapons/slice.ogg'
|
||||
processes = TRUE
|
||||
wound_type = WOUND_SLASH
|
||||
treatable_by = list(/obj/item/stack/medical/suture)
|
||||
treatable_by_grabbed = list(/obj/item/gun/energy/laser)
|
||||
treatable_tool = TOOL_CAUTERY
|
||||
base_treat_time = 3 SECONDS
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
|
||||
|
||||
/// How much blood we start losing when this wound is first applied
|
||||
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 fast our blood flow will naturally decrease per tick, not only do larger cuts bleed more faster, they clot slower
|
||||
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
|
||||
var/demotes_to
|
||||
|
||||
/// How much staunching per type (cautery, suturing, bandaging) you can have before that type is no longer effective for this cut NOT IMPLEMENTED
|
||||
var/max_per_type
|
||||
/// The maximum flow we've had so far
|
||||
var/highest_flow
|
||||
|
||||
/// A bad system I'm using to track the worst scar we earned (since we can demote, we want the biggest our wound has been, not what it was when it was cured (probably moderate))
|
||||
var/datum/scar/highest_scar
|
||||
|
||||
/datum/wound/slash/show_wound_topic(mob/user)
|
||||
return (user == victim && blood_flow)
|
||||
|
||||
/datum/wound/slash/Topic(href, href_list)
|
||||
. = ..()
|
||||
if(href_list["wound_topic"])
|
||||
if(!usr == victim)
|
||||
return
|
||||
victim.self_grasp_bleeding_limb(limb)
|
||||
|
||||
/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = 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)
|
||||
highest_scar = old_wound.highest_scar
|
||||
old_wound.highest_scar = null
|
||||
|
||||
if(!highest_scar)
|
||||
highest_scar = new
|
||||
highest_scar.generate(limb, src, add_to_scars=FALSE)
|
||||
|
||||
/datum/wound/slash/remove_wound(ignore_limb, replaced)
|
||||
if(!replaced && highest_scar)
|
||||
already_scarred = TRUE
|
||||
highest_scar.lazy_attach(limb)
|
||||
return ..()
|
||||
|
||||
/datum/wound/slash/get_examine_description(mob/user)
|
||||
if(!limb.current_gauze)
|
||||
return ..()
|
||||
|
||||
var/list/msg = list("The cuts on [victim.p_their()] [limb.name] are wrapped with ")
|
||||
// how much life we have left in these bandages
|
||||
switch(limb.current_gauze.absorption_capacity)
|
||||
if(0 to 1.25)
|
||||
msg += "nearly ruined"
|
||||
if(1.25 to 2.75)
|
||||
msg += "badly worn"
|
||||
if(2.75 to 4)
|
||||
msg += "slightly bloodied"
|
||||
if(4 to INFINITY)
|
||||
msg += "clean"
|
||||
msg += " [limb.current_gauze.name]!"
|
||||
|
||||
return "<B>[msg.Join()]</B>"
|
||||
|
||||
/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
|
||||
|
||||
/datum/wound/slash/drag_bleed_amount()
|
||||
// say we have 3 severe cuts with 3 blood flow each, pretty reasonable
|
||||
// compare with being at 100 brute damage before, where you bled (brute/100 * 2), = 2 blood per tile
|
||||
var/bleed_amt = min(blood_flow * 0.1, 1) // 3 * 3 * 0.1 = 0.9 blood total, less than before! the share here is .3 blood of course.
|
||||
|
||||
if(limb.current_gauze && limb.current_gauze.seep_gauze(bleed_amt * 0.33, GAUZE_STAIN_BLOOD)) // gauze stops all bleeding from dragging on this limb, but wears the gauze out quicker
|
||||
return 0
|
||||
|
||||
return bleed_amt
|
||||
|
||||
/datum/wound/slash/handle_process()
|
||||
if(victim.stat == DEAD)
|
||||
blood_flow -= max(clot_rate, WOUND_SLASH_DEAD_CLOT_MIN)
|
||||
if(blood_flow < minimum_flow)
|
||||
if(demotes_to)
|
||||
replace_wound(demotes_to)
|
||||
return
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
blood_flow = min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)
|
||||
|
||||
if(victim.reagents.has_reagent(/datum/reagent/toxin/heparin))
|
||||
blood_flow += 0.5 // old herapin 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
|
||||
|
||||
if(limb.current_gauze)
|
||||
if(clot_rate > 0)
|
||||
blood_flow -= clot_rate
|
||||
//SKYRAT EDIT CHANGE BEGIN - MEDICAL
|
||||
/*
|
||||
blood_flow -= limb.current_gauze.absorption_rate
|
||||
limb.seep_gauze(limb.current_gauze.absorption_rate)
|
||||
*/
|
||||
if(limb.current_gauze && limb.current_gauze.seep_gauze(limb.current_gauze.absorption_rate, GAUZE_STAIN_BLOOD))
|
||||
blood_flow -= limb.current_gauze.absorption_rate
|
||||
//SKYRAT EDIT CHANGE END
|
||||
else
|
||||
blood_flow -= clot_rate
|
||||
|
||||
if(blood_flow > highest_flow)
|
||||
highest_flow = blood_flow
|
||||
|
||||
if(blood_flow < minimum_flow)
|
||||
if(demotes_to)
|
||||
replace_wound(demotes_to)
|
||||
else
|
||||
to_chat(victim, "<span class='green'>The cut on your [limb.name] has stopped bleeding!</span>")
|
||||
qdel(src)
|
||||
|
||||
|
||||
/datum/wound/slash/on_stasis()
|
||||
if(blood_flow >= minimum_flow)
|
||||
return
|
||||
if(demotes_to)
|
||||
replace_wound(demotes_to)
|
||||
return
|
||||
qdel(src)
|
||||
|
||||
/* BEWARE, THE BELOW NONSENSE IS MADNESS. bones.dm looks more like what I have in mind and is sufficiently clean, don't pay attention to this messiness */
|
||||
|
||||
/datum/wound/slash/check_grab_treatments(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/gun/energy/laser))
|
||||
return TRUE
|
||||
if(I.get_temperature()) // 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 TRUE
|
||||
|
||||
/datum/wound/slash/treat(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/gun/energy/laser))
|
||||
las_cauterize(I, user)
|
||||
else if(I.tool_behaviour == TOOL_CAUTERY || I.get_temperature())
|
||||
tool_cauterize(I, user)
|
||||
else if(istype(I, /obj/item/stack/medical/suture))
|
||||
suture(I, user)
|
||||
|
||||
/datum/wound/slash/try_handling(mob/living/carbon/human/user)
|
||||
if(user.pulling != victim || user.zone_selected != limb.body_zone || user.a_intent == INTENT_GRAB || !isfelinid(user) || !victim.can_inject(user, TRUE))
|
||||
return FALSE
|
||||
if(DOING_INTERACTION_WITH_TARGET(user, victim))
|
||||
to_chat(user, "<span class='warning'>You're already interacting with [victim]!</span>")
|
||||
return
|
||||
if(user.is_mouth_covered())
|
||||
to_chat(user, "<span class='warning'>Your mouth is covered, you can't lick [victim]'s wounds!</span>")
|
||||
return
|
||||
if(!user.getorganslot(ORGAN_SLOT_TONGUE))
|
||||
to_chat(user, "<span class='warning'>You can't lick wounds without a tongue!</span>") // f in chat
|
||||
return
|
||||
|
||||
lick_wounds(user)
|
||||
return TRUE
|
||||
|
||||
/// if a felinid is licking this cut to reduce bleeding
|
||||
/datum/wound/slash/proc/lick_wounds(mob/living/carbon/human/user)
|
||||
// transmission is one way patient -> felinid since google said cat saliva is antiseptic or whatever, and also because felinids are already risking getting beaten for this even without people suspecting they're spreading a deathvirus
|
||||
for(var/i in victim.diseases)
|
||||
var/datum/disease/iter_disease = i
|
||||
if(iter_disease.spread_flags & (DISEASE_SPREAD_SPECIAL | DISEASE_SPREAD_NON_CONTAGIOUS))
|
||||
continue
|
||||
user.ForceContractDisease(iter_disease)
|
||||
|
||||
user.visible_message("<span class='notice'>[user] begins licking the wounds on [victim]'s [limb.name].</span>", "<span class='notice'>You begin licking the wounds on [victim]'s [limb.name]...</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='notice'>[user] begins to lick the wounds on your [limb.name].</span")
|
||||
if(!do_after(user, base_treat_time, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
user.visible_message("<span class='notice'>[user] licks the wounds on [victim]'s [limb.name].</span>", "<span class='notice'>You lick some of the wounds on [victim]'s [limb.name]</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='green'>[user] licks the wounds on your [limb.name]!</span")
|
||||
blood_flow -= 0.5
|
||||
|
||||
if(blood_flow > minimum_flow)
|
||||
try_handling(user)
|
||||
else if(demotes_to)
|
||||
to_chat(user, "<span class='green'>You successfully lower the severity of [victim]'s cuts.</span>")
|
||||
|
||||
/datum/wound/slash/on_xadone(power)
|
||||
. = ..()
|
||||
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/slash/on_synthflesh(power)
|
||||
. = ..()
|
||||
blood_flow -= 0.075 * power // 20u * 0.075 = -1.5 blood flow, pretty good for how little effort it is
|
||||
|
||||
/// If someone's putting a laser gun up to our cut to cauterize it
|
||||
/datum/wound/slash/proc/las_cauterize(obj/item/gun/energy/laser/lasgun, mob/user)
|
||||
var/self_penalty_mult = (user == victim ? 1.25 : 1)
|
||||
user.visible_message("<span class='warning'>[user] begins aiming [lasgun] directly at [victim]'s [limb.name]...</span>", "<span class='userdanger'>You begin aiming [lasgun] directly at [user == victim ? "your" : "[victim]'s"] [limb.name]...</span>")
|
||||
if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
var/damage = lasgun.chambered.BB.damage
|
||||
lasgun.chambered.BB.wound_bonus -= 30
|
||||
lasgun.chambered.BB.damage *= self_penalty_mult
|
||||
if(!lasgun.process_fire(victim, victim, TRUE, null, limb.body_zone))
|
||||
return
|
||||
victim.emote("scream")
|
||||
blood_flow -= damage / (5 * self_penalty_mult) // 20 / 5 = 4 bloodflow removed, p good
|
||||
victim.visible_message("<span class='warning'>The cuts on [victim]'s [limb.name] scar over!</span>")
|
||||
|
||||
/// If someone is using either a cautery tool or something with heat to cauterize this cut
|
||||
/datum/wound/slash/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
|
||||
|
||||
user.visible_message("<span class='danger'>[user] begins cauterizing [victim]'s [limb.name] with [I]...</span>", "<span class='warning'>You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...</span>")
|
||||
if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
|
||||
user.visible_message("<span class='green'>[user] cauterizes some of the bleeding on [victim].</span>", "<span class='green'>You cauterize some of the bleeding on [victim].</span>")
|
||||
limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
|
||||
if(prob(30))
|
||||
victim.emote("scream")
|
||||
var/blood_cauterized = (0.6 / (self_penalty_mult * improv_penalty_mult))
|
||||
blood_flow -= blood_cauterized
|
||||
|
||||
if(blood_flow > minimum_flow)
|
||||
try_treating(I, user)
|
||||
else if(demotes_to)
|
||||
to_chat(user, "<span class='green'>You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts.</span>")
|
||||
|
||||
/// If someone is using a suture to close this cut
|
||||
/datum/wound/slash/proc/suture(obj/item/stack/medical/suture/I, mob/user)
|
||||
var/self_penalty_mult = (user == victim ? 1.4 : 1)
|
||||
user.visible_message("<span class='notice'>[user] begins stitching [victim]'s [limb.name] with [I]...</span>", "<span class='notice'>You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...</span>")
|
||||
|
||||
if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists)))
|
||||
return
|
||||
user.visible_message("<span class='green'>[user] stitches up some of the bleeding on [victim].</span>", "<span class='green'>You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].</span>")
|
||||
var/blood_sutured = I.stop_bleeding / self_penalty_mult
|
||||
blood_flow -= blood_sutured
|
||||
limb.heal_damage(I.heal_brute, I.heal_burn)
|
||||
I.use(1)
|
||||
|
||||
if(blood_flow > minimum_flow)
|
||||
try_treating(I, user)
|
||||
else if(demotes_to)
|
||||
to_chat(user, "<span class='green'>You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts.</span>")
|
||||
|
||||
|
||||
/datum/wound/slash/moderate
|
||||
name = "Rough Abrasion"
|
||||
desc = "Patient's skin has been badly scraped, generating moderate blood loss."
|
||||
treat_text = "Application of clean bandages or first-aid grade sutures, followed by food and rest."
|
||||
examine_desc = "has an open cut"
|
||||
occur_text = "is cut open, slowly leaking blood"
|
||||
sound_effect = 'sound/effects/wounds/blood1.ogg'
|
||||
severity = WOUND_SEVERITY_MODERATE
|
||||
initial_flow = 2
|
||||
minimum_flow = 0.5
|
||||
max_per_type = 3
|
||||
clot_rate = 0.12
|
||||
threshold_minimum = 20
|
||||
threshold_penalty = 10
|
||||
status_effect_type = /datum/status_effect/wound/slash/moderate
|
||||
scar_keyword = "slashmoderate"
|
||||
|
||||
/datum/wound/slash/severe
|
||||
name = "Open Laceration"
|
||||
desc = "Patient's skin is ripped clean open, allowing significant blood loss."
|
||||
treat_text = "Speedy application of first-aid grade sutures and clean bandages, followed by vitals monitoring to ensure recovery."
|
||||
examine_desc = "has a severe cut"
|
||||
occur_text = "is ripped open, veins spurting blood"
|
||||
sound_effect = 'sound/effects/wounds/blood2.ogg'
|
||||
severity = WOUND_SEVERITY_SEVERE
|
||||
initial_flow = 3.25
|
||||
minimum_flow = 2.75
|
||||
clot_rate = 0.06
|
||||
max_per_type = 4
|
||||
threshold_minimum = 50
|
||||
threshold_penalty = 25
|
||||
demotes_to = /datum/wound/slash/moderate
|
||||
status_effect_type = /datum/status_effect/wound/slash/severe
|
||||
scar_keyword = "slashsevere"
|
||||
|
||||
/datum/wound/slash/critical
|
||||
name = "Weeping Avulsion"
|
||||
desc = "Patient's skin is completely torn open, along with significant loss of tissue. Extreme blood loss will lead to quick death without intervention."
|
||||
treat_text = "Immediate bandaging and either suturing or cauterization, followed by supervised resanguination."
|
||||
examine_desc = "is carved down to the bone, spraying blood wildly"
|
||||
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.05 // critical cuts actively get worse instead of better
|
||||
max_per_type = 5
|
||||
threshold_minimum = 80
|
||||
threshold_penalty = 40
|
||||
demotes_to = /datum/wound/slash/severe
|
||||
status_effect_type = /datum/status_effect/wound/slash/critical
|
||||
scar_keyword = "slashcritical"
|
||||
wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
@@ -144,6 +144,7 @@
|
||||
#include "code\__DEFINES\~skyrat_defines\jobs.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\keybindings.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\logging.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\medical_defines.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\obj_flags.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\preferences.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\robot_defines.dm"
|
||||
@@ -3672,6 +3673,19 @@
|
||||
#include "modular_skyrat\modules\mapping\code\furniture.dm"
|
||||
#include "modular_skyrat\modules\mapping\code\planet_turfs.dm"
|
||||
#include "modular_skyrat\modules\mapping\code\pool.dm"
|
||||
#include "modular_skyrat\modules\medical\code\bodypart.dm"
|
||||
#include "modular_skyrat\modules\medical\code\bodypart_aid.dm"
|
||||
#include "modular_skyrat\modules\medical\code\carbon_defense.dm"
|
||||
#include "modular_skyrat\modules\medical\code\carbon_examine.dm"
|
||||
#include "modular_skyrat\modules\medical\code\carbon_update_icons.dm"
|
||||
#include "modular_skyrat\modules\medical\code\crafting_recipes.dm"
|
||||
#include "modular_skyrat\modules\medical\code\splint.dm"
|
||||
#include "modular_skyrat\modules\medical\code\wounds\_wounds.dm"
|
||||
#include "modular_skyrat\modules\medical\code\wounds\bones.dm"
|
||||
#include "modular_skyrat\modules\medical\code\wounds\burns.dm"
|
||||
#include "modular_skyrat\modules\medical\code\wounds\muscle.dm"
|
||||
#include "modular_skyrat\modules\medical\code\wounds\pierce.dm"
|
||||
#include "modular_skyrat\modules\medical\code\wounds\slash.dm"
|
||||
#include "modular_skyrat\modules\mentor\code\_globalvars.dm"
|
||||
#include "modular_skyrat\modules\mentor\code\client_procs.dm"
|
||||
#include "modular_skyrat\modules\mentor\code\config.dm"
|
||||
|
||||
Reference in New Issue
Block a user