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 feb531d119..4f2f4ff0b8 100644
--- a/code/__defines/dcs/signals/signals_mob/signals_mob_carbon.dm
+++ b/code/__defines/dcs/signals/signals_mob/signals_mob_carbon.dm
@@ -125,6 +125,7 @@
///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"
+ #define COMPONENT_VISIBLE_NAME_CHANGED (1<<0)
//Index for the name of the face
#define VISIBLE_NAME_FACE 1
//Index for the name of the id
diff --git a/code/__defines/dcs/signals/signals_mob/signals_mob_main.dm b/code/__defines/dcs/signals/signals_mob/signals_mob_main.dm
index 5cd035e537..eb931bbe46 100644
--- a/code/__defines/dcs/signals/signals_mob/signals_mob_main.dm
+++ b/code/__defines/dcs/signals/signals_mob/signals_mob_main.dm
@@ -313,3 +313,10 @@
#define COMSIG_OBSERVER_MOB_EQUIPPED "observer_mob_equipped"
///from end of revival_healing_action(): ()
#define COMSIG_LIVING_AHEAL "living_post_aheal"
+
+///from /mob/living/carbon/human/GetVoice(): (list/voice_data) - voice_data[1] contains the voice name
+#define COMSIG_HUMAN_GET_VOICE "human_get_voice"
+ #define COMPONENT_VOICE_CHANGED (1<<0)
+///from /mob/living/carbon/human/GetAltName(): (list/name_data) - name_data[1] contains the alt name
+#define COMSIG_HUMAN_GET_ALT_NAME "human_get_alt_name"
+ #define COMPONENT_ALT_NAME_CHANGED (1<<0)
diff --git a/code/datums/components/species/shadekin/helpers/comp_helpers.dm b/code/datums/components/species/shadekin/helpers/comp_helpers.dm
index 7664a4e498..d3fd9f7091 100644
--- a/code/datums/components/species/shadekin/helpers/comp_helpers.dm
+++ b/code/datums/components/species/shadekin/helpers/comp_helpers.dm
@@ -268,3 +268,4 @@
flicker_distance = owner.read_preference(/datum/preference/numeric/living/flicker_distance)
no_retreat = owner.read_preference(/datum/preference/toggle/living/dark_retreat_toggle)
nutrition_energy_conversion = owner.read_preference(/datum/preference/toggle/living/shadekin_nutrition_conversion)
+ hide_voice_in_phase = owner.read_preference(/datum/preference/toggle/living/shadekin_hide_voice_in_phase)
diff --git a/code/datums/components/species/shadekin/shadekin.dm b/code/datums/components/species/shadekin/shadekin.dm
index 311cab7f54..2ed5a996f1 100644
--- a/code/datums/components/species/shadekin/shadekin.dm
+++ b/code/datums/components/species/shadekin/shadekin.dm
@@ -26,6 +26,8 @@
var/doing_phase = FALSE
///Are we currently phased?
var/in_phase = FALSE
+ ///If TRUE, voice is hidden when phased (shows as "Something")
+ var/hide_voice_in_phase = TRUE
///Chance to break lights on phase-in
var/flicker_break_chance = 0
///Color that lights will flicker to on phase-in. Off by default.
@@ -108,6 +110,11 @@
else
RegisterSignal(owner, COMSIG_LIVING_LIFE, PROC_REF(handle_comp)) //Happens every life tick (mobs)
+ // Register voice/name signal handlers
+ RegisterSignal(owner, COMSIG_HUMAN_GET_VOICE, PROC_REF(on_get_voice))
+ RegisterSignal(owner, COMSIG_HUMAN_GET_ALT_NAME, PROC_REF(on_get_alt_name))
+ RegisterSignal(owner, COMSIG_HUMAN_GET_VISIBLE_NAME, PROC_REF(on_get_visible_name))
+
//generates powers and then adds them
build_and_add_abilities()
@@ -125,6 +132,7 @@
UnregisterSignal(owner, COMSIG_SHADEKIN_COMPONENT)
else
UnregisterSignal(owner, COMSIG_LIVING_LIFE)
+ UnregisterSignal(owner, list(COMSIG_HUMAN_GET_VOICE, COMSIG_HUMAN_GET_ALT_NAME, COMSIG_HUMAN_GET_VISIBLE_NAME))
remove_verb(owner, /mob/living/proc/shadekin_control_panel)
for(var/datum/power in shadekin_ability_datums)
qdel(power)
@@ -229,6 +237,7 @@
"flicker_distance" = flicker_distance,
"no_retreat" = no_retreat,
"nutrition_energy_conversion" = nutrition_energy_conversion,
+ "hide_voice_in_phase" = hide_voice_in_phase,
"extended_kin" = extended_kin,
"savefile_selected" = correct_savefile_selected()
)
@@ -283,6 +292,34 @@
var/new_retreat = !nutrition_energy_conversion
nutrition_energy_conversion = !nutrition_energy_conversion
ui.user.write_preference_directly(/datum/preference/toggle/living/shadekin_nutrition_conversion, new_retreat, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
+ if("toggle_voice")
+ var/new_voice_hide = !hide_voice_in_phase
+ hide_voice_in_phase = !hide_voice_in_phase
+ ui.user.write_preference_directly(/datum/preference/toggle/living/shadekin_hide_voice_in_phase, new_voice_hide, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
+
+/// Signal handler for GetVoice()
+/datum/component/shadekin/proc/on_get_voice(mob/living/carbon/human/source, list/voice_data)
+ SIGNAL_HANDLER
+
+ if(in_phase && hide_voice_in_phase)
+ voice_data[1] = "Something"
+ return COMPONENT_VOICE_CHANGED
+
+/// Signal handler for GetAltName()
+/datum/component/shadekin/proc/on_get_alt_name(mob/living/carbon/human/source, list/name_data)
+ SIGNAL_HANDLER
+
+ if(in_phase && hide_voice_in_phase)
+ name_data[1] = ""
+ return COMPONENT_ALT_NAME_CHANGED
+
+/// Signal handler for get_visible_name()
+/datum/component/shadekin/proc/on_get_visible_name(mob/living/source, list/name_data)
+ SIGNAL_HANDLER
+
+ if(in_phase && hide_voice_in_phase)
+ name_data[1] = "Something"
+ return COMPONENT_VISIBLE_NAME_CHANGED
/mob/living/proc/shadekin_control_panel()
set name = "Shadekin Control Panel"
diff --git a/code/modules/client/preferences/types/character/general/06_special.dm b/code/modules/client/preferences/types/character/general/06_special.dm
index 0ae50cebc4..feaf10a198 100644
--- a/code/modules/client/preferences/types/character/general/06_special.dm
+++ b/code/modules/client/preferences/types/character/general/06_special.dm
@@ -81,3 +81,14 @@
var/datum/component/shadekin/our_SK = target.get_shadekin_component()
if(our_SK)
our_SK.nutrition_energy_conversion = value
+
+/datum/preference/toggle/living/shadekin_hide_voice_in_phase
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_key = "SHADEKIN_HIDE_VOICE_IN_PHASE"
+ default_value = TRUE
+ savefile_identifier = PREFERENCE_PLAYER
+
+/datum/preference/toggle/living/shadekin_hide_voice_in_phase/apply_to_living(mob/living/target, value)
+ var/datum/component/shadekin/our_SK = target.get_shadekin_component()
+ if(our_SK)
+ our_SK.hide_voice_in_phase = value
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 7fb2d506bb..fedbb9ea7a 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -332,9 +332,10 @@
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere
/mob/living/carbon/human/get_visible_name()
- var/datum/component/shadekin/SK = get_shadekin_component()
- if(SK && SK.in_phase)
- return "Something" // Something
+ var/list/name_data = list(null)
+ if(SEND_SIGNAL(src, COMSIG_HUMAN_GET_VISIBLE_NAME, name_data) & COMPONENT_VISIBLE_NAME_CHANGED)
+ return name_data[1]
+
if(wear_mask && (wear_mask.flags_inv&HIDEFACE)) //Wearing a mask which hides our face, use id-name if possible
return get_id_name("Unknown")
if(head && (head.flags_inv&HIDEFACE))
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index f48f6fd0d5..08c46f4a2a 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -1,7 +1,8 @@
/mob/living/carbon/human/GetAltName()
- var/datum/component/shadekin/SK = get_shadekin_component()
- if(SK && SK.in_phase)
- return ""
+ var/list/name_data = list(null)
+ if(SEND_SIGNAL(src, COMSIG_HUMAN_GET_ALT_NAME, name_data) & COMPONENT_ALT_NAME_CHANGED)
+ return name_data[1]
+
if(absorbed && isbelly(loc))
var/obj/belly/B = loc
if(B.absorbedrename_enabled)
@@ -88,6 +89,12 @@
return ..()
/mob/living/carbon/human/GetVoice()
+ // Allow components to override voice (e.g., shadekin phase hiding)
+ var/list/voice_data = list(null)
+ if(SEND_SIGNAL(src, COMSIG_HUMAN_GET_VOICE, voice_data) & COMPONENT_VOICE_CHANGED)
+ return voice_data[1]
+
+ // Normal voice determination logic
var/voice_sub
if(istype(get_rig(),/obj/item/rig))
var/obj/item/rig/rig = get_rig()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 4c095cb037..51658c5059 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -21,9 +21,10 @@
AddElement(/datum/element/spontaneous_vore)
/mob/living/proc/get_visible_name()
- var/datum/component/shadekin/SK = get_shadekin_component()
- if(SK && SK.in_phase)
- return "Something"
+ var/list/name_data = list(null)
+ if(SEND_SIGNAL(src, COMSIG_HUMAN_GET_VISIBLE_NAME, name_data) & COMPONENT_VISIBLE_NAME_CHANGED)
+ return name_data[1]
+
if(real_name)
return real_name
else
diff --git a/tgui/packages/tgui/interfaces/ShadekinConfig.tsx b/tgui/packages/tgui/interfaces/ShadekinConfig.tsx
index 7168bf580d..70ae4d0ab5 100644
--- a/tgui/packages/tgui/interfaces/ShadekinConfig.tsx
+++ b/tgui/packages/tgui/interfaces/ShadekinConfig.tsx
@@ -23,6 +23,7 @@ type Data = {
extended_kin: BooleanLike;
savefile_selected: BooleanLike;
nutrition_energy_conversion: number;
+ hide_voice_in_phase: BooleanLike;
};
export const ShadekinConfig = (props) => {
@@ -38,13 +39,14 @@ export const ShadekinConfig = (props) => {
savefile_selected,
extended_kin,
nutrition_energy_conversion,
+ hide_voice_in_phase,
} = data;
const isSubtle =
flicker_time < 5 || flicker_break_chance < 5 || flicker_distance < 5;
const windowHeight =
- (isSubtle ? 220 : 190) +
+ (isSubtle ? 285 : 255) +
(extended_kin ? 95 : 0) +
(savefile_selected ? 0 : 90);
@@ -148,6 +150,17 @@ export const ShadekinConfig = (props) => {
+
+
+
+ act('toggle_voice')}
+ />
+
+
+
{!!extended_kin && (