Skip to content

Commit

Permalink
[PORT] [SEMI-MODULAR] [100% FREE LAG] Chat Colors (#157)
Browse files Browse the repository at this point in the history
* Port Chat Colors / effigyse

* Im crazy

* Thenk u mal

* Adds global chat color list

* Apply suggestions from code review

* extra line

* Makes this happen when you spawn as opposed to when you change prefs

Less extra list entries that way

* Adds cyborg support

I think cyborg brain prefs were not working previously, either. Fixes that...

* I forgot about the AI

* Apply suggestions from code review

* Makes user's prefs apply to the TTS device that they are using

---------

Co-authored-by: Giz <[email protected]>
  • Loading branch information
2 people authored and FFMirrorBot committed Jan 4, 2024
1 parent a8c85ec commit 970b280
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 9 deletions.
4 changes: 4 additions & 0 deletions code/__DEFINES/~skyrat_defines/colors.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
#define LIGHT_COLOR_YELLOW "#E1E17D"
#define COLOR_NRI_POLICE_BLUE "#1f3347"
#define COLOR_NRI_POLICE_SILVER "#c0c0c0"

GLOBAL_LIST_INIT(chat_colors_by_mob_name, list(
"Unknown" = list("#ffffff", "#d8d8d8"),
))
4 changes: 2 additions & 2 deletions code/datums/chatmessage.dm
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@

// Calculate target color if not already present
if (!target.chat_color || target.chat_color_name != target.name)
target.chat_color = colorize_string(target.name)
target.chat_color_darkened = colorize_string(target.name, 0.85, 0.85)
target.chat_color = get_chat_color_string(target.name) // NOVA EDIT CHANGE - ORIGINAL: target.chat_color = colorize_string(target.name)
target.chat_color_darkened = get_chat_color_string(target.name, darkened = TRUE) // NOVA EDIT CHANGE - ORIGINAL: target.chat_color_darkened = colorize_string(target.name, 0.85, 0.85)
target.chat_color_name = target.name

// Get rid of any URL schemes that might cause BYOND to automatically wrap something in an anchor tag
Expand Down
4 changes: 4 additions & 0 deletions code/modules/mob/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1285,7 +1285,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) // NOVA EDIT ADDITION - Update the mob chat color list, removing the old name
GLOB.chat_colors_by_mob_name -= oldname // NOVA EDIT ADDITION

if(client) // NOVA 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) // NOVA EDIT ADDITION
log_mob_tag("TAG: [tag] RENAMED: [key_name(src)]")

return TRUE
Expand Down
4 changes: 4 additions & 0 deletions modular_nova/master_files/code/modules/client/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,7 @@
safe_transfer_prefs_to(character, icon_updates, is_antag)
qdel(added_tracker)

// 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
81 changes: 81 additions & 0 deletions modular_nova/modules/chat_colors/code/chat_color.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/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
#define CM_COLOR_SAT_MIN 0
#define CM_COLOR_SAT_MAX 1
#define CM_COLOR_LUM_MIN 0.35
#define CM_COLOR_LUM_MAX 1

