diff --git a/code/__DEFINES/~doppler_defines/colors.dm b/code/__DEFINES/~doppler_defines/colors.dm new file mode 100644 index 0000000000000..683e280cff990 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/colors.dm @@ -0,0 +1,3 @@ +GLOBAL_LIST_INIT(chat_colors_by_mob_name, list( + "Unknown" = list("#ffffff", "#d8d8d8"), +)) diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm index ee278cdae6212..3efa4a4a884a5 100644 --- a/code/datums/chatmessage.dm +++ b/code/datums/chatmessage.dm @@ -159,8 +159,8 @@ // Calculate target color if not already present if (!target.chat_color || target.chat_color_name != chat_color_name_to_use) - target.chat_color = colorize_string(chat_color_name_to_use) - target.chat_color_darkened = colorize_string(chat_color_name_to_use, 0.85, 0.85) + target.chat_color = get_chat_color_string(chat_color_name_to_use) // DOPPLER EDIT CHANGE - ORIGINAL: target.chat_color = colorize_string(chat_color_name_to_use) + target.chat_color_darkened = get_chat_color_string(chat_color_name_to_use, darkened = TRUE) // DOPPLER EDIT CHANGE - ORIGINAL: target.chat_color_darkened = colorize_string(chat_color_name_to_use, 0.85, 0.85) target.chat_color_name = chat_color_name_to_use // Append language icon if the language uses one diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index dda3d0f3ffc1e..3098300115d2e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1189,7 +1189,11 @@ // Only update if this player is a target if(obj.target && obj.target.current && obj.target.current.real_name == name) obj.update_explanation_text() + if(client) // DOPPLER EDIT ADDITION - Update the mob chat color list, removing the old name + GLOB.chat_colors_by_mob_name -= oldname // DOPPLER EDIT ADDITION + if(client) // DOPPLER EDIT ADDITION - Update the mob chat color list, adding the new name + GLOB.chat_colors_by_mob_name[name] = list(chat_color, chat_color_darkened) // DOPPLER EDIT ADDITION log_mob_tag("TAG: [tag] RENAMED: [key_name(src)]") return TRUE diff --git a/modular_doppler/modular_customization/preferences/chat_color.dm b/modular_doppler/modular_customization/preferences/chat_color.dm new file mode 100644 index 0000000000000..7095c72744a48 --- /dev/null +++ b/modular_doppler/modular_customization/preferences/chat_color.dm @@ -0,0 +1,109 @@ +/datum/preference/color/chat_color + category = PREFERENCE_CATEGORY_NON_CONTEXTUAL + priority = PREFERENCE_PRIORITY_NAME_MODIFICATIONS + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "ic_chat_color" + +/datum/preference/color/chat_color/apply_to_human(mob/living/carbon/human/target, value) + target.apply_preference_chat_color(value) + return + +/datum/preference/color/chat_color/deserialize(input, datum/preferences/preferences) + return process_chat_color(sanitize_hexcolor(input)) + +/datum/preference/color/chat_color/create_default_value() + return process_chat_color("#[random_color()]") + +/datum/preference/color/chat_color/serialize(input) + return process_chat_color(sanitize_hexcolor(input)) + +/mob/living/carbon/human/proc/apply_preference_chat_color(value) + if(isnull(value)) + return FALSE + + chat_color = process_chat_color(value, sat_shift = 1, lum_shift = 1) + chat_color_darkened = process_chat_color(value, sat_shift = 0.85, lum_shift = 0.85) + chat_color_name = name + return TRUE + +#define CHAT_COLOR_NORMAL 1 +#define CHAT_COLOR_DARKENED 2 + +/// Get the mob's chat color by looking up their name in the cached list, if no match is found default to colorize_string(). +/datum/chatmessage/proc/get_chat_color_string(name, darkened) + var/chat_color_strings = GLOB.chat_colors_by_mob_name[name] + if(chat_color_strings) + return darkened ? chat_color_strings[CHAT_COLOR_DARKENED] : chat_color_strings[CHAT_COLOR_NORMAL] + if(darkened) + return colorize_string(name, 0.85, 0.85) + + return colorize_string(name) + +#undef CHAT_COLOR_NORMAL +#undef CHAT_COLOR_DARKENED + +// NCM for Nova chatmessage +#define NCM_COLOR_HUE 1 +#define NCM_COLOR_SATURATION 2 +#define NCM_COLOR_LUMINANCE 3 + +#define NCM_COLOR_SAT_MAX 90 // 90% saturation is the default ceiling +#define NCM_COLOR_LUM_MIN 40 // 40% luminosity is the default floor +#define NCM_COLOR_LUM_MIN_GREY 35 // 35% luminosity for greys +#define NCM_COLOR_LUM_MAX_DARK_RANGE 45 // 45% luminosity for dark blues/reds/violets + +#define NCM_COLOR_HUE_RANGE_LOWER 180 +#define NCM_COLOR_HUE_RANGE_UPPER 350 +#define NCM_COLOR_HUE_GREY 0 + +/** + * Converts a given color to comply within a smaller subset of colors to be used in runechat. + * If a color is outside the min/max saturation or lum, it will be set at the nearest + * value that passes validation. + * + * Arguments: + * * color - The color to process + * * sat_shift - A value between 0 and 1 that will be multiplied against the saturation + * * lum_shift - A value between 0 and 1 that will be multiplied against the luminescence + */ +/proc/process_chat_color(color, sat_shift = 1, lum_shift = 1) + if(isnull(color)) + return "#FFFFFF" + + // Convert color hex to HSL + var/hsl_color = rgb2num(color, COLORSPACE_HSL) + + // Hue / saturation / luminance + var/hue = hsl_color[NCM_COLOR_HUE] + var/saturation = hsl_color[NCM_COLOR_SATURATION] + var/luminance = hsl_color[NCM_COLOR_LUMINANCE] + + // Cap the saturation at 90% + saturation = min(saturation, NCM_COLOR_SAT_MAX) + + // Now clamp the luminance according to the hue + var/processed_luminance + + // There are special cases for greyscale and the red/blue/violet range + if(hue == NCM_COLOR_HUE_GREY) + processed_luminance = max(luminance, NCM_COLOR_LUM_MIN_GREY) // greys have a lower floor on the allowed luminance value than the default + else if(NCM_COLOR_HUE_RANGE_UPPER > hue > NCM_COLOR_HUE_RANGE_LOWER) + processed_luminance = min(luminance, NCM_COLOR_LUM_MAX_DARK_RANGE) // colors in the deep reds/blues/violets range will have a slightly higher luminance floor than the default + else + processed_luminance = max(luminance, NCM_COLOR_LUM_MIN) // everything else gets the default floor + + // Convert it back to a hex + return rgb(hue, saturation*sat_shift, processed_luminance*lum_shift, space = COLORSPACE_HSL) + +#undef NCM_COLOR_HUE +#undef NCM_COLOR_SATURATION +#undef NCM_COLOR_LUMINANCE + +#undef NCM_COLOR_SAT_MAX +#undef NCM_COLOR_LUM_MIN +#undef NCM_COLOR_LUM_MIN_GREY +#undef NCM_COLOR_LUM_MAX_DARK_RANGE + +#undef NCM_COLOR_HUE_RANGE_LOWER +#undef NCM_COLOR_HUE_RANGE_UPPER +#undef NCM_COLOR_HUE_GREY diff --git a/modular_doppler/modular_customization/preferences/preferences.dm b/modular_doppler/modular_customization/preferences/preferences.dm index 8d9cbe28c989d..9ed518d142c65 100644 --- a/modular_doppler/modular_customization/preferences/preferences.dm +++ b/modular_doppler/modular_customization/preferences/preferences.dm @@ -2,3 +2,8 @@ /datum/preferences /// Preference of how the preview should show the character. var/preview_pref = PREVIEW_PREF_JOB + +// Updates the mob's chat color in the global cache +/datum/preferences/safe_transfer_prefs_to(mob/living/carbon/human/character, icon_updates = TRUE, is_antag = FALSE) + . = ..() + GLOB.chat_colors_by_mob_name[character.name] = list(character.chat_color, character.chat_color_darkened) // by now the mob has had its prefs applied to it diff --git a/tgstation.dme b/tgstation.dme index 0677d12dcdb6a..2c6317a5610a4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -404,6 +404,7 @@ #include "code\__DEFINES\~doppler_defines\banning.dm" #include "code\__DEFINES\~doppler_defines\cells.dm" #include "code\__DEFINES\~doppler_defines\colony_fabricator_misc.dm" +#include "code\__DEFINES\~doppler_defines\colors.dm" #include "code\__DEFINES\~doppler_defines\construction.dm" #include "code\__DEFINES\~doppler_defines\declarations.dm" #include "code\__DEFINES\~doppler_defines\DNA.dm" @@ -6768,6 +6769,7 @@ #include "modular_doppler\modular_customization\preferences\antennae.dm" #include "modular_doppler\modular_customization\preferences\body_marking_lizard.dm" #include "modular_doppler\modular_customization\preferences\body_marking_moth.dm" +#include "modular_doppler\modular_customization\preferences\chat_color.dm" #include "modular_doppler\modular_customization\preferences\ears.dm" #include "modular_doppler\modular_customization\preferences\fluff.dm" #include "modular_doppler\modular_customization\preferences\frills.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/chat_color.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/chat_color.tsx new file mode 100644 index 0000000000000..45c9139950f76 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/chat_color.tsx @@ -0,0 +1,6 @@ +import { Feature, FeatureColorInput } from '../base'; + +export const ic_chat_color: Feature = { + name: 'Chat Message Color', + component: FeatureColorInput, +};