Skip to content

Commit 82a3410

Browse files
authored
wound cleanup (#1213)
* wound cleanup * fix * neck bite adjustment * whoops * refactor wound display
1 parent cc045a6 commit 82a3410

15 files changed

+351
-272
lines changed

code/modules/mob/living/carbon/human/examine.dm

+7-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@
1212
var/t_s = p_s()
1313
var/obscure_name
1414

15+
var/viewer_hallucinating = FALSE
1516
if(isliving(user))
1617
var/mob/living/L = user
1718
if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA) || HAS_TRAIT(L, TRAIT_INVISIBLE_MAN))
1819
obscure_name = TRUE
1920

21+
if(ishuman(user))
22+
var/mob/living/carbon/H = user
23+
viewer_hallucinating = H.hal_screwyhud
24+
2025
var/obscured = check_obscured_slots()
2126
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
2227

@@ -173,7 +178,7 @@
173178
break
174179
if(!is_bloody)
175180
msg += span_notice("[t_His] [body_part.plaintext_zone] is covered.\n")
176-
for(var/string in body_part.mob_examine(hal_screwyhud, TRUE))
181+
for(var/string in body_part.mob_examine(viewer_hallucinating, TRUE))
177182
msg += "[string]</br>"
178183

179184
continue
@@ -182,7 +187,7 @@
182187
if((body_part.brute_dam + body_part.burn_dam) >= body_part.max_damage * 0.8)
183188
fucked_reasons["[t_His] [body_part.plaintext_zone] is greviously injured."] = 3
184189

185-
for(var/string in body_part.mob_examine(hal_screwyhud, FALSE))
190+
for(var/string in body_part.mob_examine(viewer_hallucinating, FALSE))
186191
msg += "[string]</br>"
187192

188193
for(var/X in disabled)

code/modules/mob/living/carbon/human/human.dm

+5-1
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,11 @@
821821
if(HM.quality != POSITIVE)
822822
dna.remove_mutation(HM.name)
823823
set_coretemperature(get_body_temp_normal(apply_change=FALSE))
824-
return ..()
824+
825+
. = ..()
826+
for(var/obj/item/bodypart/BP as anything in bodyparts)
827+
for(var/datum/wound/W as anything in BP.wounds)
828+
qdel(W)
825829

826830
/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1)
827831
if(blood && (NOBLOOD in dna.species.species_traits) && !HAS_TRAIT(src, TRAIT_TOXINLOVER))

code/modules/mob/living/carbon/human/species.dm

+5-1
Original file line numberDiff line numberDiff line change
@@ -1055,11 +1055,15 @@ GLOBAL_LIST_EMPTY(features_by_species)
10551055
log_combat(user, target, "attempted to punch (missed)")
10561056
return FALSE
10571057

1058+
var/attack_sharpness = NONE
10581059
switch(atk_effect)
10591060
if(ATTACK_EFFECT_BITE)
10601061
target.add_trace_DNA_on_clothing_or_self(user, attacking_zone)
1062+
attack_sharpness |= SHARP_POINTY
1063+
10611064
if(ATTACK_EFFECT_PUNCH, ATTACK_EFFECT_CLAW, ATTACK_EFFECT_SLASH)
10621065
target.add_fingerprint_on_clothing_or_self(user, attacking_zone)
1066+
attack_sharpness |= SHARP_EDGED
10631067

10641068
var/armor_block = target.run_armor_check(affecting, BLUNT)
10651069

@@ -1088,7 +1092,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
10881092

10891093
else//other attacks deal full raw damage + 1.5x in stamina damage
10901094

1091-
target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction)
1095+
target.apply_damage(damage, attack_type, affecting, armor_block, sharpness = attack_sharpness, attack_direction = attack_direction)
10921096
target.stamina.adjust(-STAMINA_DAMAGE_UNARMED)
10931097
log_combat(user, target, "punched")
10941098
. |= ATTACK_CONSUME_STAMINA

code/modules/surgery/bodyparts/_bodyparts.dm

