diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
index 1ea6ef446de..75b809b5403 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
@@ -116,11 +116,6 @@
#define MOVABLE_SAY_QUOTE_MESSAGE_SPANS 2
#define MOVABLE_SAY_QUOTE_MESSAGE_MODS 3
-/// Sent from /atom/movable/proc/compose_message() after the name part: (list/stored_name, visible_name)
-#define COMSIG_MOVABLE_MESSAGE_GET_NAME_PART "movable_message_get_name_part"
- ///The index of the name part
- #define NAME_PART_INDEX 1
-
/// From /datum/element/immerse/proc/add_submerge_overlay(): (visual_overlay)
#define COMSIG_MOVABLE_EDIT_UNIQUE_IMMERSE_OVERLAY "movable_edit_unique_submerge_overlay"
/// From base of area/Exited(): (area/left, direction)
diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index 097a2592e64..ecbbb3ec04b 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -143,6 +143,3 @@
///Defines for priorities for the bubble_icon_override comp
#define BUBBLE_ICON_PRIORITY_ACCESSORY 2
#define BUBBLE_ICON_PRIORITY_ORGAN 1
-
-/// Sent from /atom/movable/proc/compose_message() to find an honorific. Compatible with NAME_PART_INDEX: (list/stored_name, mob/living/carbon/carbon_human)
-#define COMSIG_ID_GET_HONORIFIC "id_get_honorific"
diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm
index 108fc197404..9d73f12a980 100644
--- a/code/__DEFINES/surgery.dm
+++ b/code/__DEFINES/surgery.dm
@@ -80,8 +80,10 @@
#define HEAD_EYEHOLES (1<<5)
/// Head can have debrain overlay
#define HEAD_DEBRAIN (1<<6)
-/// All head flags, default for most heads
-#define HEAD_ALL_FEATURES (HEAD_HAIR|HEAD_FACIAL_HAIR|HEAD_LIPS|HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN)
+/// Head will never be disfigured by damage
+#define HEAD_NO_DISFIGURE (1<<7)
+/// Default for most heads
+#define HEAD_DEFAULT_FEATURES (HEAD_HAIR|HEAD_FACIAL_HAIR|HEAD_LIPS|HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN)
/// Return value when the surgery step fails :(
#define SURGERY_STEP_FAIL -1
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 47fd640341b..cb522ac9947 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -619,7 +619,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_BLIND_TOOL "blind_tool"
/// The person with this trait always appears as 'unknown'.
-#define TRAIT_UNKNOWN "unknown"
+#define TRAIT_UNKNOWN_APPEARANCE "unknown_appearance"
+/// The person with this trait always talks as 'unknown'
+#define TRAIT_UNKNOWN_VOICE "unknown_voice"
+/// Spoken voice always matches any worn ID. If no worn ID, defaults to actual name.
+#define TRAIT_VOICE_MATCHES_ID "voice_matches_id"
/// If the mob has this trait and die, their bomb implant doesn't detonate automatically. It must be consciously activated.
#define TRAIT_PREVENT_IMPLANT_AUTO_EXPLOSION "prevent_implant_auto_explosion"
diff --git a/code/__HELPERS/pronouns.dm b/code/__HELPERS/pronouns.dm
index cc907f1bc49..cc1f357fcf6 100644
--- a/code/__HELPERS/pronouns.dm
+++ b/code/__HELPERS/pronouns.dm
@@ -411,7 +411,7 @@
return gender
/mob/living/carbon/human/get_visible_gender()
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
return PLURAL
// If both face and uniform are hidden, can't assess gender
if(obscured_slots & (HIDEFACE|HIDEJUMPSUIT) == (HIDEFACE|HIDEJUMPSUIT))
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index 1e661883b23..bba6f9e0287 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -589,7 +589,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE,
"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE,
"TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH,
- "TRAIT_UNKNOWN" = TRAIT_UNKNOWN,
+ "TRAIT_UNKNOWN_APPEARANCE" = TRAIT_UNKNOWN_APPEARANCE,
+ "TRAIT_UNKNOWN_VOICE" = TRAIT_UNKNOWN_VOICE,
"TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES,
"TRAIT_UNOBSERVANT" = TRAIT_UNOBSERVANT,
"TRAIT_UNSTABLE" = TRAIT_UNSTABLE,
@@ -602,6 +603,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_VENTCRAWLER_NUDE" = TRAIT_VENTCRAWLER_NUDE,
"TRAIT_VIRUSIMMUNE" = TRAIT_VIRUSIMMUNE,
"TRAIT_VIRUS_RESISTANCE" = TRAIT_VIRUS_RESISTANCE,
+ "TRAIT_VOICE_MATCHES_ID" = TRAIT_VOICE_MATCHES_ID,
"TRAIT_VORACIOUS" = TRAIT_VORACIOUS,
"TRAIT_WAS_EVOLVED" = TRAIT_WAS_EVOLVED,
"TRAIT_WATER_ADAPTATION" = TRAIT_WATER_ADAPTATION,
diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm
index c81ee3cd4d5..40e82c58bef 100644
--- a/code/_globalvars/traits/admin_tooling.dm
+++ b/code/_globalvars/traits/admin_tooling.dm
@@ -315,7 +315,8 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE,
"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE,
"TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH,
- "TRAIT_UNKNOWN" = TRAIT_UNKNOWN,
+ "TRAIT_UNKNOWN_APPEARANCE" = TRAIT_UNKNOWN_APPEARANCE,
+ "TRAIT_UNKNOWN_VOICE" = TRAIT_UNKNOWN_VOICE,
"TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES,
"TRAIT_UNOBSERVANT" = TRAIT_UNOBSERVANT,
"TRAIT_UNSTABLE" = TRAIT_UNSTABLE,
@@ -326,6 +327,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_VENTCRAWLER_NUDE" = TRAIT_VENTCRAWLER_NUDE,
"TRAIT_VIRUSIMMUNE" = TRAIT_VIRUSIMMUNE,
"TRAIT_VIRUS_RESISTANCE" = TRAIT_VIRUS_RESISTANCE,
+ "TRAIT_VOICE_MATCHES_ID" = TRAIT_VOICE_MATCHES_ID,
"TRAIT_VORACIOUS" = TRAIT_VORACIOUS,
"TRAIT_WATER_ADAPTATION" = TRAIT_WATER_ADAPTATION,
"TRAIT_WATER_HATER" = TRAIT_WATER_HATER,
diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
index ff86cb7c013..6f0b4579771 100644
--- a/code/datums/chatmessage.dm
+++ b/code/datums/chatmessage.dm
@@ -161,7 +161,7 @@
if(HAS_TRAIT(target, TRAIT_SIGN_LANG))
chat_color_name_to_use = target.get_visible_name(add_id_name = FALSE) // use face name for signers too
else
- chat_color_name_to_use = target.GetVoice() // for everything else, use the target's voice name
+ chat_color_name_to_use = target.get_voice() // for everything else, use the target's voice name
// Calculate target color if not already present
if (!target.chat_color || target.chat_color_name != chat_color_name_to_use)
diff --git a/code/datums/components/callouts.dm b/code/datums/components/callouts.dm
index f69fa39fe66..c6b27bf17dc 100644
--- a/code/datums/components/callouts.dm
+++ b/code/datums/components/callouts.dm
@@ -139,7 +139,7 @@
if (isnull(creator))
return
icon_state = callout::icon_state
- color = colorize_string(creator.GetVoice(), 2, 0.9)
+ color = colorize_string(creator.get_voice(), 2, 0.9)
update_appearance()
var/turf/target_loc = get_turf(target)
animate(src, pixel_x = (target_loc.x - loc.x) * ICON_SIZE_X + target.pixel_x, pixel_y = (target_loc.y - loc.y) * ICON_SIZE_Y + target.pixel_y, time = 0.2 SECONDS, easing = EASE_OUT)
diff --git a/code/datums/components/tactical.dm b/code/datums/components/tactical.dm
index 80ea33f2445..732e43ee766 100644
--- a/code/datums/components/tactical.dm
+++ b/code/datums/components/tactical.dm
@@ -45,7 +45,7 @@
RegisterSignal(user, COMSIG_HUMAN_GET_VISIBLE_NAME, PROC_REF(on_name_inquiry))
RegisterSignal(user, COMSIG_HUMAN_GET_FORCED_NAME, PROC_REF(on_name_inquiry))
// This forces a name update on the user, so we don't need to call name update ourselves
- ADD_TRAIT(user, TRAIT_UNKNOWN, REF(src))
+ ADD_TRAIT(user, TRAIT_UNKNOWN_APPEARANCE, REF(src))
current_slot = slot
@@ -106,7 +106,7 @@
))
current_slot = null
user.remove_alt_appearance("sneaking_mission[REF(src)]")
- REMOVE_TRAIT(user, TRAIT_UNKNOWN, REF(src))
+ REMOVE_TRAIT(user, TRAIT_UNKNOWN_APPEARANCE, REF(src))
///Checks if a mob is holding us, and if so we will modify our appearance to properly match w/ the mob.
/datum/component/tactical/proc/tactical_update(obj/item/source)
diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index 92583e1fca7..ec224147974 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -54,7 +54,7 @@
else
if(ishuman(M))
var/mob/living/carbon/human/H = M
- H.SetSpecialVoice(H.generate_random_mob_name())
+ H.override_voice = H.generate_random_mob_name()
if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.add_blocked_language(subtypesof(/datum/language) - current_language, source = LANGUAGE_VOICECHANGE)
@@ -64,7 +64,7 @@
..()
if(ishuman(A.affected_mob))
var/mob/living/carbon/human/H = A.affected_mob
- H.UnsetSpecialVoice()
+ H.override_voice = ""
if(scramble_language)
A.affected_mob.remove_blocked_language(subtypesof(/datum/language), source = LANGUAGE_VOICECHANGE)
A.affected_mob.remove_all_languages(LANGUAGE_VOICECHANGE) // In case someone managed to get more than one anyway.
diff --git a/code/datums/quirks/negative_quirks/prosopagnosia.dm b/code/datums/quirks/negative_quirks/prosopagnosia.dm
index 3911cb45056..bb70a41c1dd 100644
--- a/code/datums/quirks/negative_quirks/prosopagnosia.dm
+++ b/code/datums/quirks/negative_quirks/prosopagnosia.dm
@@ -21,7 +21,7 @@
if(!ishuman(examined) || source == examined)
return NONE
- var/id_name = examined.get_id_name("")
+ var/id_name = examined.get_id_name("", honorifics = TRUE)
name_override[1] = id_name ? "[id_name]?" : "Unknown"
return COMPONENT_EXAMINE_NAME_OVERRIDEN
@@ -31,6 +31,6 @@
if(!ishuman(hovered) || source == hovered)
return NONE
- var/id_name = hovered.get_id_name("")
+ var/id_name = hovered.get_id_name("", honorifics = TRUE)
returned_name[1] = id_name ? "[id_name]?" : "Unknown"
return SCREENTIP_NAME_SET
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 04ba0e52439..959716d230d 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -266,7 +266,7 @@ Security HUDs! Basic mode shows only the job.
SIGNAL_HANDLER
var/sechud_icon_state = wear_id?.get_sechud_job_icon_state()
- if(!sechud_icon_state || HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(!sechud_icon_state || HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
sechud_icon_state = "hudno_id"
set_hud_image_state(ID_HUD, sechud_icon_state)
sec_hud_set_security_status()
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 599d9fa7ad6..8288de30e16 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -43,6 +43,10 @@
. = ..()
cached_flat_icon = null
+/// Called to get what name this card represents
+/obj/item/card/proc/get_displayed_name(honorifics = FALSE)
+ return null
+
/// If no cached_flat_icon exists, this proc creates it and crops it. This proc then returns the cached_flat_icon. Intended for use displaying ID card icons in chat.
/obj/item/card/proc/get_cached_flat_icon()
if(!cached_flat_icon)
@@ -146,7 +150,7 @@
SSid_access.apply_trim_to_card(src, trim)
else
update_label()
- update_icon()
+ update_appearance()
// Apply any active RETA grants to this new ID card
// This will only do something if there are active grants, so it's safe to call always
@@ -156,7 +160,6 @@
register_context()
RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, PROC_REF(update_in_wallet))
- RegisterSignal(src, COMSIG_ID_GET_HONORIFIC, PROC_REF(return_message_name_part))
if(prob(1))
ADD_TRAIT(src, TRAIT_TASTEFULLY_THICK_ID_CARD, ROUNDSTART_TRAIT)
@@ -188,19 +191,25 @@
UnregisterSignal(user, COMSIG_MOVABLE_POINTED)
return ..()
-/obj/item/card/id/proc/return_message_name_part(datum/source, list/stored_name, mob/living/carbon/carbon_human)
- SIGNAL_HANDLER
- var/voice_name = carbon_human.GetVoice()
- var/end_string = ""
- var/return_string = ""
- if(carbon_human.name != voice_name)
- end_string += " (as [registered_name])"
- if(trim && honorific_position != HONORIFIC_POSITION_NONE && (carbon_human.name == voice_name)) //The voice and name are the same, so we display the title.
- return_string += honorific_title
- else
- return_string += voice_name //Name on the ID ain't the same as the speaker, so we display their real name with no title.
- return_string += end_string
- stored_name[NAME_PART_INDEX] = return_string
+/obj/item/card/id/equipped(mob/user, slot, initial = FALSE)
+ . = ..()
+ if(!(slot & ITEM_SLOT_ID))
+ return
+ if(ishuman(user))
+ var/mob/living/carbon/human/as_human = user
+ as_human.update_visible_name()
+
+/obj/item/card/id/dropped(mob/user, silent = FALSE)
+ . = ..()
+ if(ishuman(user))
+ var/mob/living/carbon/human/as_human = user
+ as_human.update_visible_name()
+
+/// Getter for the registered name, with optional honorifics
+/obj/item/card/id/get_displayed_name(honorifics = FALSE)
+ if(honorifics && honorific_position != HONORIFIC_POSITION_NONE && honorific_title)
+ return honorific_title
+ return registered_name
/obj/item/card/id/proc/on_loc_equipped(datum/source, mob/equipper, slot)
SIGNAL_HANDLER
@@ -214,7 +223,7 @@
/obj/item/card/id/proc/on_pointed(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point)
SIGNAL_HANDLER
- if ((!big_pointer && !pointer_color) || HAS_TRAIT(user, TRAIT_UNKNOWN))
+ if ((!big_pointer && !pointer_color) || HAS_TRAIT(user, TRAIT_UNKNOWN_APPEARANCE))
return
if (point.icon_state != /obj/effect/temp_visual/point::icon_state) //it differs from the original icon_state already.
return
@@ -650,7 +659,7 @@
switch(var_name)
if(NAMEOF(src, assignment), NAMEOF(src, registered_name), NAMEOF(src, registered_age))
update_label()
- update_icon()
+ update_appearance()
if(NAMEOF(src, trim))
if(ispath(trim))
SSid_access.apply_trim_to_card(src, trim)
@@ -945,6 +954,10 @@
name = "[name_string] ([assignment_string])"
+ if(ishuman(loc))
+ var/mob/living/carbon/human/human = loc
+ human.update_visible_name()
+
/// Re-generates the honorific title. Returns the compiled honorific_title value
/obj/item/card/id/proc/update_honorific()
switch(honorific_position)
@@ -1879,7 +1892,7 @@
REMOVE_TRAIT(src, TRAIT_MAGNETIC_ID_CARD, CHAMELEON_ITEM_TRAIT)
user.log_message("reset \the [initial(name)] named \"[src]\" to default.", LOG_GAME)
update_label()
- update_icon()
+ update_appearance()
forged = FALSE
to_chat(user, span_notice("You successfully reset the ID card."))
return
@@ -1939,7 +1952,7 @@
ADD_TRAIT(src, TRAIT_MAGNETIC_ID_CARD, CHAMELEON_ITEM_TRAIT)
update_label()
- update_icon()
+ update_appearance()
forged = TRUE
to_chat(user, span_notice("You successfully forge the ID card."))
user.log_message("forged \the [initial(name)] with name \"[registered_name]\", occupation \"[assignment]\" and trim \"[trim?.assignment]\".", LOG_GAME)
@@ -2057,35 +2070,8 @@
. = ..()
register_context()
-/obj/item/card/cardboard/equipped(mob/user, slot, initial = FALSE)
- . = ..()
- if(slot != ITEM_SLOT_ID)
- return
- RegisterSignal(user, COMSIG_HUMAN_GET_VISIBLE_NAME, PROC_REF(return_visible_name))
- RegisterSignal(user, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, PROC_REF(return_message_name_part))
- if(ishuman(user))
- var/mob/living/carbon/human/as_human = user
- as_human.update_visible_name()
-
-/obj/item/card/cardboard/dropped(mob/user, silent = FALSE)
- . = ..()
- UnregisterSignal(user, list(COMSIG_HUMAN_GET_VISIBLE_NAME, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART))
- if(ishuman(user))
- var/mob/living/carbon/human/as_human = user
- as_human.update_visible_name()
-
-/obj/item/card/cardboard/proc/return_visible_name(mob/living/carbon/human/source, list/identity)
- SIGNAL_HANDLER
- identity[VISIBLE_NAME_ID] = scribbled_name
-
-/obj/item/card/cardboard/proc/return_message_name_part(mob/living/carbon/human/source, list/stored_name, visible_name)
- SIGNAL_HANDLER
- if(visible_name)
- return
- var/voice_name = source.GetVoice()
- if(source.name != voice_name)
- voice_name += " (as [scribbled_name])"
- stored_name[NAME_PART_INDEX] = voice_name
+/obj/item/card/cardboard/get_displayed_name(honorifics = FALSE)
+ return scribbled_name
/obj/item/card/cardboard/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(user.can_write(tool, TRUE))
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 5dfe8ebce47..c5160b0d705 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -159,7 +159,7 @@
return
mytape.timestamp += mytape.used_capacity
- mytape.storedinfo += "\[[time2text(mytape.used_capacity,"mm:ss", NO_TIMEZONE)]\] [speaker.GetVoice()]: [raw_message]"
+ mytape.storedinfo += "\[[time2text(mytape.used_capacity,"mm:ss", NO_TIMEZONE)]\] [speaker.get_voice()]: [raw_message]"
/obj/item/taperecorder/verb/record()
diff --git a/code/game/objects/items/emags.dm b/code/game/objects/items/emags.dm
index 9c0a95877aa..219e1a3e144 100644
--- a/code/game/objects/items/emags.dm
+++ b/code/game/objects/items/emags.dm
@@ -17,6 +17,9 @@
var/prox_check = TRUE //If the emag requires you to be in range
var/type_blacklist //List of types that require a specialized emag
+/obj/item/card/emag/get_displayed_name(honorifics = FALSE)
+ return name // That's Grey Tider (as "cryptographic sequencer")
+
/obj/item/card/emag/attack_self(mob/user) //for traitors with balls of plastitanium
if(Adjacent(user))
user.visible_message(span_notice("[user] shows you: [icon2html(src, viewers(user))] [name]."), span_notice("You show [src]."))
@@ -99,6 +102,9 @@
/// Whether we are exploding
var/exploding = FALSE
+/obj/item/card/emagfake/get_displayed_name(honorifics = FALSE)
+ return name // That's Grey Tider (as "cryptographic sequencer")
+
/obj/item/card/emagfake/attack_self(mob/user) //for assistants with balls of plasteel
if(Adjacent(user))
user.visible_message(span_notice("[user] shows you: [icon2html(src, viewers(user))] [name]."), span_notice("You show [src]."))
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index a980ce95718..1e2405c126d 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -1448,7 +1448,7 @@
. = ..()
AddElement(/datum/element/toy_talk)
-/obj/item/toy/dummy/GetVoice()
+/obj/item/toy/dummy/get_voice()
return doll_name
/obj/item/toy/seashell
diff --git a/code/game/say.dm b/code/game/say.dm
index 85848ee0f48..423a39498f3 100644
--- a/code/game/say.dm
+++ b/code/game/say.dm
@@ -149,21 +149,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
//Radio freq/name display
var/freqpart = radio_freq ? "\[[get_radio_name(radio_freq, radio_freq_name)]\] " : ""
//Speaker name
- var/namepart
- var/list/stored_name = list(null)
-
- if(iscarbon(speaker)) //First, try to pull the modified title from a carbon's ID. This will override both visual and audible names.
- var/mob/living/carbon/carbon_human = speaker
- var/obj/item/id_slot = carbon_human.get_item_by_slot(ITEM_SLOT_ID)
- if(id_slot)
- var/obj/item/card/id/id_card = id_slot?.GetID()
- if(id_card)
- SEND_SIGNAL(id_card, COMSIG_ID_GET_HONORIFIC, stored_name, carbon_human)
-
- if(!stored_name[NAME_PART_INDEX]) //Otherwise, we just use whatever the name signal gives us.
- SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, visible_name)
-
- namepart = stored_name[NAME_PART_INDEX] || "[speaker.GetVoice()]"
+ var/namepart = speaker.get_message_voice(visible_name)
//End name span.
var/endspanpart = ""
@@ -333,9 +319,15 @@ GLOBAL_LIST_INIT(freqtospan, list(
return "2"
return "0"
-/atom/proc/GetVoice()
+/// Get what this atom sounds like when speaking
+/atom/proc/get_voice()
return "[src]" //Returns the atom's name, prepended with 'The' if it's not a proper noun
+/// Get what this atom appears like in chat when speaking
+/// visible_name - If TRUE, returns the visible name rather than the voice
+/atom/proc/get_message_voice(visible_name)
+ return visible_name ? get_visible_name() : get_voice()
+
//HACKY VIRTUALSPEAKER STUFF BEYOND THIS POINT
//these exist mostly to deal with the AIs hrefs and job stuff.
@@ -357,7 +349,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/virtualspeaker)
radio = _radio
source = M
if(istype(M))
- name = radio.anonymize ? "Unknown" : M.GetVoice()
+ name = radio.anonymize ? "Unknown" : M.get_voice()
verb_say = M.get_default_say_verb()
verb_ask = M.verb_ask
verb_exclaim = M.verb_exclaim
diff --git a/code/modules/antagonists/changeling/powers/mimic_voice.dm b/code/modules/antagonists/changeling/powers/mimic_voice.dm
index 99f54304580..e1d895d2b14 100644
--- a/code/modules/antagonists/changeling/powers/mimic_voice.dm
+++ b/code/modules/antagonists/changeling/powers/mimic_voice.dm
@@ -8,11 +8,11 @@
req_human = TRUE
// Fake Voice
-/datum/action/changeling/mimicvoice/sting_action(mob/user)
+/datum/action/changeling/mimicvoice/sting_action(mob/living/carbon/human/user)
var/datum/antagonist/changeling/changeling = IS_CHANGELING(user)
- if(changeling.mimicing)
- changeling.mimicing = ""
+ if(user.override_voice)
changeling.chem_recharge_slowdown -= 0.25
+ user.override_voice = ""
to_chat(user, span_notice("We return our vocal glands to their original position."))
return
@@ -20,16 +20,16 @@
if(!mimic_voice)
return
..()
- changeling.mimicing = mimic_voice
changeling.chem_recharge_slowdown += 0.25
+ user.override_voice = mimic_voice
to_chat(user, span_notice("We shape our glands to take the voice of [mimic_voice], this will slow down regenerating chemicals while active."))
to_chat(user, span_notice("Use this power again to return to our original voice and return chemical production to normal levels."))
return TRUE
-/datum/action/changeling/mimicvoice/Remove(mob/user)
+/datum/action/changeling/mimicvoice/Remove(mob/living/carbon/human/user)
var/datum/antagonist/changeling/changeling = IS_CHANGELING(user)
- if(changeling?.mimicing)
- changeling.chem_recharge_slowdown = max(0, changeling.chem_recharge_slowdown - 0.25)
- changeling.mimicing = ""
+ if(user.override_voice)
+ changeling?.chem_recharge_slowdown = max(0, changeling.chem_recharge_slowdown - 0.25)
+ user.override_voice = ""
to_chat(user, span_notice("Our vocal glands return to their original position."))
. = ..()
diff --git a/code/modules/antagonists/heretic/magic/shadow_cloak.dm b/code/modules/antagonists/heretic/magic/shadow_cloak.dm
index 0012495867a..825e1874c78 100644
--- a/code/modules/antagonists/heretic/magic/shadow_cloak.dm
+++ b/code/modules/antagonists/heretic/magic/shadow_cloak.dm
@@ -141,7 +141,7 @@
animate(cloak_image, alpha = 255, 0.2 SECONDS)
owner.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, id, cloak_image)
// Add the relevant traits and modifiers
- owner.add_traits(list(TRAIT_UNKNOWN, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
+ owner.add_traits(list(TRAIT_UNKNOWN_APPEARANCE, TRAIT_UNKNOWN_VOICE, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
owner.add_movespeed_modifier(/datum/movespeed_modifier/shadow_cloak)
owner.add_actionspeed_modifier(/datum/actionspeed_modifier/shadow_cloak)
// Register signals to cause effects
@@ -157,7 +157,7 @@
owner.remove_alt_appearance(id)
QDEL_NULL(cloak_image)
// Remove traits and modifiers
- owner.remove_traits(list(TRAIT_UNKNOWN, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
+ owner.remove_traits(list(TRAIT_UNKNOWN_APPEARANCE, TRAIT_UNKNOWN_VOICE, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
owner.remove_movespeed_modifier(/datum/movespeed_modifier/shadow_cloak)
owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/shadow_cloak)
// Clear signals
diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm
index ab327817735..3da3c43e1eb 100644
--- a/code/modules/antagonists/heretic/status_effects/buffs.dm
+++ b/code/modules/antagonists/heretic/status_effects/buffs.dm
@@ -345,11 +345,11 @@
alert_type = /atom/movable/screen/alert/status_effect/moon_grasp_hide
/datum/status_effect/moon_grasp_hide/on_apply()
- owner.add_traits(list(TRAIT_UNKNOWN, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
+ owner.add_traits(list(TRAIT_UNKNOWN_APPEARANCE, TRAIT_UNKNOWN_VOICE, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
return TRUE
/datum/status_effect/moon_grasp_hide/on_remove()
- owner.remove_traits(list(TRAIT_UNKNOWN, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
+ owner.remove_traits(list(TRAIT_UNKNOWN_APPEARANCE, TRAIT_UNKNOWN_VOICE, TRAIT_SILENT_FOOTSTEPS), TRAIT_STATUS_EFFECT(id))
/atom/movable/screen/alert/status_effect/moon_grasp_hide
name = "Blessing of The Moon"
diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm
index ffe5eab54ce..62375dc0643 100644
--- a/code/modules/assembly/voice.dm
+++ b/code/modules/assembly/voice.dm
@@ -62,7 +62,7 @@
listening = FALSE
say("Activation message is '[recorded]'.", sanitize = FALSE, language = message_language)
if(RECOGNIZER_MODE)
- recorded = speaker.GetVoice()
+ recorded = speaker.get_voice()
listening = FALSE
say("Your voice pattern is saved.", language = message_language)
if(VOICE_SENSOR_MODE)
@@ -81,7 +81,7 @@
if(raw_message == recorded)
return TRUE
if(RECOGNIZER_MODE)
- if(speaker.GetVoice() == recorded)
+ if(speaker.get_voice() == recorded)
return TRUE
if(VOICE_SENSOR_MODE)
if(length(raw_message))
diff --git a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
index 3749f84d670..a8f03b0b3f9 100644
--- a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
+++ b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
@@ -185,12 +185,15 @@ do { \
w_class = WEIGHT_CLASS_SMALL
actions_types = list(/datum/action/item_action/chameleon/change/mask)
action_slots = ALL
- /// Is our voice changer enabled or disabled?
- var/voice_change = TRUE
+ clothing_traits = list(TRAIT_VOICE_MATCHES_ID)
/obj/item/clothing/mask/chameleon/attack_self(mob/user)
- voice_change = !voice_change
- to_chat(user, span_notice("The voice changer is now [voice_change ? "on" : "off"]!"))
+ var/was_on = (TRAIT_VOICE_MATCHES_ID in clothing_traits)
+ if(was_on)
+ attach_clothing_traits(TRAIT_VOICE_MATCHES_ID)
+ else
+ detach_clothing_traits(TRAIT_VOICE_MATCHES_ID)
+ to_chat(user, span_notice("The voice changer is now [was_on ? "off" : "on"]!"))
/obj/item/clothing/mask/chameleon/broken
@@ -203,7 +206,7 @@ do { \
item_flags = DROPDEL
//Same as the drone chameleon hat, undroppable and no protection
armor_type = /datum/armor/none
- voice_change = FALSE
+ clothing_traits = null
/obj/item/clothing/mask/chameleon/drone/Initialize(mapload)
. = ..()
diff --git a/code/modules/library/skill_learning/generic_skillchips/point.dm b/code/modules/library/skill_learning/generic_skillchips/point.dm
index 8b26e413b7e..23971af80e0 100644
--- a/code/modules/library/skill_learning/generic_skillchips/point.dm
+++ b/code/modules/library/skill_learning/generic_skillchips/point.dm
@@ -26,7 +26,7 @@
/obj/item/skillchip/big_pointer/proc/fancier_pointer(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point)
SIGNAL_HANDLER
- if(HAS_TRAIT(user, TRAIT_UNKNOWN))
+ if(HAS_TRAIT(user, TRAIT_UNKNOWN_APPEARANCE))
return
point.cut_overlays()
var/datum/action/change_pointer_color/action = locate() in actions
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index a562204f65e..d7d3df762be 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -6,7 +6,7 @@
return null
/mob/living/carbon/examine(mob/user)
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
return list(span_warning("You're struggling to make out any details..."))
var/t_He = p_They()
@@ -587,7 +587,7 @@
if(undershirt.has_sensor == BROKEN_SENSORS)
. += list(span_notice("\The [undershirt]'s medical sensors are sparking."))
- if(HAS_TRAIT(src, TRAIT_UNKNOWN) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN))
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN))
return
var/limbs_text = get_mismatched_limb_text()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 79da995c053..c40e6ab1b7b 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -105,7 +105,7 @@
if(!same_id || (text2num(href_list["examine_time"]) + viable_time) < world.time)
to_chat(viewer, span_notice("You don't have that good of a memory. Examine [p_them()] again."))
return
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
to_chat(viewer, span_notice("You can't make out that ID anymore."))
return
if(!isobserver(viewer) && get_dist(viewer, src) > ID_EXAMINE_DISTANCE + 1) // leeway, ignored if the viewer is a ghost
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 78d4db6fa0a..7b455134bc5 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -70,7 +70,8 @@
var/obj/item/l_store = null
var/obj/item/s_store = null
- var/special_voice = "" // For changing our voice. Used by a symptom.
+ /// Allows for special overrides of voice
+ var/override_voice = ""
var/datum/physiology/physiology
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 5a84b21169a..1bcdb336d9f 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -8,7 +8,7 @@
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_assignment(if_no_id = "No id", if_no_job = "No job", hand_first = TRUE)
var/obj/item/card/id/id = get_idcard(hand_first)
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
return if_no_id
if(id)
. = id.assignment
@@ -25,7 +25,7 @@
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_authentification_name(if_no_id = "Unknown")
var/obj/item/card/id/id = get_idcard(FALSE)
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
return if_no_id
if(id)
return id.registered_name
@@ -48,64 +48,66 @@
var/force_set = LAZYACCESS(identity, VISIBLE_NAME_FORCED)
if(force_set) // our name is overriden by something
return signal_face // no need to null-check, because force_set will always set a signal_face
- var/face_name = !isnull(signal_face) ? signal_face : get_face_name("")
- var/id_name = !isnull(signal_id) ? signal_id : get_id_name("")
- if(force_real_name)
- var/fake_name
- if (face_name && face_name != real_name)
- fake_name = face_name
- if(add_id_name && id_name && id_name != real_name)
- if (!isnull(fake_name) && id_name != face_name)
- fake_name = "[fake_name]/[id_name]"
- else
- fake_name = id_name
- if (HAS_TRAIT(src, TRAIT_UNKNOWN) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN) || (!face_name && !id_name))
- fake_name = "Unknown"
- return "[real_name][fake_name ? " (as [fake_name])" : ""]"
- if(HAS_TRAIT(src, TRAIT_UNKNOWN) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN))
- return "Unknown"
- if(face_name)
- if(add_id_name && id_name && (id_name != face_name))
- return "[face_name] (as [id_name])"
- return face_name
- if(id_name)
- return id_name
- return "Unknown"
-/// Returns "Unknown" if facially disfigured and real_name if not.
-/// Useful for setting name when Fluacided or when updating a human's name variable
+ var/face_name = isnull(signal_face) ? get_face_name("") : signal_face
+ var/id_name = isnull(signal_id) ? get_id_name("", honorifics = TRUE) : signal_id
+
+ // We need to account for real name
+ if(force_real_name)
+ var/disguse_name = get_visible_name(add_id_name = TRUE, force_real_name = FALSE)
+ return "[real_name][disguse_name == real_name ? "" : " (as [disguse_name])"]"
+
+ // We're just some unknown guy
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN))
+ return "Unknown"
+
+ // We have a face and an ID
+ if(face_name && id_name)
+ var/normal_id_name = get_id_name("") // need to check base ID name to avoid "John (as Captain John)"
+ if(normal_id_name == face_name)
+ return id_name // (this turns "John" into "Captain John")
+ if(add_id_name)
+ return "[face_name] (as [id_name])"
+
+ // Just go down the list of stuff we recorded
+ return face_name || id_name || "Unknown"
+
+/**
+ * Gets what the face of this mob looks like
+ *
+ * * if_no_face - What to return if we have no face or our face is obscured/disfigured
+ */
/mob/living/carbon/proc/get_face_name(if_no_face = "Unknown")
return real_name
/mob/living/carbon/human/get_face_name(if_no_face = "Unknown")
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
return if_no_face //We're Unknown, no face information for you
if(obscured_slots & HIDEFACE)
return if_no_face
var/obj/item/bodypart/head = get_bodypart(BODY_ZONE_HEAD)
- if(isnull(head) || (HAS_TRAIT(src, TRAIT_DISFIGURED)) || (head.brutestate + head.burnstate) > 2 || !real_name || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN)) //disfigured. use id-name if possible
+ if(isnull(head) || !real_name || HAS_TRAIT(src, TRAIT_DISFIGURED) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN)) //disfigured. use id-name if possible
return if_no_face
return real_name
-//gets name from ID or PDA itself, ID inside PDA doesn't matter
-//Useful when player is being seen by other mobs
-/mob/living/carbon/proc/get_id_name(if_no_id = "Unknown")
+/**
+ * Gets whatever name is in our ID or PDA
+ *
+ * * if_no_id - What to return if we have no ID or PDA
+ * * honorifics - Whether to include honorifics in the returned name (if the found ID has any set)
+ */
+/mob/living/carbon/proc/get_id_name(if_no_id = "Unknown", honorifics = FALSE)
return
-/mob/living/carbon/human/get_id_name(if_no_id = "Unknown")
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
- . = if_no_id //You get NOTHING, no id name, good day sir
+/mob/living/carbon/human/get_id_name(if_no_id = "Unknown", honorifics = FALSE)
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
var/list/identity = list(null, null, null)
SEND_SIGNAL(src, COMSIG_HUMAN_GET_FORCED_NAME, identity)
- if(identity[VISIBLE_NAME_FORCED])
- return identity[VISIBLE_NAME_FACE] // to return forced names when unknown, instead of ID
- else
- var/obj/item/card/id/id = astype(wear_id, /obj/item/card/id) \
- || astype(wear_id, /obj/item/storage/wallet)?.front_id \
- || astype(wear_id, /obj/item/modular_computer)?.stored_id
- . = id?.registered_name
- if(!.)
- . = if_no_id //to prevent null-names making the mob unclickable
+ return identity[VISIBLE_NAME_FORCED] ? identity[VISIBLE_NAME_FACE] : if_no_id
+
+ // either results in an ID card, a generic card, or null
+ var/obj/item/card/id = wear_id?.GetID() || astype(wear_id, /obj/item/card)
+ return id?.get_displayed_name(honorifics) || if_no_id
/mob/living/carbon/human/get_idcard(hand_first = TRUE)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human_say.dm b/code/modules/mob/living/carbon/human/human_say.dm
index 053582174d1..a962b5d33cc 100644
--- a/code/modules/mob/living/carbon/human/human_say.dm
+++ b/code/modules/mob/living/carbon/human/human_say.dm
@@ -29,40 +29,22 @@
return "gurgles"
return tongue.temp_say_mod || tongue.say_mod || ..()
-/mob/living/carbon/human/GetVoice()
- if(HAS_TRAIT(src, TRAIT_UNKNOWN))
- return ("Unknown")
-
- if(istype(wear_mask, /obj/item/clothing/mask/chameleon))
- var/obj/item/clothing/mask/chameleon/V = wear_mask
- if(V.voice_change && wear_id)
- var/obj/item/card/id/idcard = wear_id.GetID()
- if(istype(idcard))
- return idcard.registered_name
- else
- return real_name
- else
- return real_name
-
- if(mind)
- var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling?.mimicing)
- return changeling.mimicing
- if(GetSpecialVoice())
- return GetSpecialVoice()
+/mob/living/carbon/human/get_voice()
+ if(HAS_TRAIT(src, TRAIT_UNKNOWN_VOICE))
+ return "Unknown"
+ var/id_name = get_id_name("")
+ if(HAS_TRAIT(src, TRAIT_VOICE_MATCHES_ID) && id_name)
+ return id_name
+ if(override_voice)
+ return override_voice
+ if(real_name == id_name) // Allows for "Captain John" to have the voice "Captain Join" and not "John"
+ return get_id_name("", honorifics = TRUE)
return real_name
-/mob/living/carbon/human/proc/SetSpecialVoice(new_voice)
- if(new_voice)
- special_voice = new_voice
- return
-
-/mob/living/carbon/human/proc/UnsetSpecialVoice()
- special_voice = ""
- return
-
-/mob/living/carbon/human/proc/GetSpecialVoice()
- return special_voice
+/mob/living/carbon/human/get_message_voice(visible_name)
+ . = ..()
+ if(. != name)
+ . += " (as [get_id_name("Unknown", honorifics = TRUE)])"
/mob/living/carbon/human/binarycheck()
if(stat >= SOFT_CRIT)
diff --git a/code/modules/mob/living/carbon/human/init_signals.dm b/code/modules/mob/living/carbon/human/init_signals.dm
index 06016b7a07c..827716b91a6 100644
--- a/code/modules/mob/living/carbon/human/init_signals.dm
+++ b/code/modules/mob/living/carbon/human/init_signals.dm
@@ -1,10 +1,9 @@
/mob/living/carbon/human/register_init_signals()
. = ..()
- RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_UNKNOWN), SIGNAL_REMOVETRAIT(TRAIT_UNKNOWN)), PROC_REF(update_ID_card))
+ RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_UNKNOWN_APPEARANCE), SIGNAL_REMOVETRAIT(TRAIT_UNKNOWN_APPEARANCE)), PROC_REF(update_ID_card))
RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_DWARF), SIGNAL_REMOVETRAIT(TRAIT_DWARF)), PROC_REF(on_dwarf_trait))
RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_TOO_TALL), SIGNAL_REMOVETRAIT(TRAIT_TOO_TALL)), PROC_REF(on_tootall_trait))
- RegisterSignal(src, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, PROC_REF(get_name_part))
RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT)), PROC_REF(on_fat))
RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_NOHUNGER), SIGNAL_REMOVETRAIT(TRAIT_NOHUNGER)), PROC_REF(on_nohunger))
@@ -33,21 +32,6 @@
SIGNAL_HANDLER
update_mob_height()
-///From compose_message(). Snowflake code converted into its own signal proc
-/mob/living/carbon/human/proc/get_name_part(datum/source, list/stored_name, visible_name)
- SIGNAL_HANDLER
- /**
- * For if the message can be seen but not heard, shows our visible identity (like when using sign language)
- * Also used by hallucinations, so it doesn't give source's identity away.
- */
- if(visible_name)
- stored_name[NAME_PART_INDEX] = get_visible_name()
- return
- var/voice_name = GetVoice()
- if(name != voice_name)
- voice_name += " (as [get_id_name("Unknown")])"
- stored_name[NAME_PART_INDEX] = voice_name
-
/mob/living/carbon/human/proc/on_fat(datum/source)
SIGNAL_HANDLER
hud_used?.hunger?.update_hunger_bar()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index d8352bacb74..bab3c20164b 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -2953,7 +2953,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
/// Create a report string about how strong this person looks, generated in a somewhat arbitrary fashion
/mob/living/proc/compare_fitness(mob/living/scouter)
- if (HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if (HAS_TRAIT(src, TRAIT_UNKNOWN_APPEARANCE))
return span_warning("It's impossible to tell whether this person lifts.")
var/our_fitness_level = calculate_fitness()
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 69c548ab937..d1c35cf77a3 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -424,7 +424,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
if(!M.client.prefs.read_preference(/datum/preference/toggle/enable_runechat) || (SSlag_switch.measures[DISABLE_RUNECHAT] && !HAS_TRAIT(src, TRAIT_BYPASS_MEASURES)))
speech_bubble_recipients.Add(M.client)
found_client = TRUE
- if(SStts.tts_enabled && voice && found_client && !message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] && !HAS_TRAIT(src, TRAIT_SIGN_LANG) && !HAS_TRAIT(src, TRAIT_UNKNOWN))
+ if(SStts.tts_enabled && voice && found_client && !message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] && !HAS_TRAIT(src, TRAIT_SIGN_LANG) && !HAS_TRAIT(src, TRAIT_UNKNOWN_VOICE))
var/tts_message_to_use = tts_message
if(!tts_message_to_use)
tts_message_to_use = message_raw
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 32811c61f80..a0c117593de 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -810,14 +810,14 @@
var/treated_message = source.generate_messagepart(raw_translation, spans, message_mods)
var/start = "Relayed Speech: "
- var/namepart
- var/list/stored_name = list(null)
- SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, FALSE)
- namepart = stored_name[NAME_PART_INDEX] || "[speaker.GetVoice()]"
+ var/namepart = speaker.get_message_voice()
var/hrefpart = ""
var/jobpart = "Unknown"
- if(!HAS_TRAIT(speaker, TRAIT_UNKNOWN)) //don't fetch the speaker's job in case they have something that conseals their identity completely
+ // if voice is concealed, job is concealed
+ // on the other hand we don't care about TRAIT_UNKNOWN_APPEARANCE
+ // (AI can associate voice -> name -> crew record -> job)
+ if(!HAS_TRAIT(speaker, TRAIT_UNKNOWN_VOICE))
if (isliving(speaker))
var/mob/living/living_speaker = speaker
if(living_speaker.job)
@@ -1092,7 +1092,7 @@
. = ..()
.[/datum/job/ai::title] = minutes
-/mob/living/silicon/ai/GetVoice()
+/mob/living/silicon/ai/get_voice()
. = ..()
if(ai_voicechanger && ai_voicechanger.changing_voice)
return ai_voicechanger.say_name
diff --git a/code/modules/mob/living/silicon/silicon_say.dm b/code/modules/mob/living/silicon/silicon_say.dm
index 7e806bbdf8c..c3edff2b94b 100644
--- a/code/modules/mob/living/silicon/silicon_say.dm
+++ b/code/modules/mob/living/silicon/silicon_say.dm
@@ -24,7 +24,7 @@
var/namepart = name
// If carbon, use voice to account for voice changers
if(iscarbon(src))
- namepart = GetVoice()
+ namepart = get_voice()
// AI in carbon body should still have its real name
var/obj/item/organ/brain/cybernetic/ai/brain = get_organ_slot(ORGAN_SLOT_BRAIN)
diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm
index 32b11f23c59..cd2e8ce06d4 100644
--- a/code/modules/mod/modules/modules_antag.dm
+++ b/code/modules/mod/modules/modules_antag.dm
@@ -419,7 +419,7 @@
incompatible_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/welding/syndicate, /obj/item/mod/module/welding, /obj/item/mod/module/headprotector)
required_slots = list(ITEM_SLOT_FEET, ITEM_SLOT_HEAD, ITEM_SLOT_OCLOTHING)
/// List of traits added when the suit is activated
- var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN, TRAIT_HEAD_INJURY_BLOCKED)
+ var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN_APPEARANCE, TRAIT_UNKNOWN_VOICE, TRAIT_HEAD_INJURY_BLOCKED)
/obj/item/mod/module/infiltrator/on_install()
. = ..()
diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm
index 409ead91fdd..6d10524ccba 100644
--- a/code/modules/religion/burdened/psyker.dm
+++ b/code/modules/religion/burdened/psyker.dm
@@ -40,7 +40,7 @@
is_dimorphic = FALSE
should_draw_greyscale = FALSE
bodypart_traits = list(TRAIT_DISFIGURED, TRAIT_BALD, TRAIT_SHAVED)
- head_flags = HEAD_DEBRAIN
+ head_flags = HEAD_DEBRAIN | HEAD_NO_DISFIGURE // ignore disfigurement by damage, as we're always disfigured
/// flavorful variant of psykerizing that deals damage and sends messages before calling psykerize()
/mob/living/carbon/human/proc/slow_psykerize(blind_them = FALSE)
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index 38731efab0a..1dc9ee3069b 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -194,7 +194,7 @@
var/unarmed_sharpness = NONE
/// Traits that are given to the holder of the part. This does not update automatically on life(), only when the organs are initially generated or inserted!
- var/list/bodypart_traits = list()
+ var/list/bodypart_traits
/// The name of the trait source that the organ gives. Should not be altered during the events of gameplay, and will cause problems if it is.
var/bodypart_trait_source = BODYPART_TRAIT
/// List of the above datums which have actually been instantiated, managed automatically
@@ -811,15 +811,15 @@
if(speed_modifier)
old_owner.update_bodypart_speed_modifier()
- if(length(bodypart_traits))
+ if(LAZYLEN(bodypart_traits))
old_owner.remove_traits(bodypart_traits, bodypart_trait_source)
UnregisterSignal(old_owner, list(
SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE),
- SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE),
+ SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE),
SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD),
SIGNAL_ADDTRAIT(TRAIT_NOBLOOD),
- ))
+ ))
UnregisterSignal(old_owner, list(COMSIG_ATOM_RESTYLE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_LIVING_SET_BODY_POSITION))
@@ -831,7 +831,7 @@
if(speed_modifier)
owner.update_bodypart_speed_modifier()
- if(length(bodypart_traits))
+ if(LAZYLEN(bodypart_traits))
owner.add_traits(bodypart_traits, bodypart_trait_source)
if(initial(can_be_disabled))
@@ -872,7 +872,7 @@
item_flags &= ~ABSTRACT
REMOVE_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT)
- if(!length(bodypart_traits))
+ if(!LAZYLEN(bodypart_traits))
return
owner.remove_traits(bodypart_traits, bodypart_trait_source)
@@ -1488,3 +1488,17 @@
return "metal"
return "error"
+
+/// Add a trait to the bodypart traits list, then applies the trait if necessary
+/obj/item/bodypart/proc/add_bodypart_trait(new_trait)
+ LAZYOR(bodypart_traits, new_trait)
+ if(isnull(owner))
+ return
+ ADD_TRAIT(owner, new_trait, bodypart_trait_source)
+
+/// Remove a trait from the bodypart traits list, then removes the trait if necessary
+/obj/item/bodypart/proc/remove_bodypart_trait(old_trait)
+ LAZYREMOVE(bodypart_traits, old_trait)
+ if(isnull(owner))
+ return
+ REMOVE_TRAIT(owner, old_trait, bodypart_trait_source)
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index 347eb6428d4..0214198ad8f 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -34,7 +34,7 @@
/// Replacement name
var/real_name = ""
/// Flags related to appearance, such as hair, lips, etc
- var/head_flags = HEAD_ALL_FEATURES
+ var/head_flags = HEAD_DEFAULT_FEATURES
/// Hair style
var/hairstyle = "Bald"
@@ -210,18 +210,20 @@
. = ..()
AddElement(/datum/element/toy_talk)
-/obj/item/bodypart/head/GetVoice()
+/obj/item/bodypart/head/get_voice()
return "The head of [real_name]"
/obj/item/bodypart/head/update_bodypart_damage_state()
- if (!ishuman(owner))
+ if (head_flags & HEAD_NO_DISFIGURE)
return ..()
+
var/old_states = brutestate + burnstate
. = ..()
var/new_states = brutestate + burnstate
- var/mob/living/carbon/human/as_human = owner
- if ((old_states >= HUMAN_DISFIGURATION_HEAD_DAMAGE_STATES && new_states < HUMAN_DISFIGURATION_HEAD_DAMAGE_STATES) || (old_states < HUMAN_DISFIGURATION_HEAD_DAMAGE_STATES && new_states >= HUMAN_DISFIGURATION_HEAD_DAMAGE_STATES))
- as_human.update_visible_name()
+ if(new_states >= HUMAN_DISFIGURATION_HEAD_DAMAGE_STATES)
+ add_bodypart_trait(TRAIT_DISFIGURED)
+ else if(old_states >= HUMAN_DISFIGURATION_HEAD_DAMAGE_STATES)
+ remove_bodypart_trait(TRAIT_DISFIGURED)
/obj/item/bodypart/head/monkey
icon = 'icons/mob/human/species/monkey/bodyparts.dmi'
diff --git a/code/modules/wiremod/components/atom/hear.dm b/code/modules/wiremod/components/atom/hear.dm
index c846c4c7f83..4dc8812efc0 100644
--- a/code/modules/wiremod/components/atom/hear.dm
+++ b/code/modules/wiremod/components/atom/hear.dm
@@ -53,6 +53,6 @@
if(message_language)
language_port.set_output(initial(message_language.name))
speaker_port.set_output(speaker)
- speaker_name.set_output(speaker.GetVoice())
+ speaker_name.set_output(speaker.get_voice())
trigger_port.set_output(COMPONENT_SIGNAL)
return TRUE