Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Separates bleeding from damage, gauze now STOPS bleeding rather than postponing it #686

Merged
merged 3 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions code/__DEFINES/dcs/signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,9 @@
/* #define SPEECH_IGNORE_SPAM 6
#define SPEECH_FORCED 7 */

///from /mob/living/life()
#define COMSIG_MOB_LIFE "mob_life"

///from /mob/say_dead(): (mob/speaker, message)
#define COMSIG_MOB_DEADSAY "mob_deadsay"
#define MOB_DEADSAY_SIGNAL_INTERCEPT (1<<0)
Expand Down Expand Up @@ -420,6 +423,8 @@
///from base of /obj/item/bodypart/proc/attach_limb(): (new_limb, special) allows you to fail limb attachment
#define COMSIG_LIVING_ATTACH_LIMB "living_attach_limb"
#define COMPONENT_NO_ATTACH 1
///from base of /obj/item/bodypart/proc/drop_limb(): (special)
#define COMSIG_LIVING_DROP_LIMB "living_drop_limb"
///from base of mob/living/set_buckled(): (new_buckled)
#define COMSIG_LIVING_SET_BUCKLED "living_set_buckled"

Expand Down
7 changes: 7 additions & 0 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
#define BLOOD_VOLUME_BAD 224
#define BLOOD_VOLUME_SURVIVE 122

// Bloodloss
#define BLOOD_LOSS_MAXIMUM 30
#define BLOOD_LOSS_DAMAGE_MAXIMUM 2
#define BLOOD_LOSS_DAMAGE_BASE 0.013
#define BLOOD_CAUTERIZATION_RATIO 10
#define BLOOD_CAUTERIZATION_DAMAGE_RATIO 300

//Sizes of mobs, used by mob/living/var/mob_size
#define MOB_SIZE_TINY 0
#define MOB_SIZE_SMALL 1
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/item_attack.dm
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
var/armor_value = run_armor_check(attack_flag = "melee", armour_penetration = I.armour_penetration) //WS Edit - Simplemobs can have armor
send_item_attack_message(I, user)
if(I.force)
apply_damage(I.force, I.damtype, break_modifier = I.force, blocked = armor_value) //Bone break modifier = item force
apply_damage(I.force, I.damtype, break_modifier = I.force, blocked = armor_value, sharpness = I.get_sharpness()) //Bone break modifier = item force
if(I.damtype == BRUTE)
if(prob(33))
I.add_mob_blood(src)
Expand Down
60 changes: 60 additions & 0 deletions code/datums/components/bandage.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#define TREATMENT_DAMAGE_MOD 2

/datum/component/bandage
/// How fast do we stop bleeding?
var/bleed_reduction = 0
/// How many healing ticks will this bandage apply? Reduced by incoming damage and current bleeding
var/lifespan = 300
var/bandage_name = "gauze"
/// The person this bandage is applied to
var/mob/living/mummy

/datum/component/bandage/Initialize(_bleed_reduction, _lifespan, _bandage_name)
if(!istype(parent, /obj/item/bodypart))
return COMPONENT_INCOMPATIBLE
var/obj/item/bodypart/BP = parent
mummy = BP.owner
if(!mummy)
return COMPONENT_INCOMPATIBLE
if(_bleed_reduction)
bleed_reduction = _bleed_reduction
if(_lifespan)
lifespan = _lifespan
if(_bandage_name)
bandage_name = _bandage_name
RegisterSignal(mummy, COMSIG_MOB_APPLY_DAMGE, PROC_REF(check_damage))
RegisterSignal(mummy, COMSIG_MOB_LIFE, PROC_REF(bandage_effects))
RegisterSignal(parent, COMSIG_LIVING_DROP_LIMB, PROC_REF(drop_bandage))

/// Checks if damage to the owner is applied to this limb and reduces lifespan (perforated bandages dont work as well)
/datum/component/bandage/proc/check_damage(attacker, damage, damagetype = BRUTE, def_zone = null)
SIGNAL_HANDLER

if(parent != mummy.get_bodypart(check_zone(def_zone)))
return
lifespan -= damage / 100 * initial(lifespan) * TREATMENT_DAMAGE_MOD //take incoming damage as a % of durability
if(lifespan <= 0)
drop_bandage()

/// Handles healing effects and passive lifespan usage
/datum/component/bandage/proc/bandage_effects()
SIGNAL_HANDLER

