mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-21 04:48:18 +01:00
6d6735aa7b
Also ensured critical limbs (the torso and head) cannot be ruined like this. <img width="876" height="448" alt="image" src="https://github.com/user-attachments/assets/ce6cd6c6-7130-48ff-a107-1d8b8dd70b91" />
254 lines
8.0 KiB
Plaintext
254 lines
8.0 KiB
Plaintext
|
|
/****************************************************
|
|
WOUNDS
|
|
****************************************************/
|
|
/datum/wound
|
|
/// number representing the current stage
|
|
var/current_stage = 0
|
|
|
|
/// description of the wound
|
|
var/desc = "wound" //default in case something borks
|
|
|
|
/// amount of damage this wound causes
|
|
var/damage = 0
|
|
|
|
/// how many times we've tried to lower the bleed timer, used to determine whether hemophilia should let bleed timer lower
|
|
var/bleed_timer_increment = 0
|
|
|
|
/// ticks of bleeding left.
|
|
var/bleed_timer = 0
|
|
|
|
/// Above this amount wounds you will need to treat the wound to stop bleeding, regardless of bleed_timer
|
|
var/bleed_threshold = 30
|
|
|
|
/// amount of damage the current wound type requires(less means we need to apply the next healing stage)
|
|
var/min_damage = 0
|
|
|
|
/// is the wound bandaged?
|
|
var/bandaged = FALSE
|
|
/// Similar to bandaged, but works differently
|
|
var/clamped = FALSE
|
|
/// is the wound salved?
|
|
var/salved = FALSE
|
|
/// is the wound disinfected?
|
|
var/disinfected = FALSE
|
|
var/created = 0
|
|
/// number of wounds of this type
|
|
var/amount = 1
|
|
/// amount of germs in the wound
|
|
var/germ_level = 0
|
|
/// the organ the wound is on, if on an organ
|
|
var/obj/item/organ/external/parent_organ
|
|
|
|
/* These are defined by the wound type and should not be changed */
|
|
|
|
/// stages such as "cut", "deep cut", etc.
|
|
var/list/stages
|
|
/// maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented.
|
|
var/max_bleeding_stage = 0
|
|
/// String (One of `DAMAGE_TYPE_*`). The wound's injury type.
|
|
var/damage_type = INJURY_TYPE_CUT
|
|
/// whether this wound needs a bandage/salve to heal at all
|
|
/// the maximum amount of damage that this wound can have and still autoheal
|
|
var/autoheal_cutoff = 15
|
|
|
|
|
|
|
|
// helper lists
|
|
var/list/embedded_objects
|
|
var/tmp/list/desc_list = list()
|
|
var/tmp/list/damage_list = list()
|
|
|
|
/datum/wound/New(damage, obj/item/organ/external/organ = null)
|
|
|
|
created = world.time
|
|
|
|
// reading from a list("stage" = damage) is pretty difficult, so build two separate
|
|
// lists from them instead
|
|
for(var/V in stages)
|
|
desc_list += V
|
|
damage_list += stages[V]
|
|
|
|
src.damage = damage
|
|
|
|
// initialize with the appropriate stage
|
|
src.init_stage(damage)
|
|
|
|
bleed_timer += damage
|
|
|
|
if(istype(organ))
|
|
parent_organ = organ
|
|
|
|
/datum/wound/Destroy()
|
|
if(parent_organ)
|
|
LAZYREMOVE(parent_organ.wounds, src)
|
|
parent_organ = null
|
|
LAZYCLEARLIST(embedded_objects)
|
|
. = ..()
|
|
|
|
///Returns TRUE if there's a next stage, FALSE otherwise
|
|
/datum/wound/proc/init_stage(initial_damage)
|
|
current_stage = length(stages)
|
|
|
|
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= initial_damage / src.amount)
|
|
src.current_stage--
|
|
|
|
src.min_damage = damage_list[current_stage]
|
|
src.desc = desc_list[current_stage]
|
|
|
|
///The amount of damage per wound
|
|
/datum/wound/proc/wound_damage()
|
|
return src.damage / src.amount
|
|
|
|
/datum/wound/proc/can_autoheal()
|
|
if(LAZYLEN(embedded_objects))
|
|
return FALSE
|
|
|
|
return (wound_damage() <= autoheal_cutoff) ? TRUE : is_treated()
|
|
|
|
/// Checks whether the wound has been appropriately treated
|
|
/datum/wound/proc/is_treated()
|
|
if(!LAZYLEN(embedded_objects))
|
|
switch(damage_type)
|
|
if(INJURY_TYPE_BRUISE, INJURY_TYPE_CUT, INJURY_TYPE_PIERCE)
|
|
return bandaged
|
|
if(INJURY_TYPE_BURN)
|
|
return salved
|
|
|
|
/// Checks whether other other can be merged into src.
|
|
/datum/wound/proc/can_merge(datum/wound/other)
|
|
if (other.type != src.type) return FALSE
|
|
if (other.current_stage != src.current_stage) return FALSE
|
|
if (other.damage_type != src.damage_type) return FALSE
|
|
if (!(other.can_autoheal()) != !(src.can_autoheal())) return FALSE
|
|
if (!(other.bandaged) != !(src.bandaged)) return FALSE
|
|
if (!(other.clamped) != !(src.clamped)) return FALSE
|
|
if (!(other.salved) != !(src.salved)) return FALSE
|
|
if (!(other.disinfected) != !(src.disinfected)) return FALSE
|
|
if (other.parent_organ != parent_organ) return FALSE
|
|
return TRUE
|
|
|
|
/datum/wound/proc/merge_wound(datum/wound/other)
|
|
if(LAZYLEN(other.embedded_objects))
|
|
LAZYDISTINCTADD(src.embedded_objects, other.embedded_objects)
|
|
src.damage += other.damage
|
|
src.amount += other.amount
|
|
src.bleed_timer += other.bleed_timer
|
|
src.bleed_timer_increment += other.bleed_timer_increment
|
|
src.germ_level = max(src.germ_level, other.germ_level)
|
|
src.created = max(src.created, other.created) //take the newer created time
|
|
qdel(other)
|
|
|
|
/// checks if wound is considered open for external infections
|
|
/// untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if wound is bigger
|
|
/datum/wound/proc/infection_check()
|
|
if (damage < 10) //small cuts, tiny bruises, and moderate burns shouldn't be infectable.
|
|
return FALSE
|
|
if (is_treated() && damage < 25) //anything less than a flesh wound (or equivalent) isn't infectable if treated properly
|
|
return FALSE
|
|
if (disinfected)
|
|
germ_level = 0 //reset this, just in case
|
|
return FALSE
|
|
|
|
if (damage_type == INJURY_TYPE_BRUISE && !bleeding()) //bruises only infectable if bleeding
|
|
return FALSE
|
|
|
|
var/dam_coef = round(damage/10)
|
|
switch (damage_type)
|
|
if (INJURY_TYPE_BRUISE)
|
|
return prob(dam_coef*5)
|
|
if (INJURY_TYPE_BURN)
|
|
return prob(dam_coef*10)
|
|
if (INJURY_TYPE_CUT)
|
|
return prob(dam_coef*20)
|
|
|
|
return FALSE
|
|
|
|
/datum/wound/proc/bandage()
|
|
bandaged = TRUE
|
|
|
|
/datum/wound/proc/salve()
|
|
salved = TRUE
|
|
|
|
/datum/wound/proc/disinfect()
|
|
disinfected = TRUE
|
|
|
|
/// Heal the given amount of damage, and if the given amount of damage was more than what esd needed to be healed, return how much heal was left
|
|
/datum/wound/proc/heal_damage(amount)
|
|
if(LAZYLEN(embedded_objects))
|
|
return amount // heal nothing
|
|
if (parent_organ \
|
|
&& ((damage_type == INJURY_TYPE_BURN && !(parent_organ.burn_ratio < 100 || (parent_organ.limb_flags & ORGAN_HEALS_OVERKILL)))\
|
|
|| !(parent_organ.brute_ratio < 100 || (parent_organ.limb_flags & ORGAN_HEALS_OVERKILL))))
|
|
return amount // We don't want to heal wounds on irreparable organs
|
|
|
|
var/healed_damage = min(src.damage, amount)
|
|
amount -= healed_damage
|
|
src.damage -= healed_damage
|
|
|
|
while(src.wound_damage() < damage_list[current_stage] && current_stage < length(src.desc_list))
|
|
current_stage++
|
|
desc = desc_list[current_stage]
|
|
src.min_damage = damage_list[current_stage]
|
|
|
|
// return amount of healing still leftover, can be used for other wounds
|
|
return amount
|
|
|
|
/// Opens the wound again
|
|
/datum/wound/proc/open_wound(damage)
|
|
src.damage += damage
|
|
bleed_timer += damage
|
|
|
|
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= src.damage / src.amount)
|
|
src.current_stage--
|
|
|
|
src.desc = desc_list[current_stage]
|
|
src.min_damage = damage_list[current_stage]
|
|
|
|
src.bandaged = FALSE
|
|
|
|
///returns whether this wound can absorb the given amount of damage.
|
|
///this will prevent large amounts of damage being trapped in less severe wound types
|
|
/datum/wound/proc/can_worsen(damage_type, damage)
|
|
if (src.damage_type != damage_type)
|
|
return FALSE //incompatible damage types
|
|
|
|
if (src.amount > 1)
|
|
return FALSE //merged wounds cannot be worsened.
|
|
|
|
//with 1.5*, a shallow cut will be able to carry at most 30 damage,
|
|
//37.5 for a deep cut
|
|
//52.5 for a flesh wound, etc.
|
|
var/max_wound_damage = 1.5*src.damage_list[1]
|
|
if (src.damage + damage > max_wound_damage)
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/datum/wound/proc/bleeding()
|
|
for(var/obj/item/thing in embedded_objects)
|
|
if(thing.w_class > WEIGHT_CLASS_SMALL)
|
|
return FALSE
|
|
|
|
if (bandaged||clamped)
|
|
return FALSE
|
|
|
|
return ((bleed_timer > 0 || wound_damage() > bleed_threshold) && current_stage <= max_bleeding_stage)
|
|
|
|
/// Called in organ_external.dm update_damages, this will update the limb's status to bleeding, and lowers the bleed_timer if applicable
|
|
/datum/wound/proc/handle_bleeding(var/mob/victim, var/obj/item/organ/external/limb)
|
|
limb.status |= ORGAN_BLEEDING
|
|
|
|
var/can_lower_bleed = TRUE
|
|
if(HAS_TRAIT(victim, TRAIT_DISABILITY_HEMOPHILIA_MAJOR)) // major will NEVER lower
|
|
can_lower_bleed = FALSE
|
|
else if(HAS_TRAIT(victim, TRAIT_DISABILITY_HEMOPHILIA) && bleed_timer_increment % 2 != 0) // basic will lower half as fast
|
|
can_lower_bleed = FALSE
|
|
|
|
if(can_lower_bleed)
|
|
bleed_timer--
|
|
bleed_timer_increment++
|
|
|
|
/datum/wound/proc/close()
|
|
return
|