People become desensitized to death from exposure (#94924)

## About The Pull Request

Desensitized is no longer binary yes/no, now scales from 0.1x to 1x (or
beyond, I guess)

Desensitized jobs start as 0.5x desensitized (which is the threshold for
being considered "truly desensitized")
Some antags are now 0.1x to 0.25x desensitized

Witnessing death of a fellow human gives you slight desensitization
(currently -0.025x).
A normal crewmember, after witnessing 20 deaths, is on par with a
roundstart desensitized crewmember.
Likewise a desensitized crewmember has almost no reaction to death after
witnessing 20 deaths.
Your own deaths count towards this value.

There's an achievement for managing to go from 1x to 0.1x across the
course of an entire round.

## Why It's Good For The Game

This is intended to contribute to the "story" people face across the
length of a round.
Rounds with few overall deaths results in crewmembers regularly getting
shocked, but bloodbaths results in crewmembers "dehumanizing and facing
the bloodshed".

## Changelog

🆑 Melbert
add: Desensitization to death is no longer binary - some antagonists are
now more used to it than others.
add: Witnessing the death of a fellow humanoid (or dying yourself) will
slightly desensitize you to future deaths.
add: Adds an achievement for managing to max out desensitization across
a round.
add: Desensitized crewmembers care less when splattered with blood.
add: Holodeck mobs have a reduced death mood impact.
/🆑
This commit is contained in:
MrMelbert
2026-01-28 20:22:07 +00:00
committed by GitHub
parent 80835982e9
commit bf22a388ca
39 changed files with 164 additions and 64 deletions
@@ -250,3 +250,10 @@
desc = "Nutritionists often recommend a balanced and varied diet. However that clearly isn't the case for some creatures."
database_id = MEDAL_SHARKDRAGON
icon_state = "dragon_plus_fish"
/datum/award/achievement/misc/desensitized
name = "In Flanders Fields"
desc = "You have witnessed more death and despair in one shift than most TerraGov marines have seen across an entire tour of duty. \
Perhaps one day you'll find peace. But not today."
database_id = MEDAL_DESENSITIZED
icon_state = "desensitized"
+2 -2
View File
@@ -37,7 +37,7 @@
antagonist.greet()
log_game("[key_name(antagonist)] has developed an obsession with [key_name(obsession)].")
RegisterSignal(owner, COMSIG_CARBON_HELPED, PROC_REF(on_hug))
ADD_TRAIT(owner, TRAIT_DESENSITIZED, REF(src))
owner.apply_status_effect(/datum/status_effect/desensitized, REF(src), DESENSITIZED_THRESHOLD)
/datum/brain_trauma/special/obsessed/on_life(seconds_per_tick)
if(!obsession || obsession.stat == DEAD)
@@ -75,7 +75,7 @@
if(obsession)
log_game("[key_name(owner)] is no longer obsessed with [key_name(obsession)].")
UnregisterSignal(obsession, COMSIG_MOB_EYECONTACT)
REMOVE_TRAIT(owner, TRAIT_DESENSITIZED, REF(src))
owner.remove_status_effect(/datum/status_effect/desensitized, REF(src))
/datum/brain_trauma/special/obsessed/handle_speech(datum/source, list/speech_args)
if(!viewing)
+4 -4
View File
@@ -483,15 +483,15 @@
/datum/brain_trauma/special/ptsd/on_gain()
owner.add_mood_event("combat_ptsd", /datum/mood_event/desentized)
owner.mob_mood?.mood_modifier -= 1 //Basically nothing can change your mood
owner.mob_mood?.sanity_level = SANITY_DISTURBED //Makes sanity on a unstable level unless cured
ADD_TRAIT(owner, TRAIT_DESENSITIZED, REF(src))
owner.mob_mood?.set_sanity(SANITY_DISTURBED, override = TRUE) //Makes sanity on a unstable level unless cured
owner.apply_status_effect(/datum/status_effect/desensitized, REF(src), DESENSITIZED_THRESHOLD)
. = ..()
/datum/brain_trauma/special/ptsd/on_lose()
owner.clear_mood_event("combat_ptsd")
owner.mob_mood?.mood_modifier += 1
owner.mob_mood?.sanity_level = SANITY_GREAT
REMOVE_TRAIT(owner, TRAIT_DESENSITIZED, REF(src))
owner.mob_mood?.set_sanity(SANITY_GREAT, override = TRUE)
owner.remove_status_effect(/datum/status_effect/desensitized, REF(src))
return ..()
/datum/brain_trauma/special/primal_instincts
+25 -2
View File
@@ -101,6 +101,12 @@
/// A list to keep track of which books a person has read (to prevent people from reading the same book again and again for positive mood events)
var/list/book_titles_read
/// How desensitized are we to death - multiplier to magnitude of death moodlet.
/// Doesn't go beneath 0.1 (but could go above 1.0 if you really wanted)
var/desensitized_level = 1
/// Counts how many humanoid deaths we've seen
var/deaths_witnessed = 0
/datum/mind/New(_key)
key = _key
init_known_skills()
@@ -211,9 +217,9 @@
new_character.client.init_verbs() // re-initialize character specific verbs
SEND_SIGNAL(src, COMSIG_MIND_TRANSFERRED, old_current)
SEND_SIGNAL(current, COMSIG_MOB_MIND_TRANSFERRED_INTO, old_current)
SEND_SIGNAL(current, COMSIG_MOB_MIND_TRANSFERRED_INTO, old_current, src)
if(!isnull(old_current))
SEND_SIGNAL(old_current, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, current)
SEND_SIGNAL(old_current, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, current, src)
//I cannot trust you fucks to do this properly
/datum/mind/proc/set_original_character(new_original_character)
@@ -543,3 +549,20 @@
work_areas += dep.primary_work_area
return work_areas
/// Called when we witness the death of a humanoid mob.
/datum/mind/proc/witnessed_death(mob/living/dead_mob)
if(HAS_TRAIT(dead_mob, TRAIT_SPAWNED_MOB) || !ishuman(dead_mob) || (dead_mob.flags_1 & ADMIN_SPAWNED_1))
return
// every humanoid death gives us % resistance to the next one
desensitized_level = max(desensitized_level - DESENSITIZED_REDUCTION_PER_DEATH, DESENSITIZED_MINIMUM)
deaths_witnessed += 1
// if you manage to gain 90% resistance to death moodlets in one shift, you get an "achievement"
if(deaths_witnessed * DESENSITIZED_REDUCTION_PER_DEATH >= (1.0 - DESENSITIZED_MINIMUM))
current.client?.give_award(/datum/award/achievement/misc/desensitized, current)
/// Called when this mob is killed, but not gibbed or dusted
/datum/mind/proc/experienced_death()
witnessed_death(current) // you get desensitized for your own death!
+8 -6
View File
@@ -32,9 +32,12 @@
mood_change *= 0.25
timeout *= 0.2
if(HAS_PERSONALITY(owner, /datum/personality/compassionate) && mood_change < 0)
mood_change *= 1.5
timeout *= 1.5
if(mood_change < 0)
mood_change = ceil(mood_change * max(DESENSITIZED_MINIMUM, owner.mind?.desensitized_level || 1.0))
if(HAS_PERSONALITY(owner, /datum/personality/compassionate))
mood_change *= 1.5
timeout *= 1.5
if(gibbed || dusted)
mood_change *= 1.2
@@ -72,7 +75,7 @@
/// Checks if our mood can get worse by seeing another death (or better if we're weird like that)
/datum/mood_event/conditional/see_death/proc/can_stack_effect(mob/dead_mob)
// if we're desensitized, don't stack unless it's a buff
if(HAS_MIND_TRAIT(owner, TRAIT_DESENSITIZED) && mood_change > 0)
if(IS_DESENSITIZED(owner) && mood_change < 0)
return FALSE
// if we're seeing a spawned mob die, don't stack
if(HAS_TRAIT(dead_mob, TRAIT_SPAWNED_MOB))
@@ -275,11 +278,10 @@
/// Desensitized brings up the rear
/datum/mood_event/conditional/see_death/desensitized
priority = DESENSITIZED_PRIORITY
mood_change = parent_type::mood_change * 0.5
timeout = parent_type::timeout * 0.5
/datum/mood_event/conditional/see_death/desensitized/condition_fulfilled(mob/living/who, mob/dead_mob, dusted, gibbed)
return HAS_MIND_TRAIT(who, TRAIT_DESENSITIZED)
return IS_DESENSITIZED(who)
/datum/mood_event/conditional/see_death/desensitized/update_effect(mob/dead_mob, dusted, gibbed)
if(gibbed)
@@ -638,6 +638,8 @@
mood_change = 0
description = "I just got coated in blood. Fascinating!"
return
if(IS_DESENSITIZED(owner))
mood_change *= 0.5
/datum/mood_event/teetotal_hangover
description = "What a disgraceful display! This is what happens when one indulges in alcohol!"
+41
View File
@@ -675,3 +675,44 @@
desc = "Bathed in soothing darkness, you will slowly heal yourself"
use_user_hud_icon = TRUE
overlay_state = "lightless"
/// Applies desensitized mood modifier to the mob, carrying between mind transfers
/datum/status_effect/desensitized
id = "desensitized"
duration = STATUS_EFFECT_PERMANENT
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
/// How much to multiply desensitization level by
var/magnitude = 1.0
/// Effect ID for removal purposes
var/effect_id
/datum/status_effect/desensitized/on_creation(mob/living/new_owner, effect_id, magnitude)
src.effect_id = effect_id
src.magnitude = max(DESENSITIZED_MINIMUM, magnitude)
return ..()
/datum/status_effect/desensitized/on_apply()
owner.mind?.desensitized_level *= magnitude
RegisterSignal(owner, COMSIG_MOB_MIND_TRANSFERRED_INTO, PROC_REF(add_magnitude))
RegisterSignal(owner, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, PROC_REF(remove_magnitude))
return TRUE
/datum/status_effect/desensitized/on_remove()
owner.mind?.desensitized_level /= magnitude
UnregisterSignal(owner, list(COMSIG_MOB_MIND_TRANSFERRED_INTO, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF))
/datum/status_effect/desensitized/before_remove(effect_id, magnitude)
if(istext(src.effect_id) && istext(effect_id)) // if an id is set, they must match
return src.effect_id == effect_id
if(isnum(magnitude)) // otherwise if a magnitude is passed, it must match
return src.magnitude == magnitude
return FALSE
/datum/status_effect/desensitized/proc/add_magnitude(datum/source, mob/living/old_body, datum/mind/swapping)
SIGNAL_HANDLER
swapping.desensitized_level *= magnitude
/datum/status_effect/desensitized/proc/remove_magnitude(datum/source, mob/living/old_body, datum/mind/swapping)
SIGNAL_HANDLER
swapping.desensitized_level /= magnitude