+9-118
Original file line numberDiff line numberDiff line change
@@ -267,117 +267,6 @@
267267
drop_limb(FALSE, TRUE)
268268
stack_trace("Bodypart moved while it still had an owner")
269269

270-
/obj/item/bodypart/examine(mob/user)
271-
SHOULD_CALL_PARENT(TRUE)
272-
. = ..()
273-
. += mob_examine()
274-
275-
/obj/item/bodypart/proc/mob_examine(hallucinating, covered, just_wounds_please)
276-
. = list()
277-
278-
if(covered)
279-
for(var/obj/item/I in embedded_objects)
280-
if(I.isEmbedHarmless())
281-
. += "<a href='?src=[REF(src)];embedded_object=[REF(I)]' class='danger'>There is \a [I] stuck to [owner.p_their()] [plaintext_zone]!</a>"
282-
else
283-
. += "<a href='?src=[REF(src)];embedded_object=[REF(I)]' class='danger'>There is \a [I] embedded in [owner.p_their()] [plaintext_zone]!</a>"
284-
285-
if(splint && istype(splint, /obj/item/stack))
286-
. += span_notice("\t <a href='?src=[REF(src)];splint_remove=1' class='notice'>[owner.p_their(TRUE)] [plaintext_zone] is splinted with [splint].</a>")
287-
288-
if(bandage)
289-
. += span_notice("\t <a href='?src=[REF(src)];bandage_remove=1' class='[bandage.absorption_capacity ? "notice" : "warning"]'>[owner.p_their(TRUE)] [plaintext_zone] is bandaged with [bandage][bandage.absorption_capacity ? "." : ", blood is trickling out."]</a>")
290-
return
291-
292-
if(hallucinating == SCREWYHUD_HEALTHY)
293-
return
294-
295-
if(hallucinating == SCREWYHUD_CRIT)
296-
var/list/flavor_text = list("a")
297-
flavor_text += pick(" pair of ", " ton of ", " several ")
298-
flavor_text += pick("large cuts", "severe burns")
299-
. += "[owner.p_they(TRUE)] [owner.p_have()] [english_list(flavor_text)] on [owner.p_their()] [plaintext_zone]."
300-
return
301-
302-
var/list/flavor_text = list()
303-
if((bodypart_flags & BP_CUT_AWAY) && !is_stump)
304-
flavor_text += "a tear at the [amputation_point] so severe that it hangs by a scrap of flesh"
305-
306-
if(!IS_ORGANIC_LIMB(src))
307-
if(brute_dam)
308-
switch(brute_dam)
309-
if(0 to 20)
310-
flavor_text += "some dents"
311-
if(21 to INFINITY)
312-
flavor_text += pick("a lot of dents","severe denting")
313-
if(burn_dam)
314-
switch(burn_dam)
315-
if(0 to 20)
316-
flavor_text += "some burns"
317-
if(21 to INFINITY)
318-
flavor_text += pick("a lot of burns","severe melting")
319-
else
320-
var/list/wound_descriptors = list()
321-
for(var/datum/wound/W as anything in wounds)
322-
var/descriptor = W.get_examine_desc()
323-
if(descriptor)
324-
wound_descriptors[descriptor] += W.amount
325-
326-
if(how_open() >= SURGERY_RETRACTED)
327-
var/bone = encased ? encased : "bone"
328-
if(bodypart_flags & BP_BROKEN_BONES)
329-
bone = "broken [bone]"
330-
wound_descriptors["[bone] exposed"] = 1
331-
332-
if(!encased || how_open() >= SURGERY_DEENCASED)
333-
var/list/bits = list()
334-
for(var/obj/item/organ/organ in contained_organs)
335-
if(organ.cosmetic_only)
336-
continue
337-
bits += organ.get_visible_state()
338-
339-
for(var/obj/item/implant in cavity_items)
340-
bits += implant.name
341-
if(length(bits))
342-
wound_descriptors["[english_list(bits)] visible in the wounds"] = 1
343-
344-
for(var/wound in wound_descriptors)
345-
switch(wound_descriptors[wound])
346-
if(1)
347-
flavor_text += "a [wound]"
348-
if(2)
349-
flavor_text += "a pair of [wound]s"
350-
if(3 to 5)
351-
flavor_text += "several [wound]s"
352-
if(6 to INFINITY)
353-
flavor_text += "a ton of [wound]\s"
354-
355-
if(just_wounds_please)
356-
return english_list(flavor_text)
357-
358-
if(owner)
359-
if(current_damage)
360-
. += "[owner.p_they(TRUE)] [owner.p_have()] [english_list(flavor_text)] on [owner.p_their()] [plaintext_zone]."
361-
362-
for(var/obj/item/I in embedded_objects)
363-
if(I.isEmbedHarmless())
364-
. += "\t <a href='?src=[REF(src)];embedded_object=[REF(I)]' class='warning'>There is \a [I] stuck to [owner.p_their()] [plaintext_zone]!</a>"
365-
else
366-
. += "\t <a href='?src=[REF(src)];embedded_object=[REF(I)]' class='warning'>There is \a [I] embedded in [owner.p_their()] [plaintext_zone]!</a>"
367-
368-
if(splint && istype(splint, /obj/item/stack))
369-
. += span_notice("\t <a href='?src=[REF(src)];splint_remove=1' class='warning'>[owner.p_their(TRUE)] [plaintext_zone] is splinted with [splint].</a>")
370-
if(bandage)
371-
. += span_notice("\n\t <a href='?src=[REF(src)];bandage_remove=1' class='notice'>[owner.p_their(TRUE)] [plaintext_zone] is bandaged with [bandage][bandage.absorption_capacity ? "." : ", <span class='warning'>it is no longer absorbing blood</span>."]</a>")
372-
return
373-
374-
else
375-
if(current_damage)
376-
. += "It has [english_list(flavor_text)]."
377-
if(bodypart_flags & BP_BROKEN_BONES)
378-
. += span_warning("It is dented and swollen.")
379-
return
380-
381270
/obj/item/bodypart/blob_act()
382271
receive_damage(max_damage)
383272

