mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 04:30:44 +01:00
[TEST-MERGE FIRST] Wound refactor number two: Full synthetic support (#78124)
## About The Pull Request Heavily refactors wounds AGAIN. The primary thing this PR does is completely change how wounds are generated and added - while the normal "hit a guy til they bleed" stuff works about the same, asking for a specific type of wound, say, like how vending machines try to apply a compound fracture sometimes, isnt going to work if we ever get any non-organic wounds, which the previous refactor allowed. With this PR, however... * You can now ask for a specific type of wound via get_corresponding_wound_type(), which takes wound types, a limb, wound series, etc. and will try to give you a wound fitting those specifications - but also, a wound that can be applied to a limb. * This will allow for a vending machine to apply a compound fracture to a human, but a collapsed superstructure (assuming my synth wounds go in) to a robot There are now new "series types" and "wound specific types" that allow us to designate what series are "mainline" and randomly generatable, and what are "alternate types" and must be generated manually - you can see the documentation in wounds.dm. The behavior of limping and interaction delays has been abstracted to datum/wound from bone wounds to allow just, general ease of development Pregen data now allows for series-specific wound penalties. Example: You could set a burn wound's series wound penalty to 40, which would make wound progression in the burn category easier - but it would not make it any easier to get a slashing wound. As it stands wound penalties are for wounds globally Scar files are now picked in a "priority" list, where the wound checks to see if the limb has a biostate before moving down in said list. Example: Wounds will check for flesh first, if it finds it - it will use the flesh scar list. Failing that, they then check bone - if it uses that, it will use the bone scar list. This allows for significantly more modular scars that dont even need much proc editing when a new wound type is added Misc changes: most initial() usage has been replaced by singleton datums, wound_type is now wound_types and thus wounds can accept multiple wound types, wounds can now accept multiple tool behaviors for treatment, wounds now have a picking weight so we can make certain wounds rarer flatly, This PR also allows for wounds to override lower severity wounds on generation, allowing eswords to jump to avulsions - but in spirit of refactoring, this has been disabled by default (see pregen data's competition_mode var). ## Why It's Good For The Game Code quality is good! Also, all the changes above allow wounds to be a MUCH more modular system, which is one of its biggest problems right now - everything is kinda hardcoded and static, making creative work within wounds harder to do. ## Changelog 🆑 refactor: Refactored wounds yet again fix: Wounds are now picked from the most severe down again, meaning eswords can jump to avulsions fix: Scar descs are now properly applied /🆑
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
// /mob/living/carbon physiology signals
|
||||
#define COMSIG_CARBON_GAIN_WOUND "carbon_gain_wound" //from /datum/wound/proc/apply_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
|
||||
#define COMSIG_CARBON_LOSE_WOUND "carbon_lose_wound" //from /datum/wound/proc/remove_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L)
|
||||
/// Called after limb AND victim has been unset
|
||||
#define COMSIG_CARBON_POST_LOSE_WOUND "carbon_post_lose_wound" //from /datum/wound/proc/remove_wound() (/datum/wound/lost_wound, /obj/item/bodypart/part, ignore_limb, replaced)
|
||||
///from base of /obj/item/bodypart/proc/can_attach_limb(): (new_limb, special) allows you to fail limb attachment
|
||||
#define COMSIG_ATTEMPT_CARBON_ATTACH_LIMB "attempt_carbon_attach_limb"
|
||||
#define COMPONENT_NO_ATTACH (1<<0)
|
||||
|
||||
+226
-43
@@ -1,4 +1,3 @@
|
||||
|
||||
// ~wound damage/rolling defines
|
||||
/// the cornerstone of the wound threshold system, your base wound roll for any attack is rand(1, damage^this), after armor reduces said damage. See [/obj/item/bodypart/proc/check_wounding]
|
||||
#define WOUND_DAMAGE_EXPONENT 1.4
|
||||
@@ -13,6 +12,10 @@
|
||||
/// set wound_bonus on an item or attack to this to disable checking wounding for the attack
|
||||
#define CANT_WOUND -100
|
||||
|
||||
/// If there are multiple possible and valid wounds for the same type and severity, weight will be used to pick among them. See _wound_pregen_data.dm for more details
|
||||
/// This is used in pick_weight, so use integers
|
||||
#define WOUND_DEFAULT_WEIGHT 50
|
||||
|
||||
// ~wound severities
|
||||
/// for jokey/meme wounds like stubbed toe, no standard messages/sounds or second winds
|
||||
#define WOUND_SEVERITY_TRIVIAL 0
|
||||
@@ -22,16 +25,26 @@
|
||||
/// outright dismemberment of limb
|
||||
#define WOUND_SEVERITY_LOSS 4
|
||||
|
||||
/// A "chronological" list of wound severities, starting at the least severe.
|
||||
GLOBAL_LIST_INIT(wound_severities_chronological, list(
|
||||
"[WOUND_SEVERITY_TRIVIAL]",
|
||||
"[WOUND_SEVERITY_MODERATE]",
|
||||
"[WOUND_SEVERITY_SEVERE]",
|
||||
"[WOUND_SEVERITY_CRITICAL]"
|
||||
))
|
||||
|
||||
// ~wound categories
|
||||
// ~wound categories: wounding_types
|
||||
/// any brute weapon/attack that doesn't have sharpness. rolls for blunt bone wounds
|
||||
#define WOUND_BLUNT 1
|
||||
#define WOUND_BLUNT "wound_blunt"
|
||||
/// any brute weapon/attack with sharpness = SHARP_EDGED. rolls for slash wounds
|
||||
#define WOUND_SLASH 2
|
||||
#define WOUND_SLASH "wound_slash"
|
||||
/// any brute weapon/attack with sharpness = SHARP_POINTY. rolls for piercing wounds
|
||||
#define WOUND_PIERCE 3
|
||||
#define WOUND_PIERCE "wound_pierce"
|
||||
/// any concentrated burn attack (lasers really). rolls for burning wounds
|
||||
#define WOUND_BURN 4
|
||||
#define WOUND_BURN "wound_burn"
|
||||
|
||||
/// Mainly a define used for wound_pregen_data, if a pregen data instance expects this, it will accept any and all wound types, even none at all
|
||||
#define WOUND_ALL "wound_all"
|
||||
|
||||
|
||||
// ~determination second wind defines
|
||||
@@ -46,6 +59,11 @@
|
||||
/// While someone has determination in their system, their bleed rate is slightly reduced
|
||||
#define WOUND_DETERMINATION_BLEED_MOD 0.85
|
||||
|
||||
/// Wounds using this competition mode will remove any wounds of a greater severity than itself in a random wound roll. In most cases, you dont want to use this.
|
||||
#define WOUND_COMPETITION_OVERPOWER_GREATERS "wound_submit"
|
||||
/// Wounds using this competition mode will remove any wounds of a lower severity than itself in a random wound roll. Used for ensuring the worse case scenario of a given injury_roll.
|
||||
#define WOUND_COMPETITION_OVERPOWER_LESSERS "wound_dominate"
|
||||
|
||||
// ~biology defines
|
||||
// What kind of biology a limb has, and what wounds it can suffer
|
||||
/// Has absolutely fucking nothing, no wounds
|
||||
@@ -54,36 +72,43 @@
|
||||
#define BIO_BONE (1<<0)
|
||||
/// Has flesh - allows the victim to suffer fleshy slash pierce and burn wounds
|
||||
#define BIO_FLESH (1<<1)
|
||||
/// Self explanatory
|
||||
#define BIO_FLESH_BONE (BIO_BONE | BIO_FLESH)
|
||||
/// Has metal - allows the victim to suffer robotic blunt and burn wounds
|
||||
#define BIO_METAL (1<<2)
|
||||
/// Is wired internally - allows the victim to suffer electrical wounds (robotic T1-T3 slash/pierce)
|
||||
#define BIO_WIRED (1<<3)
|
||||
/// Robotic: shit like cyborg limbs, mostly
|
||||
#define BIO_ROBOTIC (BIO_METAL|BIO_WIRED)
|
||||
/// Has bloodflow - can suffer bleeding wounds and can bleed
|
||||
#define BIO_BLOODED (1<<4)
|
||||
/// Is connected by a joint - can suffer T1 bone blunt wounds (dislocation)
|
||||
#define BIO_JOINTED (1<<5)
|
||||
/// Standard humanoid - can suffer all flesh wounds, such as: T1-3 slash/pierce/burn/blunt. Can also bleed
|
||||
#define BIO_STANDARD (BIO_FLESH_BONE|BIO_BLOODED)
|
||||
/// Robotic - can suffer all metal/wired wounds, such as: UNIMPLEMENTED PLEASE UPDATE ONCE SYNTH WOUNDS 9/5/2023 ~Niko
|
||||
#define BIO_ROBOTIC (BIO_METAL|BIO_WIRED)
|
||||
/// Has flesh and bone - See BIO_BONE and BIO_FLESH
|
||||
#define BIO_FLESH_BONE (BIO_BONE|BIO_FLESH)
|
||||
/// Standard humanoid - can bleed and suffer all flesh/bone wounds, such as: T1-3 slash/pierce/burn/blunt, except dislocations. Think human heads/chests
|
||||
#define BIO_STANDARD_UNJOINTED (BIO_FLESH_BONE|BIO_BLOODED)
|
||||
/// Standard humanoid limbs - can bleed and suffer all flesh/bone wounds, such as: T1-3 slash/pierce/burn/blunt. Can also bleed, and be dislocated. Think human arms and legs
|
||||
#define BIO_STANDARD_JOINTED (BIO_STANDARD_UNJOINTED|BIO_JOINTED)
|
||||
|
||||
// "Where" a specific "bio" feature is within a given limb
|
||||
// Exterior is hard shit, the last line, shit lines bones
|
||||
// Interior is soft shit, targetted by slashes and pierces (usually), protects exterior
|
||||
// Yes, it makes no sense
|
||||
/// The given biostate is on the "exterior" of the limb - hard shit, protected by interior
|
||||
#define BIO_EXTERIOR (1<<0)
|
||||
/// The given biostate is on the "exterior" of the limb - soft shit, protects exterior
|
||||
#define BIO_INTERIOR (1<<1)
|
||||
#define BIO_EXTERIOR_AND_INTERIOR (BIO_EXTERIOR|BIO_INTERIOR)
|
||||
// "Where" a specific biostate is within a given limb
|
||||
// Interior is hard shit, the last line, shit like bones
|
||||
// Exterior is soft shit, targetted by slashes and pierces (usually), protects exterior
|
||||
// A limb needs both mangled interior and exterior to be dismembered, but slash/pierce must mangle exterior to attack the interior
|
||||
// Not having exterior/interior counts as mangled exterior/interior for the purposes of dismemberment
|
||||
/// The given biostate is on the "interior" of the limb - hard shit, protected by exterior
|
||||
#define ANATOMY_INTERIOR (1<<0)
|
||||
/// The given biostate is on the "exterior" of the limb - soft shit, protects interior
|
||||
#define ANATOMY_EXTERIOR (1<<1)
|
||||
#define ANATOMY_EXTERIOR_AND_INTERIOR (ANATOMY_EXTERIOR|ANATOMY_INTERIOR)
|
||||
|
||||
GLOBAL_LIST_INIT(bio_state_states, list(
|
||||
"[BIO_WIRED]" = BIO_INTERIOR,
|
||||
"[BIO_METAL]" = BIO_EXTERIOR,
|
||||
"[BIO_FLESH]" = BIO_INTERIOR,
|
||||
"[BIO_BONE]" = BIO_EXTERIOR,
|
||||
/// A assoc list of BIO_ define to EXTERIOR/INTERIOR defines.
|
||||
/// This is where the interior/exterior state of a given biostate is set.
|
||||
/// Note that not all biostates are guaranteed to be one of these - and in fact, many are not
|
||||
/// IMPORTANT NOTE: All keys are stored as text and must be converted via text2num
|
||||
GLOBAL_LIST_INIT(bio_state_anatomy, list(
|
||||
"[BIO_WIRED]" = ANATOMY_EXTERIOR,
|
||||
"[BIO_METAL]" = ANATOMY_INTERIOR,
|
||||
"[BIO_FLESH]" = ANATOMY_EXTERIOR,
|
||||
"[BIO_BONE]" = ANATOMY_INTERIOR,
|
||||
))
|
||||
|
||||
// Wound series
|
||||
@@ -91,13 +116,169 @@ GLOBAL_LIST_INIT(bio_state_states, list(
|
||||
// Multiple wounds in a single series cannot be on a limb - the highest severity will always be prioritized, and lower ones will be skipped
|
||||
|
||||
/// T1-T3 Bleeding slash wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: slash.dm
|
||||
#define WOUND_SERIES_FLESH_SLASH_BLEED 1
|
||||
#define WOUND_SERIES_FLESH_SLASH_BLEED "wound_series_flesh_slash_bled"
|
||||
/// T1-T3 Basic blunt wounds. T1 requires jointed, but 2-3 require bone. From: bone.dm
|
||||
#define WOUND_SERIES_BONE_BLUNT_BASIC 2
|
||||
#define WOUND_SERIES_BONE_BLUNT_BASIC "wound_series_bone_blunt_basic"
|
||||
/// T1-T3 Basic burn wounds. Requires flesh. From: burns.dm
|
||||
#define WOUND_SERIES_FLESH_BURN_BASIC 3
|
||||
/// T1-3 Bleeding puncture wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: pierce.dm
|
||||
#define WOUND_SERIES_FLESH_PUNCTURE_BLEED 4
|
||||
#define WOUND_SERIES_FLESH_BURN_BASIC "wound_series_flesh_burn_basic"
|
||||
/// T1-T3 Bleeding puncture wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: pierce.dm
|
||||
#define WOUND_SERIES_FLESH_PUNCTURE_BLEED "wound_series_flesh_puncture_bleed"
|
||||
/// Generic loss wounds. See loss.dm
|
||||
#define WOUND_SERIES_LOSS_BASIC "wound_series_loss_basic"
|
||||
|
||||
/// A assoc list of (wound typepath -> wound_pregen_data instance). Every wound should have a pregen data.
|
||||
GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate_wound_static_data())
|
||||
|
||||
/// Constructs [GLOB.all_wound_pregen_data] by iterating through a typecache of pregen data, ignoring abstract types, and instantiating the rest.
|
||||
/proc/generate_wound_static_data()
|
||||
RETURN_TYPE(/list/datum/wound_pregen_data)
|
||||
|
||||
var/list/datum/wound_pregen_data/all_pregen_data = list()
|
||||
|
||||
for (var/datum/wound_pregen_data/iterated_path as anything in typecacheof(path = /datum/wound_pregen_data, ignore_root_path = TRUE))
|
||||
if (initial(iterated_path.abstract))
|
||||
continue
|
||||
|
||||
if (!isnull(all_pregen_data[initial(iterated_path.wound_path_to_generate)]))
|
||||
stack_trace("pre-existing pregen data for [initial(iterated_path.wound_path_to_generate)] when [iterated_path] was being considered: [all_pregen_data[initial(iterated_path.wound_path_to_generate)]]. \
|
||||
this is definitely a bug, and is probably because one of the two pregen data have the wrong wound typepath defined. [iterated_path] will not be instantiated")
|
||||
|
||||
continue
|
||||
|
||||
var/datum/wound_pregen_data/pregen_data = new iterated_path
|
||||
all_pregen_data[pregen_data.wound_path_to_generate] = pregen_data
|
||||
|
||||
return all_pregen_data
|
||||
|
||||
// A wound series "collection" is merely a way for us to track what is in what series, and what their types are.
|
||||
// Without this, we have no centralized way to determine what type is in what series outside of iterating over every pregen data.
|
||||
|
||||
/// A branching assoc list of (series -> list(severity -> list(typepath -> weight))). Allows you to say "I want a generic slash wound",
|
||||
/// then "Of severity 2", and get a wound of that description - via get_corresponding_wound_type()
|
||||
/// Series: A generic wound_series, such as WOUND_SERIES_BONE_BLUNT_BASIC
|
||||
/// Severity: Any wounds held within this will be of this severity.
|
||||
/// Typepath, Weight: Merely a pairing of a given typepath to its weight, held for convenience in pickweight.
|
||||
GLOBAL_LIST_INIT(wound_series_collections, generate_wound_series_collection())
|
||||
|
||||
// Series -> severity -> type -> weight
|
||||
/// Generates [wound_series_collections] by iterating through all pregen_data. Refer to the mentioned list for documentation
|
||||
/proc/generate_wound_series_collection()
|
||||
RETURN_TYPE(/list/datum/wound)
|
||||
|
||||
var/list/datum/wound/wound_collection = list()
|
||||
|
||||
for (var/datum/wound/wound_typepath as anything in typecacheof(/datum/wound, FALSE, TRUE))
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_typepath]
|
||||
if (!pregen_data)
|
||||
continue
|
||||
|
||||
if (pregen_data.abstract)
|
||||
stack_trace("somehow, a abstract wound_pregen_data instance ([pregen_data.type]) was instantiated and made it to generate_wound_series_collection()! \
|
||||
i literally have no idea how! please fix this!")
|
||||
continue
|
||||
|
||||
var/series = pregen_data.wound_series
|
||||
var/list/datum/wound/series_list = wound_collection[series]
|
||||
if (isnull(series_list))
|
||||
wound_collection[series] = list()
|
||||
series_list = wound_collection[series]
|
||||
|
||||
var/severity = "[(initial(wound_typepath.severity))]"
|
||||
var/list/datum/wound/severity_list = series_list[severity]
|
||||
if (isnull(severity_list))
|
||||
series_list[severity] = list()
|
||||
severity_list = series_list[severity]
|
||||
|
||||
severity_list[wound_typepath] = pregen_data.weight
|
||||
|
||||
return wound_collection
|
||||
|
||||
/// A branching assoc list of (wounding_type -> list(wound_series)).
|
||||
/// Allows for determining of which wound series are caused by what.
|
||||
GLOBAL_LIST_INIT(wounding_types_to_series, list(
|
||||
WOUND_BLUNT = list(
|
||||
WOUND_SERIES_BONE_BLUNT_BASIC
|
||||
),
|
||||
WOUND_SLASH = list(
|
||||
WOUND_SERIES_FLESH_SLASH_BLEED,
|
||||
),
|
||||
WOUND_BURN = list(
|
||||
WOUND_SERIES_FLESH_BURN_BASIC,
|
||||
),
|
||||
WOUND_PUNCTURE = list(
|
||||
WOUND_SERIES_FLESH_PUNCTURE_BLEED
|
||||
),
|
||||
))
|
||||
|
||||
/// Used in get_corresponding_wound_type(): Will pick the highest severity wound out of severity_min and severity_max
|
||||
#define WOUND_PICK_HIGHEST_SEVERITY 1
|
||||
/// Used in get_corresponding_wound_type(): Will pick the lowest severity wound out of severity_min and severity_max
|
||||
#define WOUND_PICK_LOWEST_SEVERITY 2
|
||||
|
||||
/**
|
||||
* Searches through all wounds for any of proper type, series, and biostate, and then returns a single one via pickweight.
|
||||
* Is able to discern between, say, a flesh slash wound, and a metallic slash wound, and will return the respective one for the provided limb.
|
||||
*
|
||||
* The severity_max and severity_pick_mode args mostly exist in case you want a wound in a series that may not have your ideal severity wound, as it lets you
|
||||
* essentially set a "fallback", where if your ideal wound doesnt exist, it'll still return something, trying to get closest to your ideal severity.
|
||||
*
|
||||
* Generally speaking, if you want a critical/severe/moderate wound, you should set severity_min to WOUND_SEVERITY_MODERATE, severity_max to your ideal wound,
|
||||
* and severity_pick_mode to WOUND_PICK_HIGHEST_SEVERITY - UNLESS you for some reason want the LOWEST severity, in which case you should set
|
||||
* severity_max to the highest wound you're willing to tolerate, and severity_pick_mode to WOUND_PICK_LOWEST_SEVERITY.
|
||||
*
|
||||
* Args:
|
||||
* * list/wounding_types: A list of wounding_types. Only wounds that accept these wound types will be considered.
|
||||
* * obj/item/bodypart/part: The limb we are considering. Extremely important for biostates.
|
||||
* * severity_min: The minimum wound severity we will search for.
|
||||
* * severity_max = severity_min: The maximum wound severity we will search for.
|
||||
* * severity_pick_mode = WOUND_PICK_HIGHEST_SEVERITY: The "pick mode" we will use when considering multiple wounds of acceptable severity. See the above defines.
|
||||
* * random_roll = TRUE: If this is considered a "random" consideration. If true, only wounds that can be randomly generated will be considered.
|
||||
* * duplicates_allowed = FALSE: If exact duplicates of a given wound on part are tolerated. Useful for simply getting a path and not instantiating.
|
||||
* * care_about_existing_wounds = TRUE: If we iterate over wounds to see if any are above or at a given wounds severity, and disregard it if any are. Useful for simply getting a path and not instantiating.
|
||||
*
|
||||
* Returns:
|
||||
* A randomly picked wound typepath meeting all the above criteria and being applicable to the part's biotype - or null if there were none.
|
||||
*/
|
||||
/proc/get_corresponding_wound_type(list/wounding_types, obj/item/bodypart/part, severity_min, severity_max = severity_min, severity_pick_mode = WOUND_PICK_HIGHEST_SEVERITY, random_roll = TRUE, duplicates_allowed = FALSE, care_about_existing_wounds = TRUE)
|
||||
RETURN_TYPE(/datum/wound) // note that just because its set to return this doesnt mean its non-nullable
|
||||
|
||||
var/list/wounding_type_list = list()
|
||||
for (var/wounding_type as anything in wounding_types)
|
||||
wounding_type_list += GLOB.wounding_types_to_series[wounding_type]
|
||||
if (!length(wounding_type_list))
|
||||
return null
|
||||
|
||||
var/list/datum/wound/paths_to_pick_from = list()
|
||||
for (var/series as anything in shuffle(wounding_type_list))
|
||||
var/list/severity_list = GLOB.wound_series_collections[series]
|
||||
if (!length(severity_list))
|
||||
continue
|
||||
|
||||
var/picked_severity
|
||||
for (var/severity_text as anything in shuffle(GLOB.wound_severities_chronological))
|
||||
var/severity = text2num(severity_text)
|
||||
if (severity > severity_min || severity < severity_max)
|
||||
continue
|
||||
|
||||
if (isnull(picked_severity) || ((severity_pick_mode == WOUND_PICK_HIGHEST_SEVERITY && severity > picked_severity) || (severity_pick_mode == WOUND_PICK_LOWEST_SEVERITY && severity < picked_severity)))
|
||||
picked_severity = severity
|
||||
|
||||
var/list/wound_typepaths = severity_list["[picked_severity]"]
|
||||
if (!length(wound_typepaths))
|
||||
continue
|
||||
|
||||
for (var/datum/wound/iterated_path as anything in wound_typepaths)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[iterated_path]
|
||||
if (pregen_data.can_be_applied_to(part, wounding_types, random_roll = random_roll, duplicates_allowed = duplicates_allowed, care_about_existing_wounds = care_about_existing_wounds))
|
||||
paths_to_pick_from[iterated_path] = wound_typepaths[iterated_path]
|
||||
|
||||
return pick_weight(paths_to_pick_from) // we found our winners!
|
||||
|
||||
/// Assoc list of biotype -> ideal scar file to be used and grab stuff from.
|
||||
GLOBAL_LIST_INIT(biotypes_to_scar_file, list(
|
||||
"[BIO_FLESH]" = FLESH_SCAR_FILE,
|
||||
"[BIO_BONE]" = BONE_SCAR_FILE
|
||||
))
|
||||
|
||||
// ~burn wound infection defines
|
||||
// Thresholds for infection for burn wounds, once infestation hits each threshold, things get steadily worse
|
||||
@@ -125,23 +306,25 @@ GLOBAL_LIST_INIT(bio_state_states, list(
|
||||
|
||||
|
||||
// ~mangling defines
|
||||
// With the wounds pt. 2 update, general dismemberment now requires 2 things for a limb to be dismemberable (bone only creatures just need the second):
|
||||
// 1. Flesh is mangled: A critical slash or pierce wound on that limb
|
||||
// 2. Bone is mangled: At least a severe bone wound on that limb
|
||||
// see [/obj/item/bodypart/proc/get_mangled_state] for more information
|
||||
// With the wounds pt. 2 update, general dismemberment now requires 2 things for a limb to be dismemberable (exterior/bone only creatures just need the second):
|
||||
// 1. Exterior is mangled: A critical slash or pierce wound on that limb
|
||||
// 2. Interior is mangled: At least a severe bone wound on that limb
|
||||
// Lack of exterior or interior count as mangled exterior/interior respectively
|
||||
// see [/obj/item/bodypart/proc/get_mangled_state] for more information, as well as GLOB.bio_state_anatomy
|
||||
#define BODYPART_MANGLED_NONE NONE
|
||||
#define BODYPART_MANGLED_BONE (1<<0)
|
||||
#define BODYPART_MANGLED_FLESH (1<<1)
|
||||
#define BODYPART_MANGLED_BOTH (BODYPART_MANGLED_BONE | BODYPART_MANGLED_FLESH)
|
||||
#define BODYPART_MANGLED_INTERIOR (1<<0)
|
||||
#define BODYPART_MANGLED_EXTERIOR (1<<1)
|
||||
#define BODYPART_MANGLED_BOTH (BODYPART_MANGLED_INTERIOR | BODYPART_MANGLED_EXTERIOR)
|
||||
|
||||
// ~wound flag defines
|
||||
/// If having this wound counts as mangled flesh for dismemberment
|
||||
#define MANGLES_FLESH (1<<0)
|
||||
/// If having this wound counts as mangled bone for dismemberment
|
||||
#define MANGLES_BONE (1<<1)
|
||||
/// If having this wound counts as mangled exterior for dismemberment
|
||||
#define MANGLES_EXTERIOR (1<<0)
|
||||
/// If having this wound counts as mangled interior for dismemberment
|
||||
#define MANGLES_INTERIOR (1<<1)
|
||||
/// If this wound marks the limb as being allowed to have gauze applied
|
||||
#define ACCEPTS_GAUZE (1<<2)
|
||||
|
||||
/// If this wound allows the victim to grasp it
|
||||
#define CAN_BE_GRASPED (1<<3)
|
||||
|
||||
// ~scar persistence defines
|
||||
// The following are the order placements for persistent scar save formats
|
||||
|
||||
@@ -91,11 +91,8 @@
|
||||
log_combat(user, H, "wounded via throat slitting", source)
|
||||
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec
|
||||
var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(slit_throat)
|
||||
var/datum/wound/slash/flesh/critical/screaming_through_a_slit_throat = new
|
||||
if (!screaming_through_a_slit_throat.apply_wound(slit_throat, wound_source = "throat slit"))
|
||||
qdel(screaming_through_a_slit_throat)
|
||||
H.apply_status_effect(/datum/status_effect/neck_slice)
|
||||
if (H.cause_wound_of_type_and_severity(WOUND_SLASH, slit_throat, WOUND_SEVERITY_CRITICAL))
|
||||
H.apply_status_effect(/datum/status_effect/neck_slice)
|
||||
|
||||
/**
|
||||
* Handles a user butchering a target
|
||||
|
||||
@@ -93,7 +93,8 @@
|
||||
if(harmful)
|
||||
victim.throw_alert(ALERT_EMBEDDED_OBJECT, /atom/movable/screen/alert/embeddedobject)
|
||||
playsound(victim,'sound/weapons/bladeslice.ogg', 40)
|
||||
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
|
||||
if (limb.can_bleed())
|
||||
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
|
||||
damage += weapon.w_class * impact_pain_mult
|
||||
victim.add_mood_event("embedded", /datum/mood_event/embedded)
|
||||
|
||||
@@ -303,7 +304,7 @@
|
||||
return
|
||||
var/damage = weapon.w_class * remove_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage * 1.5, sharpness=SHARP_EDGED) // Performs exit wounds and flings the user to the caster if nearby
|
||||
limb.force_wound_upwards(/datum/wound/pierce/bleed/moderate)
|
||||
victim.cause_wound_of_type_and_severity(WOUND_PIERCE, limb, WOUND_SEVERITY_MODERATE)
|
||||
victim.adjustStaminaLoss(pain_stam_pct * damage)
|
||||
playsound(get_turf(victim), 'sound/effects/wounds/blood2.ogg', 50, TRUE)
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@
|
||||
var/damage_dealt = wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE]
|
||||
var/w_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS]
|
||||
var/bw_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS]
|
||||
var/wound_type = (initial(P.damage_type) == BRUTE) ? WOUND_BLUNT : WOUND_BURN // sharpness is handled in the wound rolling
|
||||
var/wounding_type = (initial(P.damage_type) == BRUTE) ? WOUND_BLUNT : WOUND_BURN // sharpness is handled in the wound rolling
|
||||
wound_info_by_part -= hit_part
|
||||
|
||||
// technically this only checks armor worn the moment that all the pellets resolve rather than as each one hits you,
|
||||
@@ -320,7 +320,7 @@
|
||||
armor_factor *= ARMOR_WEAKENED_MULTIPLIER
|
||||
damage_dealt *= max(0, 1 - armor_factor*0.01)
|
||||
|
||||
hit_part.painless_wound_roll(wound_type, damage_dealt, w_bonus, bw_bonus, initial(P.sharpness))
|
||||
hit_part.painless_wound_roll(wounding_type, damage_dealt, w_bonus, bw_bonus, initial(P.sharpness))
|
||||
|
||||
var/limb_hit_text = ""
|
||||
if(hit_part)
|
||||
|
||||
@@ -80,9 +80,11 @@
|
||||
|
||||
if(do_after(attacker, 3 SECONDS, target, interaction_key = weapon))
|
||||
attacker.visible_message(span_warning("[attacker] swings [attacker.p_their()] [weapon] at [target]'s kneecaps!"), span_danger("You swing \the [weapon] at [target]'s kneecaps!"))
|
||||
var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe
|
||||
var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical
|
||||
leg.receive_damage(brute = weapon.force, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10), damage_source = "kneecapping")
|
||||
|
||||
var/min_wound = leg.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 30, wound_source = weapon)
|
||||
var/max_wound = leg.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 50, wound_source = weapon)
|
||||
|
||||
leg.receive_damage(brute = weapon.force, wound_bonus = rand(min_wound, max_wound + 10), damage_source = "kneecapping")
|
||||
target.emote("scream")
|
||||
log_combat(attacker, target, "broke the kneecaps of", weapon)
|
||||
target.update_damage_overlays()
|
||||
|
||||
@@ -63,13 +63,19 @@
|
||||
*arg1 is the arm to evaluate damage of and possibly break.
|
||||
*/
|
||||
/datum/mutation/human/hulk/proc/break_an_arm(obj/item/bodypart/arm)
|
||||
var/severity
|
||||
switch(arm.brute_dam)
|
||||
if(45 to 50)
|
||||
arm.force_wound_upwards(/datum/wound/blunt/bone/critical, wound_source = "hulk smashing")
|
||||
severity = WOUND_SEVERITY_CRITICAL
|
||||
if(41 to 45)
|
||||
arm.force_wound_upwards(/datum/wound/blunt/bone/severe, wound_source = "hulk smashing")
|
||||
severity = WOUND_SEVERITY_SEVERE
|
||||
if(35 to 41)
|
||||
arm.force_wound_upwards(/datum/wound/blunt/bone/moderate, wound_source = "hulk smashing")
|
||||
severity = WOUND_SEVERITY_MODERATE
|
||||
|
||||
if (isnull(severity))
|
||||
return
|
||||
|
||||
owner.cause_wound_of_type_and_severity(WOUND_BLUNT, arm, severity, wound_source = "hulk smashing")
|
||||
|
||||
/datum/mutation/human/hulk/on_life(seconds_per_tick, times_fired)
|
||||
if(owner.health < owner.crit_threshold)
|
||||
|
||||
@@ -215,8 +215,8 @@
|
||||
if(iscarbon(victim))
|
||||
var/mob/living/carbon/carbon_victim = victim
|
||||
var/obj/item/bodypart/chest = carbon_victim.get_bodypart(BODY_ZONE_CHEST)
|
||||
if(chest)
|
||||
chest.force_wound_upwards(/datum/wound/blunt/bone/severe, wound_source = "human force to the chest")
|
||||
carbon_victim.cause_wound_of_type_and_severity(WOUND_BLUNT, chest, WOUND_SEVERITY_SEVERE, wound_source = "human force to the chest")
|
||||
|
||||
playsound(owner, 'sound/creatures/crack_vomit.ogg', 120, extrarange = 5, falloff_exponent = 4)
|
||||
vomit_up()
|
||||
|
||||
|
||||
@@ -408,7 +408,9 @@
|
||||
|
||||
var/still_bleeding = FALSE
|
||||
for(var/datum/wound/bleeding_thing as anything in throat.wounds)
|
||||
if(bleeding_thing.wound_type == WOUND_SLASH && bleeding_thing.severity > WOUND_SEVERITY_MODERATE)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[bleeding_thing.type]
|
||||
|
||||
if(pregen_data.wounding_types_valid(list(WOUND_SLASH)) && bleeding_thing.severity > WOUND_SEVERITY_MODERATE && bleeding_thing.blood_flow > 0)
|
||||
still_bleeding = TRUE
|
||||
break
|
||||
if(!still_bleeding)
|
||||
|
||||
@@ -54,11 +54,11 @@
|
||||
right = C.get_bodypart(BODY_ZONE_R_LEG)
|
||||
update_limp()
|
||||
RegisterSignal(C, COMSIG_MOVABLE_MOVED, PROC_REF(check_step))
|
||||
RegisterSignals(C, list(COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB), PROC_REF(update_limp))
|
||||
RegisterSignals(C, list(COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_POST_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB), PROC_REF(update_limp))
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/limp/on_remove()
|
||||
UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB))
|
||||
UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_POST_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB))
|
||||
|
||||
/atom/movable/screen/alert/status_effect/limp
|
||||
name = "Limping"
|
||||
@@ -165,37 +165,25 @@
|
||||
if(W == linked_wound)
|
||||
qdel(src)
|
||||
|
||||
|
||||
// bones
|
||||
/datum/status_effect/wound/blunt/bone
|
||||
|
||||
/datum/status_effect/wound/blunt/bone/on_apply()
|
||||
. = ..()
|
||||
RegisterSignal(owner, COMSIG_MOB_SWAP_HANDS, PROC_REF(on_swap_hands))
|
||||
on_swap_hands()
|
||||
|
||||
/datum/status_effect/wound/blunt/bone/on_remove()
|
||||
. = ..()
|
||||
UnregisterSignal(owner, COMSIG_MOB_SWAP_HANDS)
|
||||
var/mob/living/carbon/wound_owner = owner
|
||||
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound)
|
||||
|
||||
/datum/status_effect/wound/blunt/bone/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/blunt_wound, (linked_wound.interaction_efficiency_penalty - 1))
|
||||
else
|
||||
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound)
|
||||
|
||||
/datum/status_effect/wound/blunt/bone/nextmove_modifier()
|
||||
/datum/status_effect/wound/nextmove_modifier()
|
||||
var/mob/living/carbon/C = owner
|
||||
|
||||
if(C.get_active_hand() == linked_limb)
|
||||
return linked_wound.interaction_efficiency_penalty
|
||||
return linked_wound.get_action_delay_mult()
|
||||
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/wound/nextmove_adjust()
|
||||
var/mob/living/carbon/C = owner
|
||||
|
||||
if(C.get_active_hand() == linked_limb)
|
||||
return linked_wound.get_action_delay_increment()
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
// bones
|
||||
/datum/status_effect/wound/blunt/bone
|
||||
|
||||
// blunt
|
||||
/datum/status_effect/wound/blunt/bone/moderate
|
||||
|
||||
@@ -2,28 +2,6 @@
|
||||
// For example: You can make a pregen_data subtype for your wound that overrides can_be_applied_to to only apply to specifically slimeperson limbs.
|
||||
// Without this, youre stuck with very static initial variables.
|
||||
|
||||
GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate_wound_static_data())
|
||||
|
||||
/proc/generate_wound_static_data()
|
||||
RETURN_TYPE(/list/datum/wound_pregen_data)
|
||||
|
||||
var/list/datum/wound_pregen_data/data = list()
|
||||
|
||||
for (var/datum/wound_pregen_data/path as anything in typecacheof(path = /datum/wound_pregen_data, ignore_root_path = TRUE))
|
||||
if (initial(path.abstract))
|
||||
continue
|
||||
|
||||
if (!isnull(data[initial(path.wound_path_to_generate)]))
|
||||
stack_trace("pre-existing pregen data for [initial(path.wound_path_to_generate)] when [path] was being considered: [data[initial(path.wound_path_to_generate)]]. \
|
||||
this is definitely a bug, and is probably because one of the two pregen data have the wrong wound typepath defined. [path] will not be instantiated")
|
||||
|
||||
continue
|
||||
|
||||
var/datum/wound_pregen_data/pregen_data = new path
|
||||
data[pregen_data.wound_path_to_generate] = pregen_data
|
||||
|
||||
return data
|
||||
|
||||
/// A singleton datum that holds pre-gen and static data about a wound. Each wound datum should have a corresponding wound_pregen_data.
|
||||
/datum/wound_pregen_data
|
||||
/// The typepath of the wound we will be handling and storing data of. NECESSARY IF THIS IS A NON-ABSTRACT TYPE!
|
||||
@@ -38,7 +16,7 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate
|
||||
/// A list of biostates a limb must have to receive our wound, in wounds.dm.
|
||||
var/required_limb_biostate
|
||||
/// If false, we will check if the limb has all of our required biostates instead of just any.
|
||||
var/check_for_any = FALSE
|
||||
var/require_any_biostate = FALSE
|
||||
|
||||
/// If false, we will iterate through wounds on a given limb, and if any match our type, we wont add our wound.
|
||||
var/duplicates_allowed = FALSE
|
||||
@@ -48,6 +26,30 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate
|
||||
|
||||
/// A list of bodyzones we are applicable to.
|
||||
var/list/viable_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
/// The types of attack that can generate this wound. E.g. WOUND_SLASH = A sharp attack can cause this, WOUND_BLUNT = an attack with no sharpness/an attack with sharpness against a limb with mangled exterior can cause this.
|
||||
var/list/required_wounding_types
|
||||
/// If true, this wound can only be generated by all [required_wounding_types] at once, not just any.
|
||||
var/match_all_wounding_types = FALSE
|
||||
|
||||
/// The weight that will be used if, by the end of wound selection, there are multiple valid wounds. This will be inserted into pick_weight, so use integers.
|
||||
var/weight = WOUND_DEFAULT_WEIGHT
|
||||
|
||||
/// The minimum injury roll a attack must get to generate us. Affected by our wound's threshold_penalty and series_threshold_penalty, as well as the attack's wound_bonus. See check_wounding_mods().
|
||||
var/threshold_minimum
|
||||
|
||||
/// The series of wounds this is in. See wounds.dm (the defines file) for a more detailed explanation - but tldr is that no 2 wounds of the same series can be on a limb.
|
||||
var/wound_series
|
||||
|
||||
/// If true, we will attempt to, during a random wound roll, overpower and remove other wound typepaths from the possible wounds list using [competition_mode] and [overpower_wounds_of_even_severity].
|
||||
var/compete_for_wounding = TRUE
|
||||
/// The competition mode with which we will remove other wounds from a possible wound roll assuming [compete_for_wounding] is TRUE. See wounds.dm, the defines file, for more information on what these do.
|
||||
var/competition_mode = WOUND_COMPETITION_OVERPOWER_LESSERS
|
||||
/// If this and [compete_for_wounding] is true, we will remove wounds of an even severity to us during a random wound roll.
|
||||
var/overpower_wounds_of_even_severity = FALSE
|
||||
|
||||
/// A list of BIO_ defines that will be iterated over in order to determine the scar file our wound will generate.
|
||||
/// Use generate_scar_priorities to create a custom list.
|
||||
var/list/scar_priorities
|
||||
|
||||
/datum/wound_pregen_data/New()
|
||||
. = ..()
|
||||
@@ -58,21 +60,33 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate
|
||||
if (wound_path_to_generate == null)
|
||||
stack_trace("wound_path_to_generate null - please set it! occured on: [src.type]")
|
||||
|
||||
scar_priorities = generate_scar_priorities()
|
||||
|
||||
/// Should return a list of BIO_ biostate priorities, in order. See [scar_priorities] for further documentation.
|
||||
/datum/wound_pregen_data/proc/generate_scar_priorities()
|
||||
RETURN_TYPE(/list)
|
||||
|
||||
var/list/priorities = list(
|
||||
"[BIO_FLESH]",
|
||||
"[BIO_BONE]",
|
||||
)
|
||||
|
||||
return priorities
|
||||
|
||||
// this proc is the primary reason this datum exists - a singleton instance so we can always run this proc even without the wound existing
|
||||
/**
|
||||
* Args:
|
||||
* * obj/item/bodypart/limb: The limb we are considering.
|
||||
* * wound_type: The type of the "wound acquisition attempt". Example: A slashing attack cannot proc a blunt wound, so wound_type = WOUND_SLASH would
|
||||
* fail if we expect WOUND_BLUNT. Defaults to the wound type we expect.
|
||||
* * list/suggested_wounding_types: The wounding types to be checked against the wounding types we require. Defaults to required_wounding_types.
|
||||
* * datum/wound/old_wound: If we would replace a wound, this would be said wound. Nullable.
|
||||
* * random_roll = FALSE: If this is in the context of a random wound generation, and this wound wasn't specifically checked.
|
||||
*
|
||||
* Returns:
|
||||
* FALSE if the limb cannot be wounded, if wound_type is not ours, if we have a higher severity wound already in our series,
|
||||
* FALSE if the limb cannot be wounded, if the wounding types dont match ours (via wounding_types_valid()), if we have a higher severity wound already in our series,
|
||||
* if we have a biotype mismatch, if the limb isnt in a viable zone, or if theres any duplicate wound types.
|
||||
* TRUE otherwise.
|
||||
*/
|
||||
/datum/wound_pregen_data/proc/can_be_applied_to(obj/item/bodypart/limb, wound_type = initial(wound_path_to_generate.wound_type), datum/wound/old_wound, random_roll = FALSE)
|
||||
/datum/wound_pregen_data/proc/can_be_applied_to(obj/item/bodypart/limb, list/suggested_wounding_types = required_wounding_types, datum/wound/old_wound, random_roll = FALSE, duplicates_allowed = src.duplicates_allowed, care_about_existing_wounds = TRUE)
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
|
||||
if (!istype(limb) || !limb.owner)
|
||||
@@ -84,11 +98,13 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate
|
||||
if (HAS_TRAIT(limb.owner, TRAIT_NEVER_WOUNDED) || (limb.owner.status_flags & GODMODE))
|
||||
return FALSE
|
||||
|
||||
if (wound_type != initial(wound_path_to_generate.wound_type))
|
||||
return
|
||||
else
|
||||
if (!wounding_types_valid(suggested_wounding_types))
|
||||
return FALSE
|
||||
|
||||
if (care_about_existing_wounds)
|
||||
for (var/datum/wound/preexisting_wound as anything in limb.wounds)
|
||||
if (preexisting_wound.wound_series == initial(wound_path_to_generate.wound_series))
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[preexisting_wound.type]
|
||||
if (pregen_data.wound_series == wound_series)
|
||||
if (preexisting_wound.severity >= initial(wound_path_to_generate.severity))
|
||||
return FALSE
|
||||
|
||||
@@ -111,7 +127,7 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate
|
||||
|
||||
/// Returns true if we have the given biostates, or any biostate in it if check_for_any is true. False otherwise.
|
||||
/datum/wound_pregen_data/proc/biostate_valid(biostate)
|
||||
if (check_for_any)
|
||||
if (require_any_biostate)
|
||||
if (!(biostate & required_limb_biostate))
|
||||
return FALSE
|
||||
else if (!((biostate & required_limb_biostate) == required_limb_biostate)) // check for all
|
||||
@@ -119,6 +135,50 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* A simple getter for [weight], with arguments supplied to allow custom behavior.
|
||||
*
|
||||
* Args:
|
||||
* * obj/item/bodypart/limb: The limb we are contemplating being added to. Nullable.
|
||||
* * woundtype: The woundtype of the assumed attack that would generate us. Nullable.
|
||||
* * damage: The raw damage that would cause us. Nullable.
|
||||
* * attack_direction: The direction of the attack that'd cause us. Nullable.
|
||||
* * damage_source: The entity that would cause us. Nullable.
|
||||
*
|
||||
* Returns:
|
||||
* Our weight.
|
||||
*/
|
||||
/datum/wound_pregen_data/proc/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source)
|
||||
return weight
|
||||
|
||||
/// Returns TRUE if we use WOUND_ALL, or we require all types and have all/if we require any and have any, FALSE otherwise.
|
||||
/datum/wound_pregen_data/proc/wounding_types_valid(list/suggested_wounding_types)
|
||||
if (WOUND_ALL in required_wounding_types)
|
||||
return TRUE
|
||||
if (!length(suggested_wounding_types))
|
||||
return FALSE
|
||||
|
||||
for (var/iter_wounding_type as anything in suggested_wounding_types)
|
||||
if (!(iter_wounding_type in required_wounding_types))
|
||||
if (match_all_wounding_types)
|
||||
return FALSE
|
||||
else
|
||||
if (!match_all_wounding_types)
|
||||
return TRUE
|
||||
|
||||
return match_all_wounding_types // if we get here, we've matched everything
|
||||
|
||||
/**
|
||||
* A simple getter for [threshold_minimum], with arguments supplied to allow custom behavior.
|
||||
*
|
||||
* Args:
|
||||
* * obj/item/bodypart/part: The limb we are contemplating being added to.
|
||||
* * attack_direction: The direction of the attack that'd generate us. Nullable.
|
||||
* * damage_source: The source of the damage that'd cause us. Nullable.
|
||||
*/
|
||||
/datum/wound_pregen_data/proc/get_threshold_for(obj/item/bodypart/part, attack_direction, damage_source)
|
||||
return threshold_minimum
|
||||
|
||||
/// Returns a new instance of our wound datum.
|
||||
/datum/wound_pregen_data/proc/generate_instance(obj/item/bodypart/limb, ...)
|
||||
RETURN_TYPE(/datum/wound)
|
||||
@@ -126,10 +186,13 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate
|
||||
return new wound_path_to_generate
|
||||
|
||||
/datum/wound_pregen_data/Destroy(force, ...)
|
||||
stack_trace("[src], a singleton wound pregen data instance, was destroyed! This should not happen!")
|
||||
var/error_message = "[src], a singleton wound pregen data instance, was destroyed! This should not happen!"
|
||||
if (force)
|
||||
error_message += " NOTE: This Destroy() was called with force == TRUE. This instance will be deleted and replaced with a new one."
|
||||
stack_trace(error_message)
|
||||
|
||||
if (!force)
|
||||
return
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
. = ..()
|
||||
|
||||
|
||||
+224
-50
@@ -16,6 +16,11 @@
|
||||
|
||||
#define WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS 15
|
||||
|
||||
// Applied into wounds when they're scanned with the wound analyzer, halves time to treat them manually.
|
||||
#define TRAIT_WOUND_SCANNED "wound_scanned"
|
||||
// I dunno lol
|
||||
#define ANALYZER_TRAIT "analyzer_trait"
|
||||
|
||||
/datum/wound
|
||||
/// What it's named
|
||||
var/name = "Wound"
|
||||
@@ -29,8 +34,8 @@
|
||||
/// If this wound can generate a scar.
|
||||
var/can_scar = TRUE
|
||||
|
||||
/// The file we take our scar descriptions from.
|
||||
var/scar_file
|
||||
/// The default file we take our scar descriptions from, if we fail to get the ideal file.
|
||||
var/default_scar_file
|
||||
|
||||
/// needed for "your arm has a compound fracture" vs "your arm has some third degree burns"
|
||||
var/a_or_from = "a"
|
||||
@@ -43,10 +48,6 @@
|
||||
|
||||
/// Either WOUND_SEVERITY_TRIVIAL (meme wounds like stubbed toe), WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, or WOUND_SEVERITY_CRITICAL (or maybe WOUND_SEVERITY_LOSS)
|
||||
var/severity = WOUND_SEVERITY_MODERATE
|
||||
/// The type of attack that can generate this wound. E.g. WOUND_SLASH = A sword can cause us, or WOUND_BLUNT = a hammer can cause us/a sword attacking mangled flesh.
|
||||
var/wound_type
|
||||
/// The series of wounds this is in. See wounds.dm (the defines file) for a more detailed explanation - but tldr is that no 2 wounds of the same series can be on a limb.
|
||||
var/wound_series
|
||||
|
||||
/// Who owns the body part that we're wounding
|
||||
var/mob/living/carbon/victim = null
|
||||
@@ -57,8 +58,8 @@
|
||||
var/list/treatable_by
|
||||
/// Specific items such as bandages or sutures that can try directly treating this wound only if the user has the victim in an aggressive grab or higher
|
||||
var/list/treatable_by_grabbed
|
||||
/// Tools with the specified tool flag will also be able to try directly treating this wound
|
||||
var/treatable_tool
|
||||
/// Any tools with any of the flags in this list will be usable to try directly treating this wound
|
||||
var/list/treatable_tools
|
||||
/// How long it will take to treat this wound with a standard effective tool, assuming it doesn't need surgery
|
||||
var/base_treat_time = 5 SECONDS
|
||||
|
||||
@@ -72,13 +73,11 @@
|
||||
var/limp_chance
|
||||
/// How much we're contributing to this limb's bleed_rate
|
||||
var/blood_flow
|
||||
/// Essentially, keeps track of whether or not this wound is capable of bleeding (in case the owner has the NOBLOOD species trait)
|
||||
var/no_bleeding = FALSE
|
||||
|
||||
/// The minimum we need to roll on [/obj/item/bodypart/proc/check_wounding] to begin suffering this wound, see check_wounding_mods() for more
|
||||
var/threshold_minimum
|
||||
/// How much having this wound will add to all future check_wounding() rolls on this limb, to allow progression to worse injuries with repeated damage
|
||||
var/threshold_penalty
|
||||
/// How much having this wound will add to all future check_wounding() rolls on this limb, but only for wounds of its own series
|
||||
var/series_threshold_penalty = 0
|
||||
/// If we need to process each life tick
|
||||
var/processes = FALSE
|
||||
|
||||
@@ -89,9 +88,12 @@
|
||||
var/status_effect_type
|
||||
/// If we're operating on this wound and it gets healed, we'll nix the surgery too
|
||||
var/datum/surgery/attached_surgery
|
||||
/// if you're a lazy git and just throw them in cryo, the wound will go away after accumulating severity * 25 power
|
||||
/// if you're a lazy git and just throw them in cryo, the wound will go away after accumulating severity * [base_xadone_progress_to_qdel] power
|
||||
var/cryo_progress
|
||||
|
||||
/// The base amount of [cryo_progress] required to have ourselves fully healed by cryo. Multiplied against severity.
|
||||
var/base_xadone_progress_to_qdel = 33
|
||||
|
||||
/// What kind of scars this wound will create description wise once healed
|
||||
var/scar_keyword = "generic"
|
||||
/// If we've already tried scarring while removing (remove_wound can be called twice in a del chain, let's be nice to our code yeah?) TODO: make this cleaner
|
||||
@@ -102,17 +104,66 @@
|
||||
/// What flags apply to this wound
|
||||
var/wound_flags = (ACCEPTS_GAUZE)
|
||||
|
||||
/// The unique ID of our wound for use with [actionspeed_mod]. Defaults to REF(src).
|
||||
var/unique_id
|
||||
/// The actionspeed modifier we will use in case we are on the arms and have a interaction penalty. Qdelled on destroy.
|
||||
var/datum/actionspeed_modifier/wound_interaction_inefficiency/actionspeed_mod
|
||||
|
||||
/datum/wound/New()
|
||||
. = ..()
|
||||
|
||||
unique_id = generate_unique_id()
|
||||
update_actionspeed_modifier()
|
||||
|
||||
/datum/wound/Destroy()
|
||||
if(attached_surgery)
|
||||
QDEL_NULL(attached_surgery)
|
||||
QDEL_NULL(attached_surgery)
|
||||
if (limb)
|
||||
remove_wound()
|
||||
|
||||
QDEL_NULL(actionspeed_mod)
|
||||
|
||||
return ..()
|
||||
|
||||
// Applied into wounds when they're scanned with the wound analyzer, halves time to treat them manually.
|
||||
#define TRAIT_WOUND_SCANNED "wound_scanned"
|
||||
// I dunno lol
|
||||
#define ANALYZER_TRAIT "analyzer_trait"
|
||||
/// If we should have an actionspeed_mod, ensures we do and updates its slowdown. Otherwise, ensures we dont have one
|
||||
/// by qdeleting any existing modifier.
|
||||
/datum/wound/proc/update_actionspeed_modifier()
|
||||
if (should_have_actionspeed_modifier())
|
||||
if (!actionspeed_mod)
|
||||
generate_actionspeed_modifier()
|
||||
actionspeed_mod.multiplicative_slowdown = get_effective_actionspeed_modifier()
|
||||
victim?.update_actionspeed()
|
||||
else
|
||||
remove_actionspeed_modifier()
|
||||
|
||||
/// Returns TRUE if we have an interaction_efficiency_penalty, and if we are on the arms, FALSE otherwise.
|
||||
/datum/wound/proc/should_have_actionspeed_modifier()
|
||||
return (limb && victim && (limb.body_zone == BODY_ZONE_L_ARM || limb.body_zone == BODY_ZONE_R_ARM) && interaction_efficiency_penalty != 0)
|
||||
|
||||
/// If we have no actionspeed_mod, generates a new one with our unique ID, sets actionspeed_mod to it, then returns it.
|
||||
/datum/wound/proc/generate_actionspeed_modifier()
|
||||
RETURN_TYPE(/datum/actionspeed_modifier)
|
||||
|
||||
if (actionspeed_mod)
|
||||
return actionspeed_mod
|
||||
|
||||
var/datum/actionspeed_modifier/wound_interaction_inefficiency/new_modifier = new /datum/actionspeed_modifier/wound_interaction_inefficiency(unique_id, src)
|
||||
new_modifier.multiplicative_slowdown = get_effective_actionspeed_modifier()
|
||||
victim?.add_actionspeed_modifier(new_modifier)
|
||||
|
||||
actionspeed_mod = new_modifier
|
||||
return actionspeed_mod
|
||||
|
||||
/// If we have an actionspeed_mod, qdels it and sets our ref of it to null.
|
||||
/datum/wound/proc/remove_actionspeed_modifier()
|
||||
if (!actionspeed_mod)
|
||||
return
|
||||
|
||||
victim?.remove_actionspeed_modifier(actionspeed_mod)
|
||||
QDEL_NULL(actionspeed_mod)
|
||||
|
||||
/// Generates the ID we use for [unique_id], which is also set as our actionspeed mod's ID
|
||||
/datum/wound/proc/generate_unique_id()
|
||||
return REF(src) // unique, cannot change, a perfect id
|
||||
|
||||
/**
|
||||
* apply_wound() is used once a wound type is instantiated to assign it to a bodypart, and actually come into play.
|
||||
@@ -142,7 +193,6 @@
|
||||
set_limb(L)
|
||||
LAZYADD(victim.all_wounds, src)
|
||||
LAZYADD(limb.wounds, src)
|
||||
no_bleeding = HAS_TRAIT(victim, TRAIT_NOBLOOD)
|
||||
update_descriptions()
|
||||
limb.update_wounds()
|
||||
if(status_effect_type)
|
||||
@@ -162,7 +212,7 @@
|
||||
var/msg = span_danger("[victim]'s [limb.plaintext_zone] [occur_text]!")
|
||||
var/vis_dist = COMBAT_MESSAGE_RANGE
|
||||
|
||||
if(severity != WOUND_SEVERITY_MODERATE)
|
||||
if(severity > WOUND_SEVERITY_MODERATE)
|
||||
msg = "<b>[msg]</b>"
|
||||
vis_dist = DEFAULT_MESSAGE_RANGE
|
||||
|
||||
@@ -183,7 +233,7 @@
|
||||
// We assume we aren't being randomly applied - we have no reason to believe we are
|
||||
// And, besides, if we were, you could just as easily check our pregen data rather than run this proc
|
||||
// Generally speaking this proc is called in apply_wound, which is called when the caller is already confidant in its ability to be applied
|
||||
return pregen_data.can_be_applied_to(L, wound_type, old_wound)
|
||||
return pregen_data.can_be_applied_to(L, old_wound = old_wound)
|
||||
|
||||
/// Returns the zones we can be applied to.
|
||||
/datum/wound/proc/get_viable_zones()
|
||||
@@ -205,13 +255,66 @@
|
||||
SIGNAL_HANDLER
|
||||
set_victim(null)
|
||||
|
||||
/// Setter for [victim]. Should completely transfer signals, attributes, etc. To the new victim - if there is any, as it can be null.
|
||||
/datum/wound/proc/set_victim(new_victim)
|
||||
if(victim)
|
||||
UnregisterSignal(victim, list(COMSIG_QDELETING, COMSIG_MOB_SWAP_HANDS, COMSIG_CARBON_POST_REMOVE_LIMB, COMSIG_CARBON_POST_ATTACH_LIMB))
|
||||
UnregisterSignal(victim, COMSIG_QDELETING)
|
||||
UnregisterSignal(victim, COMSIG_MOB_SWAP_HANDS)
|
||||
UnregisterSignal(victim, COMSIG_CARBON_POST_REMOVE_LIMB)
|
||||
if (actionspeed_mod)
|
||||
victim.remove_actionspeed_modifier(actionspeed_mod) // no need to qdelete it, just remove it from our victim
|
||||
|
||||
remove_wound_from_victim()
|
||||
victim = new_victim
|
||||
if(victim)
|
||||
RegisterSignal(victim, COMSIG_QDELETING, PROC_REF(null_victim))
|
||||
RegisterSignals(victim, list(COMSIG_MOB_SWAP_HANDS, COMSIG_CARBON_POST_REMOVE_LIMB, COMSIG_CARBON_POST_ATTACH_LIMB), PROC_REF(add_or_remove_actionspeed_mod))
|
||||
|
||||
if (limb)
|
||||
start_limping_if_we_should() // the status effect already handles removing itself
|
||||
add_or_remove_actionspeed_mod()
|
||||
|
||||
/// Proc called to change the variable `limb` and react to the event.
|
||||
/datum/wound/proc/set_limb(obj/item/bodypart/new_value, replaced = FALSE)
|
||||
if(limb == new_value)
|
||||
return FALSE //Limb can either be a reference to something or `null`. Returning the number variable makes it clear no change was made.
|
||||
. = limb
|
||||
if(limb) // if we're nulling limb, we're basically detaching from it, so we should remove ourselves in that case
|
||||
UnregisterSignal(limb, COMSIG_QDELETING)
|
||||
UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED))
|
||||
LAZYREMOVE(limb.wounds, src)
|
||||
limb.update_wounds(replaced)
|
||||
if (disabling)
|
||||
limb.remove_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src))
|
||||
|
||||
limb = new_value
|
||||
|
||||
// POST-CHANGE
|
||||
|
||||
if (limb)
|
||||
RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(source_died))
|
||||
RegisterSignals(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED), PROC_REF(gauze_state_changed))
|
||||
if (disabling)
|
||||
limb.add_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src))
|
||||
|
||||
if (victim)
|
||||
start_limping_if_we_should() // the status effect already handles removing itself
|
||||
add_or_remove_actionspeed_mod()
|
||||
|
||||
update_inefficiencies()
|
||||
|
||||
/datum/wound/proc/add_or_remove_actionspeed_mod()
|
||||
update_actionspeed_modifier()
|
||||
if (actionspeed_mod)
|
||||
if(victim.get_active_hand() == limb)
|
||||
victim.add_actionspeed_modifier(actionspeed_mod, TRUE)
|
||||
else
|
||||
victim.remove_actionspeed_modifier(actionspeed_mod)
|
||||
|
||||
/datum/wound/proc/start_limping_if_we_should()
|
||||
if ((limb.body_zone == BODY_ZONE_L_LEG || limb.body_zone == BODY_ZONE_R_LEG) && limp_slowdown > 0 && limp_chance > 0)
|
||||
victim.apply_status_effect(/datum/status_effect/limp)
|
||||
|
||||
/datum/wound/proc/source_died()
|
||||
SIGNAL_HANDLER
|
||||
@@ -220,18 +323,27 @@
|
||||
/// Remove the wound from whatever it's afflicting, and cleans up whateverstatus effects it had or modifiers it had on interaction times. ignore_limb is used for detachments where we only want to forget the victim
|
||||
/datum/wound/proc/remove_wound(ignore_limb, replaced = FALSE)
|
||||
//TODO: have better way to tell if we're getting removed without replacement (full heal) scar stuff
|
||||
var/old_victim = victim
|
||||
var/old_limb = limb
|
||||
|
||||
set_disabling(FALSE)
|
||||
if(limb && can_scar && !already_scarred && !replaced)
|
||||
already_scarred = TRUE
|
||||
var/datum/scar/new_scar = new
|
||||
new_scar.generate(limb, src)
|
||||
|
||||
remove_actionspeed_modifier()
|
||||
|
||||
null_victim() // we use the proc here because some behaviors may depend on changing victim to some new value
|
||||
|
||||
if(limb && !ignore_limb)
|
||||
set_limb(null, replaced) // since we're removing limb's ref to us, we should do the same
|
||||
// if you want to keep the ref, do it externally, theres no reason for us to remember it
|
||||
|
||||
if (ismob(old_victim))
|
||||
var/mob/mob_victim = old_victim
|
||||
SEND_SIGNAL(mob_victim, COMSIG_CARBON_POST_LOSE_WOUND, src, old_limb, ignore_limb, replaced)
|
||||
|
||||
/datum/wound/proc/remove_wound_from_victim()
|
||||
if(!victim)
|
||||
return
|
||||
@@ -259,28 +371,6 @@
|
||||
/datum/wound/proc/wound_injury(datum/wound/old_wound = null, attack_direction = null)
|
||||
return
|
||||
|
||||
/// Proc called to change the variable `limb` and react to the event.
|
||||
/datum/wound/proc/set_limb(obj/item/bodypart/new_value, replaced = FALSE)
|
||||
if(limb == new_value)
|
||||
return FALSE //Limb can either be a reference to something or `null`. Returning the number variable makes it clear no change was made.
|
||||
. = limb
|
||||
if(limb) // if we're nulling limb, we're basically detaching from it, so we should remove ourselves in that case
|
||||
UnregisterSignal(limb, COMSIG_QDELETING)
|
||||
LAZYREMOVE(limb.wounds, src)
|
||||
limb.update_wounds(replaced)
|
||||
if (disabling)
|
||||
limb.remove_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src))
|
||||
|
||||
limb = new_value
|
||||
|
||||
// POST-CHANGE
|
||||
|
||||
if (limb)
|
||||
RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(source_died))
|
||||
if(limb)
|
||||
if(disabling)
|
||||
limb.add_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src))
|
||||
|
||||
/// Proc called to change the variable `disabling` and react to the event.
|
||||
/datum/wound/proc/set_disabling(new_value)
|
||||
if(disabling == new_value)
|
||||
@@ -295,6 +385,60 @@
|
||||
if(limb?.can_be_disabled)
|
||||
limb.update_disabled()
|
||||
|
||||
/// Setter for [interaction_efficiency_penalty]. Updates the actionspeed of our actionspeed mod.
|
||||
/datum/wound/proc/set_interaction_efficiency_penalty(new_value)
|
||||
var/should_update = (new_value != interaction_efficiency_penalty)
|
||||
|
||||
interaction_efficiency_penalty = new_value
|
||||
|
||||
if (should_update)
|
||||
update_actionspeed_modifier()
|
||||
|
||||
/// Returns a "adjusted" interaction_efficiency_penalty that will be used for the actionspeed mod.
|
||||
/datum/wound/proc/get_effective_actionspeed_modifier()
|
||||
return interaction_efficiency_penalty - 1
|
||||
|
||||
/// Returns the decisecond multiplier of any click interactions, assuming our limb is being used.
|
||||
/datum/wound/proc/get_action_delay_mult()
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
|
||||
return interaction_efficiency_penalty
|
||||
|
||||
/// Returns the decisecond increment of any click interactions, assuming our limb is being used.
|
||||
/datum/wound/proc/get_action_delay_increment()
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
|
||||
return 0
|
||||
|
||||
/// Signal proc for if gauze has been applied or removed from our limb.
|
||||
/datum/wound/proc/gauze_state_changed()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (wound_flags & ACCEPTS_GAUZE)
|
||||
update_inefficiencies()
|
||||
|
||||
/// Updates our limping and interaction penalties in accordance with our gauze.
|
||||
/datum/wound/proc/update_inefficiencies()
|
||||
if (wound_flags & ACCEPTS_GAUZE)
|
||||
if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(limb.current_gauze?.splint_factor)
|
||||
limp_slowdown = initial(limp_slowdown) * limb.current_gauze.splint_factor
|
||||
limp_chance = initial(limp_chance) * limb.current_gauze.splint_factor
|
||||
else
|
||||
limp_slowdown = initial(limp_slowdown)
|
||||
limp_chance = initial(limp_chance)
|
||||
else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
if(limb.current_gauze?.splint_factor)
|
||||
set_interaction_efficiency_penalty(1 + ((get_effective_actionspeed_modifier()) * limb.current_gauze.splint_factor))
|
||||
else
|
||||
set_interaction_efficiency_penalty(initial(interaction_efficiency_penalty))
|
||||
|
||||
if(initial(disabling))
|
||||
set_disabling(!limb.current_gauze)
|
||||
|
||||
limb.update_wounds()
|
||||
|
||||
start_limping_if_we_should()
|
||||
|
||||
/// Additional beneficial effects when the wound is gained, in case you want to give a temporary boost to allow the victim to try an escape or last stand
|
||||
/datum/wound/proc/second_wind()
|
||||
@@ -349,9 +493,9 @@
|
||||
/// Returns TRUE if the item can be used to treat our wounds. Hooks into treat() - only things that return TRUE here may be used there.
|
||||
/datum/wound/proc/item_can_treat(obj/item/potential_treater, mob/user)
|
||||
// check if we have a valid treatable tool
|
||||
if(potential_treater.tool_behaviour == treatable_tool)
|
||||
if(potential_treater.tool_behaviour in treatable_tools)
|
||||
return TRUE
|
||||
if(treatable_tool == TOOL_CAUTERY && potential_treater.get_temperature() && user == victim) // allow improvised cauterization on yourself without an aggro grab
|
||||
if(TOOL_CAUTERY in treatable_tools && potential_treater.get_temperature() && user == victim) // allow improvised cauterization on yourself without an aggro grab
|
||||
return TRUE
|
||||
// failing that, see if we're aggro grabbing them and if we have an item that works for aggro grabs only
|
||||
if(user.pulling == victim && user.grab_state >= GRAB_AGGRESSIVE && check_grab_treatments(potential_treater, user))
|
||||
@@ -388,9 +532,20 @@
|
||||
/// Called from cryoxadone and pyroxadone when they're proc'ing. Wounds will slowly be fixed separately from other methods when these are in effect. crappy name but eh
|
||||
/datum/wound/proc/on_xadone(power)
|
||||
cryo_progress += power
|
||||
if(cryo_progress > 33 * severity)
|
||||
|
||||
return handle_xadone_progress()
|
||||
|
||||
/// Does various actions based on [cryo_progress]. By default, qdeletes the wound past a certain threshold.
|
||||
/datum/wound/proc/handle_xadone_progress()
|
||||
if(cryo_progress > get_xadone_progress_to_qdel())
|
||||
qdel(src)
|
||||
|
||||
/// Returns the amount of [cryo_progress] we need to be qdeleted.
|
||||
/datum/wound/proc/get_xadone_progress_to_qdel()
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
|
||||
return base_xadone_progress_to_qdel * severity
|
||||
|
||||
/// When synthflesh is applied to the victim, we call this. No sense in setting up an entire chem reaction system for wounds when we only care for a few chems. Probably will change in the future
|
||||
/datum/wound/proc/on_synthflesh(power)
|
||||
return
|
||||
@@ -499,7 +654,6 @@
|
||||
if(WOUND_SEVERITY_CRITICAL)
|
||||
return "Critical"
|
||||
|
||||
|
||||
/// Returns TRUE if our limb is the head or chest, FALSE otherwise.
|
||||
/// Essential in the sense of "we cannot live without it".
|
||||
/datum/wound/proc/limb_essential()
|
||||
@@ -511,7 +665,17 @@
|
||||
|
||||
/// Getter proc for our scar_file, in case we might have some custom scar gen logic.
|
||||
/datum/wound/proc/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars)
|
||||
return scar_file
|
||||
var/datum/wound_pregen_data/pregen_data = get_pregen_data()
|
||||
// basically we iterate over biotypes until we find the one we want
|
||||
// fleshy burns will look for flesh then bone
|
||||
// dislocations will look for flesh, then bone, then metal
|
||||
var/file = default_scar_file
|
||||
for (var/biotype as anything in pregen_data.scar_priorities)
|
||||
if (scarred_limb.biological_state & text2num(biotype))
|
||||
file = GLOB.biotypes_to_scar_file[biotype]
|
||||
break
|
||||
|
||||
return file
|
||||
|
||||
/// Returns what string is displayed when a limb that has sustained this wound is examined
|
||||
/// (This is examining the LIMB ITSELF, when it's not attached to someone.)
|
||||
@@ -522,7 +686,17 @@
|
||||
/datum/wound/proc/get_dismember_chance_bonus(existing_chance)
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
|
||||
if (wound_type == WOUND_BLUNT && severity >= WOUND_SEVERITY_CRITICAL)
|
||||
var/datum/wound_pregen_data/pregen_data = get_pregen_data()
|
||||
|
||||
if (WOUND_BLUNT in pregen_data.required_wounding_types && severity >= WOUND_SEVERITY_CRITICAL)
|
||||
return WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS // we only require mangled bone (T2 blunt), but if there's a critical blunt, we'll add 15% more
|
||||
|
||||
/// Returns our pregen data, which is practically guaranteed to exist, so this proc can safely be used raw.
|
||||
/// In fact, since it's RETURN_TYPEd to wound_pregen_data, you can even directly access the variables without having to store the value of this proc in a typed variable.
|
||||
/// Ex. get_pregen_data().wound_series
|
||||
/datum/wound/proc/get_pregen_data()
|
||||
RETURN_TYPE(/datum/wound_pregen_data)
|
||||
|
||||
return GLOB.all_wound_pregen_data[type]
|
||||
|
||||
#undef WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/datum/wound/blunt
|
||||
name = "Blunt Wound"
|
||||
sound_effect = 'sound/effects/wounds/crack1.ogg'
|
||||
wound_type = WOUND_BLUNT
|
||||
|
||||
+15
-40
@@ -8,11 +8,15 @@
|
||||
abstract = TRUE
|
||||
required_limb_biostate = BIO_BONE
|
||||
|
||||
required_wounding_types = list(WOUND_BLUNT)
|
||||
|
||||
wound_series = WOUND_SERIES_BONE_BLUNT_BASIC
|
||||
|
||||
/datum/wound/blunt/bone
|
||||
name = "Blunt (Bone) Wound"
|
||||
wound_flags = (ACCEPTS_GAUZE)
|
||||
|
||||
scar_file = BONE_SCAR_FILE
|
||||
default_scar_file = BONE_SCAR_FILE
|
||||
|
||||
/// Have we been bone gel'd?
|
||||
var/gelled
|
||||
@@ -33,8 +37,6 @@
|
||||
/// 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
|
||||
|
||||
wound_series = WOUND_SERIES_BONE_BLUNT_BASIC
|
||||
|
||||
/*
|
||||
Overwriting of base procs
|
||||
*/
|
||||
@@ -65,14 +67,6 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/wound/blunt/bone/set_limb(obj/item/bodypart/new_value)
|
||||
if (limb)
|
||||
UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED))
|
||||
if (new_value)
|
||||
RegisterSignals(new_value, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED), PROC_REF(update_inefficiencies))
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/wound/blunt/bone/remove_wound(ignore_limb, replaced)
|
||||
limp_slowdown = 0
|
||||
limp_chance = 0
|
||||
@@ -180,28 +174,6 @@
|
||||
New common procs for /datum/wound/blunt/bone/
|
||||
*/
|
||||
|
||||
/datum/wound/blunt/bone/proc/update_inefficiencies()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(limb.current_gauze?.splint_factor)
|
||||
limp_slowdown = initial(limp_slowdown) * limb.current_gauze.splint_factor
|
||||
limp_chance = initial(limp_chance) * limb.current_gauze.splint_factor
|
||||
else
|
||||
limp_slowdown = initial(limp_slowdown)
|
||||
limp_chance = initial(limp_chance)
|
||||
victim.apply_status_effect(/datum/status_effect/limp)
|
||||
else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
if(limb.current_gauze?.splint_factor)
|
||||
interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_gauze.splint_factor)
|
||||
else
|
||||
interaction_efficiency_penalty = initial(interaction_efficiency_penalty)
|
||||
|
||||
if(initial(disabling))
|
||||
set_disabling(!limb.current_gauze)
|
||||
|
||||
limb.update_wounds()
|
||||
|
||||
/datum/wound/blunt/bone/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars)
|
||||
if (scarred_limb.biological_state & BIO_BONE && (!(scarred_limb.biological_state & BIO_FLESH))) // only bone
|
||||
return BONE_SCAR_FILE
|
||||
@@ -221,11 +193,10 @@
|
||||
interaction_efficiency_penalty = 1.3
|
||||
limp_slowdown = 3
|
||||
limp_chance = 50
|
||||
threshold_minimum = 35
|
||||
threshold_penalty = 15
|
||||
treatable_tool = TOOL_BONESET
|
||||
treatable_tools = list(TOOL_BONESET)
|
||||
status_effect_type = /datum/status_effect/wound/blunt/bone/moderate
|
||||
scar_keyword = "bluntmoderate"
|
||||
scar_keyword = "dislocate"
|
||||
|
||||
/datum/wound_pregen_data/bone/dislocate
|
||||
abstract = FALSE
|
||||
@@ -234,6 +205,8 @@
|
||||
|
||||
required_limb_biostate = BIO_JOINTED
|
||||
|
||||
threshold_minimum = 35
|
||||
|
||||
/datum/wound/blunt/bone/moderate/Destroy()
|
||||
if(victim)
|
||||
UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED)
|
||||
@@ -350,7 +323,6 @@
|
||||
interaction_efficiency_penalty = 2
|
||||
limp_slowdown = 6
|
||||
limp_chance = 60
|
||||
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/bone/severe
|
||||
@@ -358,7 +330,7 @@
|
||||
brain_trauma_group = BRAIN_TRAUMA_MILD
|
||||
trauma_cycle_cooldown = 1.5 MINUTES
|
||||
internal_bleeding_chance = 40
|
||||
wound_flags = (ACCEPTS_GAUZE | MANGLES_BONE)
|
||||
wound_flags = (ACCEPTS_GAUZE | MANGLES_INTERIOR)
|
||||
regen_ticks_needed = 120 // ticks every 2 seconds, 240 seconds, so roughly 4 minutes default
|
||||
|
||||
/datum/wound_pregen_data/bone/hairline
|
||||
@@ -366,6 +338,8 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/blunt/bone/severe
|
||||
|
||||
threshold_minimum = 60
|
||||
|
||||
/// Compound Fracture (Critical Blunt)
|
||||
/datum/wound/blunt/bone/critical
|
||||
name = "Compound Fracture"
|
||||
@@ -379,7 +353,6 @@
|
||||
limp_slowdown = 7
|
||||
limp_chance = 70
|
||||
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)
|
||||
@@ -388,7 +361,7 @@
|
||||
brain_trauma_group = BRAIN_TRAUMA_SEVERE
|
||||
trauma_cycle_cooldown = 2.5 MINUTES
|
||||
internal_bleeding_chance = 60
|
||||
wound_flags = (ACCEPTS_GAUZE | MANGLES_BONE)
|
||||
wound_flags = (ACCEPTS_GAUZE | MANGLES_INTERIOR)
|
||||
regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default
|
||||
|
||||
/datum/wound_pregen_data/bone/compound
|
||||
@@ -396,6 +369,8 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/blunt/bone/critical
|
||||
|
||||
threshold_minimum = 115
|
||||
|
||||
// doesn't make much sense for "a" bone to stick out of your head
|
||||
/datum/wound/blunt/bone/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown")
|
||||
if(L.body_zone == BODY_ZONE_HEAD)
|
||||
|
||||
+14
-12
@@ -7,28 +7,24 @@
|
||||
/datum/wound/burn
|
||||
name = "Burn Wound"
|
||||
a_or_from = "from"
|
||||
wound_type = WOUND_BURN
|
||||
sound_effect = 'sound/effects/wounds/sizzle1.ogg'
|
||||
|
||||
/datum/wound/burn/flesh
|
||||
name = "Burn (Flesh) Wound"
|
||||
a_or_from = "from"
|
||||
wound_type = WOUND_BURN
|
||||
processes = TRUE
|
||||
|
||||
scar_file = FLESH_SCAR_FILE
|
||||
|
||||
wound_series = WOUND_SERIES_FLESH_BURN_BASIC
|
||||
default_scar_file = FLESH_SCAR_FILE
|
||||
|
||||
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
|
||||
// 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)
|
||||
// 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
|
||||
@@ -272,8 +268,11 @@
|
||||
/datum/wound_pregen_data/flesh_burn
|
||||
abstract = TRUE
|
||||
|
||||
required_wounding_types = list(WOUND_BURN)
|
||||
required_limb_biostate = BIO_FLESH
|
||||
|
||||
wound_series = WOUND_SERIES_FLESH_BURN_BASIC
|
||||
|
||||
/datum/wound/burn/get_limb_examine_description()
|
||||
return span_warning("The flesh on this limb appears badly cooked.")
|
||||
|
||||
@@ -286,7 +285,6 @@
|
||||
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/flesh/moderate
|
||||
flesh_damage = 5
|
||||
@@ -297,6 +295,8 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/burn/flesh/moderate
|
||||
|
||||
threshold_minimum = 40
|
||||
|
||||
/datum/wound/burn/flesh/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."
|
||||
@@ -305,7 +305,6 @@
|
||||
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/flesh/severe
|
||||
treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
|
||||
@@ -318,6 +317,8 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/burn/flesh/severe
|
||||
|
||||
threshold_minimum = 80
|
||||
|
||||
/datum/wound/burn/flesh/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."
|
||||
@@ -327,7 +328,6 @@
|
||||
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/flesh/critical
|
||||
treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
|
||||
@@ -340,6 +340,8 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/burn/flesh/critical
|
||||
|
||||
threshold_minimum = 140
|
||||
|
||||
///special severe wound caused by sparring interference or other god related punishments.
|
||||
/datum/wound/burn/flesh/severe/brand
|
||||
name = "Holy Brand"
|
||||
@@ -347,7 +349,7 @@
|
||||
examine_desc = "appears to have holy symbols painfully branded into their flesh, leaving severe burns."
|
||||
occur_text = "chars rapidly into a strange pattern of holy symbols, burned into the flesh."
|
||||
|
||||
/datum/wound_pregen_data/flesh_burn/holy
|
||||
/datum/wound_pregen_data/flesh_burn/third_degree/holy
|
||||
abstract = FALSE
|
||||
can_be_randomly_generated = FALSE
|
||||
|
||||
@@ -363,7 +365,7 @@
|
||||
/datum/wound/burn/flesh/severe/cursed_brand/get_limb_examine_description()
|
||||
return span_warning("The flesh on this limb has several ornate symbols burned into it, with pitting throughout.")
|
||||
|
||||
/datum/wound_pregen_data/flesh_burn/cursed_brand
|
||||
/datum/wound_pregen_data/flesh_burn/third_degree/cursed_brand
|
||||
abstract = FALSE
|
||||
can_be_randomly_generated = FALSE
|
||||
|
||||
|
||||
+13
-25
@@ -3,7 +3,13 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/loss
|
||||
required_limb_biostate = NONE
|
||||
check_for_any = TRUE
|
||||
require_any_biostate = TRUE
|
||||
|
||||
required_wounding_types = list(WOUND_ALL)
|
||||
|
||||
wound_series = WOUND_SERIES_LOSS_BASIC
|
||||
|
||||
threshold_minimum = WOUND_DISMEMBER_OUTRIGHT_THRESH // not actually used since dismembering is handled differently, but may as well assign it since we got it
|
||||
|
||||
/datum/wound/loss
|
||||
name = "Dismemberment Wound"
|
||||
@@ -11,14 +17,13 @@
|
||||
|
||||
sound_effect = 'sound/effects/dismember.ogg'
|
||||
severity = WOUND_SEVERITY_LOSS
|
||||
threshold_minimum = WOUND_DISMEMBER_OUTRIGHT_THRESH // not actually used since dismembering is handled differently, but may as well assign it since we got it
|
||||
status_effect_type = null
|
||||
scar_keyword = "dismember"
|
||||
wound_flags = null
|
||||
already_scarred = TRUE // We manually assign scars for dismembers through endround missing limbs and aheals
|
||||
|
||||
/// The wound_type of the attack that caused us. Used to generate the description of our scar. Currently unused, but primarily exists in case non-biological wounds are added.
|
||||
var/loss_wound_type
|
||||
/// The wounding_type of the attack that caused us. Used to generate the description of our scar. Currently unused, but primarily exists in case non-biological wounds are added.
|
||||
var/loss_wounding_type
|
||||
|
||||
/// Our special proc for our special dismembering, the wounding type only matters for what text we have
|
||||
/datum/wound/loss/proc/apply_dismember(obj/item/bodypart/dismembered_part, wounding_type = WOUND_SLASH, outright = FALSE, attack_direction)
|
||||
@@ -39,14 +44,14 @@
|
||||
|
||||
victim.visible_message(msg, span_userdanger("Your [dismembered_part.plaintext_zone] [self_msg ? self_msg : occur_text]"))
|
||||
|
||||
loss_wound_type = wounding_type
|
||||
loss_wounding_type = wounding_type
|
||||
|
||||
set_limb(dismembered_part)
|
||||
second_wind()
|
||||
log_wound(victim, src)
|
||||
if(dismembered_part.can_bleed() && wounding_type != WOUND_BURN && victim.blood_volume)
|
||||
victim.spray_blood(attack_direction, severity)
|
||||
dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE, wound_type = wounding_type)
|
||||
dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE, wounding_type = wounding_type)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
@@ -64,17 +69,8 @@
|
||||
if(WOUND_BURN)
|
||||
occur_text = "is outright incinerated, falling to dust!"
|
||||
else
|
||||
var/bone_text
|
||||
if (biological_state & BIO_BONE)
|
||||
bone_text = "bone"
|
||||
else if (biological_state & BIO_METAL)
|
||||
bone_text = "metal"
|
||||
|
||||
var/tissue_text
|
||||
if (biological_state & BIO_FLESH)
|
||||
tissue_text = "flesh"
|
||||
else if (biological_state & BIO_WIRED)
|
||||
tissue_text = "wire"
|
||||
var/bone_text = get_internal_description()
|
||||
var/tissue_text = get_external_description()
|
||||
|
||||
switch(wounding_type)
|
||||
if(WOUND_BLUNT)
|
||||
@@ -87,11 +83,3 @@
|
||||
occur_text = "is completely incinerated, falling to dust!"
|
||||
|
||||
return occur_text
|
||||
|
||||
/datum/wound/loss/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars)
|
||||
if (scarred_limb.biological_state & BIO_FLESH)
|
||||
return FLESH_SCAR_FILE
|
||||
if (scarred_limb.biological_state & BIO_BONE)
|
||||
return BONE_SCAR_FILE
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -3,20 +3,17 @@
|
||||
Piercing wounds
|
||||
*/
|
||||
/datum/wound/pierce
|
||||
wound_type = WOUND_PIERCE
|
||||
|
||||
/datum/wound/pierce/bleed
|
||||
name = "Piercing Wound"
|
||||
sound_effect = 'sound/weapons/slice.ogg'
|
||||
processes = TRUE
|
||||
treatable_by = list(/obj/item/stack/medical/suture)
|
||||
treatable_tool = TOOL_CAUTERY
|
||||
treatable_tools = list(TOOL_CAUTERY)
|
||||
base_treat_time = 3 SECONDS
|
||||
wound_flags = (ACCEPTS_GAUZE)
|
||||
wound_flags = (ACCEPTS_GAUZE | CAN_BE_GRASPED)
|
||||
|
||||
wound_series = WOUND_SERIES_FLESH_PUNCTURE_BLEED
|
||||
|
||||
scar_file = FLESH_SCAR_FILE
|
||||
default_scar_file = FLESH_SCAR_FILE
|
||||
|
||||
/// How much blood we start losing when this wound is first applied
|
||||
var/initial_flow
|
||||
@@ -30,13 +27,13 @@
|
||||
|
||||
/datum/wound/pierce/bleed/wound_injury(datum/wound/old_wound = null, attack_direction = null)
|
||||
set_blood_flow(initial_flow)
|
||||
if(!no_bleeding && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY)
|
||||
if(limb.can_bleed() && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY)
|
||||
victim.spray_blood(attack_direction, severity)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/wound/pierce/bleed/receive_damage(wounding_type, wounding_dmg, wound_bonus)
|
||||
if(victim.stat == DEAD || (wounding_dmg < 5) || no_bleeding || !victim.blood_volume || !prob(internal_bleeding_chance + wounding_dmg))
|
||||
if(victim.stat == DEAD || (wounding_dmg < 5) || !limb.can_bleed() || !victim.blood_volume || !prob(internal_bleeding_chance + wounding_dmg))
|
||||
return
|
||||
if(limb.current_gauze?.splint_factor)
|
||||
wounding_dmg *= (1 - limb.current_gauze.splint_factor)
|
||||
@@ -59,7 +56,7 @@
|
||||
|
||||
/datum/wound/pierce/bleed/get_bleed_rate_of_change()
|
||||
//basically if a species doesn't bleed, the wound is stagnant and will not heal on it's own (nor get worse)
|
||||
if(no_bleeding)
|
||||
if(!limb.can_bleed())
|
||||
return BLOOD_FLOW_STEADY
|
||||
if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
|
||||
return BLOOD_FLOW_INCREASING
|
||||
@@ -73,7 +70,7 @@
|
||||
|
||||
set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW))
|
||||
|
||||
if(!no_bleeding)
|
||||
if(limb.can_bleed())
|
||||
if(victim.bodytemperature < (BODYTEMP_NORMAL - 10))
|
||||
adjust_blood_flow(-0.1 * seconds_per_tick)
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
@@ -127,7 +124,7 @@
|
||||
|
||||
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
|
||||
return TRUE
|
||||
var/bleeding_wording = (no_bleeding ? "holes" : "bleeding")
|
||||
var/bleeding_wording = (!limb.can_bleed() ? "holes" : "bleeding")
|
||||
user.visible_message(span_green("[user] stitches up some of the [bleeding_wording] on [victim]."), span_green("You stitch up some of the [bleeding_wording] on [user == victim ? "yourself" : "[victim]"]."))
|
||||
var/blood_sutured = I.stop_bleeding / self_penalty_mult
|
||||
adjust_blood_flow(-blood_sutured)
|
||||
@@ -157,7 +154,7 @@
|
||||
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
|
||||
return TRUE
|
||||
|
||||
var/bleeding_wording = (no_bleeding ? "holes" : "bleeding")
|
||||
var/bleeding_wording = (!limb.can_bleed() ? "holes" : "bleeding")
|
||||
user.visible_message(span_green("[user] cauterizes some of the [bleeding_wording] on [victim]."), span_green("You cauterize some of the [bleeding_wording] on [victim]."))
|
||||
limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
|
||||
if(prob(30))
|
||||
@@ -173,6 +170,9 @@
|
||||
abstract = TRUE
|
||||
|
||||
required_limb_biostate = (BIO_FLESH)
|
||||
required_wounding_types = list(WOUND_PIERCE)
|
||||
|
||||
wound_series = WOUND_SERIES_FLESH_PUNCTURE_BLEED
|
||||
|
||||
/datum/wound/pierce/get_limb_examine_description()
|
||||
return span_warning("The flesh on this limb appears badly perforated.")
|
||||
@@ -189,7 +189,6 @@
|
||||
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"
|
||||
@@ -199,8 +198,10 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/pierce/bleed/moderate
|
||||
|
||||
threshold_minimum = 30
|
||||
|
||||
/datum/wound/pierce/bleed/moderate/update_descriptions()
|
||||
if(no_bleeding)
|
||||
if(!limb.can_bleed())
|
||||
examine_desc = "has a small, circular hole"
|
||||
occur_text = "splits a small hole open"
|
||||
|
||||
@@ -216,7 +217,6 @@
|
||||
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"
|
||||
@@ -226,8 +226,10 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/pierce/bleed/severe
|
||||
|
||||
threshold_minimum = 50
|
||||
|
||||
/datum/wound/pierce/bleed/severe/update_descriptions()
|
||||
if(no_bleeding)
|
||||
if(!limb.can_bleed())
|
||||
occur_text = "tears a hole open"
|
||||
|
||||
/datum/wound/pierce/bleed/critical
|
||||
@@ -242,13 +244,14 @@
|
||||
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 = (ACCEPTS_GAUZE | MANGLES_FLESH)
|
||||
wound_flags = (ACCEPTS_GAUZE | MANGLES_EXTERIOR | CAN_BE_GRASPED)
|
||||
|
||||
/datum/wound_pregen_data/flesh_pierce/cavity
|
||||
abstract = FALSE
|
||||
|
||||
wound_path_to_generate = /datum/wound/pierce/bleed/critical
|
||||
|
||||
threshold_minimum = 100
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
return
|
||||
|
||||
required_limb_biostate = pregen_data.required_limb_biostate
|
||||
check_any_biostates = pregen_data.check_for_any
|
||||
check_any_biostates = pregen_data.require_any_biostate
|
||||
|
||||
limb = BP
|
||||
RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(limb_gone))
|
||||
@@ -103,7 +103,7 @@
|
||||
LAZYADD(victim.all_scars, src)
|
||||
|
||||
/// Used to "load" a persistent scar
|
||||
/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity = WOUND_SEVERITY_SEVERE, required_limb_biostate = BIO_STANDARD, char_slot, check_any_biostates = FALSE)
|
||||
/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity = WOUND_SEVERITY_SEVERE, required_limb_biostate = BIO_STANDARD_UNJOINTED, char_slot, check_any_biostates = FALSE)
|
||||
if(!BP.scarrable)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
+35
-24
@@ -6,26 +6,25 @@
|
||||
/datum/wound/slash
|
||||
name = "Slashing (Cut) Wound"
|
||||
sound_effect = 'sound/weapons/slice.ogg'
|
||||
wound_type = WOUND_SLASH
|
||||
|
||||
/datum/wound_pregen_data/flesh_slash
|
||||
abstract = TRUE
|
||||
|
||||
required_wounding_types = list(WOUND_SLASH)
|
||||
required_limb_biostate = BIO_FLESH
|
||||
|
||||
wound_series = WOUND_SERIES_FLESH_SLASH_BLEED
|
||||
|
||||
/datum/wound/slash/flesh
|
||||
name = "Slashing (Cut) Flesh Wound"
|
||||
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
|
||||
treatable_tools = list(TOOL_CAUTERY)
|
||||
base_treat_time = 3 SECONDS
|
||||
wound_flags = (ACCEPTS_GAUZE)
|
||||
wound_flags = (ACCEPTS_GAUZE|CAN_BE_GRASPED)
|
||||
|
||||
scar_file = FLESH_SCAR_FILE
|
||||
|
||||
wound_series = WOUND_SERIES_FLESH_SLASH_BLEED
|
||||
default_scar_file = FLESH_SCAR_FILE
|
||||
|
||||
/// How much blood we start losing when this wound is first applied
|
||||
var/initial_flow
|
||||
@@ -43,6 +42,11 @@
|
||||
/// 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/flesh/Destroy()
|
||||
highest_scar = null
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/wound/slash/flesh/wound_injury(datum/wound/slash/flesh/old_wound = null, attack_direction = null)
|
||||
if(old_wound)
|
||||
set_blood_flow(max(old_wound.blood_flow, initial_flow))
|
||||
@@ -51,7 +55,7 @@
|
||||
old_wound.clear_highest_scar()
|
||||
else
|
||||
set_blood_flow(initial_flow)
|
||||
if(!no_bleeding && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY)
|
||||
if(limb.can_bleed() && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY)
|
||||
victim.spray_blood(attack_direction, severity)
|
||||
|
||||
if(!highest_scar)
|
||||
@@ -119,7 +123,7 @@
|
||||
|
||||
/datum/wound/slash/flesh/get_bleed_rate_of_change()
|
||||
//basically if a species doesn't bleed, the wound is stagnant and will not heal on it's own (nor get worse)
|
||||
if(no_bleeding)
|
||||
if(!limb.can_bleed())
|
||||
return BLOOD_FLOW_STEADY
|
||||
if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
|
||||
return BLOOD_FLOW_INCREASING
|
||||
@@ -134,7 +138,7 @@
|
||||
return
|
||||
|
||||
// in case the victim has the NOBLOOD trait, the wound will simply not clot on it's own
|
||||
if(!no_bleeding)
|
||||
if(limb.can_bleed())
|
||||
set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW))
|
||||
|
||||
if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
|
||||
@@ -147,7 +151,7 @@
|
||||
adjust_blood_flow(-limb.current_gauze.absorption_rate * seconds_per_tick)
|
||||
limb.seep_gauze(limb.current_gauze.absorption_rate * seconds_per_tick)
|
||||
//otherwise, only clot if it's a bleeder
|
||||
else if(!no_bleeding)
|
||||
else if(limb.can_bleed())
|
||||
adjust_blood_flow(-clot_rate * seconds_per_tick)
|
||||
|
||||
if(blood_flow > highest_flow)
|
||||
@@ -157,7 +161,7 @@
|
||||
if(demotes_to)
|
||||
replace_wound(new demotes_to)
|
||||
else
|
||||
to_chat(victim, span_green("The cut on your [limb.plaintext_zone] has [no_bleeding ? "healed up" : "stopped bleeding"]!"))
|
||||
to_chat(victim, span_green("The cut on your [limb.plaintext_zone] has [!limb.can_bleed() ? "healed up" : "stopped bleeding"]!"))
|
||||
qdel(src)
|
||||
|
||||
/datum/wound/slash/flesh/on_stasis(seconds_per_tick, times_fired)
|
||||
@@ -225,7 +229,7 @@
|
||||
|
||||
/datum/wound/slash/flesh/on_xadone(power)
|
||||
. = ..()
|
||||
|
||||
|
||||
if (limb) // parent can cause us to be removed, so its reasonable to check if we're still applied
|
||||
adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
|
||||
|
||||
@@ -264,7 +268,7 @@
|
||||
|
||||
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
|
||||
return
|
||||
var/bleeding_wording = (no_bleeding ? "cuts" : "bleeding")
|
||||
var/bleeding_wording = (!limb.can_bleed() ? "cuts" : "bleeding")
|
||||
user.visible_message(span_green("[user] cauterizes some of the [bleeding_wording] on [victim]."), span_green("You cauterize some of the [bleeding_wording] on [victim]."))
|
||||
limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
|
||||
if(prob(30))
|
||||
@@ -292,7 +296,7 @@
|
||||
|
||||
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
|
||||
return TRUE
|
||||
var/bleeding_wording = (no_bleeding ? "cuts" : "bleeding")
|
||||
var/bleeding_wording = (!limb.can_bleed() ? "cuts" : "bleeding")
|
||||
user.visible_message(span_green("[user] stitches up some of the [bleeding_wording] on [victim]."), span_green("You stitch up some of the [bleeding_wording] on [user == victim ? "yourself" : "[victim]"]."))
|
||||
var/blood_sutured = I.stop_bleeding / self_penalty_mult
|
||||
adjust_blood_flow(-blood_sutured)
|
||||
@@ -320,13 +324,12 @@
|
||||
initial_flow = 2
|
||||
minimum_flow = 0.5
|
||||
clot_rate = 0.05
|
||||
threshold_minimum = 20
|
||||
threshold_penalty = 10
|
||||
status_effect_type = /datum/status_effect/wound/slash/flesh/moderate
|
||||
scar_keyword = "slashmoderate"
|
||||
|
||||
/datum/wound/slash/flesh/moderate/update_descriptions()
|
||||
if(no_bleeding)
|
||||
if(!limb.can_bleed())
|
||||
occur_text = "is cut open"
|
||||
|
||||
/datum/wound_pregen_data/flesh_slash/abrasion
|
||||
@@ -334,6 +337,8 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/slash/flesh/moderate
|
||||
|
||||
threshold_minimum = 20
|
||||
|
||||
/datum/wound/slash/flesh/severe
|
||||
name = "Open Laceration"
|
||||
desc = "Patient's skin is ripped clean open, allowing significant blood loss."
|
||||
@@ -345,7 +350,6 @@
|
||||
initial_flow = 3.25
|
||||
minimum_flow = 2.75
|
||||
clot_rate = 0.03
|
||||
threshold_minimum = 50
|
||||
threshold_penalty = 25
|
||||
demotes_to = /datum/wound/slash/flesh/moderate
|
||||
status_effect_type = /datum/status_effect/wound/slash/flesh/severe
|
||||
@@ -356,8 +360,10 @@
|
||||
|
||||
wound_path_to_generate = /datum/wound/slash/flesh/severe
|
||||
|
||||
threshold_minimum = 50
|
||||
|
||||
/datum/wound/slash/flesh/severe/update_descriptions()
|
||||
if(no_bleeding)
|
||||
if(!limb.can_bleed())
|
||||
occur_text = "is ripped open"
|
||||
|
||||
/datum/wound/slash/flesh/critical
|
||||
@@ -371,25 +377,30 @@
|
||||
initial_flow = 4
|
||||
minimum_flow = 3.85
|
||||
clot_rate = -0.015 // critical cuts actively get worse instead of better
|
||||
threshold_minimum = 80
|
||||
threshold_penalty = 40
|
||||
demotes_to = /datum/wound/slash/flesh/severe
|
||||
status_effect_type = /datum/status_effect/wound/slash/flesh/critical
|
||||
scar_keyword = "slashcritical"
|
||||
wound_flags = (ACCEPTS_GAUZE | MANGLES_FLESH)
|
||||
wound_flags = (ACCEPTS_GAUZE | MANGLES_EXTERIOR | CAN_BE_GRASPED)
|
||||
|
||||
/datum/wound/slash/flesh/critical/update_descriptions()
|
||||
if (!limb.can_bleed())
|
||||
occur_text = "is torn open"
|
||||
|
||||
/datum/wound_pregen_data/flesh_slash/avulsion
|
||||
abstract = FALSE
|
||||
|
||||
wound_path_to_generate = /datum/wound/slash/flesh/critical
|
||||
|
||||
threshold_minimum = 80
|
||||
|
||||
/datum/wound/slash/flesh/moderate/many_cuts
|
||||
name = "Numerous Small Slashes"
|
||||
desc = "Patient's skin has numerous small slashes and cuts, generating moderate blood loss."
|
||||
examine_desc = "has a ton of small cuts"
|
||||
occur_text = "is cut numerous times, leaving many small slashes."
|
||||
|
||||
/datum/wound_pregen_data/flesh_slash/cuts
|
||||
/datum/wound_pregen_data/flesh_slash/abrasion/cuts
|
||||
abstract = FALSE
|
||||
can_be_randomly_generated = FALSE
|
||||
|
||||
@@ -402,10 +413,10 @@
|
||||
clot_rate = 0.01
|
||||
|
||||
/datum/wound/slash/flesh/critical/cleave/update_descriptions()
|
||||
if(no_bleeding)
|
||||
if(!limb.can_bleed())
|
||||
occur_text = "is ruptured"
|
||||
|
||||
/datum/wound_pregen_data/flesh_slash/cleave
|
||||
/datum/wound_pregen_data/flesh_slash/avulsion/clear
|
||||
abstract = FALSE
|
||||
can_be_randomly_generated = FALSE
|
||||
|
||||
|
||||
@@ -243,12 +243,12 @@
|
||||
|
||||
if(!(get_dist(src, attached) <= 1 && isturf(attached.loc)))
|
||||
if(isliving(attached))
|
||||
var/mob/living/attached_mob = attached
|
||||
var/mob/living/carbon/attached_mob = attached
|
||||
to_chat(attached, span_userdanger("The IV drip needle is ripped out of you, leaving an open bleeding wound!"))
|
||||
var/list/arm_zones = shuffle(list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM))
|
||||
var/obj/item/bodypart/chosen_limb = attached_mob.get_bodypart(arm_zones[1]) || attached_mob.get_bodypart(arm_zones[2]) || attached_mob.get_bodypart(BODY_ZONE_CHEST)
|
||||
chosen_limb.receive_damage(3)
|
||||
chosen_limb.force_wound_upwards(/datum/wound/pierce/bleed/moderate, wound_source = "IV needle")
|
||||
attached_mob.cause_wound_of_type_and_severity(WOUND_PIERCE, chosen_limb, WOUND_SEVERITY_MODERATE, wound_source = "IV needle")
|
||||
else
|
||||
visible_message(span_warning("[attached] is detached from [src]."))
|
||||
detach_iv()
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
return FALSE
|
||||
|
||||
var/obj/item/bodypart/head/the_head = target.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(!(the_head.biological_state & BIO_FLESH) || !IS_ORGANIC_LIMB(the_head))
|
||||
if(!(the_head.biological_state & BIO_FLESH))
|
||||
to_chat(user, span_warning("You can't noogie [target], [target.p_they()] [target.p_have()] no skin on [target.p_their()] head!"))
|
||||
return
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@
|
||||
|
||||
patient.emote("scream")
|
||||
for(var/i in patient.bodyparts)
|
||||
var/obj/item/bodypart/bone = i
|
||||
var/obj/item/bodypart/bone = i // fine to just, use these raw, its a meme anyway
|
||||
var/datum/wound/blunt/bone/severe/oof_ouch = new
|
||||
oof_ouch.apply_wound(bone, wound_source = "bone gel")
|
||||
var/datum/wound/blunt/bone/critical/oof_OUCH = new
|
||||
|
||||
@@ -37,8 +37,11 @@ can next move
|
||||
/// Other modification datums this conflicts with.
|
||||
var/conflicts_with
|
||||
|
||||
/datum/actionspeed_modifier/New()
|
||||
/datum/actionspeed_modifier/New(init_id)
|
||||
. = ..()
|
||||
|
||||
id = init_id
|
||||
|
||||
if(!id)
|
||||
id = "[type]" //We turn the path into a string.
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/datum/actionspeed_modifier/wound_interaction_inefficiency
|
||||
variable = TRUE
|
||||
|
||||
var/datum/wound/parent
|
||||
|
||||
/datum/actionspeed_modifier/wound_interaction_inefficiency/New(new_id, datum/wound/parent)
|
||||
|
||||
src.parent = parent
|
||||
|
||||
return ..()
|
||||
@@ -9,7 +9,7 @@
|
||||
return
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
for(var/_limb in carbon_target.bodyparts)
|
||||
var/obj/item/bodypart/limb = _limb
|
||||
var/obj/item/bodypart/limb = _limb // fine to use this raw, its a meme smite
|
||||
var/type_wound = pick(list(/datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/moderate))
|
||||
limb.force_wound_upwards(type_wound, smited = TRUE)
|
||||
type_wound = pick(list(/datum/wound/slash/flesh/critical, /datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/moderate))
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
for(var/obj/item/bodypart/limb as anything in carbon_target.bodyparts)
|
||||
var/type_wound = pick(list(
|
||||
/datum/wound/blunt/bone/critical,
|
||||
/datum/wound/blunt/bone/severe,
|
||||
/datum/wound/blunt/bone/critical,
|
||||
/datum/wound/blunt/bone/severe,
|
||||
/datum/wound/blunt/bone/moderate,
|
||||
var/severity = pick(list(
|
||||
"[WOUND_SEVERITY_MODERATE]",
|
||||
"[WOUND_SEVERITY_SEVERE]",
|
||||
"[WOUND_SEVERITY_SEVERE]",
|
||||
"[WOUND_SEVERITY_CRITICAL]",
|
||||
"[WOUND_SEVERITY_CRITICAL]",
|
||||
))
|
||||
limb.force_wound_upwards(type_wound, smited = TRUE)
|
||||
carbon_target.cause_wound_of_type_and_severity(WOUND_BLUNT, limb, severity)
|
||||
|
||||
@@ -269,8 +269,7 @@
|
||||
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts)
|
||||
var/datum/wound/slash/flesh/severe/crit_wound = new()
|
||||
crit_wound.apply_wound(bodypart, attack_direction = get_dir(source, target))
|
||||
carbon_target.cause_wound_of_type_and_severity(WOUND_SLASH, bodypart, WOUND_SEVERITY_SEVERE, WOUND_SEVERITY_CRITICAL)
|
||||
|
||||
/datum/heretic_knowledge/summon/stalker
|
||||
name = "Lonely Ritual"
|
||||
|
||||
@@ -74,7 +74,8 @@
|
||||
heal_amt = 3
|
||||
if(WOUND_SEVERITY_CRITICAL)
|
||||
heal_amt = 6
|
||||
if(wound.wound_type == WOUND_BURN)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound.type]
|
||||
if (pregen_data.wounding_types_valid(list(WOUND_BURN)))
|
||||
carbie.adjustFireLoss(-heal_amt)
|
||||
else
|
||||
carbie.adjustBruteLoss(-heal_amt)
|
||||
|
||||
@@ -61,8 +61,7 @@
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/human_owner = owner
|
||||
var/obj/item/bodypart/bodypart = pick(human_owner.bodyparts)
|
||||
var/datum/wound/slash/flesh/severe/crit_wound = new()
|
||||
crit_wound.apply_wound(bodypart)
|
||||
human_owner.cause_wound_of_type_and_severity(WOUND_SLASH, bodypart, WOUND_SEVERITY_SEVERE)
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -179,9 +179,10 @@
|
||||
if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
|
||||
return
|
||||
|
||||
var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe
|
||||
var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical
|
||||
target.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10), attacking_item = src)
|
||||
var/min_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 30, wound_source = src)
|
||||
var/max_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 50, wound_source = src)
|
||||
|
||||
target.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(min_wound, max_wound + 10), attacking_item = src)
|
||||
target.visible_message(
|
||||
span_danger("[src] pierces through [target]'s skull, horribly mutilating their eyes!"),
|
||||
span_userdanger("Something penetrates your skull, horribly mutilating your eyes! Holy fuck!"),
|
||||
|
||||
@@ -13,8 +13,12 @@
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/tigercultist/perforated/special(mob/living/carbon/human/spawned_human)
|
||||
. = ..()
|
||||
var/datum/wound/pierce/bleed/critical/exit_hole = new()
|
||||
exit_hole.apply_wound(spawned_human.get_bodypart(BODY_ZONE_CHEST))
|
||||
|
||||
var/obj/item/bodypart/chest/their_chest = spawned_human.get_bodypart(BODY_ZONE_CHEST)
|
||||
if (!their_chest)
|
||||
return
|
||||
|
||||
spawned_human.cause_wound_of_type_and_severity(WOUND_PIERCE, their_chest, WOUND_SEVERITY_CRITICAL)
|
||||
|
||||
/// A fun drink enjoyed by the tiger cooperative, might corrode your brain if you drink the whole bottle
|
||||
/obj/item/reagent_containers/cup/glass/bottle/ritual_wine
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
if(I.force)
|
||||
var/attack_direction = get_dir(user, src)
|
||||
apply_damage(I.force, I.damtype, affecting, wound_bonus = I.wound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness(), attack_direction = attack_direction, attacking_item = I)
|
||||
if(I.damtype == BRUTE && IS_ORGANIC_LIMB(affecting))
|
||||
if(I.damtype == BRUTE && affecting.can_bleed())
|
||||
if(prob(33))
|
||||
I.add_mob_blood(src)
|
||||
var/turf/location = get_turf(src)
|
||||
@@ -127,22 +127,35 @@
|
||||
var/message_verb_simple = length(I.attack_verb_simple) ? "[pick(I.attack_verb_simple)]" : "attack"
|
||||
|
||||
var/extra_wound_details = ""
|
||||
|
||||
if(I.damtype == BRUTE && hit_bodypart.can_dismember())
|
||||
|
||||
var/mangled_state = hit_bodypart.get_mangled_state()
|
||||
var/bio_state = hit_bodypart.biological_state
|
||||
if((mangled_state & BODYPART_MANGLED_FLESH) && (mangled_state & BODYPART_MANGLED_BONE))
|
||||
|
||||
var/bio_status = hit_bodypart.get_bio_state_status()
|
||||
|
||||
var/has_exterior = ((bio_status & ANATOMY_EXTERIOR))
|
||||
var/has_interior = ((bio_status & ANATOMY_INTERIOR))
|
||||
|
||||
var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR)))
|
||||
var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_INTERIOR)))
|
||||
|
||||
var/dismemberable = ((hit_bodypart.dismemberable_by_wound()) || hit_bodypart.dismemberable_by_total_damage())
|
||||
if (dismemberable)
|
||||
extra_wound_details = ", threatening to sever it entirely"
|
||||
else if((mangled_state & BODYPART_MANGLED_FLESH && I.get_sharpness()) || ((mangled_state & BODYPART_MANGLED_BONE) && (bio_state & BIO_BONE) && !(bio_state & BIO_FLESH)))
|
||||
extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the bone"
|
||||
else if((mangled_state & BODYPART_MANGLED_BONE && I.get_sharpness()) || ((mangled_state & BODYPART_MANGLED_FLESH) && (bio_state & BIO_FLESH) && !(bio_state & BIO_BONE)))
|
||||
extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining tissue"
|
||||
else if((has_interior && (has_exterior && exterior_ready_to_dismember) && I.get_sharpness()))
|
||||
var/bone_text = hit_bodypart.get_internal_description()
|
||||
extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the [bone_text]"
|
||||
else if(has_exterior && ((has_interior && interior_ready_to_dismember) && I.get_sharpness()))
|
||||
var/tissue_text = hit_bodypart.get_external_description()
|
||||
extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining [tissue_text]"
|
||||
|
||||
var/message_hit_area = ""
|
||||
if(hit_area)
|
||||
message_hit_area = " in the [hit_area]"
|
||||
var/attack_message_spectator = "[src] [message_verb_continuous][message_hit_area] with [I][extra_wound_details]!"
|
||||
var/attack_message_victim = "You're [message_verb_continuous][message_hit_area] with [I][extra_wound_details]!"
|
||||
var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [I]!"
|
||||
var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [I][extra_wound_details]!"
|
||||
if(user in viewers(src, null))
|
||||
attack_message_spectator = "[user] [message_verb_continuous] [src][message_hit_area] with [I][extra_wound_details]!"
|
||||
attack_message_victim = "[user] [message_verb_continuous] you[message_hit_area] with [I][extra_wound_details]!"
|
||||
@@ -698,14 +711,16 @@
|
||||
return ..()
|
||||
|
||||
var/obj/item/bodypart/grasped_part = get_bodypart(zone_selected)
|
||||
if(!grasped_part?.get_modified_bleed_rate())
|
||||
if(!grasped_part?.can_be_grasped())
|
||||
return
|
||||
var/starting_hand_index = active_hand_index
|
||||
if(starting_hand_index == grasped_part.held_index)
|
||||
to_chat(src, span_danger("You can't grasp your [grasped_part.name] with itself!"))
|
||||
return
|
||||
|
||||
to_chat(src, span_warning("You try grasping at your [grasped_part.name], trying to stop the bleeding..."))
|
||||
var/bleed_rate = grasped_part.get_modified_bleed_rate()
|
||||
var/bleeding_text = (bleed_rate ? ", trying to stop the bleeding" : "")
|
||||
to_chat(src, span_warning("You try grasping at your [grasped_part.name][bleeding_text]..."))
|
||||
if(!do_after(src, 0.75 SECONDS))
|
||||
to_chat(src, span_danger("You fail to grasp your [grasped_part.name]."))
|
||||
return
|
||||
@@ -717,6 +732,17 @@
|
||||
return
|
||||
grasp.grasp_limb(grasped_part)
|
||||
|
||||
/// If TRUE, the owner of this bodypart can try grabbing it to slow bleeding, as well as various other effects.
|
||||
/obj/item/bodypart/proc/can_be_grasped()
|
||||
if (get_modified_bleed_rate())
|
||||
return TRUE
|
||||
|
||||
for (var/datum/wound/iterated_wound as anything in wounds)
|
||||
if (iterated_wound.wound_flags & CAN_BE_GRASPED)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/// 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/hand_item/self_grasp
|
||||
name = "self-grasp"
|
||||
@@ -761,7 +787,9 @@
|
||||
RegisterSignal(user, COMSIG_QDELETING, PROC_REF(qdel_void))
|
||||
RegisterSignals(grasped_part, list(COMSIG_CARBON_REMOVE_LIMB, COMSIG_QDELETING), PROC_REF(qdel_void))
|
||||
|
||||
user.visible_message(span_danger("[user] grasps at [user.p_their()] [grasped_part.name], trying to stop the bleeding."), span_notice("You grab hold of your [grasped_part.name] tightly."), vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
var/bleed_rate = grasped_part.get_modified_bleed_rate()
|
||||
var/bleeding_text = (bleed_rate ? ", trying to stop the bleeding" : "")
|
||||
user.visible_message(span_danger("[user] grasps at [user.p_their()] [grasped_part.name][bleeding_text]."), span_notice("You grab hold of your [grasped_part.name] tightly."), vision_distance=COMBAT_MESSAGE_RANGE)
|
||||
playsound(get_turf(src), 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
/// All of the scars a carbon has afflicted throughout their limbs
|
||||
var/list/all_scars
|
||||
|
||||
/// Assoc list of BODY_ZONE -> WOUND_TYPE. Set when a limb is dismembered, unset when one is attached. Used for determining what scar to add when it comes time to generate them.
|
||||
/// Assoc list of BODY_ZONE -> wounding_type. Set when a limb is dismembered, unset when one is attached. Used for determining what scar to add when it comes time to generate them.
|
||||
var/list/body_zone_dismembered_by
|
||||
|
||||
/// Simple modifier for whether this mob can handle greater or lesser skillchip complexity. See /datum/mutation/human/biotechcompat/ for example.
|
||||
|
||||
@@ -1667,19 +1667,26 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
|
||||
// Lets pick a random body part and check for an existing burn
|
||||
var/obj/item/bodypart/bodypart = pick(humi.bodyparts)
|
||||
var/datum/wound/burn/flesh/existing_burn = locate(/datum/wound/burn) in bodypart.wounds
|
||||
|
||||
var/datum/wound/existing_burn
|
||||
for (var/datum/wound/iterated_wound as anything in bodypart.wounds)
|
||||
var/datum/wound_pregen_data/pregen_data = iterated_wound.get_pregen_data()
|
||||
if (pregen_data.wound_series in GLOB.wounding_types_to_series[WOUND_BURN])
|
||||
existing_burn = iterated_wound
|
||||
break
|
||||
// If we have an existing burn try to upgrade it
|
||||
var/severity
|
||||
if(existing_burn)
|
||||
switch(existing_burn.severity)
|
||||
if(WOUND_SEVERITY_MODERATE)
|
||||
if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 400) // 800k
|
||||
bodypart.force_wound_upwards(/datum/wound/burn/flesh/severe, wound_source = "hot temperatures")
|
||||
severity = WOUND_SEVERITY_SEVERE
|
||||
if(WOUND_SEVERITY_SEVERE)
|
||||
if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 2800) // 3200k
|
||||
bodypart.force_wound_upwards(/datum/wound/burn/flesh/critical, wound_source = "hot temperatures")
|
||||
severity = WOUND_SEVERITY_CRITICAL
|
||||
else // If we have no burn apply the lowest level burn
|
||||
bodypart.force_wound_upwards(/datum/wound/burn/flesh/moderate, wound_source = "hot temperatures")
|
||||
severity = WOUND_SEVERITY_MODERATE
|
||||
|
||||
humi.cause_wound_of_type_and_severity(WOUND_BURN, bodypart, severity, wound_source = "hot temperatures")
|
||||
|
||||
// always take some burn damage
|
||||
var/burn_damage = HEAT_DAMAGE_LEVEL_1
|
||||
|
||||
@@ -171,8 +171,9 @@
|
||||
to_chat(user, span_userdanger("You neatly cut [stored_paper][clumsy ? "... and your finger in the process!" : "."]"))
|
||||
if(clumsy)
|
||||
var/obj/item/bodypart/finger = user.get_active_hand()
|
||||
var/datum/wound/slash/flesh/moderate/papercut = new
|
||||
papercut.apply_wound(finger, wound_source = "paper cut")
|
||||
if (iscarbon(user))
|
||||
var/mob/living/carbon/carbon_user = user
|
||||
carbon_user.cause_wound_of_type_and_severity(WOUND_SLASH, finger, WOUND_SEVERITY_MODERATE, wound_source = "paper cut")
|
||||
stored_paper = null
|
||||
qdel(stored_paper)
|
||||
new /obj/item/paper/paperslip(get_turf(src))
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
span_userdanger("The spell bounces from [victim]'s skin back into your arm!"),
|
||||
)
|
||||
var/obj/item/bodypart/to_wound = caster.get_holding_bodypart_of_item(hand)
|
||||
to_wound.force_wound_upwards(/datum/wound/slash/flesh/critical)
|
||||
caster.cause_wound_of_type_and_severity(WOUND_SLASH, to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_CRITICAL)
|
||||
|
||||
/datum/action/cooldown/spell/touch/scream_for_me/cast_on_hand_hit(obj/item/melee/touch_attack/hand, mob/living/victim, mob/living/carbon/caster)
|
||||
if(!ishuman(victim))
|
||||
@@ -29,7 +29,7 @@
|
||||
var/mob/living/carbon/human/human_victim = victim
|
||||
human_victim.emote("scream")
|
||||
for(var/obj/item/bodypart/to_wound as anything in human_victim.bodyparts)
|
||||
to_wound.force_wound_upwards(/datum/wound/slash/flesh/critical)
|
||||
human_victim.cause_wound_of_type_and_severity(WOUND_SLASH, to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_CRITICAL)
|
||||
return TRUE
|
||||
|
||||
/obj/item/melee/touch_attack/scream_for_me
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
/**
|
||||
* A bitfield of biological states, exclusively used to determine which wounds this limb will get,
|
||||
* as well as how easily it will happen.
|
||||
* Set to BIO_STANDARD because most species have both flesh bone and blood in their limbs.
|
||||
* Set to BIO_STANDARD_UNJOINTED because most species have both flesh bone and blood in their limbs.
|
||||
*/
|
||||
var/biological_state = BIO_STANDARD
|
||||
var/biological_state = BIO_STANDARD_UNJOINTED
|
||||
///A bitfield of bodytypes for clothing, surgery, and misc information
|
||||
var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC
|
||||
///Defines when a bodypart should not be changed. Example: BP_BLOCK_CHANGE_SPECIES prevents the limb from being overwritten on species gain
|
||||
@@ -195,10 +195,10 @@
|
||||
var/hp_percent_to_dismemberable = 0.8
|
||||
/// If true, we will use [hp_percent_to_dismemberable] even if we are dismemberable via wounds. Useful for things with extreme wound resistance.
|
||||
var/use_alternate_dismemberment_calc_even_if_mangleable = FALSE
|
||||
/// If false, no wound that can be applied to us can mangle our flesh. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment.
|
||||
var/any_existing_wound_can_mangle_our_flesh
|
||||
/// If false, no wound that can be applied to us can mangle our bone. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment.
|
||||
var/any_existing_wound_can_mangle_our_bone
|
||||
/// If false, no wound that can be applied to us can mangle our exterior. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment.
|
||||
var/any_existing_wound_can_mangle_our_exterior
|
||||
/// If false, no wound that can be applied to us can mangle our interior. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment.
|
||||
var/any_existing_wound_can_mangle_our_interior
|
||||
|
||||
/obj/item/bodypart/apply_fantasy_bonuses(bonus)
|
||||
. = ..()
|
||||
@@ -495,73 +495,32 @@
|
||||
var/mangled_state = get_mangled_state()
|
||||
var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%)
|
||||
|
||||
var/has_exterior = FALSE
|
||||
var/has_interior = FALSE
|
||||
var/bio_status = get_bio_state_status()
|
||||
|
||||
for (var/state as anything in GLOB.bio_state_states)
|
||||
var/flag = text2num(state)
|
||||
if (!(biological_state & flag))
|
||||
continue
|
||||
var/has_exterior = ((bio_status & ANATOMY_EXTERIOR))
|
||||
var/has_interior = ((bio_status & ANATOMY_INTERIOR))
|
||||
|
||||
var/value = GLOB.bio_state_states[state]
|
||||
if (value & BIO_EXTERIOR)
|
||||
has_exterior = TRUE
|
||||
if (value & BIO_INTERIOR)
|
||||
has_interior = TRUE
|
||||
|
||||
if (has_exterior && has_interior)
|
||||
break
|
||||
|
||||
// We put this here so we dont increase init time by doing this all at once on initialization
|
||||
// Effectively, we "lazy load"
|
||||
if (isnull(any_existing_wound_can_mangle_our_bone) || isnull(any_existing_wound_can_mangle_our_flesh))
|
||||
any_existing_wound_can_mangle_our_bone = FALSE
|
||||
any_existing_wound_can_mangle_our_flesh = FALSE
|
||||
for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type]
|
||||
if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific
|
||||
continue
|
||||
if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_FLESH)
|
||||
any_existing_wound_can_mangle_our_flesh = TRUE
|
||||
if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_BONE)
|
||||
any_existing_wound_can_mangle_our_bone = TRUE
|
||||
|
||||
if (any_existing_wound_can_mangle_our_bone && any_existing_wound_can_mangle_our_flesh)
|
||||
break
|
||||
|
||||
var/can_theoretically_be_dismembered = (any_existing_wound_can_mangle_our_bone || (any_existing_wound_can_mangle_our_flesh && !has_exterior))
|
||||
|
||||
var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_BONE) == BODYPART_MANGLED_BONE))
|
||||
var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_FLESH) == BODYPART_MANGLED_FLESH))
|
||||
var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR)))
|
||||
|
||||
// if we're bone only, all cutting attacks go straight to the bone
|
||||
if(has_exterior && interior_ready_to_dismember)
|
||||
if(!has_exterior && has_interior)
|
||||
if(wounding_type == WOUND_SLASH)
|
||||
wounding_type = WOUND_BLUNT
|
||||
wounding_dmg *= (easy_dismember ? 1 : 0.6)
|
||||
else if(wounding_type == WOUND_PIERCE)
|
||||
wounding_type = WOUND_BLUNT
|
||||
wounding_dmg *= (easy_dismember ? 1 : 0.75)
|
||||
if(exterior_ready_to_dismember && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
return
|
||||
else
|
||||
// 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(has_exterior && interior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness)
|
||||
playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
|
||||
if(has_interior && exterior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_INTERIOR) && sharpness)
|
||||
if(wounding_type == WOUND_SLASH && !easy_dismember)
|
||||
wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area
|
||||
if(wounding_type == WOUND_PIERCE && !easy_dismember)
|
||||
wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
|
||||
wounding_type = WOUND_BLUNT
|
||||
else if(interior_ready_to_dismember && exterior_ready_to_dismember && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
return
|
||||
if (use_alternate_dismemberment_calc_even_if_mangleable || !can_theoretically_be_dismembered)
|
||||
var/percent_to_total_max = (get_damage() / max_damage)
|
||||
if (percent_to_total_max >= hp_percent_to_dismemberable)
|
||||
if (try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
return
|
||||
|
||||
if ((dismemberable_by_wound() || dismemberable_by_total_damage()) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
return
|
||||
// now we have our wounding_type and are ready to carry on with wounds and dealing the actual damage
|
||||
if(wounding_dmg >= WOUND_MINIMUM_DAMAGE && wound_bonus != CANT_WOUND)
|
||||
check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus, attack_direction, damage_source = damage_source)
|
||||
@@ -594,6 +553,83 @@
|
||||
owner.updatehealth()
|
||||
return update_bodypart_damage_state() || .
|
||||
|
||||
/// Returns a bitflag using ANATOMY_EXTERIOR or ANATOMY_INTERIOR. Used to determine if we as a whole have a interior or exterior biostate, or both.
|
||||
/obj/item/bodypart/proc/get_bio_state_status()
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
|
||||
var/bio_status = NONE
|
||||
|
||||
for (var/state as anything in GLOB.bio_state_anatomy)
|
||||
var/flag = text2num(state)
|
||||
if (!(biological_state & flag))
|
||||
continue
|
||||
|
||||
var/value = GLOB.bio_state_anatomy[state]
|
||||
if (value & ANATOMY_EXTERIOR)
|
||||
bio_status |= ANATOMY_EXTERIOR
|
||||
if (value & ANATOMY_INTERIOR)
|
||||
bio_status |= ANATOMY_INTERIOR
|
||||
|
||||
if ((bio_status & ANATOMY_EXTERIOR_AND_INTERIOR) == ANATOMY_EXTERIOR_AND_INTERIOR)
|
||||
break
|
||||
|
||||
return bio_status
|
||||
|
||||
/// Returns if our current mangling status allows us to be dismembered. Requires both no exterior/mangled exterior and no interior/mangled interior.
|
||||
/obj/item/bodypart/proc/dismemberable_by_wound()
|
||||
SHOULD_BE_PURE(TRUE)
|
||||
|
||||
var/mangled_state = get_mangled_state()
|
||||
|
||||
var/bio_status = get_bio_state_status()
|
||||
|
||||
var/has_exterior = ((bio_status & ANATOMY_EXTERIOR))
|
||||
var/has_interior = ((bio_status & ANATOMY_INTERIOR))
|
||||
|
||||
var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR)))
|
||||
var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_INTERIOR)))
|
||||
|
||||
return (exterior_ready_to_dismember && interior_ready_to_dismember)
|
||||
|
||||
/// Returns TRUE if our total percent damage is more or equal to our dismemberable percentage, but FALSE if a wound can cause us to be dismembered.
|
||||
/obj/item/bodypart/proc/dismemberable_by_total_damage()
|
||||
|
||||
update_wound_theory()
|
||||
|
||||
var/bio_status = get_bio_state_status()
|
||||
|
||||
var/has_interior = ((bio_status & ANATOMY_INTERIOR))
|
||||
var/can_theoretically_be_dismembered_by_wound = (any_existing_wound_can_mangle_our_interior || (any_existing_wound_can_mangle_our_exterior && has_interior))
|
||||
|
||||
var/wound_dismemberable = dismemberable_by_wound()
|
||||
var/ready_to_use_alternate_formula = (use_alternate_dismemberment_calc_even_if_mangleable || (!wound_dismemberable && !can_theoretically_be_dismembered_by_wound))
|
||||
|
||||
if (ready_to_use_alternate_formula)
|
||||
var/percent_to_total_max = (get_damage() / max_damage)
|
||||
if (percent_to_total_max >= hp_percent_to_dismemberable)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/// Updates our "can be theoretically dismembered by wounds" variables by iterating through all wound static data.
|
||||
/obj/item/bodypart/proc/update_wound_theory()
|
||||
// We put this here so we dont increase init time by doing this all at once on initialization
|
||||
// Effectively, we "lazy load"
|
||||
if (isnull(any_existing_wound_can_mangle_our_interior) || isnull(any_existing_wound_can_mangle_our_exterior))
|
||||
any_existing_wound_can_mangle_our_interior = FALSE
|
||||
any_existing_wound_can_mangle_our_exterior = FALSE
|
||||
for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type]
|
||||
if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific
|
||||
continue
|
||||
if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_EXTERIOR)
|
||||
any_existing_wound_can_mangle_our_exterior = TRUE
|
||||
if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_INTERIOR)
|
||||
any_existing_wound_can_mangle_our_interior = TRUE
|
||||
|
||||
if (any_existing_wound_can_mangle_our_interior && any_existing_wound_can_mangle_our_exterior)
|
||||
break
|
||||
|
||||
//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
|
||||
//Damage cannot go below zero.
|
||||
//Cannot remove negative damage (i.e. apply damage)
|
||||
@@ -1105,9 +1141,6 @@
|
||||
for(var/datum/wound/iter_wound as anything in wounds)
|
||||
cached_bleed_rate += iter_wound.blood_flow
|
||||
|
||||
if(!cached_bleed_rate)
|
||||
QDEL_NULL(grasped_by)
|
||||
|
||||
// Our bleed overlay is based directly off bleed_rate, so go aheead and update that would you?
|
||||
if(cached_bleed_rate != old_bleed_rate)
|
||||
update_part_wound_overlay()
|
||||
@@ -1280,3 +1313,21 @@
|
||||
|
||||
/obj/item/bodypart/proc/un_paralyze()
|
||||
REMOVE_TRAITS_IN(src, EMP_TRAIT)
|
||||
|
||||
/// Returns the generic description of our BIO_EXTERNAL feature(s), prioritizing certain ones over others. Returns error on failure.
|
||||
/obj/item/bodypart/proc/get_external_description()
|
||||
if (biological_state & BIO_FLESH)
|
||||
return "flesh"
|
||||
if (biological_state & BIO_WIRED)
|
||||
return "wiring"
|
||||
|
||||
return "error"
|
||||
|
||||
/// Returns the generic description of our BIO_INTERNAL feature(s), prioritizing certain ones over others. Returns error on failure.
|
||||
/obj/item/bodypart/proc/get_internal_description()
|
||||
if (biological_state & BIO_BONE)
|
||||
return "bone"
|
||||
if (biological_state & BIO_METAL)
|
||||
return "metal"
|
||||
|
||||
return "error"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
return TRUE
|
||||
|
||||
///Remove target limb from it's owner, with side effects.
|
||||
/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent=TRUE, wound_type)
|
||||
/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent=TRUE, wounding_type)
|
||||
if(!owner || (bodypart_flags & BODYPART_UNREMOVABLE))
|
||||
return FALSE
|
||||
var/mob/living/carbon/limb_owner = owner
|
||||
@@ -23,14 +23,14 @@
|
||||
limb_owner.add_mood_event("dismembered_[body_zone]", /datum/mood_event/dismembered, src)
|
||||
limb_owner.add_mob_memory(/datum/memory/was_dismembered, lost_limb = src)
|
||||
|
||||
if (wound_type)
|
||||
LAZYSET(limb_owner.body_zone_dismembered_by, body_zone, wound_type)
|
||||
if (wounding_type)
|
||||
LAZYSET(limb_owner.body_zone_dismembered_by, body_zone, wounding_type)
|
||||
|
||||
drop_limb()
|
||||
|
||||
limb_owner.update_equipment_speed_mods() // Update in case speed affecting item unequipped by dismemberment
|
||||
var/turf/owner_location = limb_owner.loc
|
||||
if(wound_type != WOUND_BURN && istype(owner_location) && can_bleed())
|
||||
if(wounding_type != WOUND_BURN && istype(owner_location) && can_bleed())
|
||||
limb_owner.add_splatter_floor(owner_location)
|
||||
|
||||
if(QDELETED(src)) //Could have dropped into lava/explosion/chasm/whatever
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/bodypart/chest/dismember(dam_type = BRUTE, silent=TRUE, wound_type)
|
||||
/obj/item/bodypart/chest/dismember(dam_type = BRUTE, silent=TRUE, wounding_type)
|
||||
if(!owner)
|
||||
return FALSE
|
||||
var/mob/living/carbon/chest_owner = owner
|
||||
@@ -64,7 +64,7 @@
|
||||
if(HAS_TRAIT(chest_owner, TRAIT_NODISMEMBER))
|
||||
return FALSE
|
||||
. = list()
|
||||
if(wound_type != WOUND_BURN && isturf(chest_owner.loc) && can_bleed())
|
||||
if(wounding_type != WOUND_BURN && isturf(chest_owner.loc) && can_bleed())
|
||||
chest_owner.add_splatter_floor(chest_owner.loc)
|
||||
playsound(get_turf(chest_owner), 'sound/misc/splort.ogg', 80, TRUE)
|
||||
for(var/obj/item/organ/organ as anything in chest_owner.organs)
|
||||
@@ -158,16 +158,16 @@
|
||||
* Dismemberment for flesh and bone requires the victim to have the skin on their bodypart destroyed (either a critical cut or piercing wound), and at least a hairline fracture
|
||||
* (severe bone), at which point we can start rolling for dismembering. The attack must also deal at least 10 damage, and must be a brute attack of some kind (sorry for now, cakehat, maybe later)
|
||||
*
|
||||
* Returns: BODYPART_MANGLED_NONE if we're fine, BODYPART_MANGLED_FLESH if our skin is broken, BODYPART_MANGLED_BONE if our bone is broken, or BODYPART_MANGLED_BOTH if both are broken and we're up for dismembering
|
||||
* Returns: BODYPART_MANGLED_NONE if we're fine, BODYPART_MANGLED_EXTERIOR if our skin is broken, BODYPART_MANGLED_INTERIOR if our bone is broken, or BODYPART_MANGLED_BOTH if both are broken and we're up for dismembering
|
||||
*/
|
||||
/obj/item/bodypart/proc/get_mangled_state()
|
||||
. = BODYPART_MANGLED_NONE
|
||||
|
||||
for(var/datum/wound/iter_wound as anything in wounds)
|
||||
if((iter_wound.wound_flags & MANGLES_BONE))
|
||||
. |= BODYPART_MANGLED_BONE
|
||||
if((iter_wound.wound_flags & MANGLES_FLESH))
|
||||
. |= BODYPART_MANGLED_FLESH
|
||||
if((iter_wound.wound_flags & MANGLES_INTERIOR))
|
||||
. |= BODYPART_MANGLED_INTERIOR
|
||||
if((iter_wound.wound_flags & MANGLES_EXTERIOR))
|
||||
. |= BODYPART_MANGLED_EXTERIOR
|
||||
|
||||
/**
|
||||
* try_dismember() is used, once we've confirmed that a flesh and bone bodypart has both the skin and bone mangled, to actually roll for it
|
||||
@@ -445,8 +445,8 @@
|
||||
if (LAZYLEN(dismembered_by_copy))
|
||||
var/datum/scar/scaries = new
|
||||
var/datum/wound/loss/phantom_loss = new // stolen valor, really
|
||||
phantom_loss.loss_wound_type = dismembered_by_copy?[limb_zone]
|
||||
if (phantom_loss.loss_wound_type)
|
||||
phantom_loss.loss_wounding_type = dismembered_by_copy?[limb_zone]
|
||||
if (phantom_loss.loss_wounding_type)
|
||||
scaries.generate(limb, phantom_loss)
|
||||
LAZYREMOVE(dismembered_by_copy, limb_zone) // in case we're using a passed list
|
||||
else
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
if(cavity_item)
|
||||
cavity_item.forceMove(drop_location())
|
||||
cavity_item = null
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/bodypart/chest/monkey
|
||||
icon = 'icons/mob/human/species/monkey/bodyparts.dmi'
|
||||
@@ -114,7 +114,7 @@
|
||||
/// Datum describing how to offset things held in the hands of this arm, the x offset IS functional here
|
||||
var/datum/worn_feature_offset/held_hand_offset
|
||||
|
||||
biological_state = (BIO_STANDARD|BIO_JOINTED)
|
||||
biological_state = BIO_STANDARD_JOINTED
|
||||
|
||||
/obj/item/bodypart/arm/Destroy()
|
||||
QDEL_NULL(worn_glove_offset)
|
||||
@@ -346,7 +346,7 @@
|
||||
/// Datum describing how to offset things worn on the foot of this leg, note that an x offset won't do anything here
|
||||
var/datum/worn_feature_offset/worn_foot_offset
|
||||
|
||||
biological_state = (BIO_STANDARD|BIO_JOINTED)
|
||||
biological_state = BIO_STANDARD_JOINTED
|
||||
|
||||
/obj/item/bodypart/leg/Destroy()
|
||||
QDEL_NULL(worn_foot_offset)
|
||||
|
||||
@@ -1,81 +1,40 @@
|
||||
/// Allows us to roll for and apply a wound without actually dealing damage. Used for aggregate wounding power with pellet clouds
|
||||
/obj/item/bodypart/proc/painless_wound_roll(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus, sharpness=NONE)
|
||||
/obj/item/bodypart/proc/painless_wound_roll(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus, sharpness=NONE)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
|
||||
if(!owner || phantom_wounding_dmg <= WOUND_MINIMUM_DAMAGE || wound_bonus == CANT_WOUND || (owner.status_flags & GODMODE))
|
||||
if(!owner || wounding_dmg <= WOUND_MINIMUM_DAMAGE || wound_bonus == CANT_WOUND || (owner.status_flags & GODMODE))
|
||||
return
|
||||
|
||||
var/mangled_state = get_mangled_state()
|
||||
var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%)
|
||||
|
||||
var/has_exterior = FALSE
|
||||
var/has_interior = FALSE
|
||||
var/bio_status = get_bio_state_status()
|
||||
|
||||
for (var/state as anything in GLOB.bio_state_states)
|
||||
var/flag = text2num(state)
|
||||
if (!(biological_state & flag))
|
||||
continue
|
||||
var/has_exterior = ((bio_status & ANATOMY_EXTERIOR))
|
||||
var/has_interior = ((bio_status & ANATOMY_INTERIOR))
|
||||
|
||||
var/value = GLOB.bio_state_states[state]
|
||||
if (value & BIO_EXTERIOR)
|
||||
has_exterior = TRUE
|
||||
if (value & BIO_INTERIOR)
|
||||
has_interior = TRUE
|
||||
|
||||
if (has_exterior && has_interior)
|
||||
break
|
||||
|
||||
// We put this here so we dont increase init time by doing this all at once on initialization
|
||||
// Effectively, we "lazy load"
|
||||
if (isnull(any_existing_wound_can_mangle_our_bone) || isnull(any_existing_wound_can_mangle_our_flesh))
|
||||
any_existing_wound_can_mangle_our_bone = FALSE
|
||||
any_existing_wound_can_mangle_our_flesh = FALSE
|
||||
for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type]
|
||||
if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific
|
||||
continue
|
||||
if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_FLESH)
|
||||
any_existing_wound_can_mangle_our_flesh = TRUE
|
||||
if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_BONE)
|
||||
any_existing_wound_can_mangle_our_bone = TRUE
|
||||
|
||||
if (any_existing_wound_can_mangle_our_bone && any_existing_wound_can_mangle_our_flesh)
|
||||
break
|
||||
|
||||
var/can_theoretically_be_dismembered = (any_existing_wound_can_mangle_our_bone || (any_existing_wound_can_mangle_our_flesh && !has_exterior))
|
||||
|
||||
var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_BONE) == BODYPART_MANGLED_BONE))
|
||||
var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_FLESH) == BODYPART_MANGLED_FLESH))
|
||||
var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR)))
|
||||
|
||||
// if we're bone only, all cutting attacks go straight to the bone
|
||||
if(has_exterior && interior_ready_to_dismember)
|
||||
if(!has_exterior && has_interior)
|
||||
if(wounding_type == WOUND_SLASH)
|
||||
wounding_type = WOUND_BLUNT
|
||||
phantom_wounding_dmg *= (easy_dismember ? 1 : 0.6)
|
||||
wounding_dmg *= (easy_dismember ? 1 : 0.6)
|
||||
else if(wounding_type == WOUND_PIERCE)
|
||||
wounding_type = WOUND_BLUNT
|
||||
phantom_wounding_dmg *= (easy_dismember ? 1 : 0.75)
|
||||
if(exterior_ready_to_dismember && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
return
|
||||
wounding_dmg *= (easy_dismember ? 1 : 0.75)
|
||||
else
|
||||
// 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(has_exterior && interior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness)
|
||||
playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
|
||||
if(has_interior && exterior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_INTERIOR) && sharpness)
|
||||
if(wounding_type == WOUND_SLASH && !easy_dismember)
|
||||
phantom_wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area
|
||||
wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area
|
||||
if(wounding_type == WOUND_PIERCE && !easy_dismember)
|
||||
phantom_wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
|
||||
wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
|
||||
wounding_type = WOUND_BLUNT
|
||||
else if(interior_ready_to_dismember && exterior_ready_to_dismember && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
if ((dismemberable_by_wound() || dismemberable_by_total_damage()) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
return
|
||||
if (use_alternate_dismemberment_calc_even_if_mangleable || !can_theoretically_be_dismembered)
|
||||
var/percent_to_total_max = (get_damage() / max_damage)
|
||||
if (percent_to_total_max >= hp_percent_to_dismemberable)
|
||||
if (try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
|
||||
return
|
||||
|
||||
return check_wounding(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)
|
||||
return check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)
|
||||
|
||||
/**
|
||||
* check_wounding() is where we handle rolling for, selecting, and applying a wound if we meet the criteria
|
||||
@@ -111,6 +70,8 @@
|
||||
var/base_roll = rand(1, round(damage ** WOUND_DAMAGE_EXPONENT))
|
||||
var/injury_roll = base_roll
|
||||
injury_roll += check_woundings_mods(woundtype, damage, wound_bonus, bare_wound_bonus)
|
||||
var/list/series_wounding_mods = check_series_wounding_mods()
|
||||
|
||||
if(injury_roll > WOUND_DISMEMBER_OUTRIGHT_THRESH && prob(get_damage() / max_damage * 100))
|
||||
var/datum/wound/loss/dismembering = new
|
||||
dismembering.apply_dismember(src, woundtype, outright = TRUE, attack_direction = attack_direction)
|
||||
@@ -119,8 +80,8 @@
|
||||
var/list/datum/wound/possible_wounds = list()
|
||||
for (var/datum/wound/type as anything in GLOB.all_wound_pregen_data)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[type]
|
||||
if (pregen_data.can_be_applied_to(src, woundtype, random_roll = TRUE))
|
||||
possible_wounds += type
|
||||
if (pregen_data.can_be_applied_to(src, list(woundtype), random_roll = TRUE))
|
||||
possible_wounds[type] = pregen_data.get_weight(src, woundtype, damage, attack_direction, damage_source)
|
||||
// quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/human_wearer = owner
|
||||
@@ -131,39 +92,137 @@
|
||||
bare_wound_bonus = 0
|
||||
break
|
||||
|
||||
//cycle through the wounds of the relevant category from the most severe down
|
||||
for(var/datum/wound/possible_wound as anything in possible_wounds)
|
||||
for (var/datum/wound/iterated_path as anything in possible_wounds)
|
||||
for (var/datum/wound/existing_wound as anything in wounds)
|
||||
if (iterated_path == existing_wound.type)
|
||||
possible_wounds -= iterated_path
|
||||
break // breaks out of the nested loop
|
||||
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[iterated_path]
|
||||
var/specific_injury_roll = (injury_roll + series_wounding_mods[pregen_data.wound_series])
|
||||
if (pregen_data.get_threshold_for(src, attack_direction, damage_source) > specific_injury_roll)
|
||||
possible_wounds -= iterated_path
|
||||
continue
|
||||
|
||||
if (pregen_data.compete_for_wounding)
|
||||
for (var/datum/wound/other_path as anything in possible_wounds)
|
||||
if (other_path == iterated_path)
|
||||
continue
|
||||
if (initial(iterated_path.severity) == initial(other_path.severity) && pregen_data.overpower_wounds_of_even_severity)
|
||||
possible_wounds -= other_path
|
||||
continue
|
||||
else if (pregen_data.competition_mode == WOUND_COMPETITION_OVERPOWER_LESSERS)
|
||||
if (initial(iterated_path.severity) > initial(other_path.severity))
|
||||
possible_wounds -= other_path
|
||||
continue
|
||||
else if (pregen_data.competition_mode == WOUND_COMPETITION_OVERPOWER_GREATERS)
|
||||
if (initial(iterated_path.severity) < initial(other_path.severity))
|
||||
possible_wounds -= other_path
|
||||
continue
|
||||
|
||||
while (length(possible_wounds))
|
||||
var/datum/wound/possible_wound = pick_weight(possible_wounds)
|
||||
var/datum/wound_pregen_data/possible_pregen_data = GLOB.all_wound_pregen_data[possible_wound]
|
||||
possible_wounds -= possible_wound
|
||||
|
||||
var/datum/wound/replaced_wound
|
||||
for(var/datum/wound/existing_wound as anything in wounds)
|
||||
if(existing_wound.wound_series == initial(possible_wound.wound_series))
|
||||
var/datum/wound_pregen_data/existing_pregen_data = GLOB.all_wound_pregen_data[existing_wound.type]
|
||||
if(existing_pregen_data.wound_series == possible_pregen_data.wound_series)
|
||||
if(existing_wound.severity >= initial(possible_wound.severity))
|
||||
return
|
||||
continue
|
||||
else
|
||||
replaced_wound = existing_wound // if we find something we keep iterating untilw e're done or we find we're outclassed by something in our series
|
||||
replaced_wound = existing_wound
|
||||
// if we get through this whole loop without continuing, we found our winner
|
||||
|
||||
if(initial(possible_wound.threshold_minimum) < injury_roll)
|
||||
var/datum/wound/new_wound
|
||||
if(replaced_wound)
|
||||
new_wound = replaced_wound.replace_wound(new possible_wound, attack_direction = attack_direction)
|
||||
else
|
||||
new_wound = new possible_wound
|
||||
new_wound.apply_wound(src, attack_direction = attack_direction, wound_source = damage_source)
|
||||
log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned
|
||||
return new_wound
|
||||
var/datum/wound/new_wound = new possible_wound
|
||||
if(replaced_wound)
|
||||
new_wound = replaced_wound.replace_wound(new_wound, attack_direction = attack_direction)
|
||||
else
|
||||
new_wound.apply_wound(src, attack_direction = attack_direction, wound_source = damage_source)
|
||||
log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned
|
||||
return new_wound
|
||||
|
||||
// try forcing a specific wound, but only if there isn't already a wound of that severity or greater for that type on this bodypart
|
||||
/obj/item/bodypart/proc/force_wound_upwards(specific_woundtype, smited = FALSE, wound_source)
|
||||
/obj/item/bodypart/proc/force_wound_upwards(datum/wound/potential_wound, smited = FALSE, wound_source)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
var/datum/wound/potential_wound = specific_woundtype
|
||||
if (isnull(potential_wound))
|
||||
return
|
||||
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[potential_wound]
|
||||
for(var/datum/wound/existing_wound as anything in wounds)
|
||||
if (existing_wound.wound_series == initial(potential_wound.wound_series))
|
||||
var/datum/wound_pregen_data/existing_pregen_data = existing_wound.get_pregen_data()
|
||||
if (existing_pregen_data.wound_series == pregen_data.wound_series)
|
||||
if(existing_wound.severity < initial(potential_wound.severity)) // we only try if the existing one is inferior to the one we're trying to force
|
||||
existing_wound.replace_wound(new potential_wound, smited)
|
||||
return
|
||||
|
||||
var/datum/wound/new_wound = new potential_wound
|
||||
new_wound.apply_wound(src, smited = smited, wound_source = wound_source)
|
||||
return new_wound
|
||||
|
||||
/**
|
||||
* A simple proc to force a type of wound onto this mob. If you just want to force a specific mainline (fractures, bleeding, etc.) wound, you only need to care about the first 3 args.
|
||||
*
|
||||
* Args:
|
||||
* * wounding_type: The wounding_type, e.g. WOUND_BLUNT, WOUND_SLASH to force onto the mob. Can be a list.
|
||||
* * obj/item/bodypart/limb: The limb we wil be applying the wound to. If null, a random bodypart will be picked.
|
||||
* * min_severity: The minimum severity that will be considered.
|
||||
* * max_severity: The maximum severity that will be considered.
|
||||
* * severity_pick_mode: The "pick mode" to be used. See get_corresponding_wound_type's documentation
|
||||
* * wound_source: The source of the wound to be applied. Nullable.
|
||||
*
|
||||
* For the rest of the args, refer to get_corresponding_wound_type().
|
||||
*
|
||||
* Returns:
|
||||
* A new wound instance if the application was successful, null otherwise.
|
||||
*/
|
||||
/mob/living/carbon/proc/cause_wound_of_type_and_severity(wounding_type, obj/item/bodypart/limb, min_severity, max_severity = min_severity, severity_pick_mode = WOUND_PICK_HIGHEST_SEVERITY, wound_source)
|
||||
if (isnull(limb))
|
||||
limb = pick(bodyparts)
|
||||
|
||||
var/list/type_list = wounding_type
|
||||
if (!islist(type_list))
|
||||
type_list = list(type_list)
|
||||
|
||||
var/datum/wound/corresponding_typepath = get_corresponding_wound_type(type_list, limb, min_severity, max_severity, severity_pick_mode)
|
||||
if (corresponding_typepath)
|
||||
return limb.force_wound_upwards(corresponding_typepath, wound_source = wound_source)
|
||||
|
||||
/// Limb is nullable, but picks a random one. Defers to limb.get_wound_threshold_of_wound_type, see it for documentation.
|
||||
/mob/living/carbon/proc/get_wound_threshold_of_wound_type(wounding_type, severity, default, obj/item/bodypart/limb, wound_source)
|
||||
if (isnull(limb))
|
||||
limb = pick(bodyparts)
|
||||
|
||||
if (!limb)
|
||||
return default
|
||||
|
||||
return limb.get_wound_threshold_of_wound_type(wounding_type, severity, default, wound_source)
|
||||
|
||||
/**
|
||||
* A simple proc that gets the best wound to fit the criteria laid out, then returns its wound threshold.
|
||||
*
|
||||
* Args:
|
||||
* * wounding_type: The wounding_type, e.g. WOUND_BLUNT, WOUND_SLASH to force onto the mob. Can be a list of wounding_types.
|
||||
* * severity: The severity that will be considered.
|
||||
* * return_value_if_no_wound: If no wound is found, we will return this instead. (It is reccomended to use named args for this one, as its unclear what it is without)
|
||||
* * wound_source: The theoretical source of the wound. Nullable.
|
||||
*
|
||||
* Returns:
|
||||
* return_value_if_no_wound if no wound is found - if one IS found, the wound threshold for that wound.
|
||||
*/
|
||||
/obj/item/bodypart/proc/get_wound_threshold_of_wound_type(wounding_type, severity, return_value_if_no_wound, wound_source)
|
||||
var/list/type_list = wounding_type
|
||||
if (!islist(type_list))
|
||||
type_list = list(type_list)
|
||||
|
||||
var/datum/wound/wound_path = get_corresponding_wound_type(type_list, src, severity, duplicates_allowed = TRUE, care_about_existing_wounds = FALSE)
|
||||
if (wound_path)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_path]
|
||||
return pregen_data.get_threshold_for(src, damage_source = wound_source)
|
||||
|
||||
return return_value_if_no_wound
|
||||
|
||||
/**
|
||||
* check_wounding_mods() is where we handle the various modifiers of a wound roll
|
||||
@@ -209,7 +268,20 @@
|
||||
|
||||
return injury_mod
|
||||
|
||||
/// Get whatever wound of the given type is currently attached to this limb, if any
|
||||
/// Should return an assoc list of (wound_series -> penalty). Will be used in determining series-specific penalties for wounding.
|
||||
/obj/item/bodypart/proc/check_series_wounding_mods()
|
||||
RETURN_TYPE(/list)
|
||||
|
||||
var/list/series_mods = list()
|
||||
|
||||
for (var/datum/wound/iterated_wound as anything in wounds)
|
||||
var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[iterated_wound.type]
|
||||
|
||||
series_mods[pregen_data.wound_series] += iterated_wound.series_threshold_penalty
|
||||
|
||||
return series_mods
|
||||
|
||||
/// Get whatever wound of the given type is currently attached to this limb, if any
|
||||
/obj/item/bodypart/proc/get_wound_type(checking_type)
|
||||
RETURN_TYPE(checking_type)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
|
||||
TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test")
|
||||
var/datum/wound/iter_test_wound
|
||||
var/datum/wound_pregen_data/iter_pregen_data = GLOB.all_wound_pregen_data[iter_test_wound]
|
||||
var/threshold_penalty = 0
|
||||
|
||||
for(iter_test_wound in iter_test_wound_list)
|
||||
var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty
|
||||
var/threshold = iter_pregen_data.threshold_minimum - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty
|
||||
if(dam_types[i] == BRUTE)
|
||||
tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i])
|
||||
else if(dam_types[i] == BURN)
|
||||
@@ -59,10 +60,11 @@
|
||||
|
||||
TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test")
|
||||
var/datum/wound/iter_test_wound
|
||||
var/datum/wound_pregen_data/iter_pregen_data = GLOB.all_wound_pregen_data[iter_test_wound]
|
||||
var/threshold_penalty = 0
|
||||
|
||||
for(iter_test_wound in iter_test_wound_list)
|
||||
var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty
|
||||
var/threshold = iter_pregen_data.threshold_minimum - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty
|
||||
if(dam_types[i] == BRUTE)
|
||||
tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i])
|
||||
else if(dam_types[i] == BURN)
|
||||
|
||||
@@ -121,11 +121,11 @@
|
||||
if(prob(35)) //Note: The randomstep on dump_mobs throws occupants into each other and often causes wounds regardless.
|
||||
continue
|
||||
for(var/obj/item/bodypart/head/head_to_wound as anything in carbon_occupant.bodyparts)
|
||||
var/type_wound = pick(list(
|
||||
/datum/wound/blunt/bone/moderate,
|
||||
/datum/wound/blunt/bone/severe,
|
||||
))
|
||||
head_to_wound.force_wound_upwards(type_wound, wound_source = src)
|
||||
var/pick_mode = text2num(pick(list(
|
||||
"[WOUND_PICK_LOWEST_SEVERITY]",
|
||||
"[WOUND_PICK_HIGHEST_SEVERITY]"
|
||||
)))
|
||||
carbon_occupant.cause_wound_of_type_and_severity(WOUND_BLUNT, head_to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, pick_mode)
|
||||
carbon_occupant.playsound_local(src, 'sound/weapons/flash_ring.ogg', 50)
|
||||
carbon_occupant.set_eye_blur_if_lower(rand(10 SECONDS, 20 SECONDS))
|
||||
|
||||
|
||||
@@ -954,13 +954,9 @@
|
||||
return FALSE
|
||||
var/mob/living/carbon/carbon_target = atom_target
|
||||
for(var/obj/item/bodypart/squish_part in carbon_target.bodyparts)
|
||||
var/type_wound
|
||||
if (squish_part.biological_state & BIO_BONE)
|
||||
type_wound = pick(list(/datum/wound/blunt/bone/critical, /datum/wound/blunt/bone/severe, /datum/wound/blunt/bone/moderate))
|
||||
else
|
||||
squish_part.receive_damage(brute=30)
|
||||
if (type_wound)
|
||||
squish_part.force_wound_upwards(type_wound, wound_source = "crushed by [src]")
|
||||
var/severity = pick(WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, WOUND_SEVERITY_CRITICAL)
|
||||
if (!carbon_target.cause_wound_of_type_and_severity(WOUND_BLUNT, squish_part, severity, wound_source = "crushed by [src]"))
|
||||
squish_part.receive_damage(brute = 30)
|
||||
carbon_target.visible_message(span_danger("[carbon_target]'s body is maimed underneath the mass of [src]!"), span_userdanger("Your body is maimed underneath the mass of [src]!"))
|
||||
return TRUE
|
||||
if(CRUSH_CRIT_HEADGIB) // skull squish!
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"generic": ["general disfigurement"],
|
||||
|
||||
"dislocate": [
|
||||
"the bone equivalent of a faded bruise",
|
||||
"a series of tiny chip marks"
|
||||
],
|
||||
|
||||
"bluntmoderate": [
|
||||
"the bone equivalent of a faded bruise",
|
||||
"a series of tiny chip marks"
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"generic": ["general disfigurement"],
|
||||
|
||||
"dislocate": [
|
||||
"light discoloring",
|
||||
"a slight blue tint",
|
||||
"a slightly deadened tint"
|
||||
],
|
||||
|
||||
"bluntmoderate": [
|
||||
"light discoloring",
|
||||
"a slight blue tint",
|
||||
|
||||
@@ -2480,6 +2480,7 @@
|
||||
#include "code\modules\actionspeed\modifiers\drugs.dm"
|
||||
#include "code\modules\actionspeed\modifiers\mood.dm"
|
||||
#include "code\modules\actionspeed\modifiers\status_effects.dm"
|
||||
#include "code\modules\actionspeed\modifiers\wound.dm"
|
||||
#include "code\modules\admin\admin.dm"
|
||||
#include "code\modules\admin\admin_fax_panel.dm"
|
||||
#include "code\modules\admin\admin_investigate.dm"
|
||||
|
||||
Reference in New Issue
Block a user