/**
* 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 value/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

var/input_hsv = RGBtoHSV(color)
var/list/split_hsv = ReadHSV(input_hsv)
var/split_h = split_hsv[1]
var/split_s = split_hsv[2]
var/split_v = split_hsv[3]
var/processed_s = clamp(split_s, CM_COLOR_SAT_MIN * 255, CM_COLOR_SAT_MAX * 255)
var/processed_v = clamp(split_v, CM_COLOR_LUM_MIN * 255, CM_COLOR_LUM_MAX * 255)
// adjust for shifts
processed_s *= clamp(sat_shift, 0, 1)
processed_v *= clamp(lum_shift, 0, 1)
var/processed_hsv = hsv(split_h, processed_s, processed_v)
var/processed_rgb = HSVtoRGB(processed_hsv)

return processed_rgb

#undef CM_COLOR_LUM_MAX
#undef CM_COLOR_LUM_MIN
#undef CM_COLOR_SAT_MAX
#undef CM_COLOR_SAT_MIN
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@
user.balloon_alert_to_viewers("stops typing", "stopped typing")
playsound(src, 'modular_nova/master_files/sound/items/tts/stopped_type.ogg', 50, TRUE)
return
src.say(str)

chat_color_name = name
chat_color = user.client?.prefs?.read_preference(/datum/preference/color/chat_color)
if(chat_color)
chat_color_darkened = process_chat_color(chat_color, sat_shift = 0.85, lum_shift = 0.85)

say(str)
str = null

/obj/item/ttsdevice/CtrlClick(mob/living/user)
Expand Down
1 change: 1 addition & 0 deletions modular_nova/modules/ghostcafe/code/ghost_role_spawners.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
if(new_spawn.client)
new_spawn.custom_name = null
new_spawn.updatename(new_spawn.client)
new_spawn.transfer_brain_pref(new_spawn.client)
new_spawn.gender = NEUTER
var/area/A = get_area(src)
//new_spawn.AddElement(/datum/element/ghost_role_eligibility, free_ghosting = TRUE) SKYRAT PORT -- Needs to be completely rewritten
Expand Down
52 changes: 46 additions & 6 deletions modular_nova/modules/synths/code/bodyparts/silicon_alt_brains.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,37 @@
/mob/living/silicon/robot/Initialize(mapload)
. = ..()
// Intentionally set like this, because people have different lore for their cyborgs, and there's no real non-invasive way to print posibrains that match.
RegisterSignal(src, COMSIG_MOB_MIND_TRANSFERRED_INTO, PROC_REF(update_brain_type))
RegisterSignal(src, COMSIG_MOB_MIND_TRANSFERRED_INTO, PROC_REF(on_mob_mind_transferred_into))

/// Sets the MMI type for a cyborg, if applicable.
/mob/living/silicon/robot/proc/update_brain_type()
var/obj/item/mmi/new_mmi = prefs_get_brain_to_use(client?.prefs?.read_preference(/datum/preference/choiced/brain_type), TRUE)
if(!mmi || !new_mmi || new_mmi == mmi.type)
/mob/living/silicon/proc/on_mob_mind_transferred_into(mob/living/silicon/robot)
SIGNAL_HANDLER

if(isnull(client))
return

new_mmi = new new_mmi()
transfer_silicon_prefs(client)

/// Transfers the chat color pref to the silicon mob
/mob/living/silicon/proc/transfer_chat_color_pref(client/player_client)
// Read the chat color from prefs and apply it to the mob. Cache it as well in case of any voice changing shenanigans.
var/chat_color_pref = player_client?.prefs?.read_preference(/datum/preference/color/chat_color)
if(chat_color_pref && chat_color != chat_color_pref)
var/chat_color_pref_darkened = process_chat_color(chat_color_pref, sat_shift = 0.85, lum_shift = 0.85)
chat_color = chat_color_pref
chat_color_darkened = chat_color_pref_darkened
GLOB.chat_colors_by_mob_name[real_name] = list(chat_color, chat_color_darkened)

/// Transfers the brain type pref to the silicon mob
/mob/living/silicon/proc/transfer_brain_pref(client/player_client)
return

// This is only implemented for cyborgs at the moment. AI has their own weird way of doing things.
/mob/living/silicon/robot/transfer_brain_pref(client/player_client)
// Read the brain type from prefs and apply it to the mob.
var/obj/item/mmi/new_mmi = prefs_get_brain_to_use(player_client?.prefs?.read_preference(/datum/preference/choiced/brain_type), TRUE)
if(!mmi || !new_mmi || new_mmi == mmi.type)
return
new_mmi = new new_mmi(src)

// Probably shitcode, but silicon code is spaghetti as fuck.
new_mmi.brain = new /obj/item/organ/internal/brain(new_mmi)
Expand All @@ -59,3 +81,21 @@
QDEL_NULL(mmi)

mmi = new_mmi

/// Sets the MMI type for a cyborg/AI, if applicable, as well as the chat color
/mob/living/silicon/proc/transfer_silicon_prefs(client/player_client)
transfer_chat_color_pref(player_client)
transfer_brain_pref(player_client)

/mob/living/silicon/robot/apply_prefs_job(client/player_client, datum/job/job)
. = ..()
transfer_silicon_prefs(player_client)

/mob/living/silicon/ai/apply_prefs_job(client/player_client, datum/job/job)
. = ..()
transfer_silicon_prefs(player_client)

// hooks into this proc in order to make sure chat color prefs get applied
/mob/living/silicon/robot/updatename(client/player_client)
. = ..()
transfer_chat_color_pref(player_client)
1 change: 1 addition & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -6776,6 +6776,7 @@
#include "modular_nova\modules\central_command_module\code\obj\wall.dm"
#include "modular_nova\modules\chadian\code\chadian.dm"
#include "modular_nova\modules\chaplain\code\mortis.dm"
#include "modular_nova\modules\chat_colors\code\chat_color.dm"
#include "modular_nova\modules\clock_cult\code\antagonist.dm"
#include "modular_nova\modules\clock_cult\code\area.dm"
#include "modular_nova\modules\clock_cult\code\globals.dm"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Feature, FeatureColorInput } from '../../base';

export const ic_chat_color: Feature<string> = {
name: 'Chat Message Color',
component: FeatureColorInput,
};

0 comments on commit 970b280

Please sign in to comment.