@@ -491,17 +380,15 @@
491380

492381
if(!IS_ORGANIC_LIMB(src)) //Robotic limbs don't heal or get worse.
493382
for(var/datum/wound/W as anything in wounds) //Repaired wounds disappear though
494-
if(W.damage <= 0) //and they disappear right away
383+
if(W.damage <= 0)
495384
qdel(W)
496385
return
497386

498387
for(var/datum/wound/W as anything in wounds)
499388
// wounds can disappear after 10 minutes at the earliest
500-
if(W.damage <= 0 && W.created + (10 MINUTES) <= world.time)
389+
if(W.damage <= 0 && (W.scar_expiration <= world.time))
501390
qdel(W)
502-
stack_trace("Wound with zero health collected")
503391
continue
504-
// let the GC handle the deletion of the wound
505392

506393
// slow healing
507394
var/heal_amt = 0
@@ -608,8 +495,9 @@
608495
/*
609496
// START WOUND HANDLING
610497
*/
498+
611499
// If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking
612-
var/block_cut = (pure_brute < 10) || !IS_ORGANIC_LIMB(src)
500+
var/block_cut = (pure_brute < 6) || !IS_ORGANIC_LIMB(src)
613501
var/can_cut = !block_cut && ((sharpness) || prob(brute))
614502
if(brute)
615503
var/to_create = WOUND_BRUISE
@@ -779,7 +667,7 @@
779667

780668
//update damage counts
781669
for(var/datum/wound/W as anything in wounds)
782-
if(W.damage <= 0)
670+
if(W.damage <= 0 && (W.scar_expiration <= world.time))
783671
qdel(W)
784672
continue
785673

@@ -1453,7 +1341,10 @@
14531341

