Files
RikuTheKiller c7cb0674cc Preliminary blood refactor (#93854)
## About The Pull Request

Moves all blood handling into procs and adds ways to easily hook into
basically every basic blood behavior.

This PR is not meant to fix every single case of janky blood logic in
the game. The main point and motivation of this PR is to add hooks for
blood behaviors. This allows for way more flexibility with blood code.

I am not going to fix our 3000 instances of single-letter vars, wacky
blood transfers, etc. This is just the groundwork for future PRs to
build off of, and by itself, should do very little to change blood
behavior.

I also added a rigorous set of unit tests for verifying that all of the
basic blood volume procs work correctly.

## Why It's Good For The Game

Previously, blood was handled via directly reading/writing
[var/blood_volume]. This was INCREDIBLY inconsistent and there was no
way to hook into it. This PR makes blood handling way more consistent,
which is great for all sorts of features.
2025-11-13 11:45:36 -06:00

86 lines
3.3 KiB
Plaintext

/datum/wound_pregen_data/loss
abstract = FALSE
wound_path_to_generate = /datum/wound/loss
required_limb_biostate = NONE
require_any_biostate = TRUE
required_wounding_type = 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"
desc = "oof ouch!!"
sound_effect = 'sound/effects/dismember.ogg'
severity = WOUND_SEVERITY_LOSS
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 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)
if(!istype(dismembered_part) || !dismembered_part.owner || !(dismembered_part.body_zone in get_viable_zones()) || isalien(dismembered_part.owner) || !dismembered_part.can_dismember())
qdel(src)
return
set_victim(dismembered_part.owner)
var/self_msg
if(dismembered_part.body_zone == BODY_ZONE_CHEST)
occur_text = "is split open, causing [victim.p_their()] internal organs to spill out!"
self_msg = "is split open, causing your internal organs to spill out!"
else
occur_text = dismembered_part.get_dismember_message(wounding_type, outright)
var/msg = span_bolddanger("[victim]'s [dismembered_part.plaintext_zone] [occur_text]")
victim.visible_message(msg, span_userdanger("Your [dismembered_part.plaintext_zone] [self_msg ? self_msg : occur_text]"))
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.get_blood_volume())
victim.spray_blood(attack_direction, severity)
dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE, wounding_type = wounding_type)
qdel(src)
return TRUE
/obj/item/bodypart/proc/get_dismember_message(wounding_type, outright)
var/occur_text
if(outright)
switch(wounding_type)
if(WOUND_BLUNT)
occur_text = "is outright smashed to a gross pulp, severing it completely!"
if(WOUND_SLASH)
occur_text = "is outright slashed off, severing it completely!"
if(WOUND_PIERCE)
occur_text = "is outright blasted apart, severing it completely!"
if(WOUND_BURN)
occur_text = "is outright incinerated, falling to dust!"
else
var/bone_text = get_internal_description()
var/tissue_text = get_external_description()
switch(wounding_type)
if(WOUND_BLUNT)
occur_text = "is shattered through the last [bone_text] holding it together, severing it completely!"
if(WOUND_SLASH)
occur_text = "is slashed through the last [tissue_text] holding it together, severing it completely!"
if(WOUND_PIERCE)
occur_text = "is pierced through the last [tissue_text] holding it together, severing it completely!"
if(WOUND_BURN)
occur_text = "is completely incinerated, falling to dust!"
return occur_text