var/obj/item/bodypart/heal_target = parent
lifespan -= 1 + heal_target.bleeding // particularly nasty bleeding can burn through dressing faster
heal_target.adjust_bleeding(-bleed_reduction)
if(lifespan <= 0 || !heal_target.bleeding) //remove treatment once it's no longer able to treat
drop_bandage(TRUE)

/// Handles deleting the component when the bandage runs out of lifespan or finishes healing. Special = bandage didn't get torn off
/datum/component/bandage/proc/drop_bandage(special = FALSE)
SIGNAL_HANDLER

var/obj/item/bodypart/BP = parent
if(special)
to_chat(mummy, span_notice("The [bandage_name] on your [parse_zone(BP.body_zone)] has [BP.bleeding ? "done what it can" : "stopped the bleeding"]."))
else
to_chat(mummy, span_warning("The [bandage_name] on your [parse_zone(BP.body_zone)] is damaged beyond use!"))
qdel(src)

#undef TREATMENT_DAMAGE_MOD
8 changes: 7 additions & 1 deletion code/datums/components/butchering.dm
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,17 @@
"<span class='warning'>Their neck has already been already cut, you can't make the bleeding any worse!</span>")
return

var/obj/item/bodypart/throat_in_question = H.get_bodypart(BODY_ZONE_HEAD)
if(!throat_in_question)
user.show_message("<span class='warning'>[H]... doesn't have a neck.</span>", MSG_VISUAL, \
"<span class='warning'>They don't seem to have a neck to cut.</span>")
return

H.visible_message("<span class='danger'>[user] slits [H]'s throat!</span>", \
"<span class='userdanger'>[user] slits your throat...</span>")
log_combat(user, H, "finishes slicing the throat of")
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD)
H.bleed_rate = clamp(H.bleed_rate + 20, 0, 30)
throat_in_question.adjust_bleeding(20)
H.apply_status_effect(/datum/status_effect/neck_slice)

/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
Expand Down
2 changes: 1 addition & 1 deletion code/datums/diseases/advance/symptoms/flesh_eating.dm
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Bonus
if(bleed)
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.bleed_rate += 5 * power
H.cause_bleeding(5 * power)
return 1