14541342
user.visible_message(span_notice("[user] starts inspecting [owner]'s [plaintext_zone] carefully."))
14551343
if(LAZYLEN(wounds))
1456-
to_chat(user, span_warning("You find [mob_examine(just_wounds_please = TRUE)]."))
1344+
to_chat(user, span_warning("You find the following:"))
1345+
for(var/wound_desc in get_wound_descriptions())
1346+
to_chat(user, wound_desc)
1347+
14571348
var/list/stuff = list()
14581349
for(var/datum/wound/wound as anything in wounds)
14591350
if(LAZYLEN(wound.embedded_objects))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/obj/item/bodypart/examine(mob/user)
2+
SHOULD_CALL_PARENT(TRUE)
3+
. = ..()
4+
var/hallucinating = FALSE
5+
if(ishuman(user))
6+
var/mob/living/carbon/human/human_user
7+
hallucinating = human_user.hal_screwyhud
8+
. += mob_examine(hallucinating)
9+
10+
/obj/item/bodypart/proc/mob_examine(hallucinating, covered)
11+
. = list()
12+
13+
if(covered)
14+
for(var/obj/item/I in embedded_objects)
15+
if(I.isEmbedHarmless())
16+
. += "<a href='?src=[REF(src)];embedded_object=[REF(I)]' class='danger'>There is \a [I] stuck to [owner.p_their()] [plaintext_zone]!</a>"
17+
else
18+
. += "<a href='?src=[REF(src)];embedded_object=[REF(I)]' class='danger'>There is \a [I] embedded in [owner.p_their()] [plaintext_zone]!</a>"
19+
20+
if(splint && istype(splint, /obj/item/stack))
21+
. += span_notice("\t <a href='?src=[REF(src)];splint_remove=1' class='notice'>[owner.p_their(TRUE)] [plaintext_zone] is splinted with [splint].</a>")
22+
23+
if(bandage)
24+
. += span_notice("\t <a href='?src=[REF(src)];bandage_remove=1' class='[bandage.absorption_capacity ? "notice" : "warning"]'>[owner.p_their(TRUE)] [plaintext_zone] is bandaged with [bandage][bandage.absorption_capacity ? "." : ", blood is trickling out."]</a>")
25+
return
26+
27+
. += get_wound_descriptions(hallucinating)
28+
29+
if(owner)
30+
for(var/obj/item/I in embedded_objects)
31+
if(I.isEmbedHarmless())
32+
. += "\t <a href='?src=[REF(src)];embedded_object=[REF(I)]' class='warning'>There is \a [I] stuck to [owner.p_their()] [plaintext_zone]!</a>"
33+
else
34+
. += "\t <a href='?src=[REF(src)];embedded_object=[REF(I)]' class='warning'>There is \a [I] embedded in [owner.p_their()] [plaintext_zone]!</a>"
35+
36+
if(splint && istype(splint, /obj/item/stack))
37+
. += span_notice("\t <a href='?src=[REF(src)];splint_remove=1' class='warning'>[owner.p_their(TRUE)] [plaintext_zone] is splinted with [splint].</a>")
38+
if(bandage)
39+
. += span_notice("\n\t <a href='?src=[REF(src)];bandage_remove=1' class='notice'>[owner.p_their(TRUE)] [plaintext_zone] is bandaged with [bandage][bandage.absorption_capacity ? "." : ", <span class='warning'>it is no longer absorbing blood</span>."]</a>")
40+
return
41+
42+
else
43+
if(bodypart_flags & BP_BROKEN_BONES)
44+
. += span_warning("It is dented and swollen.")
45+
return
46+
47+
/// Returns a list of wound descriptions in text form.
48+
/obj/item/bodypart/proc/get_wound_descriptions(hallucinating) as /list
49+
RETURN_TYPE(/list)
50+
51+
if(hallucinating == SCREWYHUD_HEALTHY)
52+
return list()
53+
54+
switch(hallucinating)
55+
if(SCREWYHUD_HEALTHY)
56+
return list()
57+
58+
if(SCREWYHUD_CRIT, SCREWYHUD_DEAD)
59+
var/list/hal_wounds = list("a")
60+
hal_wounds += pick("pair of", "ton of")
61+
hal_wounds += pick("large cuts", "severe burns")
62+
return list("[owner.p_they(TRUE)] [owner.p_have()] [english_list(jointext(hal_wounds, " "))] on [owner.p_their()] [plaintext_zone].")
63+
64+
if(!IS_ORGANIC_LIMB(src))
65+
var/cyber_wounds = list()
66+
if(brute_dam)
67+
switch(brute_dam)
68+
if(0 to 20)
69+
cyber_wounds += "some dents"
70+
if(21 to INFINITY)
71+
cyber_wounds += pick("a lot of dents","severe denting")
72+
if(burn_dam)
73+
switch(burn_dam)
74+
if(0 to 20)
75+
cyber_wounds += "some burns"
76+
if(21 to INFINITY)
77+
cyber_wounds += pick("a lot of burns","severe melting")
78+
79+
return list("[owner.p_they(TRUE)] [owner.p_have()] [english_list(cyber_wounds)] on [owner.p_their()] [plaintext_zone].")
80+
81+
var/list/flavor_text = list()
82+
var/list/wound_locations = list(
83+
"[plaintext_zone]" = list(),
84+
)
85+
86+
if((bodypart_flags & BP_CUT_AWAY) && !is_stump)
87+
wound_locations[plaintext_zone]["tear at the [amputation_point] so severe that it hangs by a scrap of flesh"] = 1
88+
89+
for(var/datum/wound/W as anything in wounds)
90+
var/descriptor = W.get_examine_desc()
91+
if(descriptor)
92+
var/wound_location = W.wound_location()
93+
LAZYINITLIST(wound_locations[wound_location])
94+
wound_locations[wound_location][descriptor] += W.amount
95+
96+
if(how_open() >= SURGERY_RETRACTED)
97+
var/bone = encased ? encased : "bone"
98+
if(bodypart_flags & BP_BROKEN_BONES)
99+
bone = "broken [bone]"
100+
wound_locations[plaintext_zone]["[bone] exposed"] = 1
101+
102+
if(!encased || how_open() >= SURGERY_DEENCASED)
103+
var/list/bits = list()
104+
for(var/obj/item/organ/organ in contained_organs)
105+
if(organ.cosmetic_only)
106+
continue
107+
bits += organ.get_visible_state()
108+
109+
for(var/obj/item/implant in cavity_items)
110+
bits += implant.name
111+
112+
if(length(bits))
113+
wound_locations[plaintext_zone]["[english_list(bits)] visible in the wounds"] = 1
114+
115+
if(owner)
116+
for(var/wound_loc in wound_locations)
117+
var/list/wound_text = list()
118+
if(!length(wound_locations[wound_loc]))
119+
continue
120+
121+
for(var/wound in wound_locations[wound_loc])
122+
switch(wound_locations[wound_loc][wound])
123+
if(1)
124+
wound_text += "a [wound]"
125+
if(2)
126+
wound_text += "a pair of [wound]s"
127+
if(3 to 5)
128+
wound_text += "several [wound]s"
129+
if(6 to INFINITY)
130+
wound_text += "a ton of [wound]\s"
131+
132+
if(length(wound_text))
133+
flavor_text += span_warning("[owner.p_they(TRUE)] [owner.p_have()] [english_list(wound_text)] on [owner.p_their()] [wound_loc].")
134+
else
135+
var/list/wound_text = list()
136+
for(var/wound_loc in wound_locations)
137+
if(!length(wound_locations[wound_loc]))
138+
continue
139+
140+
for(var/wound in wound_locations[wound_loc])
141+
switch(wound_locations[wound_loc][wound])
142+
if(1)
143+
wound_text += "a [wound]"
144+
if(2)
145+
wound_text += "a pair of [wound]s"
146+
if(3 to 5)
147+
wound_text += "several [wound]s"
148+
if(6 to INFINITY)
149+
wound_text += "a ton of [wound]\s"
150+
151+
if(length(wound_text))
152+
flavor_text += span_warning("It has [english_list(wound_text)].")
153+
154+
155+
return flavor_text

0 commit comments

Comments
 (0)