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 dc4d5a25ea0..07954aab2f5 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
@@ -104,3 +104,8 @@
#define MOVABLE_SAY_QUOTE_MESSAGE 1
#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
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm
index f72e47db97a..d73b5e5daf0 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm
@@ -131,6 +131,13 @@
///from /mob/living/carbon/human/proc/force_say(): ()
#define COMSIG_HUMAN_FORCESAY "human_forcesay"
+///from /mob/living/carbon/human/get_visible_name(), not sent if the mob has TRAIT_UNKNOWN: (identity)
+#define COMSIG_HUMAN_GET_VISIBLE_NAME "human_get_visible_name"
+ //Index for the name of the face
+ #define VISIBLE_NAME_FACE 1
+ //Index for the name of the id
+ #define VISIBLE_NAME_ID 2
+
// Mob transformation signals
///Called when a human turns into a monkey, from /mob/living/carbon/proc/finish_monkeyize()
#define COMSIG_HUMAN_MONKEYIZE "human_monkeyize"
diff --git a/code/datums/components/crafting/misc.dm b/code/datums/components/crafting/misc.dm
index dd850874d68..264ff981565 100644
--- a/code/datums/components/crafting/misc.dm
+++ b/code/datums/components/crafting/misc.dm
@@ -34,3 +34,13 @@
)
tool_paths = list(/obj/item/stamp/head/captain)
category = CAT_MISC
+
+/datum/crafting_recipe/cardboard_id
+ name = "Cardboard ID Card"
+ tool_behaviors = list(TOOL_WIRECUTTER)
+ result = /obj/item/card/cardboard
+ time = 4 SECONDS
+ reqs = list(
+ /obj/item/stack/sheet/cardboard = 1,
+ )
+ category = CAT_MISC
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index c4821a30523..ddaf61f3095 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -28,14 +28,28 @@
name = "card"
desc = "Does card things."
icon = 'icons/obj/card.dmi'
+ inhand_icon_state = "card-id"
+ lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
w_class = WEIGHT_CLASS_TINY
-
- var/list/files = list()
+ /// Cached icon that has been built for this card. Intended to be displayed in chat. Cardboards IDs and actual IDs use it.
+ var/icon/cached_flat_icon
/obj/item/card/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] begins to swipe [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
return BRUTELOSS
+/obj/item/card/update_overlays()
+ . = ..()
+ cached_flat_icon = 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)
+ cached_flat_icon = getFlatIcon(src)
+ cached_flat_icon.Crop(ID_ICON_BORDERS)
+ return cached_flat_icon
+
/*
* ID CARDS
*/
@@ -45,17 +59,11 @@
name = "retro identification card"
desc = "A card used to provide ID and determine access across the station."
icon_state = "card_grey"
- inhand_icon_state = "card-id"
worn_icon_state = "nothing"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
slot_flags = ITEM_SLOT_ID
armor_type = /datum/armor/card_id
resistance_flags = FIRE_PROOF | ACID_PROOF
- /// Cached icon that has been built for this card. Intended for use in chat.
- var/icon/cached_flat_icon
-
/// The name registered on the card (for example: Dr Bryan See)
var/registered_name = null
/// Linked bank account.
@@ -136,18 +144,6 @@
. = ..()
. += list("[icon2html(get_cached_flat_icon(), user, extra_classes = "bigicon")]")
-/obj/item/card/id/update_overlays()
- . = ..()
-
- cached_flat_icon = null
-
-/// If no cached_flat_icon exists, this proc creates it and crops it. This proc then returns the cached_flat_icon. Intended only for use displaying ID card icons in chat.
-/obj/item/card/id/proc/get_cached_flat_icon()
- if(!cached_flat_icon)
- cached_flat_icon = getFlatIcon(src)
- cached_flat_icon.Crop(ID_ICON_BORDERS)
- return cached_flat_icon
-
/obj/item/card/id/get_examine_string(mob/user, thats = FALSE)
return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]"
@@ -1194,8 +1190,6 @@
desc = "You are a number, you are not a free man."
icon_state = "card_prisoner"
inhand_icon_state = "orange-id"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
registered_name = "Scum"
registered_age = null
trim = /datum/id_trim/job/prisoner
@@ -1648,3 +1642,159 @@
#undef INTERN_THRESHOLD_FALLBACK_HOURS
#undef ID_ICON_BORDERS
#undef HOLOPAY_PROJECTION_INTERVAL
+
+#define INDEX_NAME_COLOR 1
+#define INDEX_ASSIGNMENT_COLOR 2
+#define INDEX_TRIM_COLOR 3
+
+/**
+ * A fake ID card any silly-willy can craft with wirecutters, cardboard and a writing utensil
+ * Beside the gimmick of changing the visible name when worn, they do nothing. They cannot have an account.
+ * They don't fit in PDAs nor wallets, They have no access. They won't trick securitrons. They won't work with chameleon masks.
+ * Etcetera etcetera. Furthermore, talking, or getting examined on will pretty much give it away.
+ */
+/obj/item/card/cardboard
+ name = "cardboard identification card"
+ desc = "A card used to provice ID and det- Heeeey, wait a second, this is just a piece of cut cardboard!"
+ icon_state = "cardboard_id"
+ inhand_icon_state = "cardboard-id"
+ worn_icon_state = "nothing"
+ resistance_flags = FLAMMABLE
+ slot_flags = ITEM_SLOT_ID
+ ///The "name" of the "owner" of this "ID"
+ var/scribbled_name
+ ///The assignment written on this card.
+ var/scribbled_assignment
+ ///An icon state used as trim.
+ var/scribbled_trim
+ ///The colors for each of the above variables, for when overlays are updated.
+ var/details_colors = list("#000000", "#000000", "#000000")
+
+/obj/item/card/cardboard/equipped(mob/user, slot, initial = FALSE)
+ . = ..()
+ if(slot == ITEM_SLOT_ID)
+ 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))
+
+/obj/item/card/cardboard/dropped(mob/user, silent = FALSE)
+ . = ..()
+ UnregisterSignal(user, list(COMSIG_HUMAN_GET_VISIBLE_NAME, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART))
+
+/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/attackby(obj/item/item, mob/living/user, params)
+ if(user.can_write(item, TRUE))
+ INVOKE_ASYNC(src, PROC_REF(modify_card), user, item)
+ return TRUE
+ return ..()
+
+///Lets the user write a name, assignment or trim on the card, or reset it. Only the name is important for the component.
+/obj/item/card/cardboard/proc/modify_card(mob/living/user, obj/item/item)
+ if(!user.mind)
+ return
+ var/popup_input = tgui_input_list(user, "What To Change", "Cardboard ID", list("Name", "Assignment", "Trim", "Reset"))
+ if(!after_input_check(user, item, popup_input))
+ return
+ switch(popup_input)
+ if("Name")
+ var/input_name = tgui_input_text(user, "What name would you like to put on this card?", "Cardboard card name", scribbled_name || (ishuman(user) ? user.real_name : user.name), MAX_NAME_LEN)
+ input_name = sanitize_name(input_name, allow_numbers = TRUE)
+ if(!after_input_check(user, item, input_name, scribbled_name))
+ return
+ scribbled_name = input_name
+ var/list/details = item.get_writing_implement_details()
+ details_colors[INDEX_NAME_COLOR] = details["color"] || "#000000"
+ if("Assignment")
+ var/input_assignment = tgui_input_text(user, "What assignment would you like to put on this card?", "Cardboard card job ssignment", scribbled_assignment || "Assistant", MAX_NAME_LEN)
+ if(!after_input_check(user, item, input_assignment, scribbled_assignment))
+ return
+ scribbled_assignment = input_assignment
+ var/list/details = item.get_writing_implement_details()
+ details_colors[INDEX_ASSIGNMENT_COLOR] = details["color"] || "#000000"
+ if("Trim")
+ var/static/list/possible_trims
+ if(!possible_trims)
+ possible_trims = list()
+ for(var/trim_path in typesof(/datum/id_trim))
+ var/datum/id_trim/trim = SSid_access.trim_singletons_by_path[trim_path]
+ if(trim?.trim_state && trim.assignment)
+ possible_trims |= replacetext(trim.trim_state, "trim_", "")
+ sortTim(possible_trims, GLOBAL_PROC_REF(cmp_typepaths_asc))
+ var/input_trim = tgui_input_list(user, "Select trim to apply to your card.\nNote: This will not grant any trim accesses.", "Forge Trim", possible_trims)
+ if(!input_trim || !after_input_check(user, item, input_trim, scribbled_trim))
+ return
+ scribbled_trim = "cardboard_[input_trim]"
+ var/list/details = item.get_writing_implement_details()
+ details_colors[INDEX_TRIM_COLOR] = details["color"] || "#000000"
+ if("Reset")
+ scribbled_name = null
+ scribbled_assignment = null
+ scribbled_trim = null
+ details_colors = list("#000000", "#000000", "#000000")
+
+ update_appearance()
+
+///Checks that the conditions to be able to modify the cardboard card are still present after user input calls.
+/obj/item/card/cardboard/proc/after_input_check(mob/living/user, obj/item/item, input, value)
+ if(!input || (value && input == value))
+ return FALSE
+ if(QDELETED(user) || QDELETED(item) || QDELETED(src) || user.incapacitated() || !user.is_holding(item) || !user.CanReach(src) || !user.can_write(item))
+ return FALSE
+ return TRUE
+
+/obj/item/card/cardboard/attack_self(mob/user)
+ if(!Adjacent(user))
+ return
+ user.visible_message(span_notice("[user] shows you: [icon2html(src, viewers(user))] [name]."), span_notice("You show \the [name]."))
+ add_fingerprint(user)
+
+/obj/item/card/cardboard/update_name()
+ . = ..()
+ if(!scribbled_name)
+ name = initial(name)
+ return
+ name = "[scribbled_name]'s ID Card ([scribbled_assignment])"
+
+/obj/item/card/cardboard/update_overlays()
+ . = ..()
+ if(scribbled_name)
+ var/mutable_appearance/name_overlay = mutable_appearance(icon, "cardboard_name")
+ name_overlay.color = details_colors[INDEX_NAME_COLOR]
+ . += name_overlay
+ if(scribbled_assignment)
+ var/mutable_appearance/assignment_overlay = mutable_appearance(icon, "cardboard_assignment")
+ assignment_overlay.color = details_colors[INDEX_ASSIGNMENT_COLOR]
+ . += assignment_overlay
+ if(scribbled_trim)
+ var/mutable_appearance/frame_overlay = mutable_appearance(icon, "cardboard_frame")
+ frame_overlay.color = details_colors[INDEX_TRIM_COLOR]
+ . += frame_overlay
+ var/mutable_appearance/trim_overlay = mutable_appearance(icon, scribbled_trim)
+ trim_overlay.color = details_colors[INDEX_TRIM_COLOR]
+ . += trim_overlay
+
+/obj/item/card/cardboard/get_id_examine_strings(mob/user)
+ . = ..()
+ . += list("[icon2html(get_cached_flat_icon(), user, extra_classes = "bigicon")]")
+
+/obj/item/card/cardboard/get_examine_string(mob/user, thats = FALSE)
+ return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]"
+
+/obj/item/card/cardboard/examine(mob/user)
+ . = ..()
+ . += span_notice("You could use a pen or crayon to forge a name, assignment or trim.")
+
+#undef INDEX_NAME_COLOR
+#undef INDEX_ASSIGNMENT_COLOR
+#undef INDEX_TRIM_COLOR
diff --git a/code/game/objects/items/emags.dm b/code/game/objects/items/emags.dm
index 84eb1d50139..56da7757c0a 100644
--- a/code/game/objects/items/emags.dm
+++ b/code/game/objects/items/emags.dm
@@ -11,9 +11,6 @@
desc = "It's a card with a magnetic strip attached to some circuitry."
name = "cryptographic sequencer"
icon_state = "emag"
- inhand_icon_state = "card-id"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
slot_flags = ITEM_SLOT_ID
worn_icon_state = "emag"
@@ -40,11 +37,8 @@
desc = "It's a card with a magnetic strip attached to some circuitry. Closer inspection shows that this card is a poorly made replica, with a \"Donk Co.\" logo stamped on the back."
name = "cryptographic sequencer"
icon_state = "emag"
- inhand_icon_state = "card-id"
slot_flags = ITEM_SLOT_ID
worn_icon_state = "emag"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
/obj/item/card/emagfake/attack_self(mob/user) //for assistants with balls of plasteel
if(Adjacent(user))
diff --git a/code/game/say.dm b/code/game/say.dm
index 1a5c6525741..528c81c656d 100644
--- a/code/game/say.dm
+++ b/code/game/say.dm
@@ -104,7 +104,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
if(voice && found_client)
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), src, html_decode(tts_message_to_use), message_language, voice, filter.Join(","), listened, message_range = range, pitch = pitch, silicon = tts_silicon_voice_effect)
-/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), face_name = FALSE, visible_name = FALSE)
+/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), visible_name = FALSE)
//This proc uses [] because it is faster than continually appending strings. Thanks BYOND.
//Basic span
var/spanpart1 = ""
@@ -113,13 +113,11 @@ GLOBAL_LIST_INIT(freqtospan, list(
//Radio freq/name display
var/freqpart = radio_freq ? "\[[get_radio_name(radio_freq)]\] " : ""
//Speaker name
- var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]"
- if(face_name && ishuman(speaker))
- var/mob/living/carbon/human/H = speaker
- namepart = "[H.get_face_name()]" //So "fake" speaking like in hallucinations does not give the speaker away if disguised
- else if(visible_name && ishuman(speaker))
- var/mob/living/carbon/human/human_speaker = speaker
- namepart = "[human_speaker.get_visible_name()]" //For if the message can be seen but not heard, shows "speaker"'s visible identity (like when using sign language)
+ var/namepart
+ var/list/stored_name = list(null)
+ SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, visible_name)
+ namepart = stored_name[NAME_PART_INDEX] || "[speaker.GetVoice()]"
+
//End name span.
var/endspanpart = ""
@@ -236,8 +234,6 @@ GLOBAL_LIST_INIT(freqtospan, list(
/atom/movable/proc/GetVoice()
return "[src]" //Returns the atom's name, prepended with 'The' if it's not a proper noun
-/atom/movable/proc/get_alt_name()
-
//HACKY VIRTUALSPEAKER STUFF BEYOND THIS POINT
//these exist mostly to deal with the AIs hrefs and job stuff.
diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm
index 064b77cb518..f8bef933790 100644
--- a/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm
+++ b/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm
@@ -94,13 +94,18 @@
if(ishuman(loc))
var/mob/living/carbon/human/wearer = loc
new /obj/effect/temp_visual/dir_setting/ninja/cloak(get_turf(wearer), wearer.dir)
- wearer.name_override = disguise.name
+ RegisterSignal(wearer, COMSIG_HUMAN_GET_VISIBLE_NAME, PROC_REF(return_disguise_name))
wearer.icon = disguise.icon
wearer.icon_state = disguise.icon_state
wearer.cut_overlays()
wearer.add_overlay(disguise.overlays)
wearer.update_held_items()
+/obj/item/clothing/suit/armor/abductor/vest/proc/return_disguise_name(mob/living/carbon/human/source, list/identity)
+ SIGNAL_HANDLER
+ identity[VISIBLE_NAME_FACE] = disguise.name
+ identity[VISIBLE_NAME_ID] = ""
+
/obj/item/clothing/suit/armor/abductor/vest/proc/DeactivateStealth()
if(!stealth_active)
return
@@ -108,7 +113,7 @@
if(ishuman(loc))
var/mob/living/carbon/human/wearer = loc
new /obj/effect/temp_visual/dir_setting/ninja(get_turf(wearer), wearer.dir)
- wearer.name_override = null
+ UnregisterSignal(wearer, COMSIG_HUMAN_GET_VISIBLE_NAME)
wearer.cut_overlays()
wearer.regenerate_icons()
diff --git a/code/modules/hallucination/fake_chat.dm b/code/modules/hallucination/fake_chat.dm
index 47a99d2088b..049a337c110 100644
--- a/code/modules/hallucination/fake_chat.dm
+++ b/code/modules/hallucination/fake_chat.dm
@@ -34,7 +34,7 @@
humans += crew_mind.current
if(humans.len)
speaker = pick(humans)
-
+
if(!speaker)
return
@@ -87,7 +87,7 @@
hallucinator.create_chat_message(speaker, understood_language, chosen, spans)
// And actually show them the message, for real.
- var/message = hallucinator.compose_message(speaker, understood_language, chosen, is_radio ? "[FREQ_COMMON]" : null, spans, face_name = TRUE)
+ var/message = hallucinator.compose_message(speaker, understood_language, chosen, is_radio ? "[FREQ_COMMON]" : null, spans, visible_name = TRUE)
to_chat(hallucinator, message)
// Then clean up.
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 26b070dc5c6..36dcc80fa12 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -61,8 +61,6 @@
var/special_voice = "" // For changing our voice. Used by a symptom.
- var/name_override //For temporary visible name changes
-
var/datum/physiology/physiology
var/list/datum/bioware/biowares
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index f61d19ff318..805dc01249a 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -58,12 +58,14 @@
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a separate proc as it'll be useful elsewhere
/mob/living/carbon/human/get_visible_name()
- var/face_name = get_face_name("")
- var/id_name = get_id_name("")
if(HAS_TRAIT(src, TRAIT_UNKNOWN))
return "Unknown"
- if(name_override)
- return name_override
+ var/list/identity = list(null, null)
+ SEND_SIGNAL(src, COMSIG_HUMAN_GET_VISIBLE_NAME, identity)
+ var/signal_face = LAZYACCESS(identity, VISIBLE_NAME_FACE)
+ var/signal_id = LAZYACCESS(identity, VISIBLE_NAME_ID)
+ var/face_name = !isnull(signal_face) ? signal_face : get_face_name("")
+ var/id_name = !isnull(signal_id) ? signal_id : get_id_name("")
if(face_name)
if(id_name && (id_name != face_name))
return "[face_name] (as [id_name])"
diff --git a/code/modules/mob/living/carbon/human/human_say.dm b/code/modules/mob/living/carbon/human/human_say.dm
index 7089e5ed048..27298f466dd 100644
--- a/code/modules/mob/living/carbon/human/human_say.dm
+++ b/code/modules/mob/living/carbon/human/human_say.dm
@@ -82,7 +82,3 @@
return ITALICS | REDUCE_RANGE
return FALSE
-
-/mob/living/carbon/human/get_alt_name()
- if(name != GetVoice())
- return " (as [get_id_name("Unknown")])"
diff --git a/code/modules/mob/living/carbon/human/init_signals.dm b/code/modules/mob/living/carbon/human/init_signals.dm
index 44a377c2b3d..9a4a55bb7ac 100644
--- a/code/modules/mob/living/carbon/human/init_signals.dm
+++ b/code/modules/mob/living/carbon/human/init_signals.dm
@@ -3,6 +3,7 @@
RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_UNKNOWN), SIGNAL_REMOVETRAIT(TRAIT_UNKNOWN)), PROC_REF(on_unknown_trait))
RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_DWARF), SIGNAL_REMOVETRAIT(TRAIT_DWARF)), PROC_REF(on_dwarf_trait))
+ RegisterSignal(src, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, PROC_REF(get_name_part))
/// Gaining or losing [TRAIT_UNKNOWN] updates our name and our sechud
/mob/living/carbon/human/proc/on_unknown_trait(datum/source)
@@ -22,3 +23,18 @@
passtable_on(src, TRAIT_DWARF)
else
passtable_off(src, TRAIT_DWARF)
+
+///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
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 62a3f10f6b8..5c06bc69e39 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -288,7 +288,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args)
if(HAS_TRAIT(speaker, TRAIT_SIGN_LANG)) //Checks if speaker is using sign language
- deaf_message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mods, FALSE, TRUE)
+ deaf_message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mods, TRUE)
if(speaker != src)
if(!radio_freq) //I'm about 90% sure there's a way to make this less cluttered
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 4fa56abf9b2..c0f093c38c6 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -893,7 +893,10 @@
var/treated_message = source.say_quote(raw_translation, spans, message_mods)
var/start = "Relayed Speech: "
- var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]"
+ 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/hrefpart = ""
var/jobpart = "Unknown"
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 9e1e3ecf138..5e2ef600a67 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1234,10 +1234,16 @@
* Proc that returns TRUE if the mob can write using the writing_instrument, FALSE otherwise.
*
* This proc a side effect, outputting a message to the mob's chat with a reason if it returns FALSE.
+ * Unless silent_if_not_writing_tool is TRUE. In that case it'll be silent if it isn't a writing implement/tool/instrument w/e.
*/
-/mob/proc/can_write(obj/item/writing_instrument)
- if(!istype(writing_instrument))
- to_chat(src, span_warning("You can't write with the [writing_instrument]!"))
+/mob/proc/can_write(obj/item/writing_instrument, silent_if_not_writing_tool = FALSE)
+ if(!writing_instrument)
+ return FALSE
+
+ var/pen_info = writing_instrument.get_writing_implement_details()
+ if(!pen_info || (pen_info["interaction_mode"] != MODE_WRITING))
+ if(!silent_if_not_writing_tool)
+ to_chat(src, span_warning("You can't write with the [writing_instrument]!"))
return FALSE
if(HAS_MIND_TRAIT(src, TRAIT_MIMING) && !istype(writing_instrument, /obj/item/toy/crayon/mime))
@@ -1252,11 +1258,6 @@
to_chat(src, span_warning("It's too dark in here to write anything!"))
return FALSE
- var/pen_info = writing_instrument.get_writing_implement_details()
- if(!pen_info || (pen_info["interaction_mode"] != MODE_WRITING))
- to_chat(src, span_warning("You can't write with the [writing_instrument]!"))
- return FALSE
-
if(has_gravity())
return TRUE
diff --git a/icons/mob/inhands/equipment/idcards_lefthand.dmi b/icons/mob/inhands/equipment/idcards_lefthand.dmi
index 53b40584e7b..90b96bd4d47 100644
Binary files a/icons/mob/inhands/equipment/idcards_lefthand.dmi and b/icons/mob/inhands/equipment/idcards_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/idcards_righthand.dmi b/icons/mob/inhands/equipment/idcards_righthand.dmi
index 19a6f77c283..a4b0ec4bb74 100644
Binary files a/icons/mob/inhands/equipment/idcards_righthand.dmi and b/icons/mob/inhands/equipment/idcards_righthand.dmi differ
diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi
index 95a5504f18c..a5c4e828301 100644
Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