/*
Expand Down
3 changes: 2 additions & 1 deletion code/datums/status_effects/debuffs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@

/datum/status_effect/neck_slice/tick()
var/mob/living/carbon/human/H = owner
if(H.stat == DEAD || H.bleed_rate <= 8)
var/obj/item/bodypart/throat_in_question = H.get_bodypart(BODY_ZONE_HEAD)
if(H.stat == DEAD || throat_in_question?.bleeding <= 8)
H.remove_status_effect(/datum/status_effect/neck_slice)
if(prob(10))
H.emote(pick("gasp", "gag", "choke"))
Expand Down
2 changes: 1 addition & 1 deletion code/game/machinery/medical_kiosk.dm
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
sickness_data = "\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]"

if(altPatient.has_dna()) //Blood levels Information
if(altPatient.bleed_rate)
if(LAZYLEN(altPatient.get_bleeding_parts()))
bleed_status = "Patient is currently bleeding!"
if(blood_percent <= 80)
blood_warning = " Patient has low blood levels. Seek a large meal, or iron supplements."
Expand Down
6 changes: 6 additions & 0 deletions code/game/machinery/suit_storage_unit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,12 @@
else
visible_message(span_warning("[src]'s door slides open, barraging you with the nauseating smell of charred flesh."))
mob_occupant.radiation = 0
if(iscarbon(mob_occupant))
var/mob/living/carbon/bacon = mob_occupant
for(var/obj/item/bodypart/grilling as anything in bacon.get_bleeding_parts(TRUE))
if(!grilling.can_bandage())
continue
grilling.apply_bandage(0.005, 600, "cauterization")
playsound(src, 'sound/machines/airlocks/standard/close.ogg', 25, TRUE)
var/list/things_to_clear = list() //Done this way since using GetAllContents on the SSU itself would include circuitry and such.
if(suit)
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/devices/scanners.dm
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ GENE SCANNER
if(blood_id)
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(H.bleed_rate)
if(LAZYLEN(H.get_bleeding_parts()))
render_list += "<span class='alert ml-1'><b>Subject is bleeding!</b></span>\n"
var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
var/blood_type = C.dna.blood_type.name
Expand Down
24 changes: 14 additions & 10 deletions code/game/objects/items/stacks/medical.dm
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,13 @@

/obj/item/stack/medical/gauze
name = "medical gauze"
desc = "A roll of elastic cloth that is extremely effective at stopping bleeding, but does not heal wounds."
desc = "A roll of elastic cloth that is extremely effective at stopping bleeding and slowly heals wounds."
gender = PLURAL
singular_name = "medical gauze"
icon_state = "gauze"
apply_sounds = list('sound/effects/rip1.ogg', 'sound/effects/rip2.ogg')
var/stop_bleeding = 1800
var/bleed_reduction = 0.02
var/lifespan = 150
self_delay = 20
max_amount = 12
grind_results = list(/datum/reagent/cellulose = 2)
Expand All @@ -152,13 +153,16 @@
amount = 12

/obj/item/stack/medical/gauze/heal(mob/living/target, mob/user)
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(!H.bleedsuppress && H.bleed_rate) //so you can't stack bleed suppression
H.suppress_bloodloss(stop_bleeding)
to_chat(user, "<span class='notice'>You stop the bleeding of [target]!</span>")
if(iscarbon(target))
var/mob/living/carbon/C = target
var/obj/item/bodypart/BP = C.get_bodypart(check_zone(user.zone_selected))
if(!BP)
to_chat(user, span_warning("[C] doesn't have \a [parse_zone(user.zone_selected)]!"))
return
if(BP.can_bandage(user))
BP.apply_bandage(bleed_reduction, lifespan, name)
user.visible_message(span_notice("[user] wraps [C]'s [parse_zone(BP.body_zone)] with [src]."), span_notice("You wrap [C]'s [parse_zone(check_zone(user.zone_selected))] with [src]."), span_hear("You hear ruffling cloth."))
return TRUE
to_chat(user, "<span class='warning'>You can not use \the [src] on [target]!</span>")

/obj/item/stack/medical/gauze/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_WIRECUTTER || I.get_sharpness())
Expand All @@ -178,8 +182,8 @@
/obj/item/stack/medical/gauze/improvised
name = "improvised gauze"
singular_name = "improvised gauze"
desc = "A roll of cloth roughly cut from something that can stop bleeding, but does not heal wounds."
stop_bleeding = 900
desc = "A roll of cloth roughly cut from something that can stop bleeding and slowly heal wounds."
bleed_reduction = 0.005

/obj/item/stack/medical/gauze/cyborg
custom_materials = null
Expand Down
24 changes: 10 additions & 14 deletions code/game/objects/items/stacks/tape.dm
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@
grind_results = list(/datum/reagent/cellulose = 5)
usesound = 'sound/items/tape.ogg'

var/stop_bleed = 600
var/lifespan = 300
var/bleed_reduction = 0.002
var/nonorganic_heal = 5
var/self_delay = 30 //! Also used for the tapecuff delay
var/other_delay = 10
Expand Down Expand Up @@ -173,21 +174,17 @@
if(!affecting) //Missing limb?
to_chat(user, "<span class='warning'>[C] doesn't have \a [parse_zone(user.zone_selected)]!</span>")
return
if(!IS_ORGANIC_LIMB(affecting))
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(!H.bleedsuppress && H.bleed_rate)
H.suppress_bloodloss(stop_bleed)
to_chat(user, "<span class='notice'>You tape up the bleeding of [C]!</span>")
return TRUE
to_chat(user, "<span class='warning'>[C] has a problem \the [src] won't fix!</span>")
else //Robotic patch-up
if(IS_ROBOTIC_LIMB(affecting)) //Robotic patch-up
if(affecting.brute_dam)
user.visible_message("<span class='notice'>[user] applies \the [src] on [C]'s [affecting.name].</span>", "<span class='green'>You apply \the [src] on [C]'s [affecting.name].</span>")
if(affecting.heal_damage(nonorganic_heal))
C.update_damage_overlays()
return TRUE
to_chat(user, "<span class='warning'>[src] can't patch what [C] has...</span>")
if(affecting.can_bandage(user))
affecting.apply_bandage(bleed_reduction, lifespan, name)
to_chat(user, "<span class='notice'>You tape up [C]'s [parse_zone(affecting.body_zone)]!</span>")
return TRUE
to_chat(user, "<span class='warning'>[src] can't patch what [C] has...</span>")

/obj/item/stack/tape/proc/apply_gag(mob/living/carbon/target, mob/user)
if(target.is_muzzled() || target.is_mouth_covered())
Expand Down Expand Up @@ -272,7 +269,7 @@
desc = "This roll of silver sorcery can fix just about anything."
icon_state = "tape_d"

stop_bleed = 800
lifespan = 400
nonorganic_heal = 20
prefix = "super sticky"
conferred_embed = EMBED_HARMLESS_SUPERIOR
Expand All @@ -297,7 +294,6 @@
desc = "Specialty insulated strips of adhesive plastic. Made for securing cables."
icon_state = "tape_e"

stop_bleed = 400
nonorganic_heal = 10
prefix = "insulated sticky"
siemens_coefficient = 0
Expand All @@ -321,6 +317,6 @@
desc = "Now THIS is engineering."
icon_state = "tape_y"

stop_bleed = 1000
lifespan = 500
nonorganic_heal = 30
prefix = "industry-standard sticky"
5 changes: 4 additions & 1 deletion code/game/objects/structures/petrified_statue.dm
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@

if(petrified_mob)
petrified_mob.status_flags &= ~GODMODE
if(ishuman(petrified_mob))
var/mob/living/carbon/human/H = petrified_mob
H.bleedsuppress = FALSE
petrified_mob.forceMove(loc)
REMOVE_TRAIT(petrified_mob, TRAIT_MUTE, STATUE_MUTE)
petrified_mob.take_overall_damage((petrified_mob.health - obj_integrity + 100)) //any new damage the statue incurred is transfered to the mob
Expand All @@ -80,7 +83,7 @@
return 0
var/obj/structure/statue/petrified/S = new(loc, src, statue_timer)
S.name = "statue of [name]"
bleedsuppress = 1
bleedsuppress = TRUE
S.copy_overlays(src)
var/newcolor = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
S.add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
Expand Down
6 changes: 6 additions & 0 deletions code/modules/food_and_drinks/kitchen_machinery/microwave.dm
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,12 @@
playsound(src, 'sound/items/cig_light.ogg', 50, 1)
moveToNullspace()


/obj/item/ration_heater/get_temperature()
if(!uses)
return 0
. = ..()

/obj/item/ration_heater/proc/clear_cooking(datum/source)
SIGNAL_HANDLER
UnregisterSignal(tocook, COMSIG_PARENT_QDELETING)
Expand Down
35 changes: 9 additions & 26 deletions code/modules/mob/living/blood.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,6 @@
BLOOD SYSTEM
****************************************************/

