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