Improves the "Check mood" printout, reworks the "Check self" printout, minor embed changes (#89854)

## About The Pull Request

1. Reformats "Check Mood" 

Basically just cleaning it up.
- Moodlets are bullet pointed.
- Hunter is displayed here now.
- Quirks are displayed here now.
- It now tells you how drunk you feel.

Sample


![image](https://github.com/user-attachments/assets/1aac1180-1eed-45f7-9615-005eeecef8c8)

2. Reworks "Check self"

Big reworks done here.
- Organs now don't outright say "Your hear is hurty" "Your lugs are
hurty". Now they'll say something like, "Your chest feels tight" -
Unless you're self aware, then it will say "Your heart is hurty".
- Check self no longer reports wounds with 100% accuracy. You get an
approximate of what the wound is like - "Your chest has an open cut".
More severe wounds will still be bolded, though.

Sample 


![image](https://github.com/user-attachments/assets/3da6336c-63db-4298-9fcb-76748608c848)


![image](https://github.com/user-attachments/assets/6e797ef3-cb04-46cd-aa3c-520c9240953d)

3. Embed tweaks

Embeds can be hidden, and thus will only show up on health analyzers.
This means you can't rip them out by hand.
Right now only bullet shrapnel and explosion shrapnel is hidden.

## Why It's Good For The Game

1. Just some cleanup, largely. Stuff like quirks and hunger make more
sense when checking your mental rather than checking your body. Though
this might be weird for if mood is config-disabled, I might have to
revisit htat.

2. I always found that clicking on yourself and just getting a print out
of "Your liver's non-functional, your chest has a weeping avulsion, etc"
is pretty lame... it kind of diminishes diagnosis / doctor's job.
Ultimately, the goal of this is to open up a little more doctor gameplay
- primarily I think it'll allow for some fully roleplay moments, like
"Doc my chest hurts a lil" "You have 7 bullets and broken ribs bro"

3. Adds more punch to some embeds. Mostly for larp though.

## Changelog

🆑 Melbert
add: Your mood printout (clicking on the mood face) has been
reformatted, and should generally be cleaner.
add: Self examining was reworked, and overall gives you a lot less
perfect information, unless you are self-aware.
add: Bullet and grenade shrapnel is now hidden from examining - it's
skin deep. You can't rip them out with your hands, but hemostats /
wirecutters still suffice if you know they're there. Health analyzers
still pick them up too.
qol: Ghosts aren't notified about NPCs getting appendicitis 
/🆑
This commit is contained in:
MrMelbert
2025-03-15 00:51:06 -05:00
committed by GitHub
parent cf56275ce4
commit 1406210b6e
30 changed files with 342 additions and 157 deletions

View File

@@ -35,6 +35,10 @@
var/pain_stam_pct = 0
/// Traits which make target immune to us embedding into them, any trait from the list works
var/list/immune_traits = list(TRAIT_PIERCEIMMUNE)
/// The embed doesn't show up on examine, only on health analyzers.
/// (Note: This means you can't rip it out)
/// It will also hide its name (and downplay its severity) when referring to in messages.
var/stealthy_embed = FALSE
/// Thing that we're attached to
VAR_FINAL/obj/item/parent
@@ -85,6 +89,7 @@
brother.jostle_pain_mult = jostle_pain_mult
brother.pain_stam_pct = pain_stam_pct
brother.immune_traits = immune_traits.Copy()
brother.stealthy_embed = stealthy_embed
return brother
///Someone inspected our embeddable item
@@ -222,12 +227,13 @@
var/damage = parent.throwforce
if (!is_harmless(consider_stamina = TRUE))
owner.throw_alert(ALERT_EMBEDDED_OBJECT, /atom/movable/screen/alert/embeddedobject)
if(!stealthy_embed)
owner.throw_alert(ALERT_EMBEDDED_OBJECT, /atom/movable/screen/alert/embeddedobject)
owner.add_mood_event("embedded", /datum/mood_event/embedded)
if (!is_harmless())
playsound(owner,'sound/items/weapons/bladeslice.ogg', 40)
if (owner_limb.can_bleed())
parent.add_mob_blood(owner) // it embedded itself in you, of course it's bloody!
owner.add_mood_event("embedded", /datum/mood_event/embedded)
damage += parent.w_class * impact_pain_mult
SEND_SIGNAL(parent, COMSIG_ITEM_EMBEDDED, victim, target_limb)
@@ -397,7 +403,10 @@
damagetype = STAMINA,
)
to_chat(owner, span_userdanger("[parent] embedded in your [owner_limb.plaintext_zone] jostles and stings!"))
if(stealthy_embed)
to_chat(owner, span_danger("Something in your [owner_limb.plaintext_zone] jostles and stings!"))
else
to_chat(owner, span_userdanger("[parent] embedded in your [owner_limb.plaintext_zone] jostles and stings!"))
jostle_effects()
/// Effects which should occur when the owner moves, sometimes
@@ -465,8 +474,10 @@
damage = pain_stam_pct * damage,
damagetype = STAMINA,
)
to_chat(owner, span_userdanger("[parent] embedded in your [owner_limb.plaintext_zone] [pain_stam_pct < 1 ? "hurts!" : "weighs you down."]"))
if(stealthy_embed)
to_chat(owner, span_danger("Something in your [owner_limb.plaintext_zone] [pain_stam_pct < 1 ? "hurts!" : "weighs you down."]"))
else
to_chat(owner, span_userdanger("[parent] embedded in your [owner_limb.plaintext_zone] [pain_stam_pct < 1 ? "hurts!" : "weighs you down."]"))
/// Called every process, return TRUE in order to abort further processing - if it falls out, etc
/datum/embedding/proc/process_effect(seconds_per_tick)

View File

@@ -329,66 +329,108 @@
if(user != mob_parent)
return
if(user.stat >= UNCONSCIOUS)
return
print_mood(user)
/// Prints the users mood, sanity, and moodies to chat
/datum/mood/proc/print_mood(mob/user)
var/msg = "[span_info("<EM>My current mental status:</EM>")]\n"
var/msg = "[span_info("<EM>My current mental status:</EM>")]<br>"
if(!HAS_TRAIT(src, TRAIT_NOHUNGER))
msg += span_notice("My hunger: ")
var/nutrition = mob_parent.nutrition
switch(nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
msg += "[span_info("I'm completely stuffed!")]<br>"
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
msg += "[span_info("I'm well fed!")]<br>"
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
msg += "[span_info("I'm not hungry.")]<br>"
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
msg += "[span_info("I could use a bite to eat.")]<br>"
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
msg += "[span_warning("I feel quite hungry.")]<br>"
if(0 to NUTRITION_LEVEL_STARVING)
msg += "[span_boldwarning("I'm starving!")]<br>"
var/drunkness = mob_parent.get_timed_status_effect_duration(/datum/status_effect/inebriated)
if(drunkness >= 1)
msg += span_notice("My current drunkenness: ")
switch(drunkness)
if(1 to 10)
msg += "[span_info("I'm feeling a little tipsy.")]<br>"
if(11 to 21)
msg += "[span_info("I'm feeling a bit drunk.")]<br>"
if(21 to 41)
msg += "[span_info("I'm feeling quite drunk.")]<br>"
if(41 to 61)
msg += "[span_info("I'm feeling very drunk.")]<br>"
if(61 to 81)
msg += "[span_warning("I'm feeling like a mess.")]<br>"
if(81 to INFINITY)
msg += "[span_boldwarning("I'm completely wasted.")]<br>"
msg += span_notice("My current sanity: ") //Long term
switch(sanity)
if(SANITY_GREAT to INFINITY)
msg += "[span_boldnicegreen("My mind feels like a temple!")]\n"
msg += "[span_boldnicegreen("My mind feels like a temple!")]<br>"
if(SANITY_NEUTRAL to SANITY_GREAT)
msg += "[span_nicegreen("I have been feeling great lately!")]\n"
msg += "[span_nicegreen("I have been feeling great lately!")]<br>"
if(SANITY_DISTURBED to SANITY_NEUTRAL)
msg += "[span_nicegreen("I have felt quite decent lately.")]\n"
msg += "[span_nicegreen("I have felt quite decent lately.")]<br>"
if(SANITY_UNSTABLE to SANITY_DISTURBED)
msg += "[span_warning("I'm feeling a little bit unhinged...")]\n"
msg += "[span_warning("I'm feeling a little bit unhinged...")]<br>"
if(SANITY_CRAZY to SANITY_UNSTABLE)
msg += "[span_warning("I'm freaking out!!")]\n"
msg += "[span_warning("I'm freaking out!!")]<br>"
if(SANITY_INSANE to SANITY_CRAZY)
msg += "[span_boldwarning("AHAHAHAHAHAHAHAHAHAH!!")]\n"
msg += "[span_boldwarning("AHAHAHAHAHAHAHAHAHAH!!")]<br>"
msg += span_notice("My current mood: ") //Short term
switch(mood_level)
if(MOOD_LEVEL_SAD4)
msg += "[span_boldwarning("I wish I was dead!")]\n"
msg += "[span_boldwarning("I wish I was dead!")]<br>"
if(MOOD_LEVEL_SAD3)
msg += "[span_boldwarning("I feel terrible...")]\n"
msg += "[span_boldwarning("I feel terrible...")]<br>"
if(MOOD_LEVEL_SAD2)
msg += "[span_boldwarning("I feel very upset.")]\n"
msg += "[span_boldwarning("I feel very upset.")]<br>"
if(MOOD_LEVEL_SAD1)
msg += "[span_warning("I'm a bit sad.")]\n"
msg += "[span_warning("I'm a bit sad.")]<br>"
if(MOOD_LEVEL_NEUTRAL)
msg += "[span_grey("I'm alright.")]\n"
msg += "[span_grey("I'm alright.")]<br>"
if(MOOD_LEVEL_HAPPY1)
msg += "[span_nicegreen("I feel pretty okay.")]\n"
msg += "[span_nicegreen("I feel pretty okay.")]<br>"
if(MOOD_LEVEL_HAPPY2)
msg += "[span_boldnicegreen("I feel pretty good.")]\n"
msg += "[span_boldnicegreen("I feel pretty good.")]<br>"
if(MOOD_LEVEL_HAPPY3)
msg += "[span_boldnicegreen("I feel amazing!")]\n"
msg += "[span_boldnicegreen("I feel amazing!")]<br>"
if(MOOD_LEVEL_HAPPY4)
msg += "[span_boldnicegreen("I love life!")]\n"
msg += "[span_boldnicegreen("I love life!")]<br>"
msg += "[span_notice("Moodlets:")]\n"//All moodlets
msg += "[span_notice("Moodlets:")]<br>"//All moodlets
if(mood_events.len)
for(var/category in mood_events)
var/datum/mood_event/event = mood_events[category]
msg += "&bull; "
switch(event.mood_change)
if(-INFINITY to MOOD_SAD2)
msg += span_boldwarning(event.description + "\n")
msg += "[span_boldwarning(event.description)]<br>"
if(MOOD_SAD2 to MOOD_SAD1)
msg += span_warning(event.description + "\n")
msg += "[span_warning(event.description)]<br>"
if(MOOD_SAD1 to MOOD_NEUTRAL)
msg += span_grey(event.description + "\n")
msg += "[span_grey(event.description)]<br>"
if(MOOD_NEUTRAL to MOOD_HAPPY1)
msg += span_info(event.description + "\n")
msg += "[span_info(event.description)]<br>"
if(MOOD_HAPPY1 to MOOD_HAPPY2)
msg += span_nicegreen(event.description + "\n")
msg += "[span_nicegreen(event.description)]<br>"
if(MOOD_HAPPY2 to INFINITY)
msg += span_boldnicegreen(event.description + "\n")
msg += "[span_boldnicegreen(event.description)]<br>"
else
msg += "[span_grey("I don't have much of a reaction to anything right now.")]\n"
msg += "&bull; [span_grey("I don't have much of a reaction to anything right now.")]<br>"
if(LAZYLEN(mob_parent.quirks))
msg += span_notice("You have these quirks: [mob_parent.get_quirk_string(FALSE, CAT_QUIRK_ALL)].")
to_chat(user, boxed_message(msg))
/// Updates the mob's moodies, if the area provides a mood bonus

View File

@@ -19,6 +19,8 @@
/datum/wound
/// What it's named
var/name = "Wound"
/// Optional, what is the wound named when someone is checking themselves (IE, no scanner - just with their eyes and hands)
var/undiagnosed_name
/// The description shown on the scanners
var/desc = ""
/// The basic treatment suggested by health analyzers
@@ -601,7 +603,7 @@
/datum/wound/proc/get_examine_description(mob/user)
. = get_wound_description(user)
if(HAS_TRAIT(src, TRAIT_WOUND_SCANNED))
. += span_notice("\nThere is a holo-image next to the wound that seems to contain indications for treatment.")
. += span_notice("<br>There is a holo-image next to the wound that seems to contain indications for treatment.")
return .
@@ -618,6 +620,30 @@
return get_desc_intensity(desc)
/**
* Used when a mob is examining themselves / their limbs
*
* Reports what this wound looks like to them
*
* It should be formatted as an extension of the limb:
* Input is something like "Your chest is bruised.",
* you would add something like "It is bleeding."
*
* * self_aware - if TRUE, the examiner is more aware of themselves and thus may get more detailed information
*
* Return a string, to be concatenated with other organ / limb status strings. Include spans and punctuation.
*/
/datum/wound/proc/get_self_check_description(self_aware)
switch(severity)
if(WOUND_SEVERITY_TRIVIAL)
return span_danger("It's suffering [a_or_from] [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_MODERATE)
return span_warning("It's suffering [a_or_from] [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_SEVERE)
return span_boldwarning("It's suffering [a_or_from] [LOWER_TEXT(undiagnosed_name || name)]!")
if(WOUND_SEVERITY_CRITICAL)
return span_boldwarning("It's suffering [a_or_from] [LOWER_TEXT(undiagnosed_name || name)]!!")
/// A hook proc used to modify desc before it is spanned via [get_desc_intensity]. Useful for inserting spans yourself.
/datum/wound/proc/modify_desc_before_span(desc, mob/user)
return desc

View File

@@ -1,3 +1,5 @@
/datum/wound/blunt
name = "Blunt Wound"
sound_effect = 'sound/effects/wounds/crack1.ogg'
undiagnosed_name = "Painful Bruising"
a_or_from = "some"

View File

@@ -108,7 +108,7 @@
if(!victim || !limb)
qdel(src)
return
to_chat(victim, span_green("Your [limb.plaintext_zone] has recovered from its [name]!"))
to_chat(victim, span_green("Your [limb.plaintext_zone] has recovered from its [LOWER_TEXT(undiagnosed_name || name)]!"))
remove_wound()
/// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so
@@ -229,6 +229,8 @@
/// Joint Dislocation (Moderate Blunt)
/datum/wound/blunt/bone/moderate
name = "Joint Dislocation"
undiagnosed_name = "Dislocation"
a_or_from = "a"
desc = "Patient's limb has been unset from socket, causing pain and reduced motor function."
treat_text = "Apply Bonesetter to the affected limb. \
Manual relocation by via an aggressive grab and a tight hug to the affected limb may also suffice."
@@ -271,6 +273,9 @@
return ..()
/datum/wound/blunt/bone/moderate/get_self_check_description(self_aware)
return span_warning("It feels dislocated!")
/// Getting smushed in an airlock/firelock is a last-ditch attempt to try relocating your limb
/datum/wound/blunt/bone/moderate/proc/door_crush()
SIGNAL_HANDLER
@@ -285,7 +290,7 @@
return FALSE
if(user.grab_state == GRAB_PASSIVE)
to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [LOWER_TEXT(name)]!"))
to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [LOWER_TEXT(undiagnosed_name || name)]!"))
return TRUE
if(user.grab_state >= GRAB_AGGRESSIVE)
@@ -402,6 +407,8 @@
/// Compound Fracture (Critical Blunt)
/datum/wound/blunt/bone/critical
name = "Compound Fracture"
undiagnosed_name = null // you can tell it's a compound fracture at a glance because of a skin breakage
a_or_from = "a"
desc = "Patient's bones have suffered multiple fractures, \
couped with a break in the skin, causing significant pain and near uselessness of limb."
treat_text = "Immediately bind the affected limb with gauze or a splint. Repair surgically. \

View File

@@ -6,6 +6,7 @@
// TODO: well, a lot really, but specifically I want to add potential fusing of clothing/equipment on the affected area, and limb infections, though those may go in body part code
/datum/wound/burn
name = "Burn Wound"
undiagnosed_name = "Burns"
a_or_from = "from"
sound_effect = 'sound/effects/wounds/sizzle1.ogg'

View File

@@ -3,6 +3,21 @@
Piercing wounds
*/
/datum/wound/pierce
undiagnosed_name = "Puncture"
/datum/wound/pierce/get_self_check_description(self_aware)
if(!limb.can_bleed())
return ..()
switch(severity)
if(WOUND_SEVERITY_TRIVIAL)
return span_danger("It's leaking blood from a small [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_MODERATE)
return span_warning("It's leaking blood from a [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_SEVERE)
return span_boldwarning("It's leaking blood from a serious [LOWER_TEXT(undiagnosed_name || name)]!")
if(WOUND_SEVERITY_CRITICAL)
return span_boldwarning("It's leaking blood from a major [LOWER_TEXT(undiagnosed_name || name)]!!")
/datum/wound/pierce/bleed
name = "Piercing Wound"
@@ -91,7 +106,7 @@
if(QDELETED(src))
return
if(SPT_PROB(2.5, seconds_per_tick))
to_chat(victim, span_notice("You feel the [LOWER_TEXT(name)] in your [limb.plaintext_zone] firming up from the cold!"))
to_chat(victim, span_notice("You feel the [LOWER_TEXT(undiagnosed_name || name)] in your [limb.plaintext_zone] firming up from the cold!"))
if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
adjust_blood_flow(0.25 * seconds_per_tick) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first

View File

@@ -5,8 +5,23 @@
/datum/wound/slash
name = "Slashing (Cut) Wound"
undiagnosed_name = "Cut"
sound_effect = 'sound/items/weapons/slice.ogg'
/datum/wound/slash/get_self_check_description(self_aware)
if(!limb.can_bleed())
return ..()
switch(severity)
if(WOUND_SEVERITY_TRIVIAL)
return span_danger("It's leaking blood from a small [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_MODERATE)
return span_warning("It's leaking blood from a [LOWER_TEXT(undiagnosed_name || name)].")
if(WOUND_SEVERITY_SEVERE)
return span_boldwarning("It's leaking blood from a serious [LOWER_TEXT(undiagnosed_name || name)]!")
if(WOUND_SEVERITY_CRITICAL)
return span_boldwarning("It's leaking blood from a major [LOWER_TEXT(undiagnosed_name || name)]!!")
/datum/wound_pregen_data/flesh_slash
abstract = TRUE

View File

@@ -11,6 +11,10 @@
..()
to_chat(finder, span_warning("You found an unknown alien organism in [owner]'s [zone]!"))
/obj/item/organ/body_egg/feel_for_damage(self_aware)
// keep these stealthy for now, revisit later
return ""
/obj/item/organ/body_egg/Initialize(mapload)
. = ..()
if(iscarbon(loc))

View File

@@ -47,6 +47,7 @@
embed_chance = 70
ignore_throwspeed_threshold = TRUE
fall_chance = 1
stealthy_embed = TRUE
/obj/projectile/bullet/shrapnel/short_range
range = 5
@@ -132,4 +133,3 @@
name = "\improper AP shrapnel shard"
custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 0.5)
weak_against_armour = TRUE

View File

@@ -208,6 +208,9 @@
SHOULD_CALL_PARENT(FALSE)
CRASH("Someone forgot to make their organ do something when you implant it.")
/obj/item/organ/monster_core/feel_for_damage(self_aware)
return ""
/**
* Boilerplate to set the name and icon of the cooldown action.
* Makes it call 'ui_action_click' when the action is activated.

View File

@@ -164,3 +164,7 @@
to_chat(finder, span_notice("Its pulsing tendrils reach all throughout the body."))
if(prob(stage * 2))
infest()
/obj/item/organ/legion_tumour/feel_for_damage(self_aware)
// keep stealthy for now, revisit later
return ""

View File

@@ -272,6 +272,17 @@
if(LAZYLEN(trauma_text))
return "Mental trauma: [english_list(trauma_text, and_text = ", and ")]."
/obj/item/organ/brain/feel_for_damage(self_aware)
if(damage < low_threshold)
return ""
if(self_aware)
if(damage < high_threshold)
return span_warning("Your brain hurts a bit.")
return span_warning("Your brain hurts a lot.")
if(damage < high_threshold)
return span_warning("It feels a bit fuzzy.")
return span_warning("It aches incessantly.")
/obj/item/organ/brain/attack(mob/living/carbon/C, mob/user)
if(!istype(C))
return ..()

View File

@@ -56,6 +56,8 @@
disabled += body_part
missing -= body_part.body_zone
for(var/obj/item/embedded as anything in body_part.embedded_objects)
if(embedded.get_embed().stealthy_embed)
continue
var/harmless = embedded.get_embed().is_harmless()
var/stuck_wordage = harmless ? "stuck to" : "embedded in"
var/embed_line = "\a [embedded]"
@@ -78,7 +80,7 @@
damage_text = "limp and lifeless"
else
damage_text = (body_part.brute_dam >= body_part.burn_dam) ? body_part.heavy_brute_msg : body_part.heavy_burn_msg
. += span_boldwarning("[capitalize(t_his)] [body_part.plaintext_zone] is [damage_text]!")
. += span_boldwarning("[capitalize(t_his)] [body_part.plaintext_zone] looks [damage_text]!")
//stores missing limbs
var/l_limbs_missing = 0

View File

@@ -562,119 +562,45 @@
combined_msg += span_notice("<b>You check yourself for injuries.</b>")
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/list/missing = GLOB.all_body_zones.Copy()
for(var/obj/item/bodypart/body_part as anything in bodyparts)
missing -= body_part.body_zone
if(body_part.bodypart_flags & BODYPART_PSEUDOPART) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades
continue
body_part.check_for_injuries(src, combined_msg)
var/bodypart_report = body_part.check_for_injuries(src)
if(bodypart_report)
combined_msg += "[span_notice("&rdsh;")] [bodypart_report]"
for(var/t in missing)
combined_msg += span_bolddanger("Your [parse_zone(t)] is missing!")
combined_msg += span_boldannounce("&rdsh; Your [parse_zone(t)] is missing!")
if(is_bleeding())
var/list/obj/item/bodypart/bleeding_limbs = list()
for(var/obj/item/bodypart/part as anything in bodyparts)
if(part.get_modified_bleed_rate())
bleeding_limbs += part
var/tox = getToxLoss() + (disgust / 5) + (HAS_TRAIT(src, TRAIT_SELF_AWARE) ? 0 : (rand(-3, 0) * 5))
switch(tox)
if(10 to 20)
combined_msg += span_danger("You feel sick.")
if(20 to 40)
combined_msg += span_danger("You feel nauseated.")
if(40 to INFINITY)
combined_msg += span_danger("You feel very unwell!")
var/num_bleeds = LAZYLEN(bleeding_limbs)
var/bleed_text = "<span class='danger'>You are bleeding from your"
switch(num_bleeds)
if(1 to 2)
bleed_text += " [bleeding_limbs[1].name][num_bleeds == 2 ? " and [bleeding_limbs[2].name]" : ""]"
if(3 to INFINITY)
for(var/i in 1 to (num_bleeds - 1))
var/obj/item/bodypart/BP = bleeding_limbs[i]
bleed_text += " [BP.name],"
bleed_text += " and [bleeding_limbs[num_bleeds].name]"
bleed_text += "!</span>"
combined_msg += bleed_text
var/oxy = getOxyLoss() + (losebreath * 4) + (blood_volume < BLOOD_VOLUME_NORMAL ? ((BLOOD_VOLUME_NORMAL - blood_volume) * 0.1) : 0) + (HAS_TRAIT(src, TRAIT_SELF_AWARE) ? 0 : (rand(-3, 0) * 5))
switch(oxy)
if(10 to 20)
combined_msg += span_danger("You feel lightheaded.")
if(20 to 40)
combined_msg += losebreath ? span_danger("You're choking!") : span_danger("Your thinking is clouded and distant.")
if(40 to INFINITY)
combined_msg += span_danger("You feel like you're about to pass out!")
if(getStaminaLoss())
if(getStaminaLoss() > 30)
combined_msg += span_info("You're completely exhausted.")
else
combined_msg += span_info("You feel fatigued.")
if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
if(toxloss)
if(toxloss > 10)
combined_msg += span_danger("You feel sick.")
else if(toxloss > 20)
combined_msg += span_danger("You feel nauseated.")
else if(toxloss > 40)
combined_msg += span_danger("You feel very unwell!")
if(oxyloss)
if(oxyloss > 10)
combined_msg += span_danger("You feel lightheaded.")
else if(oxyloss > 20)
combined_msg += span_danger("Your thinking is clouded and distant.")
else if(oxyloss > 30)
combined_msg += span_danger("You're choking!")
if(!HAS_TRAIT(src, TRAIT_NOHUNGER))
switch(nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
combined_msg += span_info("You're completely stuffed!")
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
combined_msg += span_info("You're well fed!")
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
combined_msg += span_info("You're not hungry.")
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
combined_msg += span_info("You could use a bite to eat.")
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
combined_msg += span_info("You feel quite hungry.")
if(0 to NUTRITION_LEVEL_STARVING)
combined_msg += span_danger("You're starving!")
//Compiles then shows the list of damaged organs and broken organs
var/list/broken = list()
var/list/damaged = list()
var/broken_message
var/damaged_message
var/broken_plural
var/damaged_plural
//Sets organs into their proper list
for(var/obj/item/organ/organ as anything in organs)
if(organ.organ_flags & ORGAN_FAILING)
if(broken.len)
broken += ", "
broken += organ.name
else if(organ.damage > organ.low_threshold)
if(damaged.len)
damaged += ", "
damaged += organ.name
//Checks to enforce proper grammar, inserts words as necessary into the list
if(broken.len)
if(broken.len > 1)
broken.Insert(broken.len, "and ")
broken_plural = TRUE
else
var/holder = broken[1] //our one and only element
if(holder[length(holder)] == "s")
broken_plural = TRUE
//Put the items in that list into a string of text
for(var/B in broken)
broken_message += B
combined_msg += span_warning("Your [broken_message] [broken_plural ? "are" : "is"] non-functional!")
if(damaged.len)
if(damaged.len > 1)
damaged.Insert(damaged.len, "and ")
damaged_plural = TRUE
else
var/holder = damaged[1]
if(holder[length(holder)] == "s")
damaged_plural = TRUE
for(var/D in damaged)
damaged_message += D
combined_msg += span_info("Your [damaged_message] [damaged_plural ? "are" : "is"] hurt.")
if(quirks.len)
combined_msg += span_notice("You have these quirks: [get_quirk_string(FALSE, CAT_QUIRK_ALL)].")
to_chat(src, boxed_message(combined_msg.Join("\n")))
to_chat(src, boxed_message(combined_msg.Join("<br>")))
/mob/living/carbon/human/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
if(damage_type != BRUTE && damage_type != BURN)

View File

@@ -25,3 +25,4 @@
pain_stam_pct=0.5
pain_mult=3
rip_time=10
stealthy_embed = TRUE

View File

@@ -123,13 +123,13 @@
var/bleed_overlay_icon
//Damage messages used by help_shake_act()
var/light_brute_msg = "bruised"
var/light_brute_msg = "bruised and feels sore"
var/medium_brute_msg = "battered"
var/heavy_brute_msg = "mangled"
var/light_burn_msg = "numb"
var/light_burn_msg = "red and feels numb"
var/medium_burn_msg = "blistered"
var/heavy_burn_msg = "peeling away"
var/heavy_burn_msg = "like its peeling away"
//Damage messages used by examine(). the desc that is most common accross all bodyparts gets shown
var/list/damage_examines = list(
@@ -298,11 +298,10 @@
/**
* Called when a bodypart is checked for injuries.
*
* Modifies the check_list list with the resulting report of the limb's status.
*/
/obj/item/bodypart/proc/check_for_injuries(mob/living/carbon/human/examiner, list/check_list)
/obj/item/bodypart/proc/check_for_injuries(mob/living/carbon/human/examiner)
var/list/check_list = list()
var/list/limb_damage = list(BRUTE = brute_dam, BURN = burn_dam)
SEND_SIGNAL(src, COMSIG_BODYPART_CHECKED_FOR_INJURY, examiner, check_list, limb_damage)
@@ -352,28 +351,47 @@
else
is_disabled += " and"
check_list += "\t <span class='[no_damage ? "notice" : "warning"]'>Your [name][is_disabled][self_aware ? " has " : " is "][status].</span>"
check_list += "<span class='[no_damage ? "notice" : "warning"]'>Your [plaintext_zone][is_disabled][self_aware ? " has " : " looks "][status].</span>"
var/adept_organ_feeler = owner == examiner && HAS_TRAIT(examiner, TRAIT_SELF_AWARE)
for(var/obj/item/organ/organ in src)
if(organ.organ_flags & ORGAN_HIDDEN)
continue
var/feeling = organ.feel_for_damage(adept_organ_feeler)
if(feeling)
check_list += "\t[feeling]"
for(var/datum/wound/wound as anything in wounds)
switch(wound.severity)
if(WOUND_SEVERITY_TRIVIAL)
check_list += "\t [span_danger("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)].")]"
if(WOUND_SEVERITY_MODERATE)
check_list += "\t [span_warning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!")]"
if(WOUND_SEVERITY_SEVERE)
check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!")]"
if(WOUND_SEVERITY_CRITICAL)
check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!!")]"
var/wound_desc = wound.get_self_check_description(adept_organ_feeler)
if(wound_desc)
check_list += "\t[wound_desc]"
for(var/obj/item/embedded_thing as anything in embedded_objects)
if(embedded_thing.get_embed().stealthy_embed)
continue
var/harmless = embedded_thing.get_embed().is_harmless()
var/stuck_wordage = harmless ? "stuck to" : "embedded in"
var/embed_text = "\t <a href='byond://?src=[REF(examiner)];embedded_object=[REF(embedded_thing)];embedded_limb=[REF(src)]'> There is [icon2html(embedded_thing, examiner)] \a [embedded_thing] [stuck_wordage] your [plaintext_zone]!</a>"
var/embed_text = "\t<a href='byond://?src=[REF(examiner)];embedded_object=[REF(embedded_thing)];embedded_limb=[REF(src)]'> There is [icon2html(embedded_thing, examiner)] \a [embedded_thing] [stuck_wordage] your [plaintext_zone]!</a>"
if (harmless)
check_list += span_italics(span_notice(embed_text))
else
check_list += span_boldwarning(embed_text)
if(current_gauze)
check_list += span_notice("\tThere is some [current_gauze.name] wrapped around it.")
else if(can_bleed())
switch(get_modified_bleed_rate())
if(0.2 to 1)
check_list += span_warning("\tIt's lightly bleeding.")
if(1 to 2)
check_list += span_warning("\tIt's bleeding.")
if(3 to 4)
check_list += span_warning("\tIt's bleeding heavily!")
if(4 to INFINITY)
check_list += span_warning("\tIt's bleeding profusely!")
return jointext(check_list, "<br>")
/obj/item/bodypart/blob_act()
receive_damage(max_damage, wound_bonus = CANT_WOUND)

View File

@@ -1,7 +1,7 @@
#define ROBOTIC_LIGHT_BRUTE_MSG "marred"
#define ROBOTIC_MEDIUM_BRUTE_MSG "dented"
#define ROBOTIC_HEAVY_BRUTE_MSG "falling apart"
#define ROBOTIC_HEAVY_BRUTE_MSG "like its falling apart"
#define ROBOTIC_LIGHT_BURN_MSG "scorched"
#define ROBOTIC_MEDIUM_BURN_MSG "charred"

View File

@@ -405,6 +405,28 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
/obj/item/organ/proc/get_status_appendix(advanced, add_tooltips)
return
/**
* Used when a mob is examining themselves / their limbs
*
* Reports how they feel based on how the status of this organ
*
* It should be formatted as an extension of the limb:
* Input is something like "Your chest is bruised. It is bleeding.",
* you would add something like "It hurts a little, and your stomach cramps."
*
* * self_aware - if TRUE, the examiner is more aware of themselves and thus may get more detailed information
*
* Return a string, to be concatenated with other organ / limb status strings. Include spans and punctuation.
*/
/obj/item/organ/proc/feel_for_damage(self_aware)
if(organ_flags & ORGAN_EXTERNAL)
return ""
if(damage < low_threshold)
return ""
if(damage < high_threshold)
return span_warning("[self_aware ? "[capitalize(slot)]" : "It"] feels a bit off.")
return span_boldwarning("[self_aware ? "[capitalize(slot)]" : "It"] feels terrible!")
/// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target
/obj/item/organ/proc/replace_into(mob/living/carbon/new_owner)
Insert(new_owner, special = TRUE, movement_flags = DELETE_IF_REPLACED)

View File

@@ -94,6 +94,11 @@
wings.burnt = FALSE
burnt = FALSE
/obj/item/organ/wings/moth/feel_for_damage(self_aware)
if(burnt)
return "Your wings are all burnt up!"
return ..()
///Moth wing bodypart overlay, including burn functionality!
/datum/bodypart_overlay/mutant/wings/moth
feature_key = "moth_wings"

View File

@@ -43,14 +43,17 @@
/obj/item/organ/appendix/proc/become_inflamed()
inflamation_stage = 1
update_appearance()
if(owner)
ADD_TRAIT(owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type)
owner.med_hud_set_status()
notify_ghosts(
"[owner] has developed spontaneous appendicitis!",
source = owner,
header = "Whoa, Sick!",
)
if(isnull(owner))
return
ADD_TRAIT(owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type)
owner.med_hud_set_status()
if(isnull(owner.client))
return
notify_ghosts(
"[owner] has developed spontaneous appendicitis!",
source = owner,
header = "Whoa, Sick!",
)
/obj/item/organ/appendix/proc/inflamation(seconds_per_tick)
var/mob/living/carbon/organ_owner = owner
@@ -72,6 +75,15 @@
organ_owner.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 95)
organ_owner.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 15)
/obj/item/organ/appendix/feel_for_damage(self_aware)
var/effective_stage = floor(inflamation_stage + (damage / maxHealth))
switch(effective_stage)
if(1)
return span_warning("Your [self_aware ? "appendix" : "lower abdomen"] feels a little off.")
if(2)
return span_warning("Your [self_aware ? "appendix" : "lower right abdomen"] feels sore.")
if(3 to INFINITY)
return span_boldwarning("Your [self_aware ? "appendix" : "lower right abdomen"] feels like it's on fire!")
/obj/item/organ/appendix/get_availability(datum/species/owner_species, mob/living/owner_mob)
return owner_species.mutantappendix

View File

@@ -7,6 +7,10 @@
failing_desc = "seems to be broken."
var/implant_color = COLOR_WHITE
/obj/item/organ/cyberimp/feel_for_damage(self_aware)
// No feeling in implants (yet?)
return ""
//[[[[BRAIN]]]]
/obj/item/organ/cyberimp/brain

View File

@@ -141,6 +141,10 @@
speech_args[SPEECH_MESSAGE] = message
return COMPONENT_UPPERCASE_SPEECH
/obj/item/organ/ears/feel_for_damage(self_aware)
// Ear damage has audible effects, so we don't really need to "feel" it when self-examining
return ""
/obj/item/organ/ears/invincible
damage_multiplier = 0

View File

@@ -391,6 +391,10 @@
damaged = TRUE
/obj/item/organ/eyes/feel_for_damage(self_aware)
// Eye damage has visual effects, so we don't really need to "feel" it when self-examining
return ""
#define BASE_BLINKING_DELAY 5 SECONDS
#define RAND_BLINKING_DELAY 1 SECONDS
#define BLINK_DURATION 0.15 SECONDS

View File

@@ -138,6 +138,15 @@
/obj/item/organ/heart/get_availability(datum/species/owner_species, mob/living/owner_mob)
return owner_species.mutantheart
/obj/item/organ/heart/feel_for_damage(self_aware)
if(owner.needs_heart() && (!beating || (organ_flags & ORGAN_FAILING)))
return span_boldwarning("[self_aware ? "Your heart is not beating!" : "You don't feel your heart beating."]")
if(damage < low_threshold)
return ""
if(damage < high_threshold)
return span_warning("[self_aware ? "Your heart hurts." : "It hurts, and your heart rate feels irregular."]")
return span_boldwarning("[self_aware ? "Your heart seriously hurts!" : "It seriously hurts, and your heart rate is all over the place."]")
/obj/item/organ/heart/cursed
name = "cursed heart"
desc = "A heart that, when inserted, will force you to pump it manually."

View File

@@ -207,6 +207,13 @@
/obj/item/organ/liver/get_availability(datum/species/owner_species, mob/living/owner_mob)
return owner_species.mutantliver
/obj/item/organ/liver/feel_for_damage(self_aware)
if(damage < low_threshold)
return
if(damage < high_threshold)
return span_warning("Your [self_aware ? "liver" : "lower abdomen"] feels sore.")
return span_boldwarning("Your [self_aware ? "liver" : "lower abdomen"] feels like it's on fire!")
// alien livers can ignore up to 15u of toxins, but they take x3 liver damage
/obj/item/organ/liver/alien
name = "alien liver" // doesnt matter for actual aliens because they dont take toxin damage

View File

@@ -852,6 +852,21 @@
/obj/item/organ/lungs/get_availability(datum/species/owner_species, mob/living/owner_mob)
return owner_species.mutantlungs
/obj/item/organ/lungs/feel_for_damage(self_aware)
if(organ_flags & ORGAN_FAILING)
if(self_aware)
return span_boldwarning("Your lungs hurt madly[HAS_TRAIT(owner, TRAIT_NOBREATH) ? "" : ", and you can't breathe"]!")
return span_boldwarning("It hurts madly[HAS_TRAIT(owner, TRAIT_NOBREATH) ? "" : ", and you can't breathe"]!")
if(damage < low_threshold)
return ""
if(damage < high_threshold)
if(self_aware)
return span_warning("Your lungs feel tight[HAS_TRAIT(owner, TRAIT_NOBREATH) ? "" : ", and breathing is harder"].")
return span_warning("It feels tight[HAS_TRAIT(owner, TRAIT_NOBREATH) ? "" : ", and breathing is harder"].")
if(self_aware)
return span_boldwarning("Your lungs feel extremely tight[HAS_TRAIT(owner, TRAIT_NOBREATH) ? "" : ", and every breath is a struggle"].")
return span_boldwarning("It feels extremely tight[HAS_TRAIT(owner, TRAIT_NOBREATH) ? "" : ", and every breath is a struggle"].")
#define SMOKER_ORGAN_HEALTH (STANDARD_ORGAN_THRESHOLD * 0.75)
#define SMOKER_LUNG_HEALING (STANDARD_ORGAN_HEALING * 0.75)

View File

@@ -397,6 +397,13 @@
UnregisterSignal(stomach_owner, list(COMSIG_CARBON_VOMITED, COMSIG_HUMAN_GOT_PUNCHED))
return ..()
/obj/item/organ/stomach/feel_for_damage(self_aware)
if(damage < low_threshold)
return ""
if(damage < high_threshold)
return span_warning("Your stomach hurts.")
return span_boldwarning("Your stomach cramps in pain!")
/// If damage is high enough, we may end up vomiting out whatever we had stored
/obj/item/organ/stomach/proc/on_punched(datum/source, mob/living/carbon/human/attacker, damage, attack_type, obj/item/bodypart/affecting, final_armor_block, kicking)
SIGNAL_HANDLER

View File

@@ -178,6 +178,10 @@
/obj/item/organ/tongue/get_availability(datum/species/owner_species, mob/living/owner_mob)
return owner_species.mutanttongue
/obj/item/organ/tongue/feel_for_damage(self_aware)
// No effect
return ""
/obj/item/organ/tongue/lizard
name = "forked tongue"
desc = "A thin and long muscle typically found in reptilian races, apparently moonlights as a nose."

View File

@@ -23,6 +23,10 @@
GLOB.zombie_infection_list -= src
. = ..()
/obj/item/organ/zombie_infection/feel_for_damage(self_aware)
// keep stealthy for now, revisit later
return ""
/obj/item/organ/zombie_infection/on_mob_insert(mob/living/carbon/new_owner, special = FALSE, movement_flags)
. = ..()
RegisterSignal(new_owner, COMSIG_LIVING_DEATH, PROC_REF(organ_owner_died))