/mob/living/carbon/human/proc/suppress_bloodloss(amount)
if(bleedsuppress)
return
else
bleedsuppress = TRUE
addtimer(CALLBACK(src, PROC_REF(resume_bleeding)), amount)

/mob/living/carbon/human/proc/resume_bleeding()
bleedsuppress = 0
if(stat != DEAD && bleed_rate)
to_chat(src, "<span class='warning'>The blood soaks through your bandage.</span>")


/mob/living/carbon/monkey/handle_blood()
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
Expand All @@ -29,7 +16,6 @@
/mob/living/carbon/human/handle_blood()

if(NOBLOOD in dna.species.species_traits)
bleed_rate = 0
return

if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
Expand Down Expand Up @@ -83,24 +69,20 @@
if(!HAS_TRAIT(src, TRAIT_NODEATH))
death()

var/temp_bleed = 0
//Bleeding out
var/limb_bleed = 0
for(var/obj/item/bodypart/BP as anything in bodyparts)
var/brutedamage = BP.brute_dam

if(BP.GetComponent(/datum/component/bandage))
continue
//We want an accurate reading of .len
listclearnulls(BP.embedded_objects)
for(var/obj/item/embeddies in BP.embedded_objects)
if(!embeddies.isEmbedHarmless())
temp_bleed += 0.5

if(brutedamage >= 20)
temp_bleed += (brutedamage * 0.013)

bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
BP.adjust_bleeding(0.1, BLOOD_LOSS_DAMAGE_MAXIMUM)
limb_bleed += BP.bleeding

if(bleed_rate && !bleedsuppress && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
bleed(bleed_rate)
if(limb_bleed && !bleedsuppress && !HAS_TRAIT(src, TRAIT_FAKEDEATH))
bleed(limb_bleed)

//Makes a blood drop, leaking amt units of blood from the mob
/mob/living/carbon/proc/bleed(amt)
Expand All @@ -125,7 +107,8 @@

/mob/living/carbon/human/restore_blood()
blood_volume = BLOOD_VOLUME_NORMAL
bleed_rate = 0
for(var/obj/item/bodypart/BP as anything in get_bleeding_parts())
BP.bleeding = 0

/****************************************************
BLOOD TRANSFERS
Expand Down
Loading
Loading