Deafness is now solely tracked by trait (#95029)

## About The Pull Request

Deletes `can_hear`, replaces it with trait-checking deafness.

The only two non-trait sources of deafness (hardcrit and lacking ears)
were refactored into using the trait.

## Why It's Good For The Game

Many places inconsistently check for the deaf trait rather than use
can_hear which meant behavior was not consistent.
Some code would treat "do we lack ears?" as being deaf, some would not. 

This unifies all the behavior so being deaf means you're deaf
everywhere.

It also means we can now easily react to gaining and losing deafness via
signal, where before we could not react to it without hooking the trait,
organ remove, AND stat change. Which no one did, of course, because who
would ever think to do that?

## Changelog

🆑 Melbert
refactor: Refactored how deafness is tracked. Please report any weird
interactions with sounds, like messages or sfx being missing.
fix: Lacking ears and being in hard crit now consistently treats you as
"being deaf". This affects a few minor interactions like empath, the
jukebox, and sleeping.
/🆑
This commit is contained in:
MrMelbert
2026-02-05 20:19:56 -05:00
committed by GitHub
parent 1b7928a956
commit e4f533111f
40 changed files with 64 additions and 68 deletions
@@ -767,18 +767,18 @@ Basically, we fill the time between now and 2s from now with hands based off the
. = ..()
random_span = pick("clown", "small", "big", "hypnophrase", "alien", "cult", "alert", "danger", "emote", "yell", "brass", "sans", "papyrus", "robot", "his_grace", "phobia")
RegisterSignal(affected_mob, COMSIG_MOVABLE_HEAR, PROC_REF(owner_hear))
to_chat(affected_mob, span_warning("Your hearing seems to be a bit off[affected_mob.can_hear() ? "!" : " - wait, that's normal."]"))
to_chat(affected_mob, span_warning("Your hearing seems to be a bit off[!HAS_TRAIT(affected_mob, TRAIT_DEAF) ? "!" : " - wait, that's normal."]"))
/datum/reagent/impurity/inacusiate/on_mob_end_metabolize(mob/living/affected_mob)
. = ..()
UnregisterSignal(affected_mob, COMSIG_MOVABLE_HEAR)
to_chat(affected_mob, span_notice("You start hearing things normally again[affected_mob.can_hear() ? "" : " - no, wait, no you don't"]."))
to_chat(affected_mob, span_notice("You start hearing things normally again[!HAS_TRAIT(affected_mob, TRAIT_DEAF) ? "" : " - no, wait, no you don't"]."))
/datum/reagent/impurity/inacusiate/proc/owner_hear(mob/living/owner, list/hearing_args)
SIGNAL_HANDLER
// don't skip messages that the owner says or can't understand (since they still make sounds)
if(!owner.can_hear())
if(HAS_TRAIT(owner, TRAIT_DEAF))
return
// not technically hearing
var/atom/movable/speaker = hearing_args[HEARING_SPEAKER]
@@ -929,7 +929,7 @@
. = ..()
if(creation_purity >= 1)
ADD_TRAIT(affected_mob, TRAIT_GOOD_HEARING, type)
if(affected_mob.can_hear())
if(!HAS_TRAIT(affected_mob, TRAIT_DEAF))
to_chat(affected_mob, span_nicegreen("You can feel your hearing drastically improve!"))
/datum/reagent/medicine/inacusiate/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, metabolization_ratio)
@@ -945,7 +945,7 @@
/datum/reagent/medicine/inacusiate/on_mob_delete(mob/living/affected_mob)
. = ..()
REMOVE_TRAIT(affected_mob, TRAIT_GOOD_HEARING, type)
if(affected_mob.can_hear())
if(!HAS_TRAIT(affected_mob, TRAIT_DEAF))
to_chat(affected_mob, span_notice("Your hearing returns to its normal acuity."))
/datum/reagent/medicine/atropine