mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-12 00:20:42 +01:00
Improve, cleanup, and expand wound code (#20757)
This PR includes several changes to bring our wound code up to date with baystation, nebula, and modern standards. Highlights include: - The usage of integers between 0 and 100 for ratios (expressed as a percentage), instead of 0.0 to 1.0. Small decimal values are prone to floating point precision errors, but by moving to a percentage instead, we can reduce the impact of this. - The untangling of damage flags and injury flags, which were used interchangably in the code. This could have caused issues should we expand any of these. - Larger embedded objects now halt bleeding in wounds, until they are pulled out. In exchange however, embedded objects will halt healing in wounds (it is difficult to close an open wound that currently has a rod stuck in it) - A lot of data, such as implanted objects and organs, are now stored in amputated limbs.
This commit is contained in:
+2
-1
@@ -3066,7 +3066,6 @@
|
||||
#include "code\modules\organs\pain.dm"
|
||||
#include "code\modules\organs\robolimbs.dm"
|
||||
#include "code\modules\organs\tendons.dm"
|
||||
#include "code\modules\organs\wound.dm"
|
||||
#include "code\modules\organs\internal\_internal.dm"
|
||||
#include "code\modules\organs\internal\appendix.dm"
|
||||
#include "code\modules\organs\internal\brain.dm"
|
||||
@@ -3137,6 +3136,8 @@
|
||||
#include "code\modules\organs\subtypes\parasite\tumours.dm"
|
||||
#include "code\modules\organs\subtypes\parasite\worms.dm"
|
||||
#include "code\modules\organs\subtypes\parasite\zombie.dm"
|
||||
#include "code\modules\organs\wounds\wound.dm"
|
||||
#include "code\modules\organs\wounds\wound_types.dm"
|
||||
#include "code\modules\overmap\_defines.dm"
|
||||
#include "code\modules\overmap\overmap_object.dm"
|
||||
#include "code\modules\overmap\overmap_shuttle.dm"
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
#define DAMAGE_PAIN "pain"
|
||||
#define DAMAGE_RADIATION "radiation"
|
||||
|
||||
#define CUT "cut"
|
||||
#define BRUISE "bruise"
|
||||
#define PIERCE "pierce"
|
||||
//#define LASER "laser"
|
||||
// Injury types for wounds
|
||||
#define INJURY_TYPE_CUT "cut"
|
||||
#define INJURY_TYPE_BRUISE "bruise"
|
||||
#define INJURY_TYPE_BURN "burn"
|
||||
#define INJURY_TYPE_PIERCE "pierce"
|
||||
#define INJURY_TYPE_LASER "laser"
|
||||
|
||||
#define DAMAGE_FLAG_EDGE 1
|
||||
#define DAMAGE_FLAG_SHARP 2
|
||||
|
||||
@@ -45,43 +45,46 @@ BREATH ANALYZER
|
||||
health_scan_mob(user, user, mode, sound_scan = sound_scan)
|
||||
add_fingerprint(user)
|
||||
|
||||
/proc/get_wound_severity(var/damage_ratio, var/uppercase = FALSE) //Used for ratios.
|
||||
/// Calculates severity based on the ratios defined external limbs.
|
||||
/proc/get_wound_severity(damage_ratio, uppercase = FALSE)
|
||||
var/degree = "none"
|
||||
|
||||
switch(damage_ratio)
|
||||
if(0.001 to 0.1)
|
||||
if (0 to 10)
|
||||
degree = "minor"
|
||||
if(0.1 to 0.2)
|
||||
if (11 to 25)
|
||||
degree = "moderate"
|
||||
if(0.2 to 0.4)
|
||||
if (26 to 50)
|
||||
degree = "significant"
|
||||
if(0.4 to 0.6)
|
||||
if (51 to 75)
|
||||
degree = "severe"
|
||||
if(0.6 to 0.8)
|
||||
degree = "critical"
|
||||
if(0.8 to 1)
|
||||
degree = "fatal"
|
||||
if (76 to 99)
|
||||
degree = "extreme"
|
||||
if (99 to INFINITY)
|
||||
degree = "irreparable"
|
||||
|
||||
if(uppercase)
|
||||
degree = capitalize(degree)
|
||||
return degree
|
||||
|
||||
/proc/get_severity(amount, var/uppercase = FALSE)
|
||||
/proc/get_severity(amount, uppercase = FALSE)
|
||||
var/output = "none"
|
||||
if(!amount)
|
||||
output = "none"
|
||||
else if(amount > 100)
|
||||
output = "fatal"
|
||||
else if(amount > 75)
|
||||
output = "critical"
|
||||
else if(amount > 50)
|
||||
output = "severe"
|
||||
else if(amount > 25)
|
||||
output = "significant"
|
||||
else if(amount > 10)
|
||||
output = "moderate"
|
||||
else
|
||||
output = "minor"
|
||||
|
||||
switch(amount)
|
||||
if (0)
|
||||
output = "none"
|
||||
if (1 to 10)
|
||||
output = "minor"
|
||||
if (11 to 25)
|
||||
output = "moderate"
|
||||
if (26 to 50)
|
||||
output = "significant"
|
||||
if (51 to 75)
|
||||
output = "severe"
|
||||
if (76 to 99)
|
||||
output = "extreme"
|
||||
if (100 to INFINITY)
|
||||
output = "irreparable"
|
||||
|
||||
if(uppercase)
|
||||
output = capitalize(output)
|
||||
|
||||
@@ -162,7 +162,7 @@ Contains:
|
||||
user.visible_message(SPAN_NOTICE("\The [user] bandages \a [W.desc] on [target_mob]'s [affecting.name]."), \
|
||||
SPAN_NOTICE("You bandage \a [W.desc] on [target_mob]'s [affecting.name]."))
|
||||
//H.add_side_effect("Itch")
|
||||
else if (W.damage_type == BRUISE)
|
||||
else if (W.damage_type == INJURY_TYPE_BRUISE)
|
||||
user.visible_message(SPAN_NOTICE("\The [user] places a bruise patch over \a [W.desc] on [target_mob]'s [affecting.name]."), \
|
||||
SPAN_NOTICE("You place a bruise patch over \a [W.desc] on [target_mob]'s [affecting.name]."))
|
||||
else
|
||||
@@ -289,7 +289,7 @@ Contains:
|
||||
user.visible_message(SPAN_NOTICE("\The [user] cleans \a [W.desc] on [target_mob]'s [affecting.name] and seals the edges with bioglue."), \
|
||||
SPAN_NOTICE("You clean and seal \a [W.desc] on [target_mob]'s [affecting.name]."))
|
||||
//H.add_side_effect("Itch")
|
||||
else if (W.damage_type == BRUISE)
|
||||
else if (W.damage_type == INJURY_TYPE_BRUISE)
|
||||
user.visible_message(SPAN_NOTICE("\The [user] places a medical patch over \a [W.desc] on [target_mob]'s [affecting.name]."), \
|
||||
SPAN_NOTICE("You place a medical patch over \a [W.desc] on [target_mob]'s [affecting.name]."))
|
||||
else
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
if(ishuman(imp_in) && part)
|
||||
//No tearing off these parts since it's pretty much killing. Mangle them.
|
||||
if(part.vital && !istype(part, /obj/item/organ/external/head)) //Head explodes
|
||||
part.createwound(BRUISE, 70)
|
||||
part.createwound(INJURY_TYPE_BRUISE, 70)
|
||||
part.add_pain(50)
|
||||
imp_in.visible_message(SPAN_WARNING("\The [imp_in]'s [part.name] bursts open with a horrible ripping noise!"),
|
||||
SPAN_DANGER("Your [part.name] bursts open with a horrible ripping noise!"),
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
|
||||
//Apply weapon damage
|
||||
var/damage_flags = I.damage_flags()
|
||||
apply_damage(effective_force, I.damtype, hit_zone, I, damage_flags, I.armor_penetration)
|
||||
var/datum/wound/created_wound = apply_damage(effective_force, I.damtype, hit_zone, I, damage_flags, I.armor_penetration)
|
||||
|
||||
//Melee weapon embedded object code.
|
||||
if (I && I.damtype == DAMAGE_BRUTE && !I.anchored && !is_robot_module(I) && I.canremove)
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
//Sharp objects will always embed if they do enough damage.
|
||||
if((sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance)))
|
||||
src.embed(I, hit_zone)
|
||||
src.embed(I, hit_zone, supplied_wound = created_wound)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@@ -284,6 +284,15 @@
|
||||
amount -= E.add_pain(amount)
|
||||
BITSET(hud_updateflag, HEALTH_HUD)
|
||||
|
||||
/mob/living/carbon/human/proc/can_autoheal(dam_type)
|
||||
if(!species || !dam_type) return FALSE
|
||||
|
||||
if (dam_type == DAMAGE_BRUTE)
|
||||
return(getBruteLoss() < species.total_health * species.autoheal_brute_ratio)
|
||||
else if (dam_type == DAMAGE_BURN)
|
||||
return(getFireLoss() < species.total_health * species.autoheal_burn_ratio)
|
||||
return FALSE
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
//Returns a list of damaged organs
|
||||
@@ -362,14 +371,14 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t
|
||||
if(status_flags & GODMODE)
|
||||
return //godmode
|
||||
var/list/obj/item/organ/external/parts = get_damageable_organs()
|
||||
var/update = 0
|
||||
var/update
|
||||
while(parts.len && (brute>0 || burn>0) )
|
||||
var/obj/item/organ/external/picked = pick(parts)
|
||||
|
||||
var/brute_was = picked.brute_dam
|
||||
var/burn_was = picked.burn_dam
|
||||
|
||||
update |= picked.take_damage(brute, burn, damage_flags, used_weapon)
|
||||
update = picked.take_damage(brute, burn, damage_flags, used_weapon) ? TRUE : FALSE
|
||||
brute -= (picked.brute_dam - brute_was)
|
||||
burn -= (picked.burn_dam - burn_was)
|
||||
|
||||
@@ -486,18 +495,19 @@ This function restores all organs.
|
||||
if(REAGENT_VOLUME(reagents, /singleton/reagent/adrenaline) < 15)
|
||||
make_adrenaline(round(damage/10))
|
||||
|
||||
var/datum/wound/created_wound
|
||||
switch(damagetype)
|
||||
if(DAMAGE_BRUTE)
|
||||
damageoverlaytemp = 20
|
||||
if(damage > 0)
|
||||
damage *= species.brute_mod
|
||||
organ.take_damage(damage, 0, damage_flags, used_weapon)
|
||||
created_wound = organ.take_damage(damage, 0, damage_flags, used_weapon)
|
||||
UpdateDamageIcon()
|
||||
if(DAMAGE_BURN)
|
||||
damageoverlaytemp = 20
|
||||
if(damage > 0)
|
||||
damage *= species.burn_mod
|
||||
organ.take_damage(0, damage, damage_flags, used_weapon)
|
||||
created_wound = organ.take_damage(0, damage, damage_flags, used_weapon)
|
||||
UpdateDamageIcon()
|
||||
if(DAMAGE_PAIN)
|
||||
organ.add_pain(damage)
|
||||
@@ -507,7 +517,7 @@ This function restores all organs.
|
||||
// Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life().
|
||||
updatehealth()
|
||||
BITSET(hud_updateflag, HEALTH_HUD)
|
||||
return TRUE
|
||||
return created_wound ? created_wound : TRUE
|
||||
|
||||
/mob/living/carbon/human/apply_radiation(var/rads)
|
||||
if(species && rads > 0)
|
||||
|
||||
@@ -441,12 +441,12 @@ emp_act
|
||||
Weaken(3)
|
||||
visible_message(SPAN_WARNING("[src] get knocked over by [H]!"), SPAN_WARNING("You get knocked over by [H]!"))
|
||||
|
||||
/mob/living/carbon/human/embed(var/obj/O, var/def_zone=null)
|
||||
/mob/living/carbon/human/embed(obj/O, def_zone=null, datum/wound/supplied_wound)
|
||||
if(!def_zone) ..()
|
||||
|
||||
var/obj/item/organ/external/affecting = get_organ(def_zone)
|
||||
if(affecting)
|
||||
affecting.embed(O)
|
||||
affecting.embed(O, supplied_wound = supplied_wound)
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
|
||||
|
||||
@@ -63,10 +63,9 @@
|
||||
I.take_damage(rand(3,5))
|
||||
|
||||
//Moving makes open wounds get infected much faster
|
||||
if (E.wounds.len)
|
||||
for(var/datum/wound/W in E.wounds)
|
||||
if (W.infection_check())
|
||||
W.germ_level += 1
|
||||
for(var/datum/wound/W in E.wounds)
|
||||
if (W.infection_check())
|
||||
W.germ_level += 1
|
||||
|
||||
/mob/living/carbon/human
|
||||
var/next_stance_collapse = 0
|
||||
|
||||
@@ -122,6 +122,10 @@
|
||||
// Combat vars.
|
||||
/// Point at which the mob will enter crit.
|
||||
var/total_health = 200
|
||||
/// Ratio at which the mob will stop autohealing a wound. For brute damage.
|
||||
var/autoheal_brute_ratio = 0.5
|
||||
/// Ratio at which the mob will stop autohealing a wound. For burn damage.
|
||||
var/autoheal_burn_ratio = 0.5
|
||||
/// Possible unarmed attacks that the mob will use in combat,
|
||||
var/list/unarmed_types = list(
|
||||
/datum/unarmed_attack,
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
src.anchored = 1
|
||||
src.pinned += O
|
||||
|
||||
/mob/living/proc/embed(var/obj/O, var/def_zone=null)
|
||||
/mob/living/proc/embed(obj/O, def_zone=null, datum/wound/supplied_wound)
|
||||
O.forceMove(src)
|
||||
src.embedded += O
|
||||
add_verb(src, /mob/proc/yank_out_object)
|
||||
|
||||
@@ -1089,13 +1089,13 @@
|
||||
/mob/proc/embedded_needs_process()
|
||||
return (embedded.len > 0)
|
||||
|
||||
/mob/proc/remove_implant(var/obj/item/implant, var/surgical_removal = FALSE)
|
||||
/mob/proc/remove_implant(obj/item/implant, surgical_removal = FALSE)
|
||||
if(!LAZYLEN(get_visible_implants(0))) //Yanking out last object - removing verb.
|
||||
remove_verb(src, /mob/proc/yank_out_object)
|
||||
for(var/obj/item/O in pinned)
|
||||
if(O == implant)
|
||||
pinned -= O
|
||||
if(!pinned.len)
|
||||
if(!length(pinned))
|
||||
anchored = 0
|
||||
implant.dropInto(loc)
|
||||
implant.add_blood(src)
|
||||
@@ -1114,6 +1114,8 @@
|
||||
break
|
||||
if(affected)
|
||||
affected.implants -= implant
|
||||
for(var/datum/wound/wound in affected.wounds)
|
||||
LAZYREMOVE(wound.embedded_objects, implant)
|
||||
if(!surgical_removal)
|
||||
shock_stage += 20
|
||||
apply_damage((implant.w_class * 7), DAMAGE_BRUTE, affected)
|
||||
@@ -1162,7 +1164,7 @@
|
||||
else
|
||||
to_chat(U, SPAN_WARNING("You attempt to get a good grip on [selection] in [S]'s body."))
|
||||
|
||||
if(!do_after(U, 30))
|
||||
if(!do_after(U, 3 SECONDS, S, DO_DEFAULT | DO_USER_UNIQUE_ACT, INCAPACITATION_DEFAULT & ~INCAPACITATION_FORCELYING)) //let people pinned to stuff yank it out, otherwise they're stuck... forever!!!
|
||||
return
|
||||
if(!selection || !S || !U)
|
||||
return
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
user.visible_message(SPAN_NOTICE("[user] starts inspecting [affecting]'s [E.name] carefully."))
|
||||
if(!do_mob(user,H, 10))
|
||||
to_chat(user, SPAN_NOTICE("You must stand still to inspect [E] for wounds."))
|
||||
else if(E.wounds.len)
|
||||
else if(LAZYLEN(E.wounds))
|
||||
to_chat(user, SPAN_WARNING("You find [E.get_wounds_desc()]"))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("You find no visible wounds."))
|
||||
|
||||
@@ -422,7 +422,14 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
surge_damage = clamp(0, surge + surge_damage, MAXIMUM_SURGE_DAMAGE) //We want X seconds at most of hampered movement or what have you.
|
||||
surge_time = world.time
|
||||
|
||||
/obj/item/organ/proc/removed(var/mob/living/carbon/human/target,var/mob/living/user)
|
||||
/**
|
||||
* Remove an organ
|
||||
*
|
||||
* drop_organ - if true, organ will be dropped at the loc of its former owner
|
||||
* detach - if true, organ will be detached from parent. Keep false for organs
|
||||
* removed together with parent, as with an amputation.
|
||||
*/
|
||||
/obj/item/organ/proc/removed(mob/living/carbon/human/target, mob/living/user, drop_organ = TRUE, detach = TRUE)
|
||||
if(!istype(owner))
|
||||
return
|
||||
|
||||
@@ -433,13 +440,13 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
owner.internal_organs_by_name -= null
|
||||
owner.internal_organs -= src
|
||||
|
||||
var/obj/item/organ/external/affected = owner.get_organ(parent_organ)
|
||||
if(affected) affected.internal_organs -= src
|
||||
if(detach)
|
||||
var/obj/item/organ/external/affected = owner.get_organ(parent_organ)
|
||||
if(affected)
|
||||
affected.internal_organs -= src
|
||||
|
||||
var/turf/T = get_turf(owner)
|
||||
// to avoid brains and things like that getting put into nullspace and thus entering spatial grids
|
||||
if(!isnull(T))
|
||||
loc = T
|
||||
if(drop_organ)
|
||||
dropInto(owner.loc)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
rejecting = null
|
||||
if (!reagents)
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
var/hair_color
|
||||
|
||||
/// A `/list` of wounds
|
||||
var/list/datum/wound/wounds = list()
|
||||
var/list/wounds
|
||||
|
||||
/// A list of implants present in this organ
|
||||
var/list/implants = list()
|
||||
@@ -223,6 +223,9 @@
|
||||
limb_flags &= ~ORGAN_HAS_TENDON
|
||||
|
||||
/obj/item/organ/external/Destroy()
|
||||
|
||||
. = ..()
|
||||
|
||||
if(parent?.children)
|
||||
parent.children -= src
|
||||
|
||||
@@ -245,9 +248,11 @@
|
||||
cached_markings = null
|
||||
mob_icon = null
|
||||
|
||||
for(var/datum/wound/wound in wounds)
|
||||
qdel(wound)
|
||||
|
||||
QDEL_LIST(children)
|
||||
QDEL_LIST(internal_organs)
|
||||
QDEL_LIST(wounds)
|
||||
QDEL_LIST(implants)
|
||||
|
||||
infect_target_internal = null
|
||||
@@ -259,13 +264,12 @@
|
||||
|
||||
QDEL_NULL(tendon)
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/external/proc/invalidate_marking_cache()
|
||||
cached_markings = null
|
||||
|
||||
/obj/item/organ/external/attack_self(var/mob/user)
|
||||
if(!contents.len)
|
||||
if(!length(contents))
|
||||
return ..()
|
||||
var/list/removable_objects = list()
|
||||
for(var/obj/item/organ/external/E in (contents + src))
|
||||
@@ -275,7 +279,7 @@
|
||||
if(istype(I,/obj/item/organ))
|
||||
continue
|
||||
removable_objects |= I
|
||||
if(removable_objects.len)
|
||||
if(length(removable_objects))
|
||||
var/obj/item/I = pick(removable_objects)
|
||||
I.forceMove(get_turf(user)) //just in case something was embedded that is not an item
|
||||
if(istype(I))
|
||||
@@ -307,9 +311,18 @@
|
||||
return
|
||||
if(2)
|
||||
if(istype(attacking_item, /obj/item/surgery/hemostat))
|
||||
if(contents.len)
|
||||
var/obj/item/removing = pick(contents)
|
||||
removing.forceMove(get_turf(user.loc))
|
||||
var/list/organs = get_contents_recursive()
|
||||
if(length(organs))
|
||||
var/obj/item/removing = pick(organs)
|
||||
var/obj/item/organ/external/current_child = removing.loc
|
||||
|
||||
current_child.implants.Remove(removing)
|
||||
current_child.internal_organs.Remove(removing)
|
||||
|
||||
status |= ORGAN_CUT_AWAY
|
||||
|
||||
removing.forceMove(get_turf(user))
|
||||
|
||||
if(!(user.l_hand && user.r_hand))
|
||||
user.put_in_hands(removing)
|
||||
user.visible_message(SPAN_DANGER("<b>[user]</b> extracts [removing] from [src] with [attacking_item]!"))
|
||||
@@ -318,6 +331,20 @@
|
||||
return
|
||||
..()
|
||||
|
||||
/**
|
||||
* Get a list of contents of this organ and all the child organs
|
||||
*/
|
||||
/obj/item/organ/external/proc/get_contents_recursive()
|
||||
var/list/all_items = list()
|
||||
|
||||
all_items.Add(implants)
|
||||
all_items.Add(internal_organs)
|
||||
|
||||
for(var/obj/item/organ/external/child in children)
|
||||
all_items.Add(child.get_contents_recursive())
|
||||
|
||||
return all_items
|
||||
|
||||
/obj/item/organ/external/proc/dislocate(var/primary)
|
||||
if(dislocated == -1)
|
||||
return
|
||||
@@ -358,9 +385,22 @@
|
||||
owner.organs |= src
|
||||
if(!species)
|
||||
species = owner.species
|
||||
for(var/obj/item/organ/organ in src)
|
||||
for(var/obj/item/organ/organ in internal_organs)
|
||||
organ.replaced(owner,src)
|
||||
|
||||
for(var/obj/implant in implants)
|
||||
implant.forceMove(owner)
|
||||
|
||||
if(istype(implant, /obj/item/implant))
|
||||
var/obj/item/implant/imp_device = implant
|
||||
|
||||
// we can't use implanted() here since it's often interactive
|
||||
imp_device.imp_in = owner
|
||||
imp_device.implanted = 1
|
||||
|
||||
for(var/obj/item/organ/external/organ in children)
|
||||
organ.replaced(owner)
|
||||
|
||||
if(!parent && parent_organ)
|
||||
parent = owner.organs_by_name[src.parent_organ]
|
||||
if(parent)
|
||||
@@ -369,7 +409,6 @@
|
||||
parent.children.Add(src)
|
||||
//Remove all stump wounds since limb is not missing anymore
|
||||
for(var/datum/wound/lost_limb/W in parent.wounds)
|
||||
parent.wounds -= W
|
||||
qdel(W)
|
||||
break
|
||||
parent.update_damages()
|
||||
@@ -386,12 +425,11 @@
|
||||
return (BP_IS_ROBOTIC(src) || brute_dam + burn_dam + additional_damage < max_damage * 4)
|
||||
|
||||
/obj/item/organ/external/take_damage(brute, burn, damage_flags, used_weapon = null, list/forbidden_limbs = list(), var/silent)
|
||||
brute = round(brute * brute_mod, 0.1)
|
||||
burn = round(burn * burn_mod, 0.1)
|
||||
if((brute <= 0) && (burn <= 0))
|
||||
return 0
|
||||
|
||||
brute *= brute_mod
|
||||
burn *= burn_mod
|
||||
|
||||
var/laser = (damage_flags & DAMAGE_FLAG_LASER)
|
||||
var/sharp = (damage_flags & DAMAGE_FLAG_SHARP)
|
||||
var/edge = (damage_flags & DAMAGE_FLAG_EDGE)
|
||||
@@ -434,21 +472,22 @@
|
||||
brute /= 2
|
||||
burn /= 2
|
||||
|
||||
var/datum/wound/created_wound
|
||||
var/can_cut = !BP_IS_ROBOTIC(src) && (sharp || prob(brute))
|
||||
if(brute)
|
||||
var/to_create = BRUISE
|
||||
var/to_create = INJURY_TYPE_BRUISE
|
||||
if(can_cut)
|
||||
to_create = CUT
|
||||
to_create = INJURY_TYPE_CUT
|
||||
//need to check sharp again here so that blunt damage that was strong enough to break skin doesn't give puncture wounds
|
||||
if(sharp && !edge)
|
||||
to_create = PIERCE
|
||||
createwound(to_create, brute)
|
||||
to_create = INJURY_TYPE_PIERCE
|
||||
created_wound = createwound(to_create, brute)
|
||||
|
||||
if(burn)
|
||||
if(laser)
|
||||
createwound(LASER, burn)
|
||||
created_wound = createwound(INJURY_TYPE_LASER, burn)
|
||||
else
|
||||
createwound(DAMAGE_BURN, burn)
|
||||
created_wound = createwound(INJURY_TYPE_BURN, burn)
|
||||
|
||||
add_pain(0.6 * burn + 0.4 * brute)
|
||||
|
||||
@@ -460,8 +499,9 @@
|
||||
update_damages()
|
||||
if(owner)
|
||||
owner.updatehealth() //droplimb will call updatehealth() again if it does end up being called
|
||||
update_icon()
|
||||
|
||||
return update_icon()
|
||||
return created_wound
|
||||
|
||||
/obj/item/organ/external/proc/damage_internal_organs(brute, burn, damage_flags)
|
||||
if(!length(internal_organs))
|
||||
@@ -553,7 +593,7 @@
|
||||
break
|
||||
|
||||
// heal brute damage
|
||||
if(W.damage_type == DAMAGE_BURN)
|
||||
if(W.damage_type == INJURY_TYPE_BURN)
|
||||
burn = W.heal_damage(burn)
|
||||
else
|
||||
brute = W.heal_damage(brute)
|
||||
@@ -581,7 +621,7 @@ This function completely restores a damaged organ to perfect condition.
|
||||
brute_dam = 0
|
||||
burn_dam = 0
|
||||
germ_level = 0
|
||||
wounds.Cut()
|
||||
QDEL_LIST(wounds)
|
||||
number_wounds = 0
|
||||
|
||||
// handle internal organs
|
||||
@@ -600,7 +640,7 @@ This function completely restores a damaged organ to perfect condition.
|
||||
owner.updatehealth()
|
||||
|
||||
|
||||
/obj/item/organ/external/proc/createwound(var/type = CUT, var/damage)
|
||||
/obj/item/organ/external/proc/createwound(type = INJURY_TYPE_CUT, damage)
|
||||
if(damage <= 0 || !owner)
|
||||
return
|
||||
|
||||
@@ -608,41 +648,41 @@ This function completely restores a damaged organ to perfect condition.
|
||||
//Possibly trigger an internal wound, too.
|
||||
var/local_damage = brute_dam + burn_dam + damage
|
||||
|
||||
var/is_burn_type_damage = (type in list(DAMAGE_BURN, LASER))
|
||||
var/is_burn_type_damage = (type in list(INJURY_TYPE_BURN, INJURY_TYPE_LASER))
|
||||
var/is_brute_type_damage = (type in list(INJURY_TYPE_CUT, INJURY_TYPE_PIERCE, INJURY_TYPE_BRUISE))
|
||||
|
||||
if(damage > (min_broken_damage / 2) && local_damage > min_broken_damage && !(status & ORGAN_ROBOT))
|
||||
if(!is_burn_type_damage)
|
||||
if(prob(damage) && sever_artery())
|
||||
owner.custom_pain("You feel something rip in your [name]!", 25)
|
||||
if(damage > (min_broken_damage / 2) && local_damage > min_broken_damage && !(status & ORGAN_ROBOT) && is_brute_type_damage)
|
||||
if(prob(damage) && sever_artery())
|
||||
owner.custom_pain("You feel something rip in your [name]!", 25)
|
||||
|
||||
if(istype(tendon) && type == CUT)
|
||||
if(istype(tendon))
|
||||
var/new_brute = damage
|
||||
if(min_broken_damage - brute_dam > 0)
|
||||
if(min_broken_damage - damage > 0)
|
||||
// Only pass on damage that goes over the broken threshold
|
||||
new_brute = brute_dam + damage - min_broken_damage
|
||||
new_brute = damage - min_broken_damage
|
||||
tendon.damage(new_brute)
|
||||
|
||||
//Burn damage can cause fluid loss due to blistering and cook-off
|
||||
if(is_burn_type_damage && (damage > 5 || damage + burn_dam >= 15) && !BP_IS_ROBOTIC(src))
|
||||
var/fluid_loss_severity
|
||||
switch(type)
|
||||
if(DAMAGE_BURN)
|
||||
if(INJURY_TYPE_BURN)
|
||||
fluid_loss_severity = FLUIDLOSS_WIDE_BURN
|
||||
if(LASER)
|
||||
if(INJURY_TYPE_LASER)
|
||||
fluid_loss_severity = FLUIDLOSS_CONC_BURN
|
||||
var/fluid_loss = (damage/(owner.maxHealth - GLOB.config.health_threshold_dead)) * DEFAULT_BLOOD_AMOUNT * fluid_loss_severity
|
||||
owner.remove_blood_simple(fluid_loss)
|
||||
|
||||
// first check whether we can widen an existing wound
|
||||
if(wounds.len > 0 && prob(max(50+(number_wounds-1)*10,90)))
|
||||
if((type == CUT || type == BRUISE) && damage >= 5)
|
||||
if(LAZYLEN(wounds) && prob(max(50+(number_wounds-1)*10,90)))
|
||||
if((type == INJURY_TYPE_CUT || type == INJURY_TYPE_BRUISE) && damage >= 5)
|
||||
//we need to make sure that the wound we are going to worsen is compatible with the type of damage...
|
||||
var/list/compatible_wounds = list()
|
||||
for (var/datum/wound/W in wounds)
|
||||
if (W.can_worsen(type, damage))
|
||||
compatible_wounds += W
|
||||
|
||||
if(compatible_wounds.len)
|
||||
if(length(compatible_wounds))
|
||||
var/datum/wound/W = pick(compatible_wounds)
|
||||
W.open_wound(damage)
|
||||
|
||||
@@ -661,13 +701,13 @@ This function completely restores a damaged organ to perfect condition.
|
||||
SPAN_WARNING("The wound on your [name] widens with a nasty ripping noise."),\
|
||||
"You hear a nasty ripping noise, as if flesh is being torn apart.")
|
||||
|
||||
return
|
||||
return W
|
||||
|
||||
//Creating wound
|
||||
var/wound_type = get_wound_type(type, damage)
|
||||
|
||||
if(wound_type)
|
||||
var/datum/wound/W = new wound_type(damage)
|
||||
var/datum/wound/W = new wound_type(damage, src)
|
||||
|
||||
//Check whether we can add the wound to an existing wound
|
||||
for(var/datum/wound/other in wounds)
|
||||
@@ -675,13 +715,13 @@ This function completely restores a damaged organ to perfect condition.
|
||||
other.merge_wound(W)
|
||||
W = null // to signify that the wound was added
|
||||
break
|
||||
if(W)
|
||||
wounds += W
|
||||
LAZYADD(wounds, W)
|
||||
|
||||
if(bandage_level)
|
||||
owner.visible_message(SPAN_WARNING("The bandages on [owner.name]'s [name] gets [is_burn_type_damage ? "burnt" : "ripped"] off!"), SPAN_WARNING("The bandages on your [name] gets [is_burn_type_damage ? "burnt" : "ripped"] off!"))
|
||||
bandage_level = BANDAGE_LEVEL_NONE
|
||||
owner.update_bandages()
|
||||
return W
|
||||
|
||||
/****************************************************
|
||||
PROCESSING & UPDATING
|
||||
@@ -926,8 +966,8 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
var/updatehud
|
||||
for(var/datum/wound/W in wounds)
|
||||
// wounds can disappear after 10 minutes at the earliest
|
||||
if(W.damage <= 0 && W.created + 6000 <= world.time)
|
||||
wounds -= W
|
||||
if(W.damage <= 0 && W.created + (10 MINUTES) <= world.time)
|
||||
qdel(W)
|
||||
continue
|
||||
// let the GC handle the deletion of the wound
|
||||
|
||||
@@ -938,7 +978,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
var/heal_amt = 0
|
||||
|
||||
// if damage >= 50 AFTER treatment then it's probably too severe to heal within the timeframe of a round.
|
||||
if (W.can_autoheal() && W.wound_damage() < 50)
|
||||
if (W.can_autoheal() && W.wound_damage() && brute_ratio < 50 && burn_ratio < 50)
|
||||
heal_amt += 0.5
|
||||
|
||||
//we only update wounds once in [wound_update_accuracy] ticks so have to emulate realtime
|
||||
@@ -946,14 +986,19 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
//configurable regen speed woo, no-regen hardcore or instaheal hugbox, choose your destiny
|
||||
heal_amt = heal_amt * GLOB.config.organ_regeneration_multiplier
|
||||
// amount of healing is spread over all the wounds
|
||||
heal_amt = heal_amt / (wounds.len + 1)
|
||||
heal_amt = heal_amt / (LAZYLEN(wounds) + 1)
|
||||
// making it look prettier on scanners
|
||||
heal_amt = round(heal_amt,0.1)
|
||||
W.heal_damage(heal_amt)
|
||||
var/dam_type = DAMAGE_BRUTE
|
||||
if (W.damage_type == INJURY_TYPE_BURN)
|
||||
dam_type = DAMAGE_BURN
|
||||
|
||||
if(owner.can_autoheal(dam_type) && (heal_amt > 0))
|
||||
W.heal_damage(heal_amt)
|
||||
|
||||
// Salving also helps against infection
|
||||
if(W.germ_level > 0 && W.salved && prob(2))
|
||||
W.disinfected = 1
|
||||
W.disinfected = TRUE
|
||||
W.germ_level = 0
|
||||
|
||||
// sync the organ's damage with its wounds
|
||||
@@ -981,11 +1026,11 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
|
||||
//update damage counts
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.damage_type == DAMAGE_BURN)
|
||||
if(W.damage_type == INJURY_TYPE_BURN)
|
||||
burn_dam += W.damage
|
||||
else
|
||||
brute_dam += W.damage
|
||||
if(W.damage_type == CUT)
|
||||
if(W.damage_type == INJURY_TYPE_CUT)
|
||||
cut_dam += W.damage
|
||||
|
||||
if(!(status & ORGAN_ROBOT) && W.bleeding() && (H && !(H.species.flags & NO_BLOOD)))
|
||||
@@ -1005,9 +1050,9 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
update_damage_ratios()
|
||||
|
||||
/obj/item/organ/external/proc/update_damage_ratios()
|
||||
var/limb_loss_threshold = max_damage
|
||||
brute_ratio = brute_dam / (limb_loss_threshold * 2)
|
||||
burn_ratio = burn_dam / (limb_loss_threshold * 2)
|
||||
var/limb_loss_threshold = max_damage * 2
|
||||
brute_ratio = Percent(brute_dam, limb_loss_threshold)
|
||||
burn_ratio = Percent(burn_dam, limb_loss_threshold)
|
||||
|
||||
// new damage icon system
|
||||
// returns just the brute/burn damage code
|
||||
@@ -1046,7 +1091,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
dir = 2
|
||||
|
||||
//Handles dismemberment
|
||||
/obj/item/organ/external/proc/droplimb(var/clean, var/disintegrate = DROPLIMB_EDGE, var/ignore_children = null)
|
||||
/obj/item/organ/external/proc/droplimb(clean, disintegrate = DROPLIMB_EDGE, ignore_children = null)
|
||||
if(!(limb_flags & ORGAN_CAN_AMPUTATE) || !owner)
|
||||
return
|
||||
|
||||
@@ -1073,7 +1118,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
SPAN_DANGER("You hear the [gore_sound]."))
|
||||
|
||||
var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed().
|
||||
var/obj/item/organ/external/parent_organ = parent
|
||||
var/obj/item/organ/external/original_parent = parent
|
||||
|
||||
if(!clean)
|
||||
victim.shock_stage += min_broken_damage
|
||||
@@ -1084,18 +1129,18 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
if(istype(last_owner) && !QDELETED(last_owner) && length(last_owner.organs) <= 1)
|
||||
last_owner.drop_all_limbs(disintegrate) // drops the last remaining part, usually the torso, as an item
|
||||
|
||||
if(parent_organ)
|
||||
if(original_parent)
|
||||
var/datum/wound/lost_limb/W = new(src, disintegrate, clean)
|
||||
if(clean)
|
||||
parent_organ.wounds |= W
|
||||
parent_organ.update_damages()
|
||||
else
|
||||
var/obj/item/organ/external/stump/stump = new(victim, 0, src)
|
||||
if(status & ORGAN_ROBOT)
|
||||
stump.robotize()
|
||||
stump.wounds |= W
|
||||
victim.organs |= stump
|
||||
stump.update_damages()
|
||||
var/obj/item/organ/external/damaged_organ = original_parent
|
||||
if(!clean)
|
||||
var/obj/item/organ/external/stump/stump = new (victim, 0, src)
|
||||
stump.add_pain(max_damage)
|
||||
damaged_organ = stump
|
||||
if(disintegrate != DROPLIMB_BURN)
|
||||
stump.sever_artery()
|
||||
W.parent_organ = damaged_organ
|
||||
LAZYADD(damaged_organ.wounds, W)
|
||||
damaged_organ.update_damages()
|
||||
|
||||
post_droplimb(victim)
|
||||
SEND_SIGNAL(victim, COMSIG_LIMB_LOSS)
|
||||
@@ -1107,6 +1152,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(rand(180))
|
||||
src.transform = M
|
||||
forceMove(get_turf(src))
|
||||
if(!clean)
|
||||
//Throw limb around.
|
||||
if(src && isturf(loc))
|
||||
@@ -1131,18 +1177,9 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
|
||||
INVOKE_ASYNC(gore, TYPE_PROC_REF(/atom/movable, throw_at), get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 4)
|
||||
|
||||
for(var/obj/item/organ/I in internal_organs)
|
||||
I.removed()
|
||||
victim.blood_squirt(2, loc, rand(2,5))
|
||||
if(istype(loc,/turf))
|
||||
INVOKE_ASYNC(I, TYPE_PROC_REF(/atom/movable, throw_at), get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 4)
|
||||
|
||||
var/turf/Tloc = get_turf(src)
|
||||
for(var/obj/item/I in src)
|
||||
if(I.w_class <= 2)
|
||||
qdel(I)
|
||||
continue
|
||||
I.forceMove(Tloc)
|
||||
I.dropInto(Tloc)
|
||||
INVOKE_ASYNC(I, TYPE_PROC_REF(/atom/movable, throw_at), get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 4)
|
||||
|
||||
qdel(src)
|
||||
@@ -1196,21 +1233,21 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
status &= ~ORGAN_BLEEDING
|
||||
for(var/datum/wound/W in wounds)
|
||||
rval |= !W.bandaged
|
||||
W.bandaged = 1
|
||||
W.bandage()
|
||||
return rval
|
||||
|
||||
/obj/item/organ/external/proc/salve()
|
||||
var/rval = 0
|
||||
for(var/datum/wound/W in wounds)
|
||||
rval |= !W.salved
|
||||
W.salved = 1
|
||||
W.salve()
|
||||
return rval
|
||||
|
||||
/obj/item/organ/external/proc/disinfect()
|
||||
var/rval = 0
|
||||
for(var/datum/wound/W in wounds)
|
||||
rval |= !W.disinfected
|
||||
W.disinfected = 1
|
||||
W.disinfect()
|
||||
W.germ_level = 0
|
||||
return rval
|
||||
|
||||
@@ -1353,14 +1390,14 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
return FALSE
|
||||
if(get_pain() > pain_disability_threshold)
|
||||
return FALSE
|
||||
if(brute_ratio > 1)
|
||||
if(brute_ratio >= 100)
|
||||
return FALSE
|
||||
if(burn_ratio > 1)
|
||||
if(burn_ratio >= 100)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/external/proc/is_malfunctioning()
|
||||
if(BP_IS_ROBOTIC(src) && (brute_ratio + burn_ratio) >= 0.3 && prob(brute_dam + burn_dam) || (surge_damage > (MAXIMUM_SURGE_DAMAGE * 0.25)))
|
||||
if(BP_IS_ROBOTIC(src) && (brute_ratio + burn_ratio) >= 10 && prob(brute_dam + burn_dam) || (surge_damage > (MAXIMUM_SURGE_DAMAGE * 0.25)))
|
||||
return TRUE
|
||||
if(robotize_type)
|
||||
var/datum/robolimb/R = GLOB.all_robolimbs[robotize_type]
|
||||
@@ -1369,7 +1406,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/item/organ/external/proc/embed(var/obj/item/W, var/silent = 0, var/supplied_message)
|
||||
/obj/item/organ/external/proc/embed(obj/item/W, silent = FALSE, supplied_message, datum/wound/supplied_wound)
|
||||
if(!owner || loc != owner)
|
||||
return
|
||||
if(!W.canremove || is_robot_module(W)) //Modules and augments cannot embed
|
||||
@@ -1383,6 +1420,16 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
owner.visible_message(SPAN_DANGER("\The [W] sticks in [owner]'s wound!"),
|
||||
SPAN_DANGER("\The [W] sticks in your wound!"))
|
||||
|
||||
if(supplied_wound)
|
||||
for(var/datum/wound/wound in wounds)
|
||||
if ((wound.damage_type == INJURY_TYPE_CUT || wound.damage_type == INJURY_TYPE_PIERCE) && wound.damage >= W.w_class * 5)
|
||||
supplied_wound = wound
|
||||
break
|
||||
|
||||
if(!supplied_wound || (W in supplied_wound.embedded_objects)) // Just in case.
|
||||
return
|
||||
|
||||
LAZYADD(supplied_wound.embedded_objects, W)
|
||||
implants += W
|
||||
owner.embedded_flag = 1
|
||||
add_verb(owner, /mob/proc/yank_out_object)
|
||||
@@ -1390,14 +1437,13 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
if(ismob(W.loc))
|
||||
var/mob/living/H = W.loc
|
||||
H.drop_from_inventory(W,owner)
|
||||
else
|
||||
W.forceMove(owner)
|
||||
W.forceMove(owner)
|
||||
|
||||
/obj/item/organ/external/removed(var/mob/living/user, var/ignore_children = 0)
|
||||
|
||||
if(!owner)
|
||||
return
|
||||
var/is_robotic = status & ORGAN_ROBOT
|
||||
var/is_robotic = BP_IS_ROBOTIC(src)
|
||||
var/mob/living/carbon/human/victim = owner
|
||||
|
||||
..(null, user)
|
||||
@@ -1407,24 +1453,30 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
for(var/atom/movable/implant in implants)
|
||||
//large items and non-item objs fall to the floor, everything else stays
|
||||
var/obj/item/I = implant
|
||||
if(istype(I) && I.w_class < 3)
|
||||
implant.forceMove(get_turf(victim.loc))
|
||||
else
|
||||
if(istype(I) && I.w_class < WEIGHT_CLASS_NORMAL)
|
||||
implant.forceMove(src)
|
||||
implants.Cut()
|
||||
|
||||
// let actual implants still inside know they're no longer implanted
|
||||
if(istype(I, /obj/item/implant))
|
||||
var/obj/item/implant/imp_device = I
|
||||
imp_device.removed()
|
||||
else
|
||||
implants.Remove(implant)
|
||||
implant.forceMove(get_turf(src))
|
||||
|
||||
// Attached organs also fly off.
|
||||
if(!ignore_children)
|
||||
for(var/obj/item/organ/external/O in children)
|
||||
O.removed()
|
||||
if(O)
|
||||
if(!QDELETED(O))
|
||||
O.forceMove(src)
|
||||
for(var/obj/item/I in O.contents)
|
||||
I.forceMove(src)
|
||||
// if we didn't lose the organ we still want it as a child
|
||||
children += O
|
||||
O.parent = src
|
||||
|
||||
// Grab all the internal giblets too.
|
||||
for(var/obj/item/organ/organ in internal_organs)
|
||||
organ.removed()
|
||||
organ.removed(user, FALSE, FALSE) // Organ stays inside and connected
|
||||
organ.forceMove(src)
|
||||
|
||||
// Remove parent references
|
||||
@@ -1434,6 +1486,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
release_restraints(victim)
|
||||
victim.organs -= src
|
||||
victim.organs_by_name[limb_name] = null // Remove from owner's vars.
|
||||
victim.organs_by_name -= organ_tag
|
||||
|
||||
//Robotic limbs explode if sabotaged.
|
||||
if(is_robotic && sabotaged)
|
||||
@@ -1497,14 +1550,20 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
wound_descriptors["an incision"] = 1
|
||||
for(var/datum/wound/W in wounds)
|
||||
var/this_wound_desc = W.desc
|
||||
if(W.damage_type == DAMAGE_BURN && W.salved) this_wound_desc = "salved [this_wound_desc]"
|
||||
if(W.bleeding()) this_wound_desc = "bleeding [this_wound_desc]"
|
||||
if(W.bandaged == 1)
|
||||
if(W.damage_type == DAMAGE_BURN && W.salved)
|
||||
this_wound_desc = "salved [this_wound_desc]"
|
||||
if(W.bleeding())
|
||||
if(W.wound_damage() > W.bleed_threshold)
|
||||
this_wound_desc = "<b>bleeding</b> [this_wound_desc]"
|
||||
else
|
||||
this_wound_desc = "bleeding [this_wound_desc]"
|
||||
else if(W.bandaged == TRUE)
|
||||
this_wound_desc = "bandaged [this_wound_desc]"
|
||||
else if(W.bandaged != 0)
|
||||
this_wound_desc = "[W.bandaged] [this_wound_desc]"
|
||||
if(W.germ_level > 600) this_wound_desc = "badly infected [this_wound_desc]"
|
||||
else if(W.germ_level > 330) this_wound_desc = "lightly infected [this_wound_desc]"
|
||||
if(W.germ_level > 600)
|
||||
this_wound_desc = "badly infected [this_wound_desc]"
|
||||
else if(W.germ_level > 330)
|
||||
this_wound_desc = "lightly infected [this_wound_desc]"
|
||||
|
||||
if(wound_descriptors[this_wound_desc])
|
||||
wound_descriptors[this_wound_desc] += W.amount
|
||||
else
|
||||
@@ -1520,7 +1579,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
var/list/bits = list()
|
||||
for(var/obj/item/organ/internal/organ in internal_organs)
|
||||
bits += organ.get_visible_state()
|
||||
if(bits.len)
|
||||
if(length(bits))
|
||||
wound_descriptors["[english_list(bits)] visible in the wounds"] = 1
|
||||
|
||||
if(wound_descriptors.len)
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
amputation_point = limb.amputation_point
|
||||
joint = limb.joint
|
||||
parent_organ = limb.parent_organ
|
||||
wounds = limb.wounds
|
||||
. = ..(mapload, internal)
|
||||
if(istype(limb))
|
||||
max_damage = limb.max_damage
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
var/list/brute_wounds = list()
|
||||
for(var/wound in O.wounds)
|
||||
var/datum/wound/W = wound
|
||||
if(W.damage_type in list(CUT, BRUISE, PIERCE))
|
||||
if(W.damage_type in list(INJURY_TYPE_CUT, INJURY_TYPE_BRUISE, INJURY_TYPE_PIERCE))
|
||||
brute_wounds += W
|
||||
for(var/wound in brute_wounds)
|
||||
var/datum/wound/W = wound
|
||||
|
||||
@@ -1,410 +0,0 @@
|
||||
|
||||
/****************************************************
|
||||
WOUNDS
|
||||
****************************************************/
|
||||
/datum/wound
|
||||
/// number representing the current stage
|
||||
var/current_stage = 0
|
||||
|
||||
/// description of the wound
|
||||
var/desc = "wound" //default in case something borks
|
||||
|
||||
/// amount of damage this wound causes
|
||||
var/damage = 0
|
||||
|
||||
/// how many times we've tried to lower the bleed timer, used to determine whether hemophilia should let bleed timer lower
|
||||
var/bleed_timer_increment = 0
|
||||
|
||||
/// ticks of bleeding left.
|
||||
var/bleed_timer = 0
|
||||
|
||||
/// Above this amount wounds you will need to treat the wound to stop bleeding, regardless of bleed_timer
|
||||
var/bleed_threshold = 30
|
||||
|
||||
/// amount of damage the current wound type requires(less means we need to apply the next healing stage)
|
||||
var/min_damage = 0
|
||||
|
||||
/// is the wound bandaged?
|
||||
var/bandaged = 0
|
||||
/// Similar to bandaged, but works differently
|
||||
var/clamped = 0
|
||||
/// is the wound salved?
|
||||
var/salved = 0
|
||||
/// is the wound disinfected?
|
||||
var/disinfected = 0
|
||||
var/created = 0
|
||||
/// number of wounds of this type
|
||||
var/amount = 1
|
||||
/// amount of germs in the wound
|
||||
var/germ_level = 0
|
||||
|
||||
/* These are defined by the wound type and should not be changed */
|
||||
|
||||
/// stages such as "cut", "deep cut", etc.
|
||||
var/list/stages
|
||||
/// maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented.
|
||||
var/max_bleeding_stage = 0
|
||||
/// one of CUT, BRUISE, PIERCE, BURN
|
||||
var/damage_type = CUT
|
||||
/// whether this wound needs a bandage/salve to heal at all
|
||||
/// the maximum amount of damage that this wound can have and still autoheal
|
||||
var/autoheal_cutoff = 15
|
||||
|
||||
|
||||
|
||||
// helper lists
|
||||
var/tmp/list/desc_list = list()
|
||||
var/tmp/list/damage_list = list()
|
||||
|
||||
/datum/wound/New(var/damage)
|
||||
|
||||
created = world.time
|
||||
|
||||
// reading from a list("stage" = damage) is pretty difficult, so build two separate
|
||||
// lists from them instead
|
||||
for(var/V in stages)
|
||||
desc_list += V
|
||||
damage_list += stages[V]
|
||||
|
||||
src.damage = damage
|
||||
|
||||
// initialize with the appropriate stage
|
||||
src.init_stage(damage)
|
||||
|
||||
bleed_timer += damage
|
||||
|
||||
// returns 1 if there's a next stage, 0 otherwise
|
||||
/datum/wound/proc/init_stage(var/initial_damage)
|
||||
current_stage = stages.len
|
||||
|
||||
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= initial_damage / src.amount)
|
||||
src.current_stage--
|
||||
|
||||
src.min_damage = damage_list[current_stage]
|
||||
src.desc = desc_list[current_stage]
|
||||
|
||||
// the amount of damage per wound
|
||||
/datum/wound/proc/wound_damage()
|
||||
return src.damage / src.amount
|
||||
|
||||
/datum/wound/proc/can_autoheal()
|
||||
if(src.wound_damage() <= autoheal_cutoff)
|
||||
return 1
|
||||
|
||||
return is_treated()
|
||||
|
||||
// checks whether the wound has been appropriately treated
|
||||
/datum/wound/proc/is_treated()
|
||||
switch(damage_type)
|
||||
if(BRUISE, CUT, PIERCE)
|
||||
return bandaged
|
||||
if(DAMAGE_BURN)
|
||||
return salved
|
||||
|
||||
// Checks whether other other can be merged into src.
|
||||
/datum/wound/proc/can_merge(var/datum/wound/other)
|
||||
if (other.type != src.type) return 0
|
||||
if (other.current_stage != src.current_stage) return 0
|
||||
if (other.damage_type != src.damage_type) return 0
|
||||
if (!(other.can_autoheal()) != !(src.can_autoheal())) return 0
|
||||
if (!(other.bandaged) != !(src.bandaged)) return 0
|
||||
if (!(other.clamped) != !(src.clamped)) return 0
|
||||
if (!(other.salved) != !(src.salved)) return 0
|
||||
if (!(other.disinfected) != !(src.disinfected)) return 0
|
||||
//if (other.germ_level != src.germ_level) return 0
|
||||
return 1
|
||||
|
||||
/datum/wound/proc/merge_wound(var/datum/wound/other)
|
||||
src.damage += other.damage
|
||||
src.amount += other.amount
|
||||
src.bleed_timer += other.bleed_timer
|
||||
src.bleed_timer_increment += other.bleed_timer_increment
|
||||
src.germ_level = (src.germ_level + other.germ_level)/2
|
||||
src.created = max(src.created, other.created) //take the newer created time
|
||||
|
||||
// checks if wound is considered open for external infections
|
||||
// untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if wound is bigger
|
||||
/datum/wound/proc/infection_check()
|
||||
if (damage < 10) //small cuts, tiny bruises, and moderate burns shouldn't be infectable.
|
||||
return 0
|
||||
if (is_treated() && damage < 25) //anything less than a flesh wound (or equivalent) isn't infectable if treated properly
|
||||
return 0
|
||||
if (disinfected)
|
||||
germ_level = 0 //reset this, just in case
|
||||
return 0
|
||||
|
||||
if (damage_type == BRUISE && !bleeding()) //bruises only infectable if bleeding
|
||||
return 0
|
||||
|
||||
var/dam_coef = round(damage/10)
|
||||
switch (damage_type)
|
||||
if (BRUISE)
|
||||
return prob(dam_coef*5)
|
||||
if (DAMAGE_BURN)
|
||||
return prob(dam_coef*10)
|
||||
if (CUT)
|
||||
return prob(dam_coef*20)
|
||||
|
||||
return 0
|
||||
|
||||
/datum/wound/proc/bandage(var/examine_desc)
|
||||
if(!examine_desc)
|
||||
bandaged = 1
|
||||
else bandaged = examine_desc
|
||||
|
||||
/datum/wound/proc/salve()
|
||||
salved = 1
|
||||
|
||||
/datum/wound/proc/disinfect()
|
||||
disinfected = 1
|
||||
|
||||
// heal the given amount of damage, and if the given amount of damage was more
|
||||
// than what needed to be healed, return how much heal was left
|
||||
// set @heals_internal to also heal internal organ damage
|
||||
/datum/wound/proc/heal_damage(amount, heals_internal = 0)
|
||||
var/healed_damage = min(src.damage, amount)
|
||||
amount -= healed_damage
|
||||
src.damage -= healed_damage
|
||||
|
||||
while(src.wound_damage() < damage_list[current_stage] && current_stage < src.desc_list.len)
|
||||
current_stage++
|
||||
desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
// return amount of healing still leftover, can be used for other wounds
|
||||
return amount
|
||||
|
||||
// opens the wound again
|
||||
/datum/wound/proc/open_wound(damage)
|
||||
src.damage += damage
|
||||
bleed_timer += damage
|
||||
|
||||
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= src.damage / src.amount)
|
||||
src.current_stage--
|
||||
|
||||
src.desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
src.bandaged = FALSE
|
||||
|
||||
// returns whether this wound can absorb the given amount of damage.
|
||||
// this will prevent large amounts of damage being trapped in less severe wound types
|
||||
/datum/wound/proc/can_worsen(damage_type, damage)
|
||||
if (src.damage_type != damage_type)
|
||||
return 0 //incompatible damage types
|
||||
|
||||
if (src.amount > 1)
|
||||
return 0
|
||||
|
||||
//with 1.5*, a shallow cut will be able to carry at most 30 damage,
|
||||
//37.5 for a deep cut
|
||||
//52.5 for a flesh wound, etc.
|
||||
var/max_wound_damage = 1.5*src.damage_list[1]
|
||||
if (src.damage + damage > max_wound_damage)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/wound/proc/bleeding()
|
||||
if (current_stage > max_bleeding_stage)
|
||||
return 0
|
||||
|
||||
if (bandaged||clamped)
|
||||
return 0
|
||||
|
||||
if (bleed_timer <= 0 && wound_damage() <= bleed_threshold)
|
||||
return 0 //Bleed timer has run out. Once a wound is big enough though, you'll need a bandage to stop it
|
||||
|
||||
return 1
|
||||
|
||||
/// Called in organ_external.dm update_damages, this will update the limb's status to bleeding, and lowers the bleed_timer if applicable
|
||||
/datum/wound/proc/handle_bleeding(var/mob/victim, var/obj/item/organ/external/limb)
|
||||
limb.status |= ORGAN_BLEEDING
|
||||
|
||||
var/can_lower_bleed = TRUE
|
||||
if(HAS_TRAIT(victim, TRAIT_DISABILITY_HEMOPHILIA_MAJOR)) // major will NEVER lower
|
||||
can_lower_bleed = FALSE
|
||||
else if(HAS_TRAIT(victim, TRAIT_DISABILITY_HEMOPHILIA) && bleed_timer_increment % 2 != 0) // basic will lower half as fast
|
||||
can_lower_bleed = FALSE
|
||||
|
||||
if(can_lower_bleed)
|
||||
bleed_timer--
|
||||
bleed_timer_increment++
|
||||
|
||||
/** WOUND DEFINITIONS **/
|
||||
|
||||
//Note that the MINIMUM damage before a wound can be applied should correspond to
|
||||
//the damage amount for the stage with the same name as the wound.
|
||||
//e.g. /datum/wound/cut/deep should only be applied for 15 damage and up,
|
||||
//because in it's stages list, "deep cut" = 15.
|
||||
/proc/get_wound_type(var/type = CUT, var/damage)
|
||||
switch(type)
|
||||
if(CUT)
|
||||
switch(damage)
|
||||
if(70 to INFINITY)
|
||||
return /datum/wound/cut/massive
|
||||
if(60 to 70)
|
||||
return /datum/wound/cut/gaping_big
|
||||
if(50 to 60)
|
||||
return /datum/wound/cut/gaping
|
||||
if(25 to 50)
|
||||
return /datum/wound/cut/flesh
|
||||
if(15 to 25)
|
||||
return /datum/wound/cut/deep
|
||||
if(0 to 15)
|
||||
return /datum/wound/cut/small
|
||||
if(PIERCE)
|
||||
switch(damage)
|
||||
if(60 to INFINITY)
|
||||
return /datum/wound/puncture/massive
|
||||
if(50 to 60)
|
||||
return /datum/wound/puncture/gaping_big
|
||||
if(30 to 50)
|
||||
return /datum/wound/puncture/gaping
|
||||
if(15 to 30)
|
||||
return /datum/wound/puncture/flesh
|
||||
if(0 to 15)
|
||||
return /datum/wound/puncture/small
|
||||
|
||||
if(BRUISE)
|
||||
return /datum/wound/bruise
|
||||
if(DAMAGE_BURN, LASER)
|
||||
switch(damage)
|
||||
if(50 to INFINITY)
|
||||
return /datum/wound/burn/carbonised
|
||||
if(40 to 50)
|
||||
return /datum/wound/burn/deep
|
||||
if(30 to 40)
|
||||
return /datum/wound/burn/severe
|
||||
if(15 to 30)
|
||||
return /datum/wound/burn/large
|
||||
if(0 to 15)
|
||||
return /datum/wound/burn/moderate
|
||||
return null //no wound
|
||||
|
||||
/** CUTS **/
|
||||
|
||||
/datum/wound/cut
|
||||
bleed_threshold = 5
|
||||
damage_type = CUT
|
||||
|
||||
/datum/wound/cut/small
|
||||
// link wound descriptions to amounts of damage
|
||||
// Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name.
|
||||
// The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor).
|
||||
max_bleeding_stage = 3
|
||||
stages = list("ugly ripped cut" = 20, "ripped cut" = 10, "cut" = 5, "healing cut" = 2, "small scab" = 0)
|
||||
|
||||
/datum/wound/cut/deep
|
||||
max_bleeding_stage = 3
|
||||
stages = list("ugly deep ripped cut" = 25, "deep ripped cut" = 20, "deep cut" = 15, "clotted cut" = 8, "scab" = 2, "fresh skin" = 0)
|
||||
|
||||
/datum/wound/cut/flesh
|
||||
max_bleeding_stage = 4
|
||||
stages = list("ugly ripped flesh wound" = 35, "ugly flesh wound" = 30, "flesh wound" = 25, "blood soaked clot" = 15, "large scab" = 5, "fresh skin" = 0)
|
||||
|
||||
/datum/wound/cut/gaping
|
||||
max_bleeding_stage = 3
|
||||
stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "blood soaked clot" = 15, "small angry scar" = 5, "small straight scar" = 0)
|
||||
|
||||
/datum/wound/cut/gaping_big
|
||||
max_bleeding_stage = 3
|
||||
stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large blood soaked clot" = 25, "large angry scar" = 10, "large straight scar" = 0)
|
||||
|
||||
/datum/wound/cut/massive
|
||||
max_bleeding_stage = 3
|
||||
stages = list("massive wound" = 70, "massive healing wound" = 50, "massive blood soaked clot" = 25, "massive angry scar" = 10, "massive jagged scar" = 0)
|
||||
|
||||
/** PUNCTURES **/
|
||||
|
||||
/datum/wound/puncture
|
||||
bleed_threshold = 10
|
||||
damage_type = PIERCE
|
||||
|
||||
/datum/wound/puncture/can_worsen(damage_type, damage)
|
||||
return 0
|
||||
|
||||
/datum/wound/puncture/small
|
||||
max_bleeding_stage = 2
|
||||
stages = list("puncture" = 5, "healing puncture" = 2, "small scab" = 0)
|
||||
|
||||
/datum/wound/puncture/flesh
|
||||
max_bleeding_stage = 2
|
||||
stages = list("puncture wound" = 15, "blood soaked clot" = 5, "large scab" = 2, "small round scar" = 0)
|
||||
|
||||
/datum/wound/puncture/gaping
|
||||
max_bleeding_stage = 3
|
||||
stages = list("gaping hole" = 30, "large blood soaked clot" = 15, "blood soaked clot" = 10, "small angry scar" = 5, "small round scar" = 0)
|
||||
|
||||
/datum/wound/puncture/gaping_big
|
||||
max_bleeding_stage = 3
|
||||
stages = list("big gaping hole" = 50, "healing gaping hole" = 20, "large blood soaked clot" = 15, "large angry scar" = 10, "large round scar" = 0)
|
||||
|
||||
/datum/wound/puncture/massive
|
||||
max_bleeding_stage = 3
|
||||
stages = list("massive wound" = 60, "massive healing wound" = 30, "massive blood soaked clot" = 25, "massive angry scar" = 10, "massive jagged scar" = 0)
|
||||
|
||||
/** BRUISES **/
|
||||
|
||||
/datum/wound/bruise
|
||||
stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,
|
||||
"moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5)
|
||||
bleed_threshold = 20
|
||||
max_bleeding_stage = 3 //only large bruise and above can bleed.
|
||||
autoheal_cutoff = 30
|
||||
damage_type = BRUISE
|
||||
|
||||
/** BURNS **/
|
||||
|
||||
/datum/wound/burn
|
||||
damage_type = DAMAGE_BURN
|
||||
max_bleeding_stage = 0
|
||||
|
||||
/datum/wound/burn/bleeding()
|
||||
return 0
|
||||
|
||||
/datum/wound/burn/moderate
|
||||
stages = list("ripped burn" = 10, "moderate burn" = 5, "healing moderate burn" = 2, "fresh skin" = 0)
|
||||
|
||||
/datum/wound/burn/large
|
||||
stages = list("ripped large burn" = 20, "large burn" = 15, "healing large burn" = 5, "fresh skin" = 0)
|
||||
|
||||
/datum/wound/burn/severe
|
||||
stages = list("ripped severe burn" = 35, "severe burn" = 30, "healing severe burn" = 10, "burn scar" = 0)
|
||||
|
||||
/datum/wound/burn/deep
|
||||
stages = list("ripped deep burn" = 45, "deep burn" = 40, "healing deep burn" = 15, "large burn scar" = 0)
|
||||
|
||||
/datum/wound/burn/carbonised
|
||||
stages = list("carbonised area" = 50, "healing carbonised area" = 20, "massive burn scar" = 0)
|
||||
|
||||
/** EXTERNAL ORGAN LOSS **/
|
||||
/datum/wound/lost_limb
|
||||
|
||||
/datum/wound/lost_limb/New(var/obj/item/organ/external/lost_limb, var/losstype, var/clean)
|
||||
var/damage_amt = lost_limb.max_damage
|
||||
if(clean) damage_amt /= 2
|
||||
|
||||
switch(losstype)
|
||||
if(DROPLIMB_EDGE, DROPLIMB_BLUNT)
|
||||
damage_type = CUT
|
||||
max_bleeding_stage = 3 //clotted stump and above can bleed.
|
||||
stages = list(
|
||||
"ripped stump" = damage_amt*1.3,
|
||||
"bloody stump" = damage_amt,
|
||||
"clotted stump" = damage_amt*0.5,
|
||||
"scarred stump" = 0
|
||||
)
|
||||
if(DROPLIMB_BURN)
|
||||
damage_type = DAMAGE_BURN
|
||||
stages = list(
|
||||
"ripped charred stump" = damage_amt*1.3,
|
||||
"charred stump" = damage_amt,
|
||||
"scarred stump" = damage_amt*0.5,
|
||||
"scarred stump" = 0
|
||||
)
|
||||
|
||||
..(damage_amt)
|
||||
|
||||
/datum/wound/lost_limb/can_merge(var/datum/wound/other)
|
||||
return 0 //cannot be merged
|
||||
@@ -0,0 +1,254 @@
|
||||
|
||||
/****************************************************
|
||||
WOUNDS
|
||||
****************************************************/
|
||||
/datum/wound
|
||||
/// number representing the current stage
|
||||
var/current_stage = 0
|
||||
|
||||
/// description of the wound
|
||||
var/desc = "wound" //default in case something borks
|
||||
|
||||
/// amount of damage this wound causes
|
||||
var/damage = 0
|
||||
|
||||
/// how many times we've tried to lower the bleed timer, used to determine whether hemophilia should let bleed timer lower
|
||||
var/bleed_timer_increment = 0
|
||||
|
||||
/// ticks of bleeding left.
|
||||
var/bleed_timer = 0
|
||||
|
||||
/// Above this amount wounds you will need to treat the wound to stop bleeding, regardless of bleed_timer
|
||||
var/bleed_threshold = 30
|
||||
|
||||
/// amount of damage the current wound type requires(less means we need to apply the next healing stage)
|
||||
var/min_damage = 0
|
||||
|
||||
/// is the wound bandaged?
|
||||
var/bandaged = FALSE
|
||||
/// Similar to bandaged, but works differently
|
||||
var/clamped = FALSE
|
||||
/// is the wound salved?
|
||||
var/salved = FALSE
|
||||
/// is the wound disinfected?
|
||||
var/disinfected = FALSE
|
||||
var/created = 0
|
||||
/// number of wounds of this type
|
||||
var/amount = 1
|
||||
/// amount of germs in the wound
|
||||
var/germ_level = 0
|
||||
/// the organ the wound is on, if on an organ
|
||||
var/obj/item/organ/external/parent_organ
|
||||
|
||||
/* These are defined by the wound type and should not be changed */
|
||||
|
||||
/// stages such as "cut", "deep cut", etc.
|
||||
var/list/stages
|
||||
/// maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented.
|
||||
var/max_bleeding_stage = 0
|
||||
/// String (One of `DAMAGE_TYPE_*`). The wound's injury type.
|
||||
var/damage_type = INJURY_TYPE_CUT
|
||||
/// whether this wound needs a bandage/salve to heal at all
|
||||
/// the maximum amount of damage that this wound can have and still autoheal
|
||||
var/autoheal_cutoff = 15
|
||||
|
||||
|
||||
|
||||
// helper lists
|
||||
var/list/embedded_objects
|
||||
var/tmp/list/desc_list = list()
|
||||
var/tmp/list/damage_list = list()
|
||||
|
||||
/datum/wound/New(damage, obj/item/organ/external/organ = null)
|
||||
|
||||
created = world.time
|
||||
|
||||
// reading from a list("stage" = damage) is pretty difficult, so build two separate
|
||||
// lists from them instead
|
||||
for(var/V in stages)
|
||||
desc_list += V
|
||||
damage_list += stages[V]
|
||||
|
||||
src.damage = damage
|
||||
|
||||
// initialize with the appropriate stage
|
||||
src.init_stage(damage)
|
||||
|
||||
bleed_timer += damage
|
||||
|
||||
if(istype(organ))
|
||||
parent_organ = organ
|
||||
|
||||
/datum/wound/Destroy()
|
||||
if(parent_organ)
|
||||
LAZYREMOVE(parent_organ.wounds, src)
|
||||
parent_organ = null
|
||||
LAZYCLEARLIST(embedded_objects)
|
||||
. = ..()
|
||||
|
||||
///Returns TRUE if there's a next stage, FALSE otherwise
|
||||
/datum/wound/proc/init_stage(initial_damage)
|
||||
current_stage = length(stages)
|
||||
|
||||
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= initial_damage / src.amount)
|
||||
src.current_stage--
|
||||
|
||||
src.min_damage = damage_list[current_stage]
|
||||
src.desc = desc_list[current_stage]
|
||||
|
||||
///The amount of damage per wound
|
||||
/datum/wound/proc/wound_damage()
|
||||
return src.damage / src.amount
|
||||
|
||||
/datum/wound/proc/can_autoheal()
|
||||
if(LAZYLEN(embedded_objects))
|
||||
return FALSE
|
||||
|
||||
return (wound_damage() <= autoheal_cutoff) ? TRUE : is_treated()
|
||||
|
||||
/// Checks whether the wound has been appropriately treated
|
||||
/datum/wound/proc/is_treated()
|
||||
if(!LAZYLEN(embedded_objects))
|
||||
switch(damage_type)
|
||||
if(INJURY_TYPE_BRUISE, INJURY_TYPE_CUT, INJURY_TYPE_PIERCE)
|
||||
return bandaged
|
||||
if(INJURY_TYPE_BURN)
|
||||
return salved
|
||||
|
||||
/// Checks whether other other can be merged into src.
|
||||
/datum/wound/proc/can_merge(datum/wound/other)
|
||||
if (other.type != src.type) return FALSE
|
||||
if (other.current_stage != src.current_stage) return FALSE
|
||||
if (other.damage_type != src.damage_type) return FALSE
|
||||
if (!(other.can_autoheal()) != !(src.can_autoheal())) return FALSE
|
||||
if (!(other.bandaged) != !(src.bandaged)) return FALSE
|
||||
if (!(other.clamped) != !(src.clamped)) return FALSE
|
||||
if (!(other.salved) != !(src.salved)) return FALSE
|
||||
if (!(other.disinfected) != !(src.disinfected)) return FALSE
|
||||
if (other.parent_organ != parent_organ) return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/wound/proc/merge_wound(datum/wound/other)
|
||||
if(LAZYLEN(other.embedded_objects))
|
||||
LAZYDISTINCTADD(src.embedded_objects, other.embedded_objects)
|
||||
src.damage += other.damage
|
||||
src.amount += other.amount
|
||||
src.bleed_timer += other.bleed_timer
|
||||
src.bleed_timer_increment += other.bleed_timer_increment
|
||||
src.germ_level = max(src.germ_level, other.germ_level)
|
||||
src.created = max(src.created, other.created) //take the newer created time
|
||||
qdel(other)
|
||||
|
||||
/// checks if wound is considered open for external infections
|
||||
/// untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if wound is bigger
|
||||
/datum/wound/proc/infection_check()
|
||||
if (damage < 10) //small cuts, tiny bruises, and moderate burns shouldn't be infectable.
|
||||
return FALSE
|
||||
if (is_treated() && damage < 25) //anything less than a flesh wound (or equivalent) isn't infectable if treated properly
|
||||
return FALSE
|
||||
if (disinfected)
|
||||
germ_level = 0 //reset this, just in case
|
||||
return FALSE
|
||||
|
||||
if (damage_type == INJURY_TYPE_BRUISE && !bleeding()) //bruises only infectable if bleeding
|
||||
return FALSE
|
||||
|
||||
var/dam_coef = round(damage/10)
|
||||
switch (damage_type)
|
||||
if (INJURY_TYPE_BRUISE)
|
||||
return prob(dam_coef*5)
|
||||
if (INJURY_TYPE_BURN)
|
||||
return prob(dam_coef*10)
|
||||
if (INJURY_TYPE_CUT)
|
||||
return prob(dam_coef*20)
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/wound/proc/bandage()
|
||||
bandaged = TRUE
|
||||
|
||||
/datum/wound/proc/salve()
|
||||
salved = TRUE
|
||||
|
||||
/datum/wound/proc/disinfect()
|
||||
disinfected = TRUE
|
||||
|
||||
/// Heal the given amount of damage, and if the given amount of damage was more than what esd needed to be healed, return how much heal was left
|
||||
/datum/wound/proc/heal_damage(amount)
|
||||
if(LAZYLEN(embedded_objects))
|
||||
return amount // heal nothing
|
||||
if(parent_organ)
|
||||
if (damage_type == INJURY_TYPE_BURN && !(parent_organ.burn_ratio < 100))
|
||||
return amount // We don't want to heal wounds on irreparable organs
|
||||
else if(!(parent_organ.brute_ratio < 100))
|
||||
return amount
|
||||
|
||||
var/healed_damage = min(src.damage, amount)
|
||||
amount -= healed_damage
|
||||
src.damage -= healed_damage
|
||||
|
||||
while(src.wound_damage() < damage_list[current_stage] && current_stage < length(src.desc_list))
|
||||
current_stage++
|
||||
desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
// return amount of healing still leftover, can be used for other wounds
|
||||
return amount
|
||||
|
||||
/// Opens the wound again
|
||||
/datum/wound/proc/open_wound(damage)
|
||||
src.damage += damage
|
||||
bleed_timer += damage
|
||||
|
||||
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= src.damage / src.amount)
|
||||
src.current_stage--
|
||||
|
||||
src.desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
src.bandaged = FALSE
|
||||
|
||||
///returns whether this wound can absorb the given amount of damage.
|
||||
///this will prevent large amounts of damage being trapped in less severe wound types
|
||||
/datum/wound/proc/can_worsen(damage_type, damage)
|
||||
if (src.damage_type != damage_type)
|
||||
return FALSE //incompatible damage types
|
||||
|
||||
if (src.amount > 1)
|
||||
return FALSE //merged wounds cannot be worsened.
|
||||
|
||||
//with 1.5*, a shallow cut will be able to carry at most 30 damage,
|
||||
//37.5 for a deep cut
|
||||
//52.5 for a flesh wound, etc.
|
||||
var/max_wound_damage = 1.5*src.damage_list[1]
|
||||
if (src.damage + damage > max_wound_damage)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/wound/proc/bleeding()
|
||||
for(var/obj/item/thing in embedded_objects)
|
||||
if(thing.w_class > WEIGHT_CLASS_SMALL)
|
||||
return FALSE
|
||||
|
||||
if (bandaged||clamped)
|
||||
return FALSE
|
||||
|
||||
return ((bleed_timer > 0 || wound_damage() > bleed_threshold) && current_stage <= max_bleeding_stage)
|
||||
|
||||
/// Called in organ_external.dm update_damages, this will update the limb's status to bleeding, and lowers the bleed_timer if applicable
|
||||
/datum/wound/proc/handle_bleeding(var/mob/victim, var/obj/item/organ/external/limb)
|
||||
limb.status |= ORGAN_BLEEDING
|
||||
|
||||
var/can_lower_bleed = TRUE
|
||||
if(HAS_TRAIT(victim, TRAIT_DISABILITY_HEMOPHILIA_MAJOR)) // major will NEVER lower
|
||||
can_lower_bleed = FALSE
|
||||
else if(HAS_TRAIT(victim, TRAIT_DISABILITY_HEMOPHILIA) && bleed_timer_increment % 2 != 0) // basic will lower half as fast
|
||||
can_lower_bleed = FALSE
|
||||
|
||||
if(can_lower_bleed)
|
||||
bleed_timer--
|
||||
bleed_timer_increment++
|
||||
|
||||
/datum/wound/proc/close()
|
||||
return
|
||||
@@ -0,0 +1,291 @@
|
||||
/** WOUND DEFINITIONS **/
|
||||
|
||||
//Note that the MINIMUM damage before a wound can be applied should correspond to
|
||||
//the damage amount for the stage with the same name as the wound.
|
||||
//e.g. /datum/wound/cut/deep should only be applied for 15 damage and up,
|
||||
//because in it's stages list, "deep cut" = 15.
|
||||
/proc/get_wound_type(type = INJURY_TYPE_CUT, damage)
|
||||
switch(type)
|
||||
if(INJURY_TYPE_CUT)
|
||||
switch(damage)
|
||||
if(70 to INFINITY)
|
||||
return /datum/wound/cut/massive
|
||||
if(60 to 70)
|
||||
return /datum/wound/cut/gaping_big
|
||||
if(50 to 60)
|
||||
return /datum/wound/cut/gaping
|
||||
if(25 to 50)
|
||||
return /datum/wound/cut/flesh
|
||||
if(15 to 25)
|
||||
return /datum/wound/cut/deep
|
||||
if(0 to 15)
|
||||
return /datum/wound/cut/small
|
||||
if(INJURY_TYPE_PIERCE)
|
||||
switch(damage)
|
||||
if(60 to INFINITY)
|
||||
return /datum/wound/puncture/massive
|
||||
if(50 to 60)
|
||||
return /datum/wound/puncture/gaping_big
|
||||
if(30 to 50)
|
||||
return /datum/wound/puncture/gaping
|
||||
if(15 to 30)
|
||||
return /datum/wound/puncture/flesh
|
||||
if(0 to 15)
|
||||
return /datum/wound/puncture/small
|
||||
|
||||
if(INJURY_TYPE_BRUISE)
|
||||
return /datum/wound/bruise
|
||||
if(INJURY_TYPE_BURN, INJURY_TYPE_LASER)
|
||||
switch(damage)
|
||||
if(50 to INFINITY)
|
||||
return /datum/wound/burn/carbonised
|
||||
if(40 to 50)
|
||||
return /datum/wound/burn/deep
|
||||
if(30 to 40)
|
||||
return /datum/wound/burn/severe
|
||||
if(15 to 30)
|
||||
return /datum/wound/burn/large
|
||||
if(0 to 15)
|
||||
return /datum/wound/burn/moderate
|
||||
return null //no wound
|
||||
|
||||
/** CUTS **/
|
||||
|
||||
/datum/wound/cut
|
||||
bleed_threshold = 5
|
||||
damage_type = INJURY_TYPE_CUT
|
||||
|
||||
/datum/wound/cut/bandage()
|
||||
..()
|
||||
if(!autoheal_cutoff)
|
||||
autoheal_cutoff = initial(autoheal_cutoff)
|
||||
|
||||
/datum/wound/cut/close()
|
||||
current_stage = max_bleeding_stage + 1
|
||||
desc = desc_list[current_stage]
|
||||
min_damage = damage_list[current_stage]
|
||||
if(damage > min_damage)
|
||||
heal_damage(damage-min_damage)
|
||||
|
||||
/datum/wound/cut/small
|
||||
// link wound descriptions to amounts of damage
|
||||
// Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name.
|
||||
// The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor).
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"ugly ripped cut" = 20,
|
||||
"ripped cut" = 10,
|
||||
"cut" = 5,
|
||||
"healing cut" = 2,
|
||||
"small scab" = 0
|
||||
)
|
||||
|
||||
/datum/wound/cut/deep
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"ugly deep ripped cut" = 25,
|
||||
"deep ripped cut" = 20,
|
||||
"deep cut" = 15,
|
||||
"clotted cut" = 8,
|
||||
"scab" = 2,
|
||||
"fresh skin" = 0
|
||||
)
|
||||
|
||||
/datum/wound/cut/flesh
|
||||
max_bleeding_stage = 4
|
||||
stages = list(
|
||||
"ugly ripped flesh wound" = 35,
|
||||
"ugly flesh wound" = 30,
|
||||
"flesh wound" = 25,
|
||||
"blood soaked clot" = 15,
|
||||
"large scab" = 5,
|
||||
"fresh skin" = 0
|
||||
)
|
||||
|
||||
/datum/wound/cut/gaping
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"gaping wound" = 50,
|
||||
"large blood soaked clot" = 25,
|
||||
"blood soaked clot" = 15,
|
||||
"small angry scar" = 5,
|
||||
"small straight scar" = 0
|
||||
)
|
||||
|
||||
/datum/wound/cut/gaping_big
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"big gaping wound" = 60,
|
||||
"healing gaping wound" = 40,
|
||||
"large blood soaked clot" = 25,
|
||||
"large angry scar" = 10,
|
||||
"large straight scar" = 0
|
||||
)
|
||||
|
||||
/datum/wound/cut/massive
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"massive wound" = 70,
|
||||
"massive healing wound" = 50,
|
||||
"massive blood soaked clot" = 25,
|
||||
"massive angry scar" = 10,
|
||||
"massive jagged scar" = 0
|
||||
)
|
||||
|
||||
/** PUNCTURES **/
|
||||
|
||||
/datum/wound/puncture
|
||||
bleed_threshold = 10
|
||||
damage_type = INJURY_TYPE_PIERCE
|
||||
|
||||
/datum/wound/puncture/can_worsen(damage_type, damage)
|
||||
return FALSE //puncture wounds cannot be enlargened
|
||||
|
||||
/datum/wound/puncture/small
|
||||
max_bleeding_stage = 2
|
||||
stages = list(
|
||||
"puncture" = 5,
|
||||
"healing puncture" = 2,
|
||||
"small scab" = 0
|
||||
)
|
||||
|
||||
/datum/wound/puncture/flesh
|
||||
max_bleeding_stage = 2
|
||||
stages = list(
|
||||
"puncture wound" = 15,
|
||||
"blood soaked clot" = 5,
|
||||
"large scab" = 2,
|
||||
"small round scar" = 0
|
||||
)
|
||||
|
||||
/datum/wound/puncture/gaping
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"gaping hole" = 30,
|
||||
"large blood soaked clot" = 15,
|
||||
"blood soaked clot" = 10,
|
||||
"small angry scar" = 5,
|
||||
"small round scar" = 0
|
||||
)
|
||||
|
||||
/datum/wound/puncture/gaping_big
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"big gaping hole" = 50,
|
||||
"healing gaping hole" = 20,
|
||||
"large blood soaked clot" = 15,
|
||||
"large angry scar" = 10,
|
||||
"large round scar" = 0
|
||||
)
|
||||
|
||||
/datum/wound/puncture/massive
|
||||
max_bleeding_stage = 3
|
||||
stages = list(
|
||||
"massive wound" = 60,
|
||||
"massive healing wound" = 30,
|
||||
"massive blood soaked clot" = 25,
|
||||
"massive angry scar" = 10,
|
||||
"massive jagged scar" = 0
|
||||
)
|
||||
|
||||
/** BRUISES **/
|
||||
|
||||
/datum/wound/bruise
|
||||
stages = list(
|
||||
"monumental bruise" = 80,
|
||||
"huge bruise" = 50,
|
||||
"large bruise" = 30,
|
||||
"moderate bruise" = 20,
|
||||
"small bruise" = 10,
|
||||
"tiny bruise" = 5
|
||||
)
|
||||
bleed_threshold = 20
|
||||
max_bleeding_stage = 3 //only large bruise and above can bleed.
|
||||
autoheal_cutoff = 30
|
||||
damage_type = INJURY_TYPE_BRUISE
|
||||
|
||||
/** BURNS **/
|
||||
|
||||
/datum/wound/burn
|
||||
damage_type = INJURY_TYPE_BURN
|
||||
max_bleeding_stage = 0
|
||||
|
||||
/datum/wound/burn/bleeding()
|
||||
return FALSE
|
||||
|
||||
/datum/wound/burn/moderate
|
||||
stages = list(
|
||||
"ripped burn" = 10,
|
||||
"moderate burn" = 5,
|
||||
"healing moderate burn" = 2,
|
||||
"fresh skin" = 0
|
||||
)
|
||||
|
||||
/datum/wound/burn/large
|
||||
stages = list(
|
||||
"ripped large burn" = 20,
|
||||
"large burn" = 15,
|
||||
"healing large burn" = 5,
|
||||
"fresh skin" = 0
|
||||
)
|
||||
|
||||
/datum/wound/burn/severe
|
||||
stages = list(
|
||||
"ripped severe burn" = 35,
|
||||
"severe burn" = 30,
|
||||
"healing severe burn" = 10,
|
||||
"burn scar" = 0
|
||||
)
|
||||
|
||||
/datum/wound/burn/deep
|
||||
stages = list(
|
||||
"ripped deep burn" = 45,
|
||||
"deep burn" = 40,
|
||||
"healing deep burn" = 15,
|
||||
"large burn scar" = 0
|
||||
)
|
||||
|
||||
/datum/wound/burn/carbonised
|
||||
stages = list(
|
||||
"carbonised area" = 50,
|
||||
"healing carbonised area" = 20,
|
||||
"massive burn scar" = 0
|
||||
)
|
||||
|
||||
/** EXTERNAL ORGAN LOSS **/
|
||||
/datum/wound/lost_limb
|
||||
var/limb_tag
|
||||
|
||||
/datum/wound/lost_limb/New(obj/item/organ/external/lost_limb, losstype, clean)
|
||||
var/damage_amt = lost_limb.max_damage
|
||||
if(clean) damage_amt /= 2
|
||||
limb_tag = lost_limb.organ_tag
|
||||
|
||||
switch(losstype)
|
||||
if(DROPLIMB_EDGE, DROPLIMB_BLUNT)
|
||||
damage_type = INJURY_TYPE_CUT
|
||||
if(BP_IS_ROBOTIC(lost_limb))
|
||||
max_bleeding_stage = -1 //Robotic stumps do not bleed
|
||||
bleed_threshold = INFINITY
|
||||
stages = list("mangled robotic socket" = 0)
|
||||
else
|
||||
max_bleeding_stage = 3 //clotted stump and above can bleed.
|
||||
stages = list(
|
||||
"ripped stump" = damage_amt*1.3,
|
||||
"bloody stump" = damage_amt,
|
||||
"clotted stump" = damage_amt*0.5,
|
||||
"scarred stump" = 0
|
||||
)
|
||||
if(DROPLIMB_BURN)
|
||||
damage_type = INJURY_TYPE_BURN
|
||||
stages = list(
|
||||
"ripped charred stump" = damage_amt*1.3,
|
||||
"charred stump" = damage_amt,
|
||||
"scarred stump" = damage_amt*0.5,
|
||||
"scarred stump" = 0
|
||||
)
|
||||
|
||||
..(damage_amt)
|
||||
|
||||
/datum/wound/lost_limb/can_merge(var/datum/wound/other)
|
||||
return 0 //cannot be merged
|
||||
@@ -165,11 +165,10 @@
|
||||
var/obj/item/organ/external/E = A
|
||||
if(BP_IS_ROBOTIC(E))
|
||||
continue
|
||||
if (E.wounds.len)
|
||||
for(var/datum/wound/W in E.wounds)
|
||||
if(W.germ_level < INFECTION_LEVEL_ONE)
|
||||
W.germ_level = INFECTION_LEVEL_ONE
|
||||
W.germ_level += rand(10, 50)
|
||||
for(var/datum/wound/W in E.wounds)
|
||||
if(W.germ_level < INFECTION_LEVEL_ONE)
|
||||
W.germ_level = INFECTION_LEVEL_ONE
|
||||
W.germ_level += rand(10, 50)
|
||||
|
||||
/turf/simulated/floor/exoplanet/water/shallow/moghes
|
||||
icon = 'icons/turf/flooring/exoplanet/moghes.dmi'
|
||||
|
||||
@@ -578,7 +578,7 @@ By design, d1 is the smallest direction and d2 is the highest
|
||||
break
|
||||
user.visible_message(SPAN_NOTICE("\The [user] barely manages to stitch \a [W.desc] on [target_mob]'s [affecting.name]."), \
|
||||
SPAN_NOTICE("You barely manage to stitch \a [W.desc] on [target_mob]'s [affecting.name].") )
|
||||
W.bandage("cable-stitched")
|
||||
W.bandage()
|
||||
use(10)
|
||||
affecting.add_pain(25)
|
||||
if(prob(min(30 + (germ_level/5), 65))) //Less chance of infection if you clean the coil. Coil's germ level is set to GERM_LEVEL_AMBIENT
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# - (fixes bugs)
|
||||
# wip
|
||||
# - (work in progress)
|
||||
# qol
|
||||
# - (quality of life)
|
||||
# soundadd
|
||||
# - (adds a sound)
|
||||
# sounddel
|
||||
# - (removes a sound)
|
||||
# rscadd
|
||||
# - (adds a feature)
|
||||
# rscdel
|
||||
# - (removes a feature)
|
||||
# imageadd
|
||||
# - (adds an image or sprite)
|
||||
# imagedel
|
||||
# - (removes an image or sprite)
|
||||
# spellcheck
|
||||
# - (fixes spelling or grammar)
|
||||
# experiment
|
||||
# - (experimental change)
|
||||
# balance
|
||||
# - (balance changes)
|
||||
# code_imp
|
||||
# - (misc internal code change)
|
||||
# refactor
|
||||
# - (refactors code)
|
||||
# config
|
||||
# - (makes a change to the config files)
|
||||
# admin
|
||||
# - (makes changes to administrator tools)
|
||||
# server
|
||||
# - (miscellaneous changes to server)
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: GeneralCamo
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
|
||||
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- code_imp: "Damage ratios now use integers instead of decimals, reducing the impact of floating point rounding errors."
|
||||
- bugfix: "Implants now remain in amputated limbs."
|
||||
- rscadd: "Amputated external organs now retain their implants and internal organs."
|
||||
- code_imp: "Embedded objects are now stored in wounds, not in limbs (at least, not directly)."
|
||||
- balance: "Larger embedded objects now halt bleeding in wounds."
|
||||
- balance: "Embedded objects now halt healing in wounds."
|
||||
- code_imp: "Untangled damage flags and injury type flags."
|
||||
- balance: "Pinning no longer blocks yanking out items."
|
||||
- balance: "Generalise the autoheal threshold so wounds don't autoheal when a limb has taken either too much overall damage or the mob has taken significant damage."
|
||||
Reference in New Issue
Block a user