diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm index 575efae4186..69741ef4bff 100644 --- a/code/__DEFINES/achievements.dm +++ b/code/__DEFINES/achievements.dm @@ -62,6 +62,7 @@ #define MEDAL_CIGARETTES "Cigarettes" #define MEDAL_SHARKDRAGON "Sharkdragon" #define MEDAL_THEORETICAL_LIMITS "All Within Theoretical Limits" +#define MEDAL_DESENSITIZED "In Flanders Fields" //Skill medal hub IDs #define MEDAL_LEGENDARY_MINER "Legendary Miner" diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index ad7f6bba889..148c1b4c8f7 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -285,8 +285,6 @@ DEFINE_BITFIELD(job_flags, list( /// Mind traits that should be shared by every head of staff. has to be this way cause byond lists lol #define HEAD_OF_STAFF_MIND_TRAITS TRAIT_FAST_TYING, TRAIT_HIGH_VALUE_RANSOM -#define MEDICAL_MIND_TRAITS TRAIT_DESENSITIZED -#define SECURITY_MIND_TRAITS TRAIT_DESENSITIZED /// Statistically average probability of a random cop or cop-adjacent person consisting of meat of sus domesticus of suidae family, /// also known as swine or hogs, calculated by the university of random numbers diff --git a/code/__DEFINES/mood.dm b/code/__DEFINES/mood.dm index 0dcdc9340d6..80994ef5907 100644 --- a/code/__DEFINES/mood.dm +++ b/code/__DEFINES/mood.dm @@ -112,3 +112,13 @@ #define BLOCK_NEW_MOOD FALSE /// Return from /be_replaced or /be_refreshed to actually go through and allow the new mood event to be added #define ALLOW_NEW_MOOD TRUE + +/// Threshold for desensitization effects to start applying +#define DESENSITIZED_THRESHOLD 0.5 +/// Minimum level for desensitization multiplier +#define DESENSITIZED_MINIMUM 0.1 +/// Reduction in desensitization level per death witnessed +#define DESENSITIZED_REDUCTION_PER_DEATH 0.025 + +/// Check if a mob is desensitized (passes the threshold) +#define IS_DESENSITIZED(mob) ((mob.mind?.desensitized_level || 1) <= DESENSITIZED_THRESHOLD) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 8980e3f5d88..4ab1fb7ef28 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1610,9 +1610,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait that allows an item to perform holy rites akin to a nullrod #define TRAIT_NULLROD_ITEM "nullrod_item" -/// Mob gets far less severe negative moodlets from seeing death / blood -#define TRAIT_DESENSITIZED "desensitized" - /// Trait specifying that an AI has a remote connection to an integrated circuit #define TRAIT_CONNECTED_TO_CIRCUIT "connected_to_circuit" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 0bed48f0616..5e96e3b3c55 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -247,7 +247,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_DEAF" = TRAIT_DEAF, "TRAIT_DEATHCOMA" = TRAIT_DEATHCOMA, "TRAIT_DEFIB_BLACKLISTED" = TRAIT_DEFIB_BLACKLISTED, - "TRAIT_DESENSITIZED" = TRAIT_DESENSITIZED, "TRAIT_DESIGNATED_TARGET" = TRAIT_DESIGNATED_TARGET, "TRAIT_DETECTIVES_TASTE" = TRAIT_DETECTIVES_TASTE, "TRAIT_DETECT_STORM" = TRAIT_DETECT_STORM, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index b369f8cc814..83b83c94c8e 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -89,7 +89,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_DEAF" = TRAIT_DEAF, "TRAIT_DEATHCOMA" = TRAIT_DEATHCOMA, "TRAIT_DEFIB_BLACKLISTED" = TRAIT_DEFIB_BLACKLISTED, - "TRAIT_DESENSITIZED" = TRAIT_DESENSITIZED, "TRAIT_DETECT_STORM" = TRAIT_DETECT_STORM, "TRAIT_DIAGNOSTIC_HUD" = TRAIT_DIAGNOSTIC_HUD, "TRAIT_DISCOORDINATED_TOOL_USER" = TRAIT_DISCOORDINATED_TOOL_USER, diff --git a/code/datums/achievements/misc_achievements.dm b/code/datums/achievements/misc_achievements.dm index 224941e6ce3..a15977e7e53 100644 --- a/code/datums/achievements/misc_achievements.dm +++ b/code/datums/achievements/misc_achievements.dm @@ -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" diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index 8a2e13ed9e5..8cc32018531 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -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) diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index 8928f36409a..e4e6847011f 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -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 diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm index 83af9390bb5..2fef2f8f571 100644 --- a/code/datums/mind/_mind.dm +++ b/code/datums/mind/_mind.dm @@ -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! diff --git a/code/datums/mood_events/death.dm b/code/datums/mood_events/death.dm index e8da1c07b52..3101b3dea96 100644 --- a/code/datums/mood_events/death.dm +++ b/code/datums/mood_events/death.dm @@ -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) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 8102d928212..665857195f1 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -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!" diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 750bfba732f..cad5efca459 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -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 diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 4e6ade226cd..ac45ba08242 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -57,6 +57,8 @@ GLOBAL_LIST_EMPTY(antagonists) var/hardcore_random_bonus = FALSE /// A path to the audio stinger that plays upon gaining this datum. var/stinger_sound + /// Multiplicative modifier to the mind's desensitized level when this antagonist is applied. Minimum is 0.1. + var/desensitized_modifier = 1.0 //ANTAG UI @@ -262,6 +264,7 @@ GLOBAL_LIST_EMPTY(antagonists) if(type_policy) to_chat(owner.current, type_policy) + owner.desensitized_level *= max(DESENSITIZED_MINIMUM, desensitized_modifier) apply_innate_effects() give_antag_moodies() RegisterSignal(owner, COMSIG_PRE_MINDSHIELD_IMPLANT, PROC_REF(pre_mindshield)) @@ -320,6 +323,7 @@ GLOBAL_LIST_EMPTY(antagonists) if(!owner) CRASH("Antag datum with no owner.") + owner.desensitized_level /= max(DESENSITIZED_MINIMUM, desensitized_modifier) if(owner.current) remove_innate_effects() clear_antag_moodies() diff --git a/code/modules/antagonists/cult/datums/cult_team.dm b/code/modules/antagonists/cult/datums/cult_team.dm index 7cbd9fe6284..130683a9046 100644 --- a/code/modules/antagonists/cult/datums/cult_team.dm +++ b/code/modules/antagonists/cult/datums/cult_team.dm @@ -58,7 +58,6 @@ SEND_SOUND(mind.current, 'sound/music/antag/bloodcult/bloodcult_eyes.ogg') to_chat(mind.current, span_cult_large(span_warning("The veil weakens as your cult grows, your eyes begin to glow..."))) mind.current.AddElement(/datum/element/cult_eyes) - ADD_TRAIT(mind.current, TRAIT_DESENSITIZED, CULT_TRAIT) cult_risen = TRUE log_game("The blood cult has risen with [cultplayers] players.") diff --git a/code/modules/antagonists/cult/datums/cultist.dm b/code/modules/antagonists/cult/datums/cultist.dm index 9ce4dc5b13a..c637b2b45cb 100644 --- a/code/modules/antagonists/cult/datums/cultist.dm +++ b/code/modules/antagonists/cult/datums/cultist.dm @@ -8,6 +8,7 @@ pref_flag = ROLE_CULTIST antag_hud_name = "cult" stinger_sound = 'sound/music/antag/bloodcult/bloodcult_gain.ogg' + desensitized_modifier = DESENSITIZED_THRESHOLD ///Boolean on whether the starting equipment should be given to their inventory. var/give_equipment = FALSE @@ -65,7 +66,6 @@ if(cult_team.cult_risen) current.AddElement(/datum/element/cult_eyes, initial_delay = 0 SECONDS) - ADD_TRAIT(current, TRAIT_DESENSITIZED, CULT_TRAIT) if(cult_team.cult_ascendent) current.AddElement(/datum/element/cult_halo, initial_delay = 0 SECONDS) @@ -88,7 +88,6 @@ if (HAS_TRAIT(current, TRAIT_CULT_HALO)) current.RemoveElement(/datum/element/cult_halo) - REMOVE_TRAIT(current, TRAIT_DESENSITIZED, CULT_TRAIT) REMOVE_TRAIT(current, TRAIT_HEALS_FROM_CULT_PYLONS, CULT_TRAIT) /datum/antagonist/cult/on_mindshield(mob/implanter) diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index c0bf50819e0..f7ae99d8fe0 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -13,6 +13,7 @@ suicide_cry = "FOR NANOTRASEN!!" // Not 'true' antags, this disables certain interactions that assume the owner is a baddie antag_flags = ANTAG_FAKE|ANTAG_SKIP_GLOBAL_LIST + desensitized_modifier = DESENSITIZED_THRESHOLD * 0.5 var/datum/team/ert/ert_team var/leader = FALSE var/datum/outfit/outfit = /datum/outfit/centcom/ert/security @@ -36,14 +37,6 @@ equipERT() . = ..() -/datum/antagonist/ert/apply_innate_effects(mob/living/mob_override) - var/mob/living/carbon/human/officer = mob_override || owner.current - ADD_TRAIT(officer, TRAIT_DESENSITIZED, REF(src)) - -/datum/antagonist/ert/remove_innate_effects(mob/living/mob_override) - var/mob/living/carbon/human/officer = mob_override || owner.current - REMOVE_TRAIT(officer, TRAIT_DESENSITIZED, REF(src)) - /datum/antagonist/ert/get_team() return ert_team diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm index af0381db3cc..a8ce3af3509 100644 --- a/code/modules/antagonists/heretic/heretic_knowledge.dm +++ b/code/modules/antagonists/heretic/heretic_knowledge.dm @@ -654,7 +654,7 @@ if(!isnull(ascension_achievement)) user.client?.give_award(ascension_achievement, user) heretic_datum.rust_strength = RUST_RESISTANCE_ORGANIC // Ascended heretics can rust whatever they want (below RUST_RESISTANCE_ABSOLUTE) - ADD_TRAIT(user, TRAIT_DESENSITIZED, type) + user.apply_status_effect(/datum/status_effect/desensitized, type, DESENSITIZED_THRESHOLD * 0.4) return TRUE /datum/heretic_knowledge/ultimate/cleanup_atoms(list/selected_atoms) diff --git a/code/modules/antagonists/heretic/status_effects/ghoul.dm b/code/modules/antagonists/heretic/status_effects/ghoul.dm index 74e60c966a4..bc2f524e756 100644 --- a/code/modules/antagonists/heretic/status_effects/ghoul.dm +++ b/code/modules/antagonists/heretic/status_effects/ghoul.dm @@ -62,9 +62,9 @@ on_made_callback?.Invoke(human_target) ADD_TRAIT(human_target, TRAIT_FAKEDEATH, TRAIT_STATUS_EFFECT(id)) ADD_TRAIT(human_target, TRAIT_HERETIC_SUMMON, TRAIT_STATUS_EFFECT(id)) - ADD_TRAIT(human_target, TRAIT_DESENSITIZED, TRAIT_STATUS_EFFECT(id)) human_target.become_husk(TRAIT_STATUS_EFFECT(id)) human_target.add_faction(FACTION_HERETIC) + human_target.apply_status_effect(/datum/status_effect/desensitized, TRAIT_STATUS_EFFECT(id), DESENSITIZED_THRESHOLD * 0.2) if(human_target.mind) var/datum/antagonist/heretic_monster/heretic_monster = human_target.mind.add_antag_datum(/datum/antagonist/heretic_monster) @@ -93,9 +93,9 @@ on_lost_callback?.Invoke(human_target) REMOVE_TRAIT(human_target, TRAIT_FAKEDEATH, TRAIT_STATUS_EFFECT(id)) REMOVE_TRAIT(human_target, TRAIT_HERETIC_SUMMON, TRAIT_STATUS_EFFECT(id)) - REMOVE_TRAIT(human_target, TRAIT_DESENSITIZED, TRAIT_STATUS_EFFECT(id)) human_target.cure_husk(TRAIT_STATUS_EFFECT(id)) human_target.remove_faction(FACTION_HERETIC) + human_target.remove_status_effect(/datum/status_effect/desensitized, TRAIT_STATUS_EFFECT(id)) human_target.mind?.remove_antag_datum(/datum/antagonist/heretic_monster) UnregisterSignal(human_target, COMSIG_LIVING_DEATH) diff --git a/code/modules/antagonists/highlander/highlander.dm b/code/modules/antagonists/highlander/highlander.dm index d197f91f573..39a6a52eef9 100644 --- a/code/modules/antagonists/highlander/highlander.dm +++ b/code/modules/antagonists/highlander/highlander.dm @@ -6,9 +6,9 @@ can_elimination_hijack = ELIMINATION_ENABLED suicide_cry = "FOR SCOTLAND!!" // If they manage to lose their no-drop stuff somehow antag_flags = ANTAG_FAKE|ANTAG_SKIP_GLOBAL_LIST + desensitized_modifier = DESENSITIZED_THRESHOLD * 0.2 /// Traits we apply/remove to our target on-demand. var/static/list/applicable_traits = list( - TRAIT_DESENSITIZED, TRAIT_NOBREATH, TRAIT_NODISMEMBER, TRAIT_NOFIRE, diff --git a/code/modules/antagonists/nukeop/datums/operative.dm b/code/modules/antagonists/nukeop/datums/operative.dm index 59b2ca2f4af..abf38593990 100644 --- a/code/modules/antagonists/nukeop/datums/operative.dm +++ b/code/modules/antagonists/nukeop/datums/operative.dm @@ -9,6 +9,7 @@ hijack_speed = 2 //If you can't take out the station, take the shuttle instead. suicide_cry = "FOR THE SYNDICATE!!" stinger_sound = 'sound/music/antag/ops.ogg' + desensitized_modifier = DESENSITIZED_THRESHOLD * 0.5 /// Which nukie team are we on? var/datum/team/nuclear/nuke_team @@ -132,7 +133,6 @@ var/mob/living/carbon/human/operative = owner.current ADD_TRAIT(operative, TRAIT_NOFEAR_HOLDUPS, INNATE_TRAIT) - ADD_TRAIT(operative, TRAIT_DESENSITIZED, INNATE_TRAIT) if(!nukeop_outfit) // this variable is null in instances where an antagonist datum is granted via enslaving the mind (/datum/mind/proc/enslave_mind_to_creator), like in golems. return diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm index 7b09a2540ec..e3f4d00d8eb 100644 --- a/code/modules/antagonists/pirate/pirate.dm +++ b/code/modules/antagonists/pirate/pirate.dm @@ -8,6 +8,7 @@ suicide_cry = "FOR ME MATEYS!!" stinger_sound = 'sound/music/antag/pirate/pirate_start.ogg' hijack_speed = 2 // That is without doubt the worst pirate I have ever seen. + desensitized_modifier = DESENSITIZED_THRESHOLD var/datum/team/pirate/crew /datum/antagonist/pirate/greet() @@ -46,12 +47,10 @@ var/datum/language_holder/holder = owner_mob.get_language_holder() holder.grant_language(/datum/language/piratespeak, source = LANGUAGE_PIRATE) holder.selected_language = /datum/language/piratespeak - ADD_TRAIT(owner_mob, TRAIT_DESENSITIZED, REF(src)) /datum/antagonist/pirate/remove_innate_effects(mob/living/mob_override) var/mob/living/owner_mob = mob_override || owner.current owner_mob.remove_language(/datum/language/piratespeak, source = LANGUAGE_PIRATE) - REMOVE_TRAIT(owner_mob, TRAIT_DESENSITIZED, REF(src)) /datum/team/pirate name = "\improper Pirate crew" diff --git a/code/modules/antagonists/space_ninja/space_ninja.dm b/code/modules/antagonists/space_ninja/space_ninja.dm index 9cb98f928f9..5a1bed62c7f 100644 --- a/code/modules/antagonists/space_ninja/space_ninja.dm +++ b/code/modules/antagonists/space_ninja/space_ninja.dm @@ -12,17 +12,10 @@ can_assign_self_objectives = TRUE ui_name = "AntagInfoNinja" default_custom_objective = "Destroy vital station infrastructure, without being seen." + desensitized_modifier = DESENSITIZED_THRESHOLD ///Whether or not this ninja will obtain objectives var/give_objectives = TRUE -/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override) - var/mob/ninja = mob_override || owner.current - ADD_TRAIT(ninja, TRAIT_DESENSITIZED, REF(src)) - -/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override) - var/mob/ninja = mob_override || owner.current - REMOVE_TRAIT(ninja, TRAIT_DESENSITIZED, REF(src)) - /** * Proc that equips the space ninja outfit on a given individual. By default this is the owner of the antagonist datum. * diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm index fbff1b5a861..2f61f9e832e 100644 --- a/code/modules/holodeck/holo_effect.dm +++ b/code/modules/holodeck/holo_effect.dm @@ -63,7 +63,7 @@ our_mob.flags_1 |= HOLOGRAM_1 // these vars are not really standardized but all would theoretically create stuff on death - our_mob.add_traits(list(TRAIT_PERMANENTLY_MORTAL, TRAIT_NO_BLOOD_OVERLAY, TRAIT_NOBLOOD, TRAIT_NOHUNGER), INNATE_TRAIT) + our_mob.add_traits(list(TRAIT_PERMANENTLY_MORTAL, TRAIT_NO_BLOOD_OVERLAY, TRAIT_NOBLOOD, TRAIT_NOHUNGER, TRAIT_SPAWNED_MOB), INNATE_TRAIT) RegisterSignal(our_mob, COMSIG_QDELETING, PROC_REF(handle_mob_delete)) return our_mob diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 04ed2d91fcf..165444d106d 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -132,6 +132,9 @@ /// If set, look for a policy with this instead of the job title var/policy_override + /// How desensitized this job is to seeing death as a base - applied with the job + var/desensitized_base = 1.0 + /datum/job/New() . = ..() var/new_spawn_positions = CHECK_MAP_JOB_CHANGE(title, "spawn_positions") @@ -147,6 +150,8 @@ if(length(mind_traits)) spawned.mind.add_traits(mind_traits, JOB_TRAIT) + spawned.mind.desensitized_level = clamp(desensitized_base, DESENSITIZED_MINIMUM, spawned.mind.desensitized_level) + var/obj/item/organ/liver/liver = spawned.get_organ_slot(ORGAN_SLOT_LIVER) if(liver && length(liver_traits)) liver.add_traits(liver_traits, JOB_TRAIT) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 718751bf787..a3ad2d52aa8 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -22,7 +22,8 @@ paycheck = PAYCHECK_COMMAND paycheck_department = ACCOUNT_SEC - mind_traits = list(HEAD_OF_STAFF_MIND_TRAITS, TRAIT_DESENSITIZED) + mind_traits = list(HEAD_OF_STAFF_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_ROYAL_METABOLISM) display_order = JOB_DISPLAY_ORDER_CAPTAIN diff --git a/code/modules/jobs/job_types/chaplain/chaplain.dm b/code/modules/jobs/job_types/chaplain/chaplain.dm index 75fd0a7c00a..d4c39db5bee 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain.dm @@ -12,7 +12,8 @@ outfit = /datum/outfit/job/chaplain plasmaman_outfit = /datum/outfit/plasmaman/chaplain - mind_traits = list(TRAIT_SPIRITUAL, TRAIT_DESENSITIZED) + mind_traits = list(TRAIT_SPIRITUAL) + desensitized_base = DESENSITIZED_THRESHOLD paycheck = PAYCHECK_CREW paycheck_department = ACCOUNT_SRV diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 4cab7531da4..3b4a856a118 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -26,7 +26,8 @@ paycheck = PAYCHECK_COMMAND paycheck_department = ACCOUNT_MED - mind_traits = list(HEAD_OF_STAFF_MIND_TRAITS, MEDICAL_MIND_TRAITS) + mind_traits = list(HEAD_OF_STAFF_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_MEDICAL_METABOLISM, TRAIT_ROYAL_METABOLISM) display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm index c4013d122ad..aebe1b9ca80 100644 --- a/code/modules/jobs/job_types/cook.dm +++ b/code/modules/jobs/job_types/cook.dm @@ -15,7 +15,7 @@ paycheck = PAYCHECK_CREW paycheck_department = ACCOUNT_SRV - mind_traits = list(TRAIT_DESENSITIZED) // butcher + desensitized_base = DESENSITIZED_THRESHOLD // butcher liver_traits = list(TRAIT_CULINARY_METABOLISM) display_order = JOB_DISPLAY_ORDER_COOK diff --git a/code/modules/jobs/job_types/coroner.dm b/code/modules/jobs/job_types/coroner.dm index ddb1ad7e83f..150d029d35c 100644 --- a/code/modules/jobs/job_types/coroner.dm +++ b/code/modules/jobs/job_types/coroner.dm @@ -12,7 +12,8 @@ outfit = /datum/outfit/job/coroner plasmaman_outfit = /datum/outfit/plasmaman/coroner - mind_traits = list(TRAIT_MORBID, MEDICAL_MIND_TRAITS) + mind_traits = list(TRAIT_MORBID) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_CORONER_METABOLISM) paycheck = PAYCHECK_CREW diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index e56225c42a1..4926749c636 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -22,7 +22,7 @@ paycheck = PAYCHECK_CREW paycheck_department = ACCOUNT_SEC - mind_traits = list(SECURITY_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_DETECTIVE diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 4fcad1b97af..936028f86f0 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -23,7 +23,8 @@ /datum/job_department/command, ) - mind_traits = list(HEAD_OF_STAFF_MIND_TRAITS, SECURITY_MIND_TRAITS) + mind_traits = list(HEAD_OF_STAFF_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM, TRAIT_ROYAL_METABOLISM) paycheck = PAYCHECK_COMMAND diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index d7963faeedf..f357bcac8ac 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -15,7 +15,7 @@ paycheck = PAYCHECK_CREW paycheck_department = ACCOUNT_MED - mind_traits = list(MEDICAL_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_MEDICAL_METABOLISM) display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm index 85aae2f1f94..ad9244333b8 100644 --- a/code/modules/jobs/job_types/paramedic.dm +++ b/code/modules/jobs/job_types/paramedic.dm @@ -15,7 +15,7 @@ paycheck = PAYCHECK_CREW paycheck_department = ACCOUNT_MED - mind_traits = list(MEDICAL_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_MEDICAL_METABOLISM) display_order = JOB_DISPLAY_ORDER_PARAMEDIC @@ -79,4 +79,3 @@ mask = /obj/item/clothing/mask/breath/medical r_pocket = /obj/item/flashlight/pen internals_slot = ITEM_SLOT_SUITSTORE - diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 78ea30f1fc1..06c78c25f1c 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -19,7 +19,7 @@ paycheck = PAYCHECK_CREW paycheck_department = ACCOUNT_SEC - mind_traits = list(SECURITY_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_SECURITY_OFFICER diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index c759552c049..bcc07dfd2d6 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -20,7 +20,7 @@ paycheck = PAYCHECK_CREW paycheck_department = ACCOUNT_SEC - mind_traits = list(SECURITY_MIND_TRAITS) + desensitized_base = DESENSITIZED_THRESHOLD liver_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM, TRAIT_PRETENDER_ROYAL_METABOLISM) display_order = JOB_DISPLAY_ORDER_WARDEN diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index e87b425acd7..80189ae4902 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -180,9 +180,13 @@ return for(var/mob/living/nearby in viewers(src)) - if(nearby.stat >= UNCONSCIOUS || nearby.is_blind()) + if(nearby == src || nearby.stat >= UNCONSCIOUS || nearby.is_blind()) continue nearby.add_mood_event("saw_death", /datum/mood_event/conditional/see_death, src, dusted, gibbed) + nearby.mind?.witnessed_death(src) + + if(!gibbed && !dusted) + mind?.experienced_death() /mob/living/silicon/send_death_moodlets(dusted = FALSE, gibbed = FALSE) return // You are a machine (Future todo, roboticists feel sad though) diff --git a/code/modules/unit_tests/death_moodlets.dm b/code/modules/unit_tests/death_moodlets.dm index ded468abbb1..4b1b2fc3512 100644 --- a/code/modules/unit_tests/death_moodlets.dm +++ b/code/modules/unit_tests/death_moodlets.dm @@ -6,6 +6,7 @@ /datum/unit_test/death_moodlets/Run() var/mob/living/carbon/human/consistent/dummy = allocate(__IMPLIED_TYPE__) + dummy.mind_initialize() prepare_dummy(dummy) var/mob/living/dying = get_dying_mob() @@ -47,7 +48,7 @@ desired_moodlet = /datum/mood_event/conditional/see_death/desensitized /datum/unit_test/death_moodlets/human/desensitized/prepare_dummy(mob/living/carbon/human/consistent/dummy) - ADD_TRAIT(dummy, TRAIT_DESENSITIZED, TRAIT_SOURCE_UNIT_TESTS) + dummy.mind.desensitized_level = DESENSITIZED_THRESHOLD /// Test callous moodlet /datum/unit_test/death_moodlets/human/callous @@ -61,8 +62,8 @@ desired_moodlet = /datum/mood_event/conditional/see_death/dontcare /datum/unit_test/death_moodlets/human/desensitized_and_callous/prepare_dummy(mob/living/carbon/human/consistent/dummy) - ADD_TRAIT(dummy, TRAIT_DESENSITIZED, TRAIT_SOURCE_UNIT_TESTS) dummy.add_personality(/datum/personality/callous) + dummy.mind.desensitized_level = DESENSITIZED_THRESHOLD /// Test cultist positive moodlet /datum/unit_test/death_moodlets/human/cultist @@ -87,7 +88,7 @@ desired_moodlet = /datum/mood_event/conditional/see_death/pet /datum/unit_test/death_moodlets/pet/desensitized_to_pet/prepare_dummy(mob/living/carbon/human/consistent/dummy) - ADD_TRAIT(dummy, TRAIT_DESENSITIZED, TRAIT_SOURCE_UNIT_TESTS) + dummy.mind.desensitized_level = DESENSITIZED_THRESHOLD /// Tests callous moodlet when a pet dies /datum/unit_test/death_moodlets/pet/callous_to_pet @@ -102,3 +103,23 @@ /datum/unit_test/death_moodlets/pet/animal_disliker_to_pet/prepare_dummy(mob/living/carbon/human/consistent/dummy) dummy.add_personality(/datum/personality/animal_disliker) + +// This one just tests that the death desensitized status effect works as expected +/datum/unit_test/desensitized_status_effect + +/datum/unit_test/desensitized_status_effect/Run() + var/mob/living/carbon/human/consistent/normal_dummy = EASY_ALLOCATE() + var/mob/living/carbon/human/consistent/desensitized_dummy = EASY_ALLOCATE() + desensitized_dummy.mind_initialize() + + desensitized_dummy.apply_status_effect(/datum/status_effect/desensitized, TRAIT_SOURCE_UNIT_TESTS, DESENSITIZED_THRESHOLD) + TEST_ASSERT_EQUAL(desensitized_dummy.mind.desensitized_level, DESENSITIZED_THRESHOLD, "Desensitized level not set correctly on application of desensitized status effect.") + + desensitized_dummy.mind.transfer_to(normal_dummy) + TEST_ASSERT_EQUAL(normal_dummy.mind.desensitized_level, 1.0, "Desensitized level not reset to normal on transfer of mind from desensitized mob.") + + normal_dummy.mind.transfer_to(desensitized_dummy) + TEST_ASSERT_EQUAL(desensitized_dummy.mind.desensitized_level, DESENSITIZED_THRESHOLD, "Desensitized level not restored on transfer of mind back to desensitized mob.") + + desensitized_dummy.remove_status_effect(/datum/status_effect/desensitized, TRAIT_SOURCE_UNIT_TESTS) + TEST_ASSERT_EQUAL(desensitized_dummy.mind.desensitized_level, 1.0, "Desensitized level not reset to normal on removal of desensitized status effect.") diff --git a/icons/ui/achievements/achievements.dmi b/icons/ui/achievements/achievements.dmi index 80ebc9cd297..d5bef5c42f8 100644 Binary files a/icons/ui/achievements/achievements.dmi and b/icons/ui/achievements/achievements.